Files
OneCAD-Draft/src/scene/pipeline/mesh_gpu.rs
T
Hakan SevenandClaude Opus 4.7 8dbdebeedc feat(render): wireframe modes hide mesh & 3D fills
Wireframe 2D/3D modlarında Solid3D meshlerini edge-only çizmek için
LineList topolojili bir mesh wireframe pipeline ve her üçgenin
(a,b),(b,c),(c,a) kenarlarına genişletilmiş ayrı bir index buffer
eklendi. PolyfaceMesh / PolygonMesh face fill'leri (fill_tris + dolu
points) wireframe'de gizleniyor; text greek / MultiLeader gibi 2D
fill'ler (points boş) etkilenmiyor.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 05:28:20 +03:00

143 lines
5.0 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Mesh GPU buffers — TriangleList rendering for solid objects.
//
// Vertex layout (40 bytes):
// position [f32; 3] offset 0 12 B
// normal [f32; 3] offset 12 12 B
// color [f32; 4] offset 24 16 B
// ------
// 40 B / vertex
use crate::scene::mesh_model::{MeshLodSet, MeshModel};
use iced::wgpu;
use iced::wgpu::util::DeviceExt;
// ── Vertex layout ─────────────────────────────────────────────────────────
#[repr(C)]
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
pub struct MeshVertex {
pub position: [f32; 3],
pub normal: [f32; 3],
pub color: [f32; 4],
}
impl MeshVertex {
pub fn layout<'a>() -> wgpu::VertexBufferLayout<'a> {
wgpu::VertexBufferLayout {
array_stride: std::mem::size_of::<MeshVertex>() as u64,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: &[
wgpu::VertexAttribute {
offset: 0,
shader_location: 0,
format: wgpu::VertexFormat::Float32x3,
},
wgpu::VertexAttribute {
offset: 12,
shader_location: 1,
format: wgpu::VertexFormat::Float32x3,
},
wgpu::VertexAttribute {
offset: 24,
shader_location: 2,
format: wgpu::VertexFormat::Float32x4,
},
],
}
}
}
// ── GPU handle ────────────────────────────────────────────────────────────
pub struct MeshGpu {
pub vertex_buffer: wgpu::Buffer,
pub index_buffer: wgpu::Buffer,
pub index_count: u32,
/// Line-list index buffer: every triangle `(a, b, c)` from the
/// solid index buffer is expanded into three segments
/// `(a,b)(b,c)(c,a)`. Used by the wireframe-mode render path so 3D
/// solids draw as their triangle edges without needing the
/// `POLYGON_MODE_LINE` device feature.
pub wire_index_buffer: wgpu::Buffer,
pub wire_index_count: u32,
}
/// GPU-side bundle of MeshLodSet — one MeshGpu per available LOD plus
/// the world-XY AABB needed to pick a level per frame.
pub struct MeshLodGpu {
pub lods: Vec<MeshGpu>,
pub world_aabb: [f32; 4],
}
impl MeshLodGpu {
pub fn new(device: &wgpu::Device, set: &MeshLodSet) -> Self {
Self {
lods: set
.lods
.iter()
.filter(|m| !m.indices.is_empty())
.map(|m| MeshGpu::new(device, m))
.collect(),
world_aabb: set.world_aabb,
}
}
}
impl MeshGpu {
pub fn new(device: &wgpu::Device, mesh: &MeshModel) -> Self {
let has_normals = mesh.normals.len() == mesh.verts.len();
let vertices: Vec<MeshVertex> = mesh
.verts
.iter()
.enumerate()
.map(|(i, &pos)| {
let normal = if has_normals {
mesh.normals[i]
} else {
[0.0, 1.0, 0.0]
};
MeshVertex {
position: pos,
normal,
color: mesh.color,
}
})
.collect();
let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some(&format!("mesh.vbuf.{}", mesh.name)),
contents: bytemuck::cast_slice(&vertices),
usage: wgpu::BufferUsages::VERTEX,
});
let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some(&format!("mesh.ibuf.{}", mesh.name)),
contents: bytemuck::cast_slice(&mesh.indices),
usage: wgpu::BufferUsages::INDEX,
});
// Wireframe-mode index buffer: expand each triangle into its
// three edge segments. Allocates ~2× the solid index count but
// is cheap compared to mesh tessellation and only happens when
// a new mesh is uploaded.
let mut wire_indices: Vec<u32> = Vec::with_capacity(mesh.indices.len() * 2);
for tri in mesh.indices.chunks_exact(3) {
let (a, b, c) = (tri[0], tri[1], tri[2]);
wire_indices.extend_from_slice(&[a, b, b, c, c, a]);
}
let wire_index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some(&format!("mesh.wire_ibuf.{}", mesh.name)),
contents: bytemuck::cast_slice(&wire_indices),
usage: wgpu::BufferUsages::INDEX,
});
Self {
vertex_buffer,
index_buffer,
index_count: mesh.indices.len() as u32,
wire_index_buffer,
wire_index_count: wire_indices.len() as u32,
}
}
}