1mod point_gen;
2
3use bytemuck::{Pod, Zeroable};
4use glam::Vec3;
5use nanorand::{Rng, WyRand};
6use std::{f32::consts, iter};
7use wgpu::util::DeviceExt;
8
9const SIZE: f32 = 29.0;
18
19const CAMERA: Vec3 = glam::Vec3::new(-200.0, 70.0, 200.0);
24
25struct Matrices {
26 view: glam::Mat4,
27 flipped_view: glam::Mat4,
28 projection: glam::Mat4,
29}
30
31#[repr(C)]
32#[derive(Copy, Clone, Debug, PartialEq, Pod, Zeroable)]
33struct TerrainUniforms {
34 view_projection: [f32; 16],
35 clipping_plane: [f32; 4],
36}
37
38#[repr(C)]
39#[derive(Copy, Clone, Debug, PartialEq, Pod, Zeroable)]
40struct WaterUniforms {
41 view: [f32; 16],
42 projection: [f32; 16],
43 time_size_width: [f32; 4],
44 height: [f32; 4],
45}
46
47struct Uniforms {
48 terrain_normal: TerrainUniforms,
49 terrain_flipped: TerrainUniforms,
50 water: WaterUniforms,
51}
52
53struct Example {
54 water_vertex_buf: wgpu::Buffer,
55 water_vertex_count: usize,
56 water_bind_group_layout: wgpu::BindGroupLayout,
57 water_bind_group: wgpu::BindGroup,
58 water_uniform_buf: wgpu::Buffer,
59 water_pipeline: wgpu::RenderPipeline,
60
61 terrain_vertex_buf: wgpu::Buffer,
62 terrain_vertex_count: usize,
63 terrain_normal_bind_group: wgpu::BindGroup,
64 terrain_normal_uniform_buf: wgpu::Buffer,
65 terrain_flipped_uniform_buf: wgpu::Buffer,
70 terrain_pipeline: wgpu::RenderPipeline,
71
72 terrain_bundle: wgpu::RenderBundle,
78
79 reflect_view: wgpu::TextureView,
80
81 depth_buffer: wgpu::TextureView,
82
83 current_frame: usize,
84
85 active: Option<usize>,
90}
91
92impl Example {
93 fn generate_matrices(aspect_ratio: f32) -> Matrices {
97 let projection = glam::Mat4::perspective_rh(consts::FRAC_PI_4, aspect_ratio, 10.0, 400.0);
98 let reg_view = glam::Mat4::look_at_rh(
99 CAMERA,
100 glam::Vec3::new(0f32, 0.0, 0.0),
101 glam::Vec3::Y, );
103
104 let scale = glam::Mat4::from_scale(glam::Vec3::new(8.0, 1.5, 8.0));
105
106 let reg_view = reg_view * scale;
107
108 let flipped_view = glam::Mat4::look_at_rh(
109 glam::Vec3::new(CAMERA.x, -CAMERA.y, CAMERA.z),
110 glam::Vec3::ZERO,
111 glam::Vec3::Y,
112 );
113
114 let flipped_view = flipped_view * scale;
115
116 Matrices {
117 view: reg_view,
118 flipped_view,
119 projection,
120 }
121 }
122
123 fn generate_uniforms(width: u32, height: u32) -> Uniforms {
124 let Matrices {
125 view,
126 flipped_view,
127 projection,
128 } = Self::generate_matrices(width as f32 / height as f32);
129
130 Uniforms {
131 terrain_normal: TerrainUniforms {
132 view_projection: *(projection * view).as_ref(),
133 clipping_plane: [0.0; 4],
134 },
135 terrain_flipped: TerrainUniforms {
136 view_projection: *(projection * flipped_view).as_ref(),
137 clipping_plane: [0., 1., 0., 0.],
138 },
139 water: WaterUniforms {
140 view: *view.as_ref(),
141 projection: *projection.as_ref(),
142 time_size_width: [0.0, 1.0, SIZE * 2.0, width as f32],
143 height: [height as f32, 0.0, 0.0, 0.0],
144 },
145 }
146 }
147
148 fn initialize_resources(
152 config: &wgpu::SurfaceConfiguration,
153 device: &wgpu::Device,
154 queue: &wgpu::Queue,
155 water_uniforms: &wgpu::Buffer,
156 terrain_normal_uniforms: &wgpu::Buffer,
157 terrain_flipped_uniforms: &wgpu::Buffer,
158 water_bind_group_layout: &wgpu::BindGroupLayout,
159 ) -> (wgpu::TextureView, wgpu::TextureView, wgpu::BindGroup) {
160 let Uniforms {
163 terrain_normal,
164 terrain_flipped,
165 water,
166 } = Self::generate_uniforms(config.width, config.height);
167
168 queue.write_buffer(
170 terrain_normal_uniforms,
171 0,
172 bytemuck::cast_slice(&[terrain_normal]),
173 );
174 queue.write_buffer(
175 terrain_flipped_uniforms,
176 0,
177 bytemuck::cast_slice(&[terrain_flipped]),
178 );
179 queue.write_buffer(water_uniforms, 0, bytemuck::cast_slice(&[water]));
180
181 let texture_extent = wgpu::Extent3d {
182 width: config.width,
183 height: config.height,
184 depth_or_array_layers: 1,
185 };
186
187 let reflection_texture = device.create_texture(&wgpu::TextureDescriptor {
188 label: Some("Reflection Render Texture"),
189 size: texture_extent,
190 mip_level_count: 1,
191 sample_count: 1,
192 dimension: wgpu::TextureDimension::D2,
193 format: config.view_formats[0],
194 usage: wgpu::TextureUsages::TEXTURE_BINDING
195 | wgpu::TextureUsages::COPY_DST
196 | wgpu::TextureUsages::RENDER_ATTACHMENT,
197 view_formats: &[],
198 });
199
200 let draw_depth_buffer = device.create_texture(&wgpu::TextureDescriptor {
201 label: Some("Depth Buffer"),
202 size: texture_extent,
203 mip_level_count: 1,
204 sample_count: 1,
205 dimension: wgpu::TextureDimension::D2,
206 format: wgpu::TextureFormat::Depth32Float,
207 usage: wgpu::TextureUsages::TEXTURE_BINDING
208 | wgpu::TextureUsages::COPY_DST
209 | wgpu::TextureUsages::RENDER_ATTACHMENT,
210 view_formats: &[],
211 });
212
213 let color_sampler = device.create_sampler(&wgpu::SamplerDescriptor {
214 label: Some("Color Sampler"),
215 address_mode_u: wgpu::AddressMode::ClampToEdge,
216 address_mode_v: wgpu::AddressMode::ClampToEdge,
217 address_mode_w: wgpu::AddressMode::ClampToEdge,
218 mag_filter: wgpu::FilterMode::Nearest,
219 min_filter: wgpu::FilterMode::Linear,
220 mipmap_filter: wgpu::FilterMode::Nearest,
221 ..Default::default()
222 });
223
224 let depth_sampler = device.create_sampler(&wgpu::SamplerDescriptor {
225 label: Some("Depth Sampler"),
226 ..Default::default()
227 });
228
229 let depth_view = draw_depth_buffer.create_view(&wgpu::TextureViewDescriptor::default());
230
231 let water_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
232 layout: water_bind_group_layout,
233 entries: &[
234 wgpu::BindGroupEntry {
235 binding: 0,
236 resource: water_uniforms.as_entire_binding(),
237 },
238 wgpu::BindGroupEntry {
239 binding: 1,
240 resource: wgpu::BindingResource::TextureView(
241 &reflection_texture.create_view(&wgpu::TextureViewDescriptor::default()),
242 ),
243 },
244 wgpu::BindGroupEntry {
245 binding: 2,
246 resource: wgpu::BindingResource::TextureView(&depth_view),
247 },
248 wgpu::BindGroupEntry {
249 binding: 3,
250 resource: wgpu::BindingResource::Sampler(&color_sampler),
251 },
252 wgpu::BindGroupEntry {
253 binding: 4,
254 resource: wgpu::BindingResource::Sampler(&depth_sampler),
255 },
256 ],
257 label: Some("Water Bind Group"),
258 });
259
260 (
261 reflection_texture.create_view(&wgpu::TextureViewDescriptor::default()),
262 depth_view,
263 water_bind_group,
264 )
265 }
266}
267
268impl crate::framework::Example for Example {
269 fn init(
270 config: &wgpu::SurfaceConfiguration,
271 _adapter: &wgpu::Adapter,
272 device: &wgpu::Device,
273 queue: &wgpu::Queue,
274 ) -> Self {
275 let water_vertex_size = size_of::<point_gen::WaterVertexAttributes>();
277
278 let water_vertices = point_gen::HexWaterMesh::generate(SIZE).generate_points();
279
280 let terrain_vertex_size = size_of::<point_gen::TerrainVertexAttributes>();
282
283 let terrain_noise = noise::OpenSimplex::default();
285
286 let mut terrain_random = WyRand::new_seed(42);
288
289 let terrain =
291 point_gen::HexTerrainMesh::generate(SIZE, |point| -> point_gen::TerrainVertex {
292 use noise::NoiseFn;
293 let noise = terrain_noise.get([point[0] as f64 / 5.0, point[1] as f64 / 5.0]) + 0.1;
294
295 let y = noise as f32 * 22.0;
296
297 fn mul_arr(mut arr: [u8; 4], by: f32) -> [u8; 4] {
299 arr[0] = (arr[0] as f32 * by).min(255.0) as u8;
300 arr[1] = (arr[1] as f32 * by).min(255.0) as u8;
301 arr[2] = (arr[2] as f32 * by).min(255.0) as u8;
302 arr
303 }
304
305 const DARK_SAND: [u8; 4] = [235, 175, 71, 255];
307 const SAND: [u8; 4] = [217, 191, 76, 255];
309 const GRASS: [u8; 4] = [122, 170, 19, 255];
311 const SNOW: [u8; 4] = [175, 224, 237, 255];
313
314 let random = terrain_random.generate::<f32>() * 0.2 + 0.9;
316
317 let colour = if y <= 0.0 {
319 DARK_SAND
320 } else if y <= 0.8 {
321 SAND
322 } else if y <= 10.0 {
323 GRASS
324 } else {
325 SNOW
326 };
327 point_gen::TerrainVertex {
328 position: Vec3::new(point[0], y, point[1]),
329 colour: mul_arr(colour, random),
330 }
331 });
332
333 let terrain_vertices = terrain.make_buffer_data();
335
336 let water_vertex_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
338 label: Some("Water vertices"),
339 contents: bytemuck::cast_slice(&water_vertices),
340 usage: wgpu::BufferUsages::VERTEX,
341 });
342
343 let terrain_vertex_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
344 label: Some("Terrain vertices"),
345 contents: bytemuck::cast_slice(&terrain_vertices),
346 usage: wgpu::BufferUsages::VERTEX,
347 });
348
349 let water_bind_group_layout =
351 device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
352 label: Some("Water Bind Group Layout"),
353 entries: &[
354 wgpu::BindGroupLayoutEntry {
356 binding: 0,
357 visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
358 ty: wgpu::BindingType::Buffer {
359 ty: wgpu::BufferBindingType::Uniform,
360 has_dynamic_offset: false,
361 min_binding_size: wgpu::BufferSize::new(
362 size_of::<WaterUniforms>() as _,
363 ),
364 },
365 count: None,
366 },
367 wgpu::BindGroupLayoutEntry {
369 binding: 1,
370 visibility: wgpu::ShaderStages::FRAGMENT,
371 ty: wgpu::BindingType::Texture {
372 multisampled: false,
373 sample_type: wgpu::TextureSampleType::Float { filterable: true },
374 view_dimension: wgpu::TextureViewDimension::D2,
375 },
376 count: None,
377 },
378 wgpu::BindGroupLayoutEntry {
380 binding: 2,
381 visibility: wgpu::ShaderStages::FRAGMENT,
382 ty: wgpu::BindingType::Texture {
383 multisampled: false,
384 sample_type: wgpu::TextureSampleType::Float { filterable: false },
385 view_dimension: wgpu::TextureViewDimension::D2,
386 },
387 count: None,
388 },
389 wgpu::BindGroupLayoutEntry {
391 binding: 3,
392 visibility: wgpu::ShaderStages::FRAGMENT,
393 ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
394 count: None,
395 },
396 wgpu::BindGroupLayoutEntry {
398 binding: 4,
399 visibility: wgpu::ShaderStages::FRAGMENT,
400 ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::NonFiltering),
401 count: None,
402 },
403 ],
404 });
405
406 let terrain_bind_group_layout =
407 device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
408 label: Some("Terrain Bind Group Layout"),
409 entries: &[
410 wgpu::BindGroupLayoutEntry {
412 binding: 0,
413 visibility: wgpu::ShaderStages::VERTEX,
414 ty: wgpu::BindingType::Buffer {
415 ty: wgpu::BufferBindingType::Uniform,
416 has_dynamic_offset: false,
417 min_binding_size: wgpu::BufferSize::new(
418 size_of::<TerrainUniforms>() as _
419 ),
420 },
421 count: None,
422 },
423 ],
424 });
425
426 let water_pipeline_layout =
428 device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
429 label: Some("water"),
430 bind_group_layouts: &[&water_bind_group_layout],
431 push_constant_ranges: &[],
432 });
433
434 let terrain_pipeline_layout =
435 device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
436 label: Some("terrain"),
437 bind_group_layouts: &[&terrain_bind_group_layout],
438 push_constant_ranges: &[],
439 });
440
441 let water_uniform_buf = device.create_buffer(&wgpu::BufferDescriptor {
442 label: Some("Water Uniforms"),
443 size: size_of::<WaterUniforms>() as _,
444 usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
445 mapped_at_creation: false,
446 });
447
448 let terrain_normal_uniform_buf = device.create_buffer(&wgpu::BufferDescriptor {
449 label: Some("Normal Terrain Uniforms"),
450 size: size_of::<TerrainUniforms>() as _,
451 usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
452 mapped_at_creation: false,
453 });
454
455 let terrain_flipped_uniform_buf = device.create_buffer(&wgpu::BufferDescriptor {
456 label: Some("Flipped Terrain Uniforms"),
457 size: size_of::<TerrainUniforms>() as _,
458 usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
459 mapped_at_creation: false,
460 });
461
462 let (reflect_view, depth_buffer, water_bind_group) = Self::initialize_resources(
466 config,
467 device,
468 queue,
469 &water_uniform_buf,
470 &terrain_normal_uniform_buf,
471 &terrain_flipped_uniform_buf,
472 &water_bind_group_layout,
473 );
474
475 let terrain_normal_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
476 layout: &terrain_bind_group_layout,
477 entries: &[wgpu::BindGroupEntry {
478 binding: 0,
479 resource: terrain_normal_uniform_buf.as_entire_binding(),
480 }],
481 label: Some("Terrain Normal Bind Group"),
482 });
483
484 let terrain_flipped_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
487 layout: &terrain_bind_group_layout,
488 entries: &[wgpu::BindGroupEntry {
489 binding: 0,
490 resource: terrain_flipped_uniform_buf.as_entire_binding(),
491 }],
492 label: Some("Terrain Flipped Bind Group"),
493 });
494
495 let terrain_module = device.create_shader_module(wgpu::include_wgsl!("terrain.wgsl"));
497 let water_module = device.create_shader_module(wgpu::include_wgsl!("water.wgsl"));
498
499 let water_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
502 label: Some("water"),
503 layout: Some(&water_pipeline_layout),
505 vertex: wgpu::VertexState {
507 module: &water_module,
508 entry_point: Some("vs_main"),
509 compilation_options: Default::default(),
510 buffers: &[wgpu::VertexBufferLayout {
516 array_stride: water_vertex_size as wgpu::BufferAddress,
517 step_mode: wgpu::VertexStepMode::Vertex,
518 attributes: &wgpu::vertex_attr_array![0 => Sint16x2, 1 => Sint8x4],
519 }],
520 },
521 fragment: Some(wgpu::FragmentState {
523 module: &water_module,
524 entry_point: Some("fs_main"),
525 compilation_options: Default::default(),
526 targets: &[Some(wgpu::ColorTargetState {
529 format: config.view_formats[0],
530 blend: Some(wgpu::BlendState {
531 color: wgpu::BlendComponent {
532 src_factor: wgpu::BlendFactor::SrcAlpha,
533 dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
534 operation: wgpu::BlendOperation::Add,
535 },
536 alpha: wgpu::BlendComponent {
537 src_factor: wgpu::BlendFactor::One,
538 dst_factor: wgpu::BlendFactor::One,
539 operation: wgpu::BlendOperation::Max,
540 },
541 }),
542 write_mask: wgpu::ColorWrites::ALL,
543 })],
544 }),
545 primitive: wgpu::PrimitiveState {
549 topology: wgpu::PrimitiveTopology::TriangleList,
551 front_face: wgpu::FrontFace::Cw,
552 ..Default::default()
553 },
554 depth_stencil: Some(wgpu::DepthStencilState {
561 format: wgpu::TextureFormat::Depth32Float,
563 depth_write_enabled: false,
564 depth_compare: wgpu::CompareFunction::Less,
565 stencil: wgpu::StencilState::default(),
566 bias: wgpu::DepthBiasState::default(),
567 }),
568 multisample: wgpu::MultisampleState::default(),
570 multiview: None,
571 cache: None,
573 });
574
575 let terrain_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
577 label: Some("terrain"),
578 layout: Some(&terrain_pipeline_layout),
579 vertex: wgpu::VertexState {
580 module: &terrain_module,
581 entry_point: Some("vs_main"),
582 compilation_options: Default::default(),
583 buffers: &[wgpu::VertexBufferLayout {
584 array_stride: terrain_vertex_size as wgpu::BufferAddress,
585 step_mode: wgpu::VertexStepMode::Vertex,
586 attributes: &wgpu::vertex_attr_array![0 => Float32x3, 1 => Float32x3, 2 => Unorm8x4],
587 }],
588 },
589 fragment: Some(wgpu::FragmentState {
590 module: &terrain_module,
591 entry_point: Some("fs_main"),
592 compilation_options: Default::default(),
593 targets: &[Some(config.view_formats[0].into())],
594 }),
595 primitive: wgpu::PrimitiveState {
596 front_face: wgpu::FrontFace::Ccw,
597 cull_mode: Some(wgpu::Face::Front),
598 ..Default::default()
599 },
600 depth_stencil: Some(wgpu::DepthStencilState {
601 format: wgpu::TextureFormat::Depth32Float,
602 depth_write_enabled: true,
603 depth_compare: wgpu::CompareFunction::Less,
604 stencil: wgpu::StencilState::default(),
605 bias: wgpu::DepthBiasState::default(),
606 }),
607 multisample: wgpu::MultisampleState::default(),
608 multiview: None,
609 cache: None
610 });
611
612 let terrain_bundle = {
614 let mut encoder =
615 device.create_render_bundle_encoder(&wgpu::RenderBundleEncoderDescriptor {
616 label: None,
617 color_formats: &[Some(config.view_formats[0])],
618 depth_stencil: Some(wgpu::RenderBundleDepthStencil {
619 format: wgpu::TextureFormat::Depth32Float,
620 depth_read_only: false,
621 stencil_read_only: true,
622 }),
623 sample_count: 1,
624 multiview: None,
625 });
626 encoder.set_pipeline(&terrain_pipeline);
627 encoder.set_bind_group(0, &terrain_flipped_bind_group, &[]);
628 encoder.set_vertex_buffer(0, terrain_vertex_buf.slice(..));
629 encoder.draw(0..terrain_vertices.len() as u32, 0..1);
630 encoder.finish(&wgpu::RenderBundleDescriptor::default())
631 };
632
633 Example {
635 water_vertex_buf,
636 water_vertex_count: water_vertices.len(),
637 water_bind_group_layout,
638 water_bind_group,
639 water_uniform_buf,
640 water_pipeline,
641
642 terrain_vertex_buf,
643 terrain_vertex_count: terrain_vertices.len(),
644 terrain_normal_bind_group,
645 terrain_normal_uniform_buf,
646 terrain_flipped_uniform_buf,
647 terrain_pipeline,
648 terrain_bundle,
649
650 reflect_view,
651
652 depth_buffer,
653
654 current_frame: 0,
655
656 active: Some(0),
657 }
658 }
659
660 fn update(&mut self, _event: winit::event::WindowEvent) {
661 }
663
664 fn resize(
665 &mut self,
666 config: &wgpu::SurfaceConfiguration,
667 device: &wgpu::Device,
668 queue: &wgpu::Queue,
669 ) {
670 if config.width == 0 && config.height == 0 {
671 self.active = None;
673 return;
674 }
675 self.active = Some(self.current_frame);
676
677 let (reflect_view, depth_buffer, water_bind_group) = Self::initialize_resources(
680 config,
681 device,
682 queue,
683 &self.water_uniform_buf,
684 &self.terrain_normal_uniform_buf,
685 &self.terrain_flipped_uniform_buf,
686 &self.water_bind_group_layout,
687 );
688 self.water_bind_group = water_bind_group;
689
690 self.depth_buffer = depth_buffer;
691 self.reflect_view = reflect_view;
692 }
693
694 fn render(&mut self, view: &wgpu::TextureView, device: &wgpu::Device, queue: &wgpu::Queue) {
695 self.current_frame += 1;
697 #[expect(clippy::eq_op, reason = "keeping common divisor on all elements")]
698 let back_color = wgpu::Color {
699 r: 161.0 / 255.0,
700 g: 246.0 / 255.0,
701 b: 255.0 / 255.0,
702 a: 1.0,
703 };
704
705 let (water_sin, water_cos) = ((self.current_frame as f32) / 600.0).sin_cos();
707 queue.write_buffer(
708 &self.water_uniform_buf,
709 size_of::<[f32; 16]>() as wgpu::BufferAddress * 2,
710 bytemuck::cast_slice(&[water_sin, water_cos]),
711 );
712
713 if let Some(active) = self.active {
715 if active >= self.current_frame {
716 return;
717 }
718 } else {
719 return;
720 }
721
722 let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
725 label: Some("Main Command Encoder"),
726 });
727
728 {
730 let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
731 label: None,
732 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
733 view: &self.reflect_view,
734 depth_slice: None,
735 resolve_target: None,
736 ops: wgpu::Operations {
737 load: wgpu::LoadOp::Clear(back_color),
738 store: wgpu::StoreOp::Store,
739 },
740 })],
741 depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
744 view: &self.depth_buffer,
745 depth_ops: Some(wgpu::Operations {
746 load: wgpu::LoadOp::Clear(1.0),
747 store: wgpu::StoreOp::Store,
748 }),
749 stencil_ops: None,
750 }),
751 timestamp_writes: None,
752 occlusion_query_set: None,
753 });
754
755 rpass.execute_bundles([&self.terrain_bundle]);
756 }
757 {
760 let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
761 label: None,
762 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
763 view,
764 depth_slice: None,
765 resolve_target: None,
766 ops: wgpu::Operations {
767 load: wgpu::LoadOp::Clear(back_color),
768 store: wgpu::StoreOp::Store,
769 },
770 })],
771 depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
772 view: &self.depth_buffer,
773 depth_ops: Some(wgpu::Operations {
774 load: wgpu::LoadOp::Clear(1.0),
775 store: wgpu::StoreOp::Store,
776 }),
777 stencil_ops: None,
778 }),
779 timestamp_writes: None,
780 occlusion_query_set: None,
781 });
782 rpass.set_pipeline(&self.terrain_pipeline);
783 rpass.set_bind_group(0, &self.terrain_normal_bind_group, &[]);
784 rpass.set_vertex_buffer(0, self.terrain_vertex_buf.slice(..));
785 rpass.draw(0..self.terrain_vertex_count as u32, 0..1);
786 }
787 {
790 let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
791 label: None,
792 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
793 view,
794 depth_slice: None,
795 resolve_target: None,
796 ops: wgpu::Operations {
797 load: wgpu::LoadOp::Load,
798 store: wgpu::StoreOp::Store,
799 },
800 })],
801 depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
802 view: &self.depth_buffer,
803 depth_ops: None,
804 stencil_ops: None,
805 }),
806 timestamp_writes: None,
807 occlusion_query_set: None,
808 });
809
810 rpass.set_pipeline(&self.water_pipeline);
811 rpass.set_bind_group(0, &self.water_bind_group, &[]);
812 rpass.set_vertex_buffer(0, self.water_vertex_buf.slice(..));
813 rpass.draw(0..self.water_vertex_count as u32, 0..1);
814 }
815
816 queue.submit(iter::once(encoder.finish()));
817 }
818}
819
820pub fn main() {
821 crate::framework::run::<Example>("water");
822}
823
824#[cfg(test)]
825#[wgpu_test::gpu_test]
826pub static TEST: crate::framework::ExampleTestParams = crate::framework::ExampleTestParams {
827 name: "water",
828 image_path: "/examples/features/src/water/screenshot.png",
829 width: 1024,
830 height: 768,
831 optional_features: wgpu::Features::default(),
832 base_test_parameters: wgpu_test::TestParameters::default()
833 .downlevel_flags(wgpu::DownlevelFlags::READ_ONLY_DEPTH_STENCIL)
834 .expect_fail(wgpu_test::FailureCase {
836 backends: Some(wgpu::Backends::VULKAN),
837 reasons: vec![wgpu_test::FailureReason::validation_error()
838 .with_message("WRITE_AFTER_WRITE hazard detected.")],
839 behavior: wgpu_test::FailureBehavior::AssertFailure,
840 ..Default::default()
841 }),
842 comparisons: &[wgpu_test::ComparisonType::Mean(0.01)],
843 _phantom: std::marker::PhantomData::<Example>,
844};