1use std::{borrow::Cow, iter, mem};
2
3use bytemuck::{Pod, Zeroable};
4use glam::{Mat4, Vec3};
5use wgpu::util::DeviceExt;
6use wgpu::{vertex_attr_array, IndexFormat, VertexBufferLayout};
7
8use crate::utils;
9
10#[repr(C)]
12#[derive(Clone, Copy, Pod, Zeroable)]
13struct Vertex {
14 _pos: [f32; 3],
15 _normal: [f32; 3],
16}
17
18fn vertex(pos: [f32; 3], normal: [f32; 3]) -> Vertex {
19 Vertex {
20 _pos: pos,
21 _normal: normal,
22 }
23}
24
25fn create_vertices() -> (Vec<Vertex>, Vec<u16>) {
26 let vertex_data = [
27 vertex([-1.0, 0.0, -1.0], [0.0, 1.0, 0.0]),
29 vertex([-1.0, 0.0, 1.0], [0.0, 1.0, 0.0]),
30 vertex([1.0, 0.0, -1.0], [0.0, 1.0, 0.0]),
31 vertex([1.0, 0.0, 1.0], [0.0, 1.0, 0.0]),
32 vertex([-(1.0 / 3.0), 0.0, 1.0], [0.0, 0.0, 1.0]),
34 vertex([-(1.0 / 3.0), 2.0 / 3.0, 1.0], [0.0, 0.0, 1.0]),
35 vertex([1.0 / 3.0, 0.0, 1.0], [0.0, 0.0, 1.0]),
36 vertex([1.0 / 3.0, 2.0 / 3.0, 1.0], [0.0, 0.0, 1.0]),
37 ];
38
39 let index_data: &[u16] = &[
40 0, 1, 2, 2, 3, 1, 4, 5, 6, 6, 7, 5,
42 ];
43
44 (vertex_data.to_vec(), index_data.to_vec())
45}
46
47#[repr(C)]
48#[derive(Clone, Copy, Pod, Zeroable)]
49struct Uniforms {
50 view_inverse: Mat4,
51 proj_inverse: Mat4,
52 vertex: Mat4,
53}
54
55struct Example {
56 uniforms: Uniforms,
57 uniform_buf: wgpu::Buffer,
58 vertex_buf: wgpu::Buffer,
59 index_buf: wgpu::Buffer,
60 pipeline: wgpu::RenderPipeline,
61 bind_group: wgpu::BindGroup,
62 animation_timer: utils::AnimationTimer,
63}
64
65const CAM_LOOK_AT: Vec3 = Vec3::new(0.0, 1.0, -1.5);
66
67fn create_matrix(config: &wgpu::SurfaceConfiguration) -> Uniforms {
68 let view = Mat4::look_at_rh(CAM_LOOK_AT, Vec3::ZERO, Vec3::Y);
69 let proj = Mat4::perspective_rh(
70 59.0_f32.to_radians(),
71 config.width as f32 / config.height as f32,
72 0.1,
73 1000.0,
74 );
75
76 Uniforms {
77 view_inverse: view.inverse(),
78 proj_inverse: proj.inverse(),
79 vertex: (proj * view),
80 }
81}
82
83impl crate::framework::Example for Example {
84 fn required_features() -> wgpu::Features {
85 wgpu::Features::EXPERIMENTAL_RAY_QUERY | wgpu::Features::IMMEDIATES
86 }
87
88 fn required_downlevel_capabilities() -> wgpu::DownlevelCapabilities {
89 wgpu::DownlevelCapabilities {
90 flags: wgpu::DownlevelFlags::COMPUTE_SHADERS,
91 ..Default::default()
92 }
93 }
94
95 fn required_limits() -> wgpu::Limits {
96 wgpu::Limits {
97 max_immediate_size: 16,
98 ..wgpu::Limits::default()
99 }
100 .using_minimum_supported_acceleration_structure_values()
101 }
102
103 fn init(
104 config: &wgpu::SurfaceConfiguration,
105 _adapter: &wgpu::Adapter,
106 device: &wgpu::Device,
107 queue: &wgpu::Queue,
108 ) -> Self {
109 let uniforms = create_matrix(config);
110
111 let uniform_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
112 label: Some("Uniform Buffer"),
113 contents: bytemuck::cast_slice(&[uniforms]),
114 usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
115 });
116
117 let (vertex_data, index_data) = create_vertices();
118
119 let vertex_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
120 label: Some("Vertex Buffer"),
121 contents: bytemuck::cast_slice(&vertex_data),
122 usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::BLAS_INPUT,
123 });
124
125 let index_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
126 label: Some("Index Buffer"),
127 contents: bytemuck::cast_slice(&index_data),
128 usage: wgpu::BufferUsages::INDEX | wgpu::BufferUsages::BLAS_INPUT,
129 });
130
131 let blas_geo_size_desc = wgpu::BlasTriangleGeometrySizeDescriptor {
132 vertex_format: wgpu::VertexFormat::Float32x3,
133 vertex_count: vertex_data.len() as u32,
134 index_format: Some(wgpu::IndexFormat::Uint16),
135 index_count: Some(index_data.len() as u32),
136 flags: wgpu::AccelerationStructureGeometryFlags::OPAQUE,
137 };
138
139 let blas = device.create_blas(
140 &wgpu::CreateBlasDescriptor {
141 label: None,
142 flags: wgpu::AccelerationStructureFlags::PREFER_FAST_TRACE,
143 update_mode: wgpu::AccelerationStructureUpdateMode::Build,
144 },
145 wgpu::BlasGeometrySizeDescriptors::Triangles {
146 descriptors: vec![blas_geo_size_desc.clone()],
147 },
148 );
149
150 let mut tlas = device.create_tlas(&wgpu::CreateTlasDescriptor {
151 label: None,
152 flags: wgpu::AccelerationStructureFlags::PREFER_FAST_TRACE,
153 update_mode: wgpu::AccelerationStructureUpdateMode::Build,
154 max_instances: 1,
155 });
156
157 let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
158 label: None,
159 source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("shader.wgsl"))),
160 });
161
162 let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
163 label: None,
164 entries: &[
165 wgpu::BindGroupLayoutEntry {
166 binding: 0,
167 visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
168 ty: wgpu::BindingType::Buffer {
169 ty: wgpu::BufferBindingType::Uniform,
170 has_dynamic_offset: false,
171 min_binding_size: None,
172 },
173 count: None,
174 },
175 wgpu::BindGroupLayoutEntry {
176 binding: 1,
177 visibility: wgpu::ShaderStages::FRAGMENT,
178 ty: wgpu::BindingType::AccelerationStructure {
179 vertex_return: false,
180 },
181 count: None,
182 },
183 ],
184 });
185
186 let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
187 label: None,
188 bind_group_layouts: &[Some(&bind_group_layout)],
189 immediate_size: 16,
190 });
191
192 let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
193 label: None,
194 layout: Some(&pipeline_layout),
195 vertex: wgpu::VertexState {
196 module: &shader,
197 entry_point: Some("vs_main"),
198 compilation_options: Default::default(),
199 buffers: &[VertexBufferLayout {
200 array_stride: mem::size_of::<Vertex>() as wgpu::BufferAddress,
201 step_mode: Default::default(),
202 attributes: &vertex_attr_array![0 => Float32x3, 1 => Float32x3],
203 }],
204 },
205 fragment: Some(wgpu::FragmentState {
206 module: &shader,
207 entry_point: Some("fs_main"),
208 compilation_options: Default::default(),
209 targets: &[Some(config.format.into())],
210 }),
211 primitive: wgpu::PrimitiveState {
212 topology: wgpu::PrimitiveTopology::TriangleList,
213 ..Default::default()
214 },
215 depth_stencil: None,
216 multisample: wgpu::MultisampleState::default(),
217 multiview_mask: None,
218 cache: None,
219 });
220
221 tlas[0] = Some(wgpu::TlasInstance::new(
222 &blas,
223 [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0],
224 0,
225 0xFF,
226 ));
227
228 let mut encoder =
229 device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
230
231 encoder.build_acceleration_structures(
232 iter::once(&wgpu::BlasBuildEntry {
233 blas: &blas,
234 geometry: wgpu::BlasGeometries::TriangleGeometries(vec![
235 wgpu::BlasTriangleGeometry {
236 size: &blas_geo_size_desc,
237 vertex_buffer: &vertex_buf,
238 first_vertex: 0,
239 vertex_stride: mem::size_of::<Vertex>() as u64,
240 index_buffer: Some(&index_buf),
241 first_index: Some(0),
242 transform_buffer: None,
243 transform_buffer_offset: None,
244 },
245 ]),
246 }),
247 iter::once(&tlas),
248 );
249
250 queue.submit(Some(encoder.finish()));
251
252 let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
253 label: None,
254 layout: &bind_group_layout,
255 entries: &[
256 wgpu::BindGroupEntry {
257 binding: 0,
258 resource: uniform_buf.as_entire_binding(),
259 },
260 wgpu::BindGroupEntry {
261 binding: 1,
262 resource: tlas.as_binding(),
263 },
264 ],
265 });
266
267 let animation_timer = utils::AnimationTimer::default();
268
269 Example {
270 uniforms,
271 uniform_buf,
272 vertex_buf,
273 index_buf,
274 pipeline,
275 bind_group,
276 animation_timer,
277 }
278 }
279
280 fn update(&mut self, _event: winit::event::WindowEvent) {}
281
282 fn resize(
283 &mut self,
284 config: &wgpu::SurfaceConfiguration,
285 _device: &wgpu::Device,
286 queue: &wgpu::Queue,
287 ) {
288 self.uniforms = create_matrix(config);
289
290 queue.write_buffer(&self.uniform_buf, 0, bytemuck::cast_slice(&[self.uniforms]));
291 queue.submit(None);
292 }
293
294 fn render(&mut self, view: &wgpu::TextureView, device: &wgpu::Device, queue: &wgpu::Queue) {
295 const LIGHT_DISTANCE: f32 = 5.0;
297 const TIME_SCALE: f32 = -0.2;
298 const INITIAL_TIME: f32 = 1.0;
299 let time = self.animation_timer.time();
300 let cos = (time * TIME_SCALE + INITIAL_TIME).cos() * LIGHT_DISTANCE;
301 let sin = (time * TIME_SCALE + INITIAL_TIME).sin() * LIGHT_DISTANCE;
302
303 let mut encoder =
304 device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
305
306 {
307 let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
308 label: None,
309 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
310 view,
311 depth_slice: None,
312 resolve_target: None,
313 ops: wgpu::Operations {
314 load: wgpu::LoadOp::Clear(wgpu::Color {
315 r: 0.1,
316 g: 0.1,
317 b: 0.1,
318 a: 1.0,
319 }),
320 store: wgpu::StoreOp::Store,
321 },
322 })],
323 depth_stencil_attachment: None,
324 timestamp_writes: None,
325 occlusion_query_set: None,
326 multiview_mask: None,
327 });
328
329 rpass.set_pipeline(&self.pipeline);
330 rpass.set_bind_group(0, Some(&self.bind_group), &[]);
331 rpass.set_immediates(0, &0.0_f32.to_ne_bytes());
332 rpass.set_immediates(4, &cos.to_ne_bytes());
333 rpass.set_immediates(8, &sin.to_ne_bytes());
334 rpass.set_vertex_buffer(0, self.vertex_buf.slice(..));
335 rpass.set_index_buffer(self.index_buf.slice(..), IndexFormat::Uint16);
336 rpass.draw_indexed(0..12, 0, 0..1);
337 }
338 queue.submit(Some(encoder.finish()));
339 device.poll(wgpu::PollType::wait_indefinitely()).unwrap();
340 }
341}
342
343pub fn main() {
344 crate::framework::run::<Example>("ray-shadows");
345}
346
347#[cfg(test)]
348#[wgpu_test::gpu_test]
349pub static TEST: crate::framework::ExampleTestParams = crate::framework::ExampleTestParams {
350 name: "ray_shadows",
351 image_path: "/examples/features/src/ray_shadows/screenshot.png",
352 width: 1024,
353 height: 768,
354 optional_features: wgpu::Features::default(),
355 base_test_parameters: wgpu_test::TestParameters::default()
356 .expect_fail(wgpu_test::FailureCase::backend(wgpu::Backends::METAL)),
358 comparisons: &[wgpu_test::ComparisonType::Mean(0.02)],
359 _phantom: std::marker::PhantomData::<Example>,
360};