summaryrefslogtreecommitdiff
path: root/engine/src/rendering/main_render_pass.rs
diff options
context:
space:
mode:
Diffstat (limited to 'engine/src/rendering/main_render_pass.rs')
-rw-r--r--engine/src/rendering/main_render_pass.rs394
1 files changed, 325 insertions, 69 deletions
diff --git a/engine/src/rendering/main_render_pass.rs b/engine/src/rendering/main_render_pass.rs
index c3278fa..225b89a 100644
--- a/engine/src/rendering/main_render_pass.rs
+++ b/engine/src/rendering/main_render_pass.rs
@@ -14,7 +14,12 @@ use crate::draw_flags::{DrawFlags, NoDraw, PolygonModeConfig};
use crate::ecs::query::term::{With, Without};
use crate::ecs::sole::Single;
use crate::ecs::Query;
-use crate::error;
+use crate::lighting::{
+ DirectionalLight,
+ Environmental as EnvironmentalLighting,
+ PointLight,
+};
+use crate::material::{Flags as MaterialFlags, Material};
use crate::mesh::Mesh;
use crate::model::{MaterialSearchResult, Model};
use crate::projection::ClipVolume as ProjectionClipVolume;
@@ -24,12 +29,11 @@ use crate::rendering::shader::cursor::{
BindingValue as ShaderBindingValue,
Cursor as ShaderCursor,
};
-use crate::rendering::shader::default::ASSET_LABEL as DEFAULT_SHADER_ASSET_LABEL;
use crate::rendering::shader::{
Context as ShaderContext,
EntrypointFlags as ShaderEntrypointFlags,
ModuleSource as ShaderModuleSource,
- Shader,
+ Program as ShaderProgram,
};
use crate::rendering::{
AssetOrValue,
@@ -40,7 +44,6 @@ use crate::rendering::{
DrawProperties,
DrawPropertiesUpdateFlags,
MeshUsage,
- PendingShaderBindings,
RenderPass,
RenderPasses,
SurfaceSpec,
@@ -63,9 +66,9 @@ use crate::windowing::window::Window;
type RenderableEntity<'a> = (
&'a Model,
Traverse<(With<Scene>, With<ActiveScene>), TraverseUp, ChildOf>,
+ Option<&'a MaterialFlags>,
+ Option<&'a Transform>,
Option<&'a DrawFlags>,
- Option<&'a Shader>,
- Option<&'a mut PendingShaderBindings>,
Without<NoDraw>,
);
@@ -75,6 +78,12 @@ pub static SKY_BOX_SHADER_ASSET_LABEL: LazyLock<AssetLabel> =
name: Some("sky_box_shader".into()),
});
+pub static MAIN_3D_SHADER_ASSET_LABEL: LazyLock<AssetLabel> =
+ LazyLock::new(|| AssetLabel {
+ path: Path::new("").into(),
+ name: Some("main_3d_shader".into()),
+ });
+
struct SkyBoxIds
{
texture_object: ObjectId,
@@ -94,11 +103,21 @@ pub fn add_main_render_pass(
)>,
window_query: Query<(&Window, &SurfaceSpec, With<TargetWindow>)>,
scene_query: Query<(
+ Option<&EnvironmentalLighting>,
Option<&SkyBox>,
Option<&SkyBoxState>,
With<Scene>,
With<ActiveScene>,
)>,
+ point_light_query: Query<(
+ &PointLight,
+ &Transform,
+ Traverse<(With<Scene>, With<ActiveScene>), TraverseUp, ChildOf>,
+ )>,
+ directional_light_query: Query<(
+ &DirectionalLight,
+ Traverse<(With<Scene>, With<ActiveScene>), TraverseUp, ChildOf>,
+ )>,
shader_context: Single<ShaderContext>,
mut assets: Single<Assets>,
mut render_passes: Single<RenderPasses>,
@@ -111,7 +130,7 @@ pub fn add_main_render_pass(
let render_passes = render_passes.get_mut()?;
let object_store = object_store.get_mut()?;
- let Some((scene_ent_id, (scene_skybox, scene_skybox_stuff))) =
+ let Some((scene_ent_id, (scene_env_lighting, scene_skybox, scene_skybox_state))) =
scene_query.iter_with_euids().next()
else {
return Ok(());
@@ -122,10 +141,23 @@ pub fn add_main_render_pass(
return Ok(());
};
- let Some(default_shader_asset) = assets
- .get_handle_to_loaded::<ShaderModuleSource>(DEFAULT_SHADER_ASSET_LABEL.clone())
+ let Some(main_3d_shader_asset) = assets
+ .get_handle_to_loaded::<ShaderModuleSource>(MAIN_3D_SHADER_ASSET_LABEL.clone())
else {
- return Err(error!("Default shader asset is not loaded"));
+ assets.store_with_label(
+ MAIN_3D_SHADER_ASSET_LABEL.clone(),
+ ShaderModuleSource {
+ name: "main_3d_shader.slang".into(),
+ file_path: Path::new("@engine/main_3d_shader").into(),
+ source: include_str!("../../res/main_3d_shader.slang").into(),
+ link_entrypoints: ShaderEntrypointFlags::VERTEX
+ | ShaderEntrypointFlags::FRAGMENT,
+ },
+ );
+
+ // shader has to be processed
+
+ return Ok(());
};
let render_pass = render_passes.passes.push_front_mut(RenderPass {
@@ -157,7 +189,7 @@ pub fn add_main_render_pass(
load_sky_box(
scene_ent_id,
&scene_skybox,
- scene_skybox_stuff.as_deref(),
+ scene_skybox_state.as_deref(),
assets,
object_store,
shader_context,
@@ -176,23 +208,7 @@ pub fn add_main_render_pass(
.commands
.push(Command::ClearBuffers(buf_clear_mask));
- for (model, draw_flags, shader, mut pending_shader_bindings) in &renderable_query
- {
- let shader_asset = match &shader {
- Some(shader) => &shader.asset_handle,
- None => &default_shader_asset,
- };
-
- let Some(pending_shader_bindings) = pending_shader_bindings.as_mut() else {
- continue;
- };
-
- if pending_shader_bindings.bindings.is_empty()
- && pending_shader_bindings.surface_specific_bindings.is_empty()
- {
- continue;
- }
-
+ for (model, material_flags, transform, draw_flags) in &renderable_query {
let Some(model_spec) = assets.get(&model.spec_asset) else {
continue;
};
@@ -207,45 +223,53 @@ pub fn add_main_render_pass(
debug_assert!(model_spec.material_names.len() <= 1);
- let model_material_asset = match model_spec.find_first_material(&assets) {
+ let model_material = match model_spec.find_first_material(&assets) {
MaterialSearchResult::Found(model_material_asset) => {
- model_material_asset.clone()
- // Some(model_material_asset.clone())
+ let Some(model_material) = assets.get(&model_material_asset) else {
+ continue;
+ };
+
+ model_material
}
- MaterialSearchResult::NotFound | MaterialSearchResult::NoMaterials => {
- // MaterialSearchResult::NotFound => {
+ MaterialSearchResult::NotFound => {
continue;
- } // MaterialSearchResult::NoMaterials => None,
+ }
+ MaterialSearchResult::NoMaterials => &Material::builder().build(),
};
- if !object_store
- .contains_maybe_pending_with_id(&ObjectId::Asset(shader_asset.id()))
+ if model_material
+ .textures()
+ .any(|texture_asset| !assets.is_loaded_and_has_type(&texture_asset))
{
- let Some(shader_program) = shader_context.get_program(&shader_asset.id())
- else {
- tracing::error!(
- "Shader context doesn't have a program for shader asset {:?}",
- assets.get_label(&shader_asset)
- );
- continue;
- };
+ continue;
+ }
- object_store.insert_pending(ObjectId::Asset(shader_asset.id()));
+ let Some(shader_program) =
+ shader_context.get_program(&main_3d_shader_asset.id())
+ else {
+ tracing::error!(
+ "Shader context doesn't have a program for shader asset {:?}",
+ assets.get_label(&main_3d_shader_asset)
+ );
+ continue;
+ };
+
+ if !object_store.contains_maybe_pending_with_id(&ObjectId::Asset(
+ main_3d_shader_asset.id(),
+ )) {
+ object_store.insert_pending(ObjectId::Asset(main_3d_shader_asset.id()));
render_pass.commands.push(Command::CreateShaderProgram(
- ObjectId::Asset(shader_asset.id()),
+ ObjectId::Asset(main_3d_shader_asset.id()),
shader_program.clone(),
));
}
render_pass
.commands
- .push(Command::ActivateShader(ObjectId::Asset(shader_asset.id())));
-
- let Some(model_material) = assets.get(&model_material_asset) else {
- // TODO: Handle this case since it may occur
- unreachable!();
- };
+ .push(Command::ActivateShader(ObjectId::Asset(
+ main_3d_shader_asset.id(),
+ )));
for texture_asset in [
&model_material.ambient_map,
@@ -267,23 +291,21 @@ pub fn add_main_render_pass(
}
}
- for shader_binding in &pending_shader_bindings.bindings {
- render_pass
- .commands
- .push(Command::SetShaderBinding(shader_binding.clone()));
- }
-
- for (shader_binding_surface_id, shader_binding) in
- &pending_shader_bindings.surface_specific_bindings
- {
- if *shader_binding_surface_id != surface_spec.id {
- continue;
- }
-
- render_pass
- .commands
- .push(Command::SetShaderBinding(shader_binding.clone()));
- }
+ add_set_3d_shader_bindings(
+ render_pass,
+ (
+ model_material,
+ material_flags.as_deref(),
+ transform.as_deref(),
+ ),
+ scene_env_lighting.as_deref(),
+ (&camera, &camera_transform),
+ &window,
+ &point_light_query,
+ &directional_light_query,
+ assets,
+ shader_program,
+ )?;
if let Some(draw_flags) = draw_flags.as_deref().and_then(|draw_flags| {
if draw_flags.polygon_mode_config != PolygonModeConfig::default() {
@@ -403,6 +425,240 @@ pub fn add_main_render_pass(
Ok(())
}
+fn add_set_3d_shader_bindings(
+ render_pass: &mut RenderPass,
+ renderable: (&Material, Option<&MaterialFlags>, Option<&Transform>),
+ scene_env_lighting: Option<&EnvironmentalLighting>,
+ (camera, camera_transform): (&Camera, &Transform),
+ window: &Window,
+ point_light_query: &Query<(
+ &PointLight,
+ &Transform,
+ Traverse<(With<Scene>, With<ActiveScene>), TraverseUp, ChildOf>,
+ )>,
+ directional_light_query: &Query<(
+ &DirectionalLight,
+ Traverse<(With<Scene>, With<ActiveScene>), TraverseUp, ChildOf>,
+ )>,
+ assets: &Assets,
+ shader_program: &ShaderProgram,
+) -> Result<(), crate::Error>
+{
+ let (material, material_flags, transform) = renderable;
+
+ let shader_cursor = ShaderCursor::new(
+ shader_program
+ .reflection(0)
+ .unwrap()
+ .global_params_var_layout()
+ .unwrap(),
+ );
+
+ let transform = match transform.as_deref() {
+ Some(transform) => transform,
+ None => &Transform::default(),
+ };
+
+ let model_matrix = transform.to_matrix();
+ let inverted_model_matrix = model_matrix.inverse();
+
+ let material_flags = material_flags
+ .as_deref()
+ .unwrap_or(&const { MaterialFlags::builder().build() });
+
+ let env_lighting = match &scene_env_lighting {
+ Some(env_lighting) => &env_lighting,
+ None => &EnvironmentalLighting::default(),
+ };
+
+ let model_3d_shader_cursor = shader_cursor.field("Uniforms").field("model_3d");
+ let lighting_shader_cursor = shader_cursor.field("Uniforms").field("lighting");
+ let material_shader_cursor = lighting_shader_cursor.field("material");
+
+ render_pass.commands.extend(
+ [
+ model_3d_shader_cursor
+ .field("model")
+ .binding(model_matrix.into())?,
+ model_3d_shader_cursor
+ .field("model_inverted")
+ .binding(inverted_model_matrix.into())?,
+ model_3d_shader_cursor
+ .field("view")
+ .binding(camera.to_view_matrix(camera_transform.position).into())?,
+ model_3d_shader_cursor.field("projection").binding(
+ camera
+ .projection
+ .to_matrix_rh(window.inner_size, ProjectionClipVolume::NegOneToOne)
+ .into(),
+ )?,
+ lighting_shader_cursor
+ .field("view_pos")
+ .binding(camera_transform.position.into())?,
+ material_shader_cursor.field("ambient").binding(
+ (if material_flags.use_ambient_color {
+ &material.ambient
+ } else {
+ &env_lighting.ambient_color
+ }
+ .clone())
+ .into(),
+ )?,
+ material_shader_cursor
+ .field("diffuse")
+ .binding(material.diffuse.clone().into())?,
+ material_shader_cursor
+ .field("specular")
+ .binding(material.specular.clone().into())?,
+ shader_cursor
+ .field("ambient_map")
+ .binding(ShaderBindingValue::Texture(
+ material
+ .ambient_map
+ .as_ref()
+ .map(|ambient_map| ambient_map.clone())
+ .unwrap_or_else(|| {
+ assets
+ .get_handle_to_loaded(
+ TEXTURE_WHITE_1X1_ASSET_LABEL.clone(),
+ )
+ .expect("Not possible")
+ })
+ .id()
+ .into(),
+ ShaderBindingTextureKind::Texture2D,
+ ))?,
+ shader_cursor
+ .field("diffuse_map")
+ .binding(ShaderBindingValue::Texture(
+ material
+ .diffuse_map
+ .as_ref()
+ .map(|diffuse_map| diffuse_map.clone())
+ .unwrap_or_else(|| {
+ assets
+ .get_handle_to_loaded(
+ TEXTURE_WHITE_1X1_ASSET_LABEL.clone(),
+ )
+ .expect("Not possible")
+ })
+ .id()
+ .into(),
+ ShaderBindingTextureKind::Texture2D,
+ ))?,
+ shader_cursor
+ .field("specular_map")
+ .binding(ShaderBindingValue::Texture(
+ material
+ .specular_map
+ .as_ref()
+ .map(|specular_map| specular_map.clone())
+ .unwrap_or_else(|| {
+ assets
+ .get_handle_to_loaded(
+ TEXTURE_WHITE_1X1_ASSET_LABEL.clone(),
+ )
+ .expect("Not possible")
+ })
+ .id()
+ .into(),
+ ShaderBindingTextureKind::Texture2D,
+ ))?,
+ material_shader_cursor
+ .field("shininess")
+ .binding(material.shininess.into())?,
+ lighting_shader_cursor
+ .field("directional_light_cnt")
+ .binding(
+ u32::try_from(directional_light_query.iter().count())
+ .expect(
+ "Directional light count does not fit in 32-bit unsigned integer",
+ )
+ .into(),
+ )?,
+ lighting_shader_cursor.field("point_light_cnt").binding(
+ u32::try_from(point_light_query.iter().count())
+ .expect("Point light count does not fit in 32-bit unsigned integer")
+ .into(),
+ )?,
+ ]
+ .into_iter()
+ .map(Command::SetShaderBinding),
+ );
+
+ render_pass
+ .commands
+ .reserve(point_light_query.iter().count() * 6);
+
+ for (point_light_index, (point_light, point_light_transform)) in
+ point_light_query.iter().enumerate()
+ {
+ let point_light_shader_cursor = lighting_shader_cursor
+ .field("point_lights")
+ .element(point_light_index);
+
+ let phong_shader_cursor = point_light_shader_cursor.field("phong");
+
+ let attenuation_props_shader_cursor =
+ point_light_shader_cursor.field("attenuation_props");
+
+ render_pass.commands.extend(
+ [
+ phong_shader_cursor
+ .field("diffuse")
+ .binding(point_light.diffuse.clone().into())?,
+ phong_shader_cursor
+ .field("specular")
+ .binding(point_light.specular.clone().into())?,
+ point_light_shader_cursor.field("position").binding(
+ (point_light_transform.position + point_light.local_position).into(),
+ )?,
+ attenuation_props_shader_cursor
+ .field("constant")
+ .binding(point_light.attenuation_params.constant.into())?,
+ attenuation_props_shader_cursor
+ .field("linear")
+ .binding(point_light.attenuation_params.linear.into())?,
+ attenuation_props_shader_cursor
+ .field("quadratic")
+ .binding(point_light.attenuation_params.quadratic.into())?,
+ ]
+ .map(Command::SetShaderBinding),
+ );
+ }
+
+ render_pass
+ .commands
+ .reserve(directional_light_query.iter().count() * 3);
+
+ for (directional_light_index, (directional_light,)) in
+ directional_light_query.iter().enumerate()
+ {
+ let directional_light_shader_cursor = lighting_shader_cursor
+ .field("directional_lights")
+ .element(directional_light_index);
+
+ let phong_shader_cursor = directional_light_shader_cursor.field("phong");
+
+ render_pass.commands.extend(
+ [
+ phong_shader_cursor
+ .field("diffuse")
+ .binding(directional_light.diffuse.clone().into())?,
+ phong_shader_cursor
+ .field("specular")
+ .binding(directional_light.specular.clone().into())?,
+ directional_light_shader_cursor
+ .field("direction")
+ .binding(directional_light.direction.into())?,
+ ]
+ .map(Command::SetShaderBinding),
+ );
+ }
+
+ Ok(())
+}
+
fn load_sky_box(
scene_ent_id: Uid,
sky_box: &SkyBox,