summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-01-19 20:36:21 +0100
committermetamuffin <metamuffin@disroot.org>2025-01-19 20:36:21 +0100
commit5ef0fc14d1d12cc5e7cc6a1fb896953d6d668891 (patch)
tree7a8a3258965b250e7c6bce39cfad3b8c0c452a5e /client
parent736c0c34b9e727bf4b25e800f748199d13ff561f (diff)
downloadweareserver-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.rs3
-rw-r--r--client/src/scene_prepare.rs71
-rw-r--r--client/src/scene_render.rs27
-rw-r--r--client/src/shader.wgsl13
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;