diff options
Diffstat (limited to 'engine/src/rendering/main_render_pass.rs')
| -rw-r--r-- | engine/src/rendering/main_render_pass.rs | 394 |
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, |
