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: "vs_main",
517 buffers: &[MeshVertex::desc()],
518 compilation_options: wgpu::PipelineCompilationOptions::default(),
519 },
520 fragment: Some(wgpu::FragmentState {
521 module: shader,
522 entry_point: "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 })
565 }
566
567 pub fn update_camera(&mut self, view_matrix: Matrix4<f32>, proj_matrix: Matrix4<f32>, camera_pos: Vector3<f32>) {
569 self.camera_uniform.view_proj = (proj_matrix * view_matrix).into();
570 self.camera_uniform.view_pos = camera_pos.into();
571
572 self.gpu_context.queue.write_buffer(
573 &self.camera_buffer,
574 0,
575 bytemuck::bytes_of(&self.camera_uniform),
576 );
577 }
578
579 pub fn update_lighting(&mut self, params: MeshLightingParams) {
581 self.lighting_params = params;
582 self.gpu_context.queue.write_buffer(
583 &self.lighting_buffer,
584 0,
585 bytemuck::bytes_of(&self.lighting_params),
586 );
587 }
588
589 pub fn resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) {
591 if new_size.width > 0 && new_size.height > 0 {
592 self.surface_config.width = new_size.width;
593 self.surface_config.height = new_size.height;
594 self.surface.configure(&self.gpu_context.device, &self.surface_config);
595
596 if self.config.enable_multisampling {
598 let msaa_texture = self.gpu_context.device.create_texture(&wgpu::TextureDescriptor {
599 label: Some("MSAA Texture"),
600 size: wgpu::Extent3d {
601 width: new_size.width,
602 height: new_size.height,
603 depth_or_array_layers: 1,
604 },
605 mip_level_count: 1,
606 sample_count: 4,
607 dimension: wgpu::TextureDimension::D2,
608 format: self.surface_config.format,
609 usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
610 view_formats: &[],
611 });
612 let msaa_view = msaa_texture.create_view(&wgpu::TextureViewDescriptor::default());
613 self.msaa_texture = Some(msaa_texture);
614 self.msaa_view = Some(msaa_view);
615 }
616 }
617 }
618
619 pub fn create_vertex_buffer(&self, vertices: &[MeshVertex]) -> wgpu::Buffer {
621 self.gpu_context.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
622 label: Some("Mesh Vertex Buffer"),
623 contents: bytemuck::cast_slice(vertices),
624 usage: wgpu::BufferUsages::VERTEX,
625 })
626 }
627
628 pub fn create_index_buffer(&self, indices: &[u32]) -> wgpu::Buffer {
630 self.gpu_context.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
631 label: Some("Mesh Index Buffer"),
632 contents: bytemuck::cast_slice(indices),
633 usage: wgpu::BufferUsages::INDEX,
634 })
635 }
636
637 pub fn create_depth_texture(&self) -> wgpu::Texture {
639 let sample_count = if self.config.enable_multisampling { 4 } else { 1 };
640
641 self.gpu_context.device.create_texture(&wgpu::TextureDescriptor {
642 label: Some("Depth Texture"),
643 size: wgpu::Extent3d {
644 width: self.surface_config.width,
645 height: self.surface_config.height,
646 depth_or_array_layers: 1,
647 },
648 mip_level_count: 1,
649 sample_count,
650 dimension: wgpu::TextureDimension::D2,
651 format: wgpu::TextureFormat::Depth32Float,
652 usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
653 view_formats: &[],
654 })
655 }
656
657 pub fn render(&self, mesh: &GpuMesh, shading_mode: ShadingMode) -> Result<()> {
659 let vertex_buffer = self.create_vertex_buffer(&mesh.vertices);
660 let index_buffer = self.create_index_buffer(&mesh.indices);
661 let depth_texture = self.create_depth_texture();
662 let depth_view = depth_texture.create_view(&wgpu::TextureViewDescriptor::default());
663
664 let output = self.surface.get_current_texture()
665 .map_err(|e| Error::Gpu(format!("Failed to get surface texture: {:?}", e)))?;
666
667 let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default());
668
669 let material_buffer = match shading_mode {
671 ShadingMode::Pbr => {
672 self.gpu_context.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
673 label: Some("PBR Material Buffer"),
674 contents: bytemuck::bytes_of(&mesh.material),
675 usage: wgpu::BufferUsages::UNIFORM,
676 })
677 }
678 ShadingMode::Flat => {
679 let flat_material = FlatMaterial {
680 color: mesh.material.albedo,
681 _padding: 0.0,
682 };
683 self.gpu_context.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
684 label: Some("Flat Material Buffer"),
685 contents: bytemuck::bytes_of(&flat_material),
686 usage: wgpu::BufferUsages::UNIFORM,
687 })
688 }
689 };
690
691 let bind_group = self.gpu_context.device.create_bind_group(&wgpu::BindGroupDescriptor {
692 layout: &self.bind_group_layout,
693 entries: &[
694 wgpu::BindGroupEntry {
695 binding: 0,
696 resource: self.camera_buffer.as_entire_binding(),
697 },
698 wgpu::BindGroupEntry {
699 binding: 1,
700 resource: material_buffer.as_entire_binding(),
701 },
702 wgpu::BindGroupEntry {
703 binding: 2,
704 resource: self.lighting_buffer.as_entire_binding(),
705 },
706 ],
707 label: Some("mesh_bind_group"),
708 });
709
710 let mut encoder = self.gpu_context.device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
711 label: Some("Mesh Render Encoder"),
712 });
713
714 let (color_attachment, resolve_target) = if let Some(ref msaa_view) = self.msaa_view {
716 (msaa_view, Some(&view))
717 } else {
718 (&view, None)
719 };
720
721 {
722 let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
723 label: Some("Mesh Render Pass"),
724 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
725 view: color_attachment,
726 resolve_target,
727 ops: wgpu::Operations {
728 load: wgpu::LoadOp::Clear(wgpu::Color {
729 r: self.config.background_color[0],
730 g: self.config.background_color[1],
731 b: self.config.background_color[2],
732 a: self.config.background_color[3],
733 }),
734 store: wgpu::StoreOp::Store,
735 },
736 })],
737 depth_stencil_attachment: if self.config.enable_depth_test {
738 Some(wgpu::RenderPassDepthStencilAttachment {
739 view: &depth_view,
740 depth_ops: Some(wgpu::Operations {
741 load: wgpu::LoadOp::Clear(1.0),
742 store: wgpu::StoreOp::Store,
743 }),
744 stencil_ops: None,
745 })
746 } else {
747 None
748 },
749 timestamp_writes: None,
750 occlusion_query_set: None,
751 });
752
753 let pipeline = match shading_mode {
754 ShadingMode::Pbr => &self.pbr_pipeline,
755 ShadingMode::Flat => &self.flat_pipeline,
756 };
757
758 render_pass.set_pipeline(pipeline);
759 render_pass.set_bind_group(0, &bind_group, &[]);
760 render_pass.set_vertex_buffer(0, vertex_buffer.slice(..));
761 render_pass.set_index_buffer(index_buffer.slice(..), wgpu::IndexFormat::Uint32);
762 render_pass.draw_indexed(0..mesh.indices.len() as u32, 0, 0..1);
763 }
764
765 self.gpu_context.queue.submit(std::iter::once(encoder.finish()));
766 output.present();
767
768 Ok(())
769 }
770}
771
772pub fn mesh_to_gpu_mesh(
774 vertices: &[Point3<f32>],
775 indices: &[u32],
776 normals: Option<&[Vector3<f32>]>,
777 colors: Option<&[[f32; 3]]>,
778 material: Option<PbrMaterial>,
779) -> GpuMesh {
780 let gpu_vertices: Vec<MeshVertex> = vertices
781 .iter()
782 .enumerate()
783 .map(|(i, vertex)| {
784 let normal = normals
785 .and_then(|n| n.get(i))
786 .map(|n| [n.x, n.y, n.z])
787 .unwrap_or([0.0, 0.0, 1.0]);
788
789 let color = colors
790 .and_then(|c| c.get(i))
791 .copied()
792 .unwrap_or([0.8, 0.8, 0.8]);
793
794 MeshVertex::new([vertex.x, vertex.y, vertex.z], normal, [0.0, 0.0], color)
795 })
796 .collect();
797
798 GpuMesh::new(
799 gpu_vertices,
800 indices.to_vec(),
801 material.unwrap_or_default(),
802 )
803}