1use threecrate_core::{Result, Error};
4use crate::GpuContext;
5use nalgebra::{Matrix4, Vector3, Point3};
6use bytemuck::{Pod, Zeroable};
7use wgpu::util::DeviceExt;
8use winit::window::Window;
9
10#[repr(C)]
12#[derive(Copy, Clone, Debug, Pod, Zeroable)]
13pub struct MeshVertex {
14 pub position: [f32; 3],
15 pub normal: [f32; 3],
16 pub tangent: [f32; 3],
17 pub bitangent: [f32; 3],
18 pub uv: [f32; 2],
19 pub color: [f32; 3],
20 pub _padding: f32,
21}
22
23impl MeshVertex {
24 pub fn new(
26 position: [f32; 3],
27 normal: [f32; 3],
28 uv: [f32; 2],
29 color: [f32; 3],
30 ) -> Self {
31 let tangent = if normal[0].abs() > 0.9 {
33 [0.0, 1.0, 0.0]
34 } else {
35 [1.0, 0.0, 0.0]
36 };
37
38 let bitangent = [
39 normal[1] * tangent[2] - normal[2] * tangent[1],
40 normal[2] * tangent[0] - normal[0] * tangent[2],
41 normal[0] * tangent[1] - normal[1] * tangent[0],
42 ];
43
44 Self {
45 position,
46 normal,
47 tangent,
48 bitangent,
49 uv,
50 color,
51 _padding: 0.0,
52 }
53 }
54
55 pub fn from_pos_normal(position: [f32; 3], normal: [f32; 3]) -> Self {
57 Self::new(position, normal, [0.0, 0.0], [0.8, 0.8, 0.8])
58 }
59
60 pub fn desc<'a>() -> wgpu::VertexBufferLayout<'a> {
62 wgpu::VertexBufferLayout {
63 array_stride: std::mem::size_of::<MeshVertex>() as wgpu::BufferAddress,
64 step_mode: wgpu::VertexStepMode::Vertex,
65 attributes: &[
66 wgpu::VertexAttribute {
68 offset: 0,
69 shader_location: 0,
70 format: wgpu::VertexFormat::Float32x3,
71 },
72 wgpu::VertexAttribute {
74 offset: std::mem::size_of::<[f32; 3]>() as wgpu::BufferAddress,
75 shader_location: 1,
76 format: wgpu::VertexFormat::Float32x3,
77 },
78 wgpu::VertexAttribute {
80 offset: std::mem::size_of::<[f32; 6]>() as wgpu::BufferAddress,
81 shader_location: 2,
82 format: wgpu::VertexFormat::Float32x3,
83 },
84 wgpu::VertexAttribute {
86 offset: std::mem::size_of::<[f32; 9]>() as wgpu::BufferAddress,
87 shader_location: 3,
88 format: wgpu::VertexFormat::Float32x3,
89 },
90 wgpu::VertexAttribute {
92 offset: std::mem::size_of::<[f32; 12]>() as wgpu::BufferAddress,
93 shader_location: 4,
94 format: wgpu::VertexFormat::Float32x2,
95 },
96 wgpu::VertexAttribute {
98 offset: std::mem::size_of::<[f32; 14]>() as wgpu::BufferAddress,
99 shader_location: 5,
100 format: wgpu::VertexFormat::Float32x3,
101 },
102 ],
103 }
104 }
105}
106
107#[repr(C)]
109#[derive(Copy, Clone, Pod, Zeroable)]
110pub struct MeshCameraUniform {
111 pub view_proj: [[f32; 4]; 4],
112 pub view_pos: [f32; 3],
113 pub _padding: f32,
114}
115
116#[repr(C)]
118#[derive(Copy, Clone, Debug, Pod, Zeroable)]
119pub struct PbrMaterial {
120 pub albedo: [f32; 3],
121 pub metallic: f32,
122 pub roughness: f32,
123 pub ao: f32,
124 pub emission: [f32; 3],
125 pub _padding: f32,
126}
127
128impl Default for PbrMaterial {
129 fn default() -> Self {
130 Self {
131 albedo: [0.7, 0.7, 0.7],
132 metallic: 0.0,
133 roughness: 0.5,
134 ao: 1.0,
135 emission: [0.0, 0.0, 0.0],
136 _padding: 0.0,
137 }
138 }
139}
140
141#[repr(C)]
143#[derive(Copy, Clone, Debug, Pod, Zeroable)]
144pub struct FlatMaterial {
145 pub color: [f32; 3],
146 pub _padding: f32,
147}
148
149impl Default for FlatMaterial {
150 fn default() -> Self {
151 Self {
152 color: [0.8, 0.8, 0.8],
153 _padding: 0.0,
154 }
155 }
156}
157
158#[repr(C)]
160#[derive(Copy, Clone, Debug, Pod, Zeroable)]
161pub struct MeshLightingParams {
162 pub light_position: [f32; 3],
163 pub light_intensity: f32,
164 pub light_color: [f32; 3],
165 pub ambient_strength: f32,
166 pub gamma: f32,
167 pub exposure: f32,
168 pub _padding: [f32; 2],
169}
170
171impl Default for MeshLightingParams {
172 fn default() -> Self {
173 Self {
174 light_position: [10.0, 10.0, 10.0],
175 light_intensity: 1.0,
176 light_color: [1.0, 1.0, 1.0],
177 ambient_strength: 0.03,
178 gamma: 2.2,
179 exposure: 1.0,
180 _padding: [0.0, 0.0],
181 }
182 }
183}
184
185#[derive(Debug, Clone)]
187pub struct MeshRenderConfig {
188 pub lighting_params: MeshLightingParams,
189 pub background_color: [f64; 4],
190 pub enable_depth_test: bool,
191 pub enable_backface_culling: bool,
192 pub enable_multisampling: bool,
193 pub wireframe_mode: bool,
194}
195
196impl Default for MeshRenderConfig {
197 fn default() -> Self {
198 Self {
199 lighting_params: MeshLightingParams::default(),
200 background_color: [0.1, 0.1, 0.1, 1.0],
201 enable_depth_test: true,
202 enable_backface_culling: true,
203 enable_multisampling: true,
204 wireframe_mode: false,
205 }
206 }
207}
208
209#[derive(Debug, Clone)]
211pub struct GpuMesh {
212 pub vertices: Vec<MeshVertex>,
213 pub indices: Vec<u32>,
214 pub material: PbrMaterial,
215}
216
217impl GpuMesh {
218 pub fn new(vertices: Vec<MeshVertex>, indices: Vec<u32>, material: PbrMaterial) -> Self {
220 Self {
221 vertices,
222 indices,
223 material,
224 }
225 }
226
227 pub fn triangle() -> Self {
229 let vertices = vec![
230 MeshVertex::new([-0.5, -0.5, 0.0], [0.0, 0.0, 1.0], [0.0, 0.0], [1.0, 0.0, 0.0]),
231 MeshVertex::new([0.5, -0.5, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0], [0.0, 1.0, 0.0]),
232 MeshVertex::new([0.0, 0.5, 0.0], [0.0, 0.0, 1.0], [0.5, 1.0], [0.0, 0.0, 1.0]),
233 ];
234
235 let indices = vec![0, 1, 2];
236
237 Self::new(vertices, indices, PbrMaterial::default())
238 }
239
240 pub fn cube() -> Self {
242 let vertices = vec![
243 MeshVertex::new([-1.0, -1.0, 1.0], [0.0, 0.0, 1.0], [0.0, 0.0], [0.8, 0.2, 0.2]),
245 MeshVertex::new([1.0, -1.0, 1.0], [0.0, 0.0, 1.0], [1.0, 0.0], [0.8, 0.2, 0.2]),
246 MeshVertex::new([1.0, 1.0, 1.0], [0.0, 0.0, 1.0], [1.0, 1.0], [0.8, 0.2, 0.2]),
247 MeshVertex::new([-1.0, 1.0, 1.0], [0.0, 0.0, 1.0], [0.0, 1.0], [0.8, 0.2, 0.2]),
248
249 MeshVertex::new([1.0, -1.0, -1.0], [0.0, 0.0, -1.0], [0.0, 0.0], [0.2, 0.8, 0.2]),
251 MeshVertex::new([-1.0, -1.0, -1.0], [0.0, 0.0, -1.0], [1.0, 0.0], [0.2, 0.8, 0.2]),
252 MeshVertex::new([-1.0, 1.0, -1.0], [0.0, 0.0, -1.0], [1.0, 1.0], [0.2, 0.8, 0.2]),
253 MeshVertex::new([1.0, 1.0, -1.0], [0.0, 0.0, -1.0], [0.0, 1.0], [0.2, 0.8, 0.2]),
254
255 MeshVertex::new([-1.0, 1.0, 1.0], [0.0, 1.0, 0.0], [0.0, 0.0], [0.2, 0.2, 0.8]),
257 MeshVertex::new([1.0, 1.0, 1.0], [0.0, 1.0, 0.0], [1.0, 0.0], [0.2, 0.2, 0.8]),
258 MeshVertex::new([1.0, 1.0, -1.0], [0.0, 1.0, 0.0], [1.0, 1.0], [0.2, 0.2, 0.8]),
259 MeshVertex::new([-1.0, 1.0, -1.0], [0.0, 1.0, 0.0], [0.0, 1.0], [0.2, 0.2, 0.8]),
260
261 MeshVertex::new([-1.0, -1.0, -1.0], [0.0, -1.0, 0.0], [0.0, 0.0], [0.8, 0.8, 0.2]),
263 MeshVertex::new([1.0, -1.0, -1.0], [0.0, -1.0, 0.0], [1.0, 0.0], [0.8, 0.8, 0.2]),
264 MeshVertex::new([1.0, -1.0, 1.0], [0.0, -1.0, 0.0], [1.0, 1.0], [0.8, 0.8, 0.2]),
265 MeshVertex::new([-1.0, -1.0, 1.0], [0.0, -1.0, 0.0], [0.0, 1.0], [0.8, 0.8, 0.2]),
266
267 MeshVertex::new([1.0, -1.0, 1.0], [1.0, 0.0, 0.0], [0.0, 0.0], [0.8, 0.2, 0.8]),
269 MeshVertex::new([1.0, -1.0, -1.0], [1.0, 0.0, 0.0], [1.0, 0.0], [0.8, 0.2, 0.8]),
270 MeshVertex::new([1.0, 1.0, -1.0], [1.0, 0.0, 0.0], [1.0, 1.0], [0.8, 0.2, 0.8]),
271 MeshVertex::new([1.0, 1.0, 1.0], [1.0, 0.0, 0.0], [0.0, 1.0], [0.8, 0.2, 0.8]),
272
273 MeshVertex::new([-1.0, -1.0, -1.0], [-1.0, 0.0, 0.0], [0.0, 0.0], [0.2, 0.8, 0.8]),
275 MeshVertex::new([-1.0, -1.0, 1.0], [-1.0, 0.0, 0.0], [1.0, 0.0], [0.2, 0.8, 0.8]),
276 MeshVertex::new([-1.0, 1.0, 1.0], [-1.0, 0.0, 0.0], [1.0, 1.0], [0.2, 0.8, 0.8]),
277 MeshVertex::new([-1.0, 1.0, -1.0], [-1.0, 0.0, 0.0], [0.0, 1.0], [0.2, 0.8, 0.8]),
278 ];
279
280 let indices = vec![
281 0, 1, 2, 2, 3, 0,
283 4, 5, 6, 6, 7, 4,
285 8, 9, 10, 10, 11, 8,
287 12, 13, 14, 14, 15, 12,
289 16, 17, 18, 18, 19, 16,
291 20, 21, 22, 22, 23, 20,
293 ];
294
295 Self::new(vertices, indices, PbrMaterial::default())
296 }
297
298 pub fn from_point_cloud(points: &[Point3<f32>], color: [f32; 3]) -> Self {
300 let vertices: Vec<MeshVertex> = points.iter().map(|p| {
301 let normal = [0.0, 0.0, 1.0]; MeshVertex::new([p.x, p.y, p.z], normal, [0.0, 0.0], color)
304 }).collect();
305
306 let indices: Vec<u32> = (0..vertices.len() as u32).collect();
308
309 Self::new(vertices, indices, PbrMaterial::default())
310 }
311}
312
313#[derive(Debug, Clone, Copy, PartialEq)]
315pub enum ShadingMode {
316 Flat,
317 Pbr,
318}
319
320pub struct MeshRenderer<'window> {
322 pub gpu_context: GpuContext,
323 pub surface: wgpu::Surface<'window>,
324 pub surface_config: wgpu::SurfaceConfiguration,
325 pub pbr_pipeline: wgpu::RenderPipeline,
326 pub flat_pipeline: wgpu::RenderPipeline,
327 pub camera_uniform: MeshCameraUniform,
328 pub camera_buffer: wgpu::Buffer,
329 pub lighting_params: MeshLightingParams,
330 pub lighting_buffer: wgpu::Buffer,
331 pub bind_group_layout: wgpu::BindGroupLayout,
332 pub config: MeshRenderConfig,
333 pub msaa_texture: Option<wgpu::Texture>,
334 pub msaa_view: Option<wgpu::TextureView>,
335}
336
337impl<'window> MeshRenderer<'window> {
338 pub async fn new(window: &'window Window, config: MeshRenderConfig) -> Result<Self> {
340 let gpu_context = GpuContext::new().await?;
341
342 let surface = gpu_context.instance.create_surface(window)
343 .map_err(|e| Error::Gpu(format!("Failed to create surface: {:?}", e)))?;
344
345 let surface_caps = surface.get_capabilities(&gpu_context.adapter);
346 let surface_format = surface_caps.formats.iter()
347 .copied()
348 .find(|f| f.is_srgb())
349 .unwrap_or(surface_caps.formats[0]);
350
351 let size = window.inner_size();
352 let sample_count = if config.enable_multisampling { 4 } else { 1 };
353
354 let surface_config = wgpu::SurfaceConfiguration {
355 usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
356 format: surface_format,
357 width: size.width,
358 height: size.height,
359 present_mode: surface_caps.present_modes[0],
360 alpha_mode: surface_caps.alpha_modes[0],
361 view_formats: vec![],
362 desired_maximum_frame_latency: 2,
363 };
364 surface.configure(&gpu_context.device, &surface_config);
365
366 let (msaa_texture, msaa_view) = if config.enable_multisampling {
368 let msaa_texture = gpu_context.device.create_texture(&wgpu::TextureDescriptor {
369 label: Some("MSAA Texture"),
370 size: wgpu::Extent3d {
371 width: size.width,
372 height: size.height,
373 depth_or_array_layers: 1,
374 },
375 mip_level_count: 1,
376 sample_count,
377 dimension: wgpu::TextureDimension::D2,
378 format: surface_format,
379 usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
380 view_formats: &[],
381 });
382 let msaa_view = msaa_texture.create_view(&wgpu::TextureViewDescriptor::default());
383 (Some(msaa_texture), Some(msaa_view))
384 } else {
385 (None, None)
386 };
387
388 let camera_uniform = MeshCameraUniform {
390 view_proj: Matrix4::identity().into(),
391 view_pos: [0.0, 0.0, 0.0],
392 _padding: 0.0,
393 };
394
395 let camera_buffer = gpu_context.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
396 label: Some("Camera Buffer"),
397 contents: bytemuck::bytes_of(&camera_uniform),
398 usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
399 });
400
401 let lighting_params = config.lighting_params;
403 let lighting_buffer = gpu_context.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
404 label: Some("Lighting Buffer"),
405 contents: bytemuck::bytes_of(&lighting_params),
406 usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
407 });
408
409 let bind_group_layout = gpu_context.device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
411 entries: &[
412 wgpu::BindGroupLayoutEntry {
413 binding: 0,
414 visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
415 ty: wgpu::BindingType::Buffer {
416 ty: wgpu::BufferBindingType::Uniform,
417 has_dynamic_offset: false,
418 min_binding_size: None,
419 },
420 count: None,
421 },
422 wgpu::BindGroupLayoutEntry {
423 binding: 1,
424 visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
425 ty: wgpu::BindingType::Buffer {
426 ty: wgpu::BufferBindingType::Uniform,
427 has_dynamic_offset: false,
428 min_binding_size: None,
429 },
430 count: None,
431 },
432 wgpu::BindGroupLayoutEntry {
433 binding: 2,
434 visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
435 ty: wgpu::BindingType::Buffer {
436 ty: wgpu::BufferBindingType::Uniform,
437 has_dynamic_offset: false,
438 min_binding_size: None,
439 },
440 count: None,
441 },
442 ],
443 label: Some("mesh_bind_group_layout"),
444 });
445
446 let pbr_shader = gpu_context.device.create_shader_module(wgpu::ShaderModuleDescriptor {
448 label: Some("PBR Mesh Shader"),
449 source: wgpu::ShaderSource::Wgsl(include_str!("shaders/mesh_pbr.wgsl").into()),
450 });
451
452 let pbr_pipeline = Self::create_render_pipeline(
453 &gpu_context.device,
454 &bind_group_layout,
455 &pbr_shader,
456 surface_format,
457 sample_count,
458 &config,
459 "PBR",
460 );
461
462 let flat_shader = gpu_context.device.create_shader_module(wgpu::ShaderModuleDescriptor {
464 label: Some("Flat Mesh Shader"),
465 source: wgpu::ShaderSource::Wgsl(include_str!("shaders/mesh_flat.wgsl").into()),
466 });
467
468 let flat_pipeline = Self::create_render_pipeline(
469 &gpu_context.device,
470 &bind_group_layout,
471 &flat_shader,
472 surface_format,
473 sample_count,
474 &config,
475 "Flat",
476 );
477
478 Ok(Self {
479 gpu_context,
480 surface,
481 surface_config,
482 pbr_pipeline,
483 flat_pipeline,
484 camera_uniform,
485 camera_buffer,
486 lighting_params,
487 lighting_buffer,
488 bind_group_layout,
489 config,
490 msaa_texture,
491 msaa_view,
492 })
493 }
494
495 fn create_render_pipeline(
497 device: &wgpu::Device,
498 bind_group_layout: &wgpu::BindGroupLayout,
499 shader: &wgpu::ShaderModule,
500 surface_format: wgpu::TextureFormat,
501 sample_count: u32,
502 config: &MeshRenderConfig,
503 label: &str,
504 ) -> wgpu::RenderPipeline {
505 let render_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
506 label: Some(&format!("{} Mesh Render Pipeline Layout", label)),
507 bind_group_layouts: &[bind_group_layout],
508 push_constant_ranges: &[],
509 });
510
511 device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
512 label: Some(&format!("{} Mesh Render Pipeline", label)),
513 layout: Some(&render_pipeline_layout),
514 vertex: wgpu::VertexState {
515 module: shader,
516 entry_point: Some("vs_main"),
517 buffers: &[MeshVertex::desc()],
518 compilation_options: wgpu::PipelineCompilationOptions::default(),
519 },
520 fragment: Some(wgpu::FragmentState {
521 module: shader,
522 entry_point: Some("fs_main"),
523 targets: &[Some(wgpu::ColorTargetState {
524 format: surface_format,
525 blend: Some(wgpu::BlendState::REPLACE),
526 write_mask: wgpu::ColorWrites::ALL,
527 })],
528 compilation_options: wgpu::PipelineCompilationOptions::default(),
529 }),
530 primitive: wgpu::PrimitiveState {
531 topology: if config.wireframe_mode {
532 wgpu::PrimitiveTopology::LineList
533 } else {
534 wgpu::PrimitiveTopology::TriangleList
535 },
536 strip_index_format: None,
537 front_face: wgpu::FrontFace::Ccw,
538 cull_mode: if config.enable_backface_culling {
539 Some(wgpu::Face::Back)
540 } else {
541 None
542 },
543 unclipped_depth: false,
544 polygon_mode: wgpu::PolygonMode::Fill,
545 conservative: false,
546 },
547 depth_stencil: if config.enable_depth_test {
548 Some(wgpu::DepthStencilState {
549 format: wgpu::TextureFormat::Depth32Float,
550 depth_write_enabled: true,
551 depth_compare: wgpu::CompareFunction::Less,
552 stencil: wgpu::StencilState::default(),
553 bias: wgpu::DepthBiasState::default(),
554 })
555 } else {
556 None
557 },
558 multisample: wgpu::MultisampleState {
559 count: sample_count,
560 mask: !0,
561 alpha_to_coverage_enabled: false,
562 },
563 multiview: None,
564 cache: None,
565 })
566 }
567
568 pub fn update_camera(&mut self, view_matrix: Matrix4<f32>, proj_matrix: Matrix4<f32>, camera_pos: Vector3<f32>) {
570 self.camera_uniform.view_proj = (proj_matrix * view_matrix).into();
571 self.camera_uniform.view_pos = camera_pos.into();
572
573 self.gpu_context.queue.write_buffer(
574 &self.camera_buffer,
575 0,
576 bytemuck::bytes_of(&self.camera_uniform),
577 );
578 }
579
580 pub fn update_lighting(&mut self, params: MeshLightingParams) {
582 self.lighting_params = params;
583 self.gpu_context.queue.write_buffer(
584 &self.lighting_buffer,
585 0,
586 bytemuck::bytes_of(&self.lighting_params),
587 );
588 }
589
590 pub fn resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) {
592 if new_size.width > 0 && new_size.height > 0 {
593 self.surface_config.width = new_size.width;
594 self.surface_config.height = new_size.height;
595 self.surface.configure(&self.gpu_context.device, &self.surface_config);
596
597 if self.config.enable_multisampling {
599 let msaa_texture = self.gpu_context.device.create_texture(&wgpu::TextureDescriptor {
600 label: Some("MSAA Texture"),
601 size: wgpu::Extent3d {
602 width: new_size.width,
603 height: new_size.height,
604 depth_or_array_layers: 1,
605 },
606 mip_level_count: 1,
607 sample_count: 4,
608 dimension: wgpu::TextureDimension::D2,
609 format: self.surface_config.format,
610 usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
611 view_formats: &[],
612 });
613 let msaa_view = msaa_texture.create_view(&wgpu::TextureViewDescriptor::default());
614 self.msaa_texture = Some(msaa_texture);
615 self.msaa_view = Some(msaa_view);
616 }
617 }
618 }
619
620 pub fn create_vertex_buffer(&self, vertices: &[MeshVertex]) -> wgpu::Buffer {
622 self.gpu_context.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
623 label: Some("Mesh Vertex Buffer"),
624 contents: bytemuck::cast_slice(vertices),
625 usage: wgpu::BufferUsages::VERTEX,
626 })
627 }
628
629 pub fn create_index_buffer(&self, indices: &[u32]) -> wgpu::Buffer {
631 self.gpu_context.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
632 label: Some("Mesh Index Buffer"),
633 contents: bytemuck::cast_slice(indices),
634 usage: wgpu::BufferUsages::INDEX,
635 })
636 }
637
638 pub fn create_depth_texture(&self) -> wgpu::Texture {
640 let sample_count = if self.config.enable_multisampling { 4 } else { 1 };
641
642 self.gpu_context.device.create_texture(&wgpu::TextureDescriptor {
643 label: Some("Depth Texture"),
644 size: wgpu::Extent3d {
645 width: self.surface_config.width,
646 height: self.surface_config.height,
647 depth_or_array_layers: 1,
648 },
649 mip_level_count: 1,
650 sample_count,
651 dimension: wgpu::TextureDimension::D2,
652 format: wgpu::TextureFormat::Depth32Float,
653 usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
654 view_formats: &[],
655 })
656 }
657
658 pub fn render(&self, mesh: &GpuMesh, shading_mode: ShadingMode) -> Result<()> {
660 let vertex_buffer = self.create_vertex_buffer(&mesh.vertices);
661 let index_buffer = self.create_index_buffer(&mesh.indices);
662 let depth_texture = self.create_depth_texture();
663 let depth_view = depth_texture.create_view(&wgpu::TextureViewDescriptor::default());
664
665 let output = self.surface.get_current_texture()
666 .map_err(|e| Error::Gpu(format!("Failed to get surface texture: {:?}", e)))?;
667
668 let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default());
669
670 let material_buffer = match shading_mode {
672 ShadingMode::Pbr => {
673 self.gpu_context.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
674 label: Some("PBR Material Buffer"),
675 contents: bytemuck::bytes_of(&mesh.material),
676 usage: wgpu::BufferUsages::UNIFORM,
677 })
678 }
679 ShadingMode::Flat => {
680 let flat_material = FlatMaterial {
681 color: mesh.material.albedo,
682 _padding: 0.0,
683 };
684 self.gpu_context.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
685 label: Some("Flat Material Buffer"),
686 contents: bytemuck::bytes_of(&flat_material),
687 usage: wgpu::BufferUsages::UNIFORM,
688 })
689 }
690 };
691
692 let bind_group = self.gpu_context.device.create_bind_group(&wgpu::BindGroupDescriptor {
693 layout: &self.bind_group_layout,
694 entries: &[
695 wgpu::BindGroupEntry {
696 binding: 0,
697 resource: self.camera_buffer.as_entire_binding(),
698 },
699 wgpu::BindGroupEntry {
700 binding: 1,
701 resource: material_buffer.as_entire_binding(),
702 },
703 wgpu::BindGroupEntry {
704 binding: 2,
705 resource: self.lighting_buffer.as_entire_binding(),
706 },
707 ],
708 label: Some("mesh_bind_group"),
709 });
710
711 let mut encoder = self.gpu_context.device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
712 label: Some("Mesh Render Encoder"),
713 });
714
715 let (color_attachment, resolve_target) = if let Some(ref msaa_view) = self.msaa_view {
717 (msaa_view, Some(&view))
718 } else {
719 (&view, None)
720 };
721
722 {
723 let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
724 label: Some("Mesh Render Pass"),
725 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
726 view: color_attachment,
727 resolve_target,
728 ops: wgpu::Operations {
729 load: wgpu::LoadOp::Clear(wgpu::Color {
730 r: self.config.background_color[0],
731 g: self.config.background_color[1],
732 b: self.config.background_color[2],
733 a: self.config.background_color[3],
734 }),
735 store: wgpu::StoreOp::Store,
736 },
737 })],
738 depth_stencil_attachment: if self.config.enable_depth_test {
739 Some(wgpu::RenderPassDepthStencilAttachment {
740 view: &depth_view,
741 depth_ops: Some(wgpu::Operations {
742 load: wgpu::LoadOp::Clear(1.0),
743 store: wgpu::StoreOp::Store,
744 }),
745 stencil_ops: None,
746 })
747 } else {
748 None
749 },
750 timestamp_writes: None,
751 occlusion_query_set: None,
752 });
753
754 let pipeline = match shading_mode {
755 ShadingMode::Pbr => &self.pbr_pipeline,
756 ShadingMode::Flat => &self.flat_pipeline,
757 };
758
759 render_pass.set_pipeline(pipeline);
760 render_pass.set_bind_group(0, &bind_group, &[]);
761 render_pass.set_vertex_buffer(0, vertex_buffer.slice(..));
762 render_pass.set_index_buffer(index_buffer.slice(..), wgpu::IndexFormat::Uint32);
763 render_pass.draw_indexed(0..mesh.indices.len() as u32, 0, 0..1);
764 }
765
766 self.gpu_context.queue.submit(std::iter::once(encoder.finish()));
767 output.present();
768
769 Ok(())
770 }
771}
772
773pub fn mesh_to_gpu_mesh(
775 vertices: &[Point3<f32>],
776 indices: &[u32],
777 normals: Option<&[Vector3<f32>]>,
778 colors: Option<&[[f32; 3]]>,
779 material: Option<PbrMaterial>,
780) -> GpuMesh {
781 let gpu_vertices: Vec<MeshVertex> = vertices
782 .iter()
783 .enumerate()
784 .map(|(i, vertex)| {
785 let normal = normals
786 .and_then(|n| n.get(i))
787 .map(|n| [n.x, n.y, n.z])
788 .unwrap_or([0.0, 0.0, 1.0]);
789
790 let color = colors
791 .and_then(|c| c.get(i))
792 .copied()
793 .unwrap_or([0.8, 0.8, 0.8]);
794
795 MeshVertex::new([vertex.x, vertex.y, vertex.z], normal, [0.0, 0.0], color)
796 })
797 .collect();
798
799 GpuMesh::new(
800 gpu_vertices,
801 indices.to_vec(),
802 material.unwrap_or_default(),
803 )
804}