diff options
Diffstat (limited to 'client/src/scene_prepare.rs')
-rw-r--r-- | client/src/scene_prepare.rs | 158 |
1 files changed, 152 insertions, 6 deletions
diff --git a/client/src/scene_prepare.rs b/client/src/scene_prepare.rs index 4e57e77..4b298a1 100644 --- a/client/src/scene_prepare.rs +++ b/client/src/scene_prepare.rs @@ -15,10 +15,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ use crate::{ - armature::{self, RArmature}, + armature::RArmature, download::Downloader, meshops::{generate_normals, generate_tangents, generate_texcoords}, scene_render::SceneBgLayouts, + shaders::SceneShaders, }; use anyhow::Result; use bytemuck::{Pod, Zeroable}; @@ -38,12 +39,17 @@ use std::{ use weareshared::{ Affine3A, packets::Resource, - resources::{Armature, Image, MeshPart, Prefab}, + resources::{Image, MeshPart, Prefab}, }; use wgpu::{ AddressMode, BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayout, BindingResource, - Buffer, BufferUsages, Device, Extent3d, FilterMode, Queue, SamplerDescriptor, Texture, + BlendState, Buffer, BufferUsages, ColorTargetState, ColorWrites, CompareFunction, + DepthBiasState, DepthStencilState, Device, Extent3d, Face, FilterMode, FragmentState, + FrontFace, MultisampleState, PipelineCompilationOptions, PipelineLayoutDescriptor, PolygonMode, + PrimitiveState, PrimitiveTopology, PushConstantRange, Queue, RenderPipeline, + RenderPipelineDescriptor, SamplerDescriptor, ShaderStages, StencilState, Texture, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages, TextureViewDescriptor, + VertexAttribute, VertexBufferLayout, VertexFormat, VertexState, VertexStepMode, util::{BufferInitDescriptor, DeviceExt, TextureDataOrder}, }; @@ -90,6 +96,8 @@ pub struct ScenePreparer { device: Arc<Device>, queue: Arc<Queue>, layouts: SceneBgLayouts, + shaders: SceneShaders, + render_format: TextureFormat, textures: DemandMap<(Resource<Image<'static>>, bool), (Arc<Texture>, Arc<BindGroup>)>, placeholder_textures: DemandMap<TextureIdentityKind, (Arc<Texture>, Arc<BindGroup>)>, @@ -100,11 +108,20 @@ pub struct ScenePreparer { generated_texcoord_buffers: DemandMap<TexcoordBufferSpec, Arc<Buffer>>, mesh_parts: DemandMap<Resource<MeshPart>, Arc<RMeshPart>>, materials: DemandMap<Material, Arc<BindGroup>>, + pipelines: DemandMap<PipelineConfig, Arc<RenderPipeline>>, pub prefabs: DemandMap<Resource<Prefab>, Arc<RPrefab>>, } +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct PipelineConfig { + format: TextureFormat, + skin: bool, + backface_culling: bool, +} + pub struct RPrefab(pub Vec<(Affine3A, Arc<RMeshPart>)>); pub struct RMeshPart { + pub pipeline: Arc<RenderPipeline>, pub index_count: u32, pub index: Arc<Buffer>, pub va_position: Arc<Buffer>, @@ -157,11 +174,13 @@ struct Material { } impl ScenePreparer { - pub fn new(device: Arc<Device>, queue: Arc<Queue>, layouts: SceneBgLayouts) -> Self { + pub fn new(device: Arc<Device>, queue: Arc<Queue>, render_format: TextureFormat) -> Self { Self { + render_format, + layouts: SceneBgLayouts::load(&device), + shaders: SceneShaders::load(&device), device, queue, - layouts, index_buffers: DemandMap::new(), vertex_buffers: DemandMap::new(), mesh_parts: DemandMap::new(), @@ -172,6 +191,7 @@ impl ScenePreparer { generated_normal_buffers: DemandMap::new(), generated_texcoord_buffers: DemandMap::new(), materials: DemandMap::new(), + pipelines: DemandMap::new(), } } pub fn update(&self, dls: &Downloader) -> Result<usize> { @@ -347,7 +367,7 @@ impl ScenePreparer { }); let bind_group = self.device.create_bind_group(&BindGroupDescriptor { label: Some("material"), - layout: &self.material_bgl, + layout: &self.layouts.material, entries: &[BindGroupEntry { binding: 0, resource: buffer.as_entire_binding(), @@ -355,6 +375,13 @@ impl ScenePreparer { }); self.materials.insert(spec, Arc::new(bind_group), 0); } + for spec in self.pipelines.needed() { + self.pipelines.insert( + spec.clone(), + Arc::new(spec.create(&self.device, &self.layouts, &self.shaders)), + 0, + ); + } for pres in self.mesh_parts.needed() { let start = Instant::now(); if let Some(part) = dls.try_get(pres.clone())? { @@ -461,7 +488,14 @@ impl ScenePreparer { Some(None) }; + let pipeline = self.pipelines.try_get(PipelineConfig { + format: self.render_format, + skin: false, + backface_culling: part.g_double_sided.is_none(), + }); + if let ( + Some(pipeline), Some((index, index_count)), Some(va_normal), Some(va_tangent), @@ -474,6 +508,7 @@ impl ScenePreparer { Some(tex_albedo), Some(material), ) = ( + pipeline, index, normal, tangent, @@ -499,6 +534,7 @@ impl ScenePreparer { self.mesh_parts.insert( pres, Arc::new(RMeshPart { + pipeline, index_count, index, va_normal, @@ -582,6 +618,110 @@ fn create_texture( (Arc::new(texture), Arc::new(bindgroup)) } +impl PipelineConfig { + pub fn create( + &self, + device: &Device, + layouts: &SceneBgLayouts, + shaders: &SceneShaders, + ) -> RenderPipeline { + let pipeline_layout = device.create_pipeline_layout(&PipelineLayoutDescriptor { + label: None, + bind_group_layouts: &[&layouts.texture, &layouts.texture, &layouts.material], + push_constant_ranges: &[PushConstantRange { + range: 0..((4 * 4 + 3 * 4) * size_of::<f32>() as u32), + stages: ShaderStages::VERTEX, + }], + }); + device.create_render_pipeline(&RenderPipelineDescriptor { + label: None, + layout: Some(&pipeline_layout), + fragment: Some(FragmentState { + module: &shaders.fragment_pbr, + entry_point: Some("main"), + targets: &[Some(ColorTargetState { + blend: Some(BlendState::PREMULTIPLIED_ALPHA_BLENDING), + format: self.format, + write_mask: ColorWrites::all(), + })], + compilation_options: PipelineCompilationOptions::default(), + }), + vertex: VertexState { + module: if self.skin { + &shaders.vertex_world_skin + } else { + &shaders.vertex_world + }, + entry_point: Some("main"), + buffers: &[ + // position + VertexBufferLayout { + step_mode: VertexStepMode::Vertex, + array_stride: 3 * size_of::<f32>() as u64, + attributes: &[VertexAttribute { + format: VertexFormat::Float32x3, + offset: 0, + shader_location: 0, + }], + }, + // normal + VertexBufferLayout { + step_mode: VertexStepMode::Vertex, + array_stride: 3 * size_of::<f32>() as u64, + attributes: &[VertexAttribute { + format: VertexFormat::Float32x3, + offset: 0, + shader_location: 1, + }], + }, + // tangent + VertexBufferLayout { + step_mode: VertexStepMode::Vertex, + array_stride: 3 * size_of::<f32>() as u64, + attributes: &[VertexAttribute { + format: VertexFormat::Float32x3, + offset: 0, + shader_location: 2, + }], + }, + // texcoord + VertexBufferLayout { + step_mode: VertexStepMode::Vertex, + array_stride: 2 * size_of::<f32>() as u64, + attributes: &[VertexAttribute { + format: VertexFormat::Float32x2, + offset: 0, + shader_location: 3, + }], + }, + ], + compilation_options: PipelineCompilationOptions::default(), + }, + primitive: PrimitiveState { + topology: PrimitiveTopology::TriangleList, + front_face: FrontFace::Ccw, + cull_mode: if self.backface_culling { + Some(Face::Back) + } else { + None + }, + polygon_mode: PolygonMode::Fill, + ..Default::default() + }, + depth_stencil: Some(DepthStencilState { + depth_write_enabled: true, + depth_compare: CompareFunction::Less, + format: TextureFormat::Depth32Float, + bias: DepthBiasState::default(), + stencil: StencilState::default(), + }), + multisample: MultisampleState::default(), + multiview: None, + cache: None, + }) + } +} + impl<K, V> Widget for &DemandMap<K, V> { fn ui(self, ui: &mut egui::Ui) -> egui::Response { let state = self.inner.read().unwrap(); @@ -618,6 +758,8 @@ impl ScenePreparer { &self.generated_texcoord_buffers, ); visit("textures", &self.textures); + visit("materials", &self.materials); + visit("pipelines", &self.pipelines); } } @@ -644,6 +786,10 @@ impl Widget for &ScenePreparer { self.generated_texcoord_buffers.ui(ui); ui.label("textures"); self.textures.ui(ui); + ui.label("materials"); + self.materials.ui(ui); + ui.label("pipelines"); + self.pipelines.ui(ui); }) .response } |