Add placeholder fog volume

This commit is contained in:
Lauri Räsänen 2023-11-08 13:47:45 +02:00
parent 4b03671a62
commit ca9ed36c37
5 changed files with 227 additions and 23 deletions

46
res/shaders/fog.wgsl Normal file
View file

@ -0,0 +1,46 @@
#include globals.wgsl
@vertex
fn vs_main(
model: VertexInput,
instance: InstanceInput,
) -> VertexOutput {
let model_matrix = mat4x4<f32>(
instance.model_matrix_0,
instance.model_matrix_1,
instance.model_matrix_2,
instance.model_matrix_3,
);
let normal_matrix = mat3x3<f32>(
instance.normal_matrix_0,
instance.normal_matrix_1,
instance.normal_matrix_2,
);
let world_normal = normalize(normal_matrix * model.normal);
let world_tangent = normalize(normal_matrix * model.tangent);
let world_bitangent = normalize(normal_matrix * model.bitangent);
let tangent_matrix = transpose(mat3x3<f32>(
world_tangent,
world_bitangent,
world_normal,
));
let world_position = model_matrix * vec4<f32>(model.position, 1.0);
var out: VertexOutput;
out.clip_position = camera.proj * camera.view * world_position;
out.tex_coords = model.tex_coords;
out.tangent_position = tangent_matrix * world_position.xyz;
out.tangent_light_position = tangent_matrix * light.position;
out.tangent_view_position = tangent_matrix * camera.position.xyz;
out.world_position = world_position;
return out;
}
@fragment
fn fs_main(vert: VertexOutput) -> @location(0) vec4<f32> {
return vec4<f32>(0.5, 0.5, 0.5, 0.1);
}

View file

@ -3,6 +3,7 @@ use super::model::Vertex;
pub struct Instance { pub struct Instance {
pub position: cgmath::Vector3<f32>, pub position: cgmath::Vector3<f32>,
pub rotation: cgmath::Quaternion<f32>, pub rotation: cgmath::Quaternion<f32>,
pub scale: cgmath::Vector3<f32>,
} }
#[repr(C)] #[repr(C)]
@ -16,6 +17,7 @@ impl Instance {
pub fn to_raw(&self) -> InstanceRaw { pub fn to_raw(&self) -> InstanceRaw {
InstanceRaw { InstanceRaw {
model: (cgmath::Matrix4::from_translation(self.position) model: (cgmath::Matrix4::from_translation(self.position)
* cgmath::Matrix4::from_nonuniform_scale(self.scale.x, self.scale.y, self.scale.z)
* cgmath::Matrix4::from(self.rotation)) * cgmath::Matrix4::from(self.rotation))
.into(), .into(),
normal: cgmath::Matrix3::from(self.rotation).into(), normal: cgmath::Matrix3::from(self.rotation).into(),

View file

@ -155,4 +155,63 @@ impl Mesh {
v.bitangent = (cgmath::Vector3::from(v.bitangent) * denom).into(); v.bitangent = (cgmath::Vector3::from(v.bitangent) * denom).into();
} }
} }
/*
pub fn cube(device: &wgpu::Device, size: [f32; 3], name: &str, material_index: usize) -> Mesh {
#[rustfmt::skip]
let mut vertices = vec![
// front
ModelVertex { position: [-size[0], -size[1], -size[2]], tex_coords: [0.0, 0.0], normal: [-size[0], -size[1], -size[2]], ..Default::default() },
ModelVertex { position: [ size[0], -size[1], -size[2]], tex_coords: [0.0, 0.0], normal: [ size[0], -size[1], -size[2]], ..Default::default() },
ModelVertex { position: [ size[0], size[1], -size[2]], tex_coords: [0.0, 0.0], normal: [ size[0], size[1], -size[2]], ..Default::default() },
ModelVertex { position: [-size[0], size[1], -size[2]], tex_coords: [0.0, 0.0], normal: [-size[0], size[1], -size[2]], ..Default::default() },
// back
ModelVertex { position: [-size[0], -size[1], size[2]], tex_coords: [0.0, 0.0], normal: [-size[0], -size[1], size[2]], ..Default::default() },
ModelVertex { position: [ size[0], -size[1], size[2]], tex_coords: [0.0, 0.0], normal: [ size[0], -size[1], size[2]], ..Default::default() },
ModelVertex { position: [ size[0], size[1], size[2]], tex_coords: [0.0, 0.0], normal: [ size[0], size[1], size[2]], ..Default::default() },
ModelVertex { position: [-size[0], size[1], size[2]], tex_coords: [0.0, 0.0], normal: [-size[0], size[1], size[2]], ..Default::default() },
];
#[rustfmt::skip]
let indices = vec![
// front
0, 1, 2,
2, 3, 0,
// back
4, 6, 5,
4, 7, 6,
// left
0, 3, 4,
3, 7, 4,
// right
1, 2, 5,
2, 6, 5,
// top
2, 7, 3,
2, 6, 7,
// bottom
1, 4, 0,
1, 5, 4
];
Mesh::calc_tangents(&indices, &mut vertices);
let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some(&format!("{:?} Vertex Buffer", name)),
contents: bytemuck::cast_slice(&vertices),
usage: wgpu::BufferUsages::VERTEX,
});
let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some(&format!("{:?} Index Buffer", name)),
contents: bytemuck::cast_slice(&indices),
usage: wgpu::BufferUsages::INDEX,
});
Mesh {
name: name.to_string(),
vertex_buffer,
index_buffer,
num_elements: indices.len() as u32,
material: material_index,
}
}
*/
} }

View file

@ -19,6 +19,7 @@ impl RenderPass {
vertex_layouts: &[VertexBufferLayout], vertex_layouts: &[VertexBufferLayout],
label: &str, label: &str,
is_shadow: bool, is_shadow: bool,
has_transparency: bool,
) -> Self { ) -> Self {
let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some((label.to_owned() + " pipeline Layout").as_str()), label: Some((label.to_owned() + " pipeline Layout").as_str()),
@ -38,6 +39,7 @@ impl RenderPass {
shader, shader,
label, label,
is_shadow, is_shadow,
has_transparency,
); );
Self { pipeline } Self { pipeline }
@ -52,14 +54,25 @@ impl RenderPass {
shader: wgpu::ShaderModuleDescriptor, shader: wgpu::ShaderModuleDescriptor,
label: &str, label: &str,
is_shadow: bool, is_shadow: bool,
has_transparency: bool,
) -> wgpu::RenderPipeline { ) -> wgpu::RenderPipeline {
let shader = device.create_shader_module(shader); let shader = device.create_shader_module(shader);
let blend_comp = if has_transparency {
wgpu::BlendComponent {
src_factor: wgpu::BlendFactor::SrcAlpha,
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
operation: wgpu::BlendOperation::Add,
}
} else {
wgpu::BlendComponent::REPLACE
};
let fragment_targets = &[Some(wgpu::ColorTargetState { let fragment_targets = &[Some(wgpu::ColorTargetState {
format: color_format.unwrap_or(wgpu::TextureFormat::Bgra8Unorm), format: color_format.unwrap_or(wgpu::TextureFormat::Bgra8Unorm),
blend: Some(wgpu::BlendState { blend: Some(wgpu::BlendState {
alpha: wgpu::BlendComponent::REPLACE, alpha: blend_comp,
color: wgpu::BlendComponent::REPLACE, color: blend_comp,
}), }),
write_mask: wgpu::ColorWrites::ALL, write_mask: wgpu::ColorWrites::ALL,
})]; })];
@ -104,8 +117,7 @@ impl RenderPass {
slope_scale: 2.0, slope_scale: 2.0,
clamp: 0.0, clamp: 0.0,
} }
} } else { wgpu::DepthBiasState::default() },
else { wgpu::DepthBiasState::default() },
}), }),
multisample: wgpu::MultisampleState { multisample: wgpu::MultisampleState {
count: 1, count: 1,

View file

@ -35,15 +35,19 @@ pub struct State {
queue: wgpu::Queue, queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration, config: wgpu::SurfaceConfiguration,
geometry_pass: RenderPass, geometry_pass: RenderPass,
fog_pass: RenderPass,
camera: Camera, camera: Camera,
camera_uniform: CameraUniform, camera_uniform: CameraUniform,
camera_buffer: wgpu::Buffer, camera_buffer: wgpu::Buffer,
camera_bind_group: wgpu::BindGroup, camera_bind_group: wgpu::BindGroup,
camera_controller: CameraController, camera_controller: CameraController,
instances: Vec<Instance>, geom_instances: Vec<Instance>,
instance_buffer: wgpu::Buffer, geom_instance_buffer: wgpu::Buffer,
fog_instances: Vec<Instance>,
fog_instance_buffer: wgpu::Buffer,
depth_texture: Texture, depth_texture: Texture,
model: Model, geom_model: Model,
fog_model: Model,
light_model: Model, light_model: Model,
light_uniform: LightUniform, light_uniform: LightUniform,
light_buffer: wgpu::Buffer, light_buffer: wgpu::Buffer,
@ -350,7 +354,7 @@ impl State {
label: Some("texture_bind_group_layout"), label: Some("texture_bind_group_layout"),
}); });
let model = resources::load_model_gltf( let geom_model = resources::load_model_gltf(
"models/Sponza.glb", "models/Sponza.glb",
&device, &device,
&queue, &queue,
@ -359,6 +363,15 @@ impl State {
.await .await
.unwrap(); .unwrap();
let fog_model = resources::load_model_gltf(
"models/Cube.glb",
&device,
&queue,
&texture_bind_group_layout,
)
.await
.unwrap();
let light_model = resources::load_model_gltf( let light_model = resources::load_model_gltf(
"models/Cube.glb", "models/Cube.glb",
&device, &device,
@ -368,15 +381,28 @@ impl State {
.await .await
.unwrap(); .unwrap();
let instances = vec![Instance { let geom_instances = vec![Instance {
position: [0.0, 0.0, 0.0].into(), // this sponza model isn't quite centered
position: [60.0, 0.0, 35.0].into(),
rotation: cgmath::Quaternion::one(), rotation: cgmath::Quaternion::one(),
scale: [1.0, 1.0, 1.0].into(),
}]; }];
let geom_instance_data = geom_instances.iter().map(Instance::to_raw).collect::<Vec<_>>();
let geom_instance_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Geometry Instance Buffer"),
contents: bytemuck::cast_slice(&geom_instance_data),
usage: wgpu::BufferUsages::VERTEX,
});
let instance_data = instances.iter().map(Instance::to_raw).collect::<Vec<_>>(); let fog_instances = vec![Instance {
let instance_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { position: [0.0, 20.0, 0.0].into(),
label: Some("Instance Buffer"), rotation: cgmath::Quaternion::one(),
contents: bytemuck::cast_slice(&instance_data), scale: [1360.0, 20.0, 600.0].into(),
}];
let fog_instance_data = fog_instances.iter().map(Instance::to_raw).collect::<Vec<_>>();
let fog_instance_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Fog Instance Buffer"),
contents: bytemuck::cast_slice(&fog_instance_data),
usage: wgpu::BufferUsages::VERTEX, usage: wgpu::BufferUsages::VERTEX,
}); });
@ -393,6 +419,7 @@ impl State {
&[ModelVertex::desc(), InstanceRaw::desc()], &[ModelVertex::desc(), InstanceRaw::desc()],
"light depth pass", "light depth pass",
true, true,
false,
); );
let geometry_pass = RenderPass::new( let geometry_pass = RenderPass::new(
@ -410,6 +437,25 @@ impl State {
&[ModelVertex::desc(), InstanceRaw::desc()], &[ModelVertex::desc(), InstanceRaw::desc()],
"geometry pass", "geometry pass",
false, false,
false,
);
let fog_pass = RenderPass::new(
&device,
&[
&camera_bind_group_layout,
&light_bind_group_layout,
&light_depth_bind_group_layout,
&texture_bind_group_layout,
],
&[],
"fog.wgsl",
Some(config.format),
Some(Texture::DEPTH_FORMAT),
&[ModelVertex::desc(), InstanceRaw::desc()],
"fog pass",
false,
true,
); );
let light_debug_pass = RenderPass::new( let light_debug_pass = RenderPass::new(
@ -422,6 +468,7 @@ impl State {
&[ModelVertex::desc()], &[ModelVertex::desc()],
"light debug pass", "light debug pass",
false, false,
false,
); );
Self { Self {
@ -431,15 +478,19 @@ impl State {
queue, queue,
config, config,
geometry_pass, geometry_pass,
fog_pass,
camera, camera,
camera_uniform, camera_uniform,
camera_buffer, camera_buffer,
camera_bind_group, camera_bind_group,
camera_controller, camera_controller,
instances, geom_instances,
instance_buffer, geom_instance_buffer,
fog_instances,
fog_instance_buffer,
depth_texture, depth_texture,
model, geom_model,
fog_model,
light_model, light_model,
light_uniform, light_uniform,
light_buffer, light_buffer,
@ -546,11 +597,11 @@ impl State {
occlusion_query_set: None, occlusion_query_set: None,
}); });
light_depth_render_pass.set_vertex_buffer(1, self.instance_buffer.slice(..)); light_depth_render_pass.set_vertex_buffer(1, self.geom_instance_buffer.slice(..));
light_depth_render_pass.set_pipeline(&self.light_depth_pass.pipeline); light_depth_render_pass.set_pipeline(&self.light_depth_pass.pipeline);
light_depth_render_pass.draw_model_instanced( light_depth_render_pass.draw_model_instanced(
&self.model, &self.geom_model,
0..self.instances.len() as u32, 0..self.geom_instances.len() as u32,
[&self.camera_bind_group, &self.light_bind_group].into(), [&self.camera_bind_group, &self.light_bind_group].into(),
); );
} }
@ -598,11 +649,45 @@ impl State {
occlusion_query_set: None, occlusion_query_set: None,
}); });
geom_render_pass.set_vertex_buffer(1, self.instance_buffer.slice(..)); geom_render_pass.set_vertex_buffer(1, self.geom_instance_buffer.slice(..));
geom_render_pass.set_pipeline(&self.geometry_pass.pipeline); geom_render_pass.set_pipeline(&self.geometry_pass.pipeline);
geom_render_pass.draw_model_instanced( geom_render_pass.draw_model_instanced(
&self.model, &self.geom_model,
0..self.instances.len() as u32, 0..self.geom_instances.len() as u32,
[&self.camera_bind_group, &self.light_bind_group, &self.light_depth_bind_group].into(),
);
}
encoder.pop_debug_group();
encoder.push_debug_group("fog pass");
{
let mut fog_render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Fog Render Pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &surface_view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Load,
store: StoreOp::Store,
},
})],
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
view: &self.depth_texture.view,
depth_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Load,
store: StoreOp::Store,
}),
stencil_ops: None,
}),
timestamp_writes: None,
occlusion_query_set: None,
});
fog_render_pass.set_vertex_buffer(1, self.fog_instance_buffer.slice(..));
fog_render_pass.set_pipeline(&self.fog_pass.pipeline);
fog_render_pass.draw_model_instanced(
&self.fog_model,
0..self.fog_instances.len() as u32,
[&self.camera_bind_group, &self.light_bind_group, &self.light_depth_bind_group].into(), [&self.camera_bind_group, &self.light_bind_group, &self.light_depth_bind_group].into(),
); );
} }