diff options
author | metamuffin <metamuffin@disroot.org> | 2025-01-19 20:36:21 +0100 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2025-01-19 20:36:21 +0100 |
commit | 5ef0fc14d1d12cc5e7cc6a1fb896953d6d668891 (patch) | |
tree | 7a8a3258965b250e7c6bce39cfad3b8c0c452a5e /client | |
parent | 736c0c34b9e727bf4b25e800f748199d13ff561f (diff) | |
download | weareserver-5ef0fc14d1d12cc5e7cc6a1fb896953d6d668891.tar weareserver-5ef0fc14d1d12cc5e7cc6a1fb896953d6d668891.tar.bz2 weareserver-5ef0fc14d1d12cc5e7cc6a1fb896953d6d668891.tar.zst |
client: send material data to shader
Diffstat (limited to 'client')
-rw-r--r-- | client/src/renderer.rs | 3 | ||||
-rw-r--r-- | client/src/scene_prepare.rs | 71 | ||||
-rw-r--r-- | client/src/scene_render.rs | 27 | ||||
-rw-r--r-- | client/src/shader.wgsl | 13 |
4 files changed, 100 insertions, 14 deletions
diff --git a/client/src/renderer.rs b/client/src/renderer.rs index 2684ed0..02859a1 100644 --- a/client/src/renderer.rs +++ b/client/src/renderer.rs @@ -92,12 +92,13 @@ impl<'a> Renderer<'a> { let device = Arc::new(device); let queue = Arc::new(queue); - let (scene_pipeline, texture_bgl) = + let (scene_pipeline, texture_bgl, material_bgl) = ScenePipeline::new(&device, surface_configuration.format); let scene_prepare = Arc::new(ScenePreparer::new( device.clone(), queue.clone(), texture_bgl, + material_bgl, )); let ui_renderer = diff --git a/client/src/scene_prepare.rs b/client/src/scene_prepare.rs index 97ab166..0e65e72 100644 --- a/client/src/scene_prepare.rs +++ b/client/src/scene_prepare.rs @@ -19,8 +19,9 @@ use crate::{ meshops::{generate_normals, generate_tangents, generate_texcoords}, }; use anyhow::Result; +use bytemuck::{Pod, Zeroable}; use egui::{Grid, Widget}; -use glam::{Vec2, Vec3}; +use glam::{UVec3, UVec4, Vec2, Vec3, Vec3A, uvec3, uvec4}; use humansize::DECIMAL; use image::ImageReader; use log::{debug, trace}; @@ -87,6 +88,7 @@ pub struct ScenePreparer { device: Arc<Device>, queue: Arc<Queue>, texture_bgl: BindGroupLayout, + material_bgl: BindGroupLayout, textures: DemandMap<(Resource<Image<'static>>, bool), (Arc<Texture>, Arc<BindGroup>)>, placeholder_textures: DemandMap<TextureIdentityKind, (Arc<Texture>, Arc<BindGroup>)>, @@ -96,6 +98,7 @@ pub struct ScenePreparer { generated_normal_buffers: DemandMap<NormalBufferSpec, Arc<Buffer>>, generated_texcoord_buffers: DemandMap<TexcoordBufferSpec, Arc<Buffer>>, mesh_parts: DemandMap<Resource<MeshPart>, Arc<RMeshPart>>, + materials: DemandMap<Material, Arc<BindGroup>>, pub prefabs: DemandMap<Resource<Prefab>, Arc<RPrefab>>, } @@ -109,6 +112,7 @@ pub struct RMeshPart { pub va_texcoord: Arc<Buffer>, pub tex_albedo: Arc<BindGroup>, pub tex_normal: Arc<BindGroup>, + pub material: Arc<BindGroup>, pub double_sided: bool, } @@ -136,10 +140,29 @@ enum TextureIdentityKind { Multiply, } +#[derive(Debug, Clone, Copy, Pod, Zeroable, Hash, PartialEq, Eq)] +#[repr(C)] +struct Material { + roughness: u32, + metallic: u32, + _pad1: [u32; 2], + albedo_alpha: UVec4, + emission: UVec3, + _pad2: u32, +} + impl ScenePreparer { - pub fn new(device: Arc<Device>, queue: Arc<Queue>, texture_bgl: BindGroupLayout) -> Self { + pub fn new( + device: Arc<Device>, + queue: Arc<Queue>, + texture_bgl: BindGroupLayout, + material_bgl: BindGroupLayout, + ) -> Self { Self { + device, + queue, texture_bgl, + material_bgl, index_buffers: DemandMap::new(), vertex_buffers: DemandMap::new(), mesh_parts: DemandMap::new(), @@ -149,8 +172,7 @@ impl ScenePreparer { generated_tangent_buffers: DemandMap::new(), generated_normal_buffers: DemandMap::new(), generated_texcoord_buffers: DemandMap::new(), - device, - queue, + materials: DemandMap::new(), } } pub fn update(&self, dls: &Downloader) -> Result<usize> { @@ -312,6 +334,22 @@ impl ScenePreparer { ); } } + for spec in self.materials.needed() { + let buffer = self.device.create_buffer_init(&BufferInitDescriptor { + label: Some("material props"), + usage: BufferUsages::COPY_DST | BufferUsages::UNIFORM, + contents: bytemuck::cast_slice(&[spec]), + }); + let bind_group = self.device.create_bind_group(&BindGroupDescriptor { + label: Some("material"), + layout: &self.material_bgl, + entries: &[BindGroupEntry { + binding: 0, + resource: buffer.as_entire_binding(), + }], + }); + self.materials.insert(spec, Arc::new(bind_group), 0); + } for pres in self.mesh_parts.needed() { let start = Instant::now(); if let Some(part) = dls.try_get(pres.clone())? { @@ -375,6 +413,28 @@ impl ScenePreparer { } } + let material = self.materials.try_get({ + let albedo = part.g_albedo.unwrap_or(Vec3A::ONE); + let emission = part.g_emission.unwrap_or(Vec3A::ONE); + Material { + roughness: part.g_roughness.unwrap_or(1.).to_bits(), + metallic: part.g_metallic.unwrap_or(0.).to_bits(), + _pad1: [0, 0], + albedo_alpha: uvec4( + albedo.x.to_bits(), + albedo.y.to_bits(), + albedo.z.to_bits(), + part.g_alpha.unwrap_or(1.).to_bits(), + ), + emission: uvec3( + emission.x.to_bits(), + emission.y.to_bits(), + emission.z.to_bits(), + ), + _pad2: 0, + } + }); + if let ( Some((index, index_count)), Some(va_normal), @@ -383,8 +443,10 @@ impl ScenePreparer { Some(va_position), Some(tex_normal), Some(tex_albedo), + Some(material), ) = ( index, normal, tangent, texcoord, position, tex_normal, tex_albedo, + material, ) { debug!("part created (took {:?}) {pres}", start.elapsed()); self.mesh_parts.insert( @@ -398,6 +460,7 @@ impl ScenePreparer { va_texcoord, tex_albedo, tex_normal, + material, double_sided: part.g_double_sided.is_some(), }), 0, diff --git a/client/src/scene_render.rs b/client/src/scene_render.rs index 3ec96b3..2100d28 100644 --- a/client/src/scene_render.rs +++ b/client/src/scene_render.rs @@ -19,8 +19,8 @@ use std::sync::Arc; use weareshared::{packets::Resource, resources::Prefab, tree::SceneTree}; use wgpu::{ BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType, BlendState, - Color, ColorTargetState, ColorWrites, CommandEncoder, CompareFunction, DepthBiasState, - DepthStencilState, Device, Face, FragmentState, FrontFace, IndexFormat, LoadOp, + BufferBindingType, Color, ColorTargetState, ColorWrites, CommandEncoder, CompareFunction, + DepthBiasState, DepthStencilState, Device, Face, FragmentState, FrontFace, IndexFormat, LoadOp, MultisampleState, Operations, PipelineCompilationOptions, PipelineLayoutDescriptor, PolygonMode, PrimitiveState, PrimitiveTopology, PushConstantRange, RenderPassColorAttachment, RenderPassDepthStencilAttachment, RenderPassDescriptor, RenderPipeline, @@ -37,10 +37,10 @@ pub struct ScenePipeline { } impl ScenePipeline { - pub fn new(device: &Device, format: TextureFormat) -> (Self, BindGroupLayout) { + pub fn new(device: &Device, format: TextureFormat) -> (Self, BindGroupLayout, BindGroupLayout) { let module = device.create_shader_module(include_wgsl!("shader.wgsl")); - let bind_group_layout = device.create_bind_group_layout(&BindGroupLayoutDescriptor { + let texture_bgl = device.create_bind_group_layout(&BindGroupLayoutDescriptor { entries: &[ BindGroupLayoutEntry { binding: 0, @@ -61,9 +61,22 @@ impl ScenePipeline { ], label: None, }); + let material_bgl = device.create_bind_group_layout(&BindGroupLayoutDescriptor { + entries: &[BindGroupLayoutEntry { + binding: 0, + count: None, + visibility: ShaderStages::FRAGMENT, + ty: BindingType::Buffer { + ty: BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + }], + label: None, + }); let pipeline_layout = device.create_pipeline_layout(&PipelineLayoutDescriptor { label: None, - bind_group_layouts: &[&bind_group_layout, &bind_group_layout], + bind_group_layouts: &[&texture_bgl, &texture_bgl, &material_bgl], push_constant_ranges: &[PushConstantRange { range: 0..((4 * 4 + 3 * 4) * size_of::<f32>() as u32), stages: ShaderStages::VERTEX, @@ -154,7 +167,8 @@ impl ScenePipeline { pipeline, pipeline_no_cull, }, - bind_group_layout, + texture_bgl, + material_bgl, ) } @@ -226,6 +240,7 @@ impl ScenePipeline { rpass.set_pipeline(pipeline); rpass.set_bind_group(0, &*part.tex_albedo, &[]); rpass.set_bind_group(1, &*part.tex_normal, &[]); + rpass.set_bind_group(2, &*part.material, &[]); rpass.set_push_constants(ShaderStages::VERTEX, 0, projection.as_flattened()); rpass.set_push_constants(ShaderStages::VERTEX, 64, model_basis); rpass.set_index_buffer(part.index.slice(..), IndexFormat::Uint32); diff --git a/client/src/shader.wgsl b/client/src/shader.wgsl index d037a94..9cf386c 100644 --- a/client/src/shader.wgsl +++ b/client/src/shader.wgsl @@ -31,11 +31,19 @@ struct PushConst { model_basis: mat3x3<f32>, } +struct Material { + roughness: f32, + metallic: f32, + albedo_alpha: vec4<f32>, + emission: vec3<f32>, +} + @group(0) @binding(0) var tex_albedo: texture_2d<f32>; @group(0) @binding(1) var tex_albedo_sampler: sampler; @group(1) @binding(0) var tex_normal: texture_2d<f32>; @group(1) @binding(1) var tex_normal_sampler: sampler; var<push_constant> pc: PushConst; +@group(2) @binding(0) var<uniform> material: Material; const LIGHT: vec3<f32> = vec3(0.64, 0.64, 0.64); @@ -59,11 +67,10 @@ fn fs_main(vo: VertexOut) -> @location(0) vec4<f32> { let tangent_basis = mat3x3(vo.tangent, cross(vo.tangent, vo.normal), vo.normal); let normal = tangent_basis * (t_normal.rgb * 2. - 1.); - let lighting = mix(1., saturate(dot(LIGHT, normal)), 0.9); - let alpha = t_albedo.a; + let lighting = mix(1., saturate(dot(LIGHT, normal)), 1.); + let color = t_albedo.rgb * lighting; - // let color = normal * 0.5 + 0.5; if fract(dot(sin(vo.clip * 123.) * 1213., vec4(3., 2., 1., 4.))) > alpha { discard; |