forked from 1b-agent/opencadstudio-upstream
fix(render): draw block-contained 3D faces
This commit is contained in:
1 parent
c8840e2706
commit
8601fd8e4b
7 files changed
+90
-60
No files matched your search
@@ -133,8 +133,7 @@ pub struct Face3DGpu {
|
||||
impl Face3DGpu {
|
||||
/// Build a batched GPU buffer from Face3D wire models and mesh fill_tris.
|
||||
///
|
||||
/// - `face3d_wires`: Face3D entities — `key_vertices` holds 4 quad corners;
|
||||
/// emits 2 triangles per face into the 3D buffer.
|
||||
/// - `face3d_wires`: kernel-triangulated Face3D entities.
|
||||
/// - `all_wires`: all entity wires — `fill_tris` holds pre-triangulated
|
||||
/// fill data. Fills with a non-empty `fill_tris_low` residual (real 3-D
|
||||
/// surfaces — PolyfaceMesh / PolygonMesh) feed the 3D buffer at their
|
||||
@@ -157,43 +156,26 @@ impl Face3DGpu {
|
||||
let mut verts_3d: Vec<Face3DVertex> = Vec::with_capacity(face3d_wires.len() * 6);
|
||||
let mut verts_2d: Vec<Face3DVertex> = Vec::new();
|
||||
|
||||
// Face3D quads (4 key_vertices → 2 triangles) — only when 3D
|
||||
// fills are wanted.
|
||||
// Face3D kernel triangles — only when 3D fills are wanted.
|
||||
if keep_3d_mesh_fills {
|
||||
for wire in face3d_wires {
|
||||
if wire.key_vertices.len() < 4 {
|
||||
if wire.fill_tris.is_empty() {
|
||||
continue;
|
||||
}
|
||||
let [r, g, b, a] = wire.color;
|
||||
let fill_color = [r * 0.45, g * 0.45, b * 0.45, a];
|
||||
let p = &wire.key_vertices;
|
||||
// key_vertices are f64 (offset-relative); split into the
|
||||
// double-single (high, low) pair the face3d shader expects.
|
||||
let v = |i: usize| {
|
||||
let [x, y, z] = p[i];
|
||||
let h = [x as f32, y as f32, z as f32];
|
||||
Face3DVertex {
|
||||
position: h,
|
||||
for (index, &position) in wire.fill_tris.iter().enumerate() {
|
||||
verts_3d.push(Face3DVertex {
|
||||
position,
|
||||
color: fill_color,
|
||||
// A 3DFACE is genuine 3D geometry: keep its real depth
|
||||
// (no draw-order bias), matching the PolyfaceMesh /
|
||||
// PolygonMesh path below. A non-zero draw-order rank
|
||||
// here yanked 3DFACEs toward the camera so they drew in
|
||||
// front of solids (which carry no such bias).
|
||||
draw_depth: 0.0,
|
||||
position_low: [
|
||||
(x - h[0] as f64) as f32,
|
||||
(y - h[1] as f64) as f32,
|
||||
(z - h[2] as f64) as f32,
|
||||
],
|
||||
}
|
||||
};
|
||||
verts_3d.push(v(0));
|
||||
verts_3d.push(v(1));
|
||||
verts_3d.push(v(2));
|
||||
verts_3d.push(v(0));
|
||||
verts_3d.push(v(2));
|
||||
verts_3d.push(v(3));
|
||||
position_low: wire
|
||||
.fill_tris_low
|
||||
.get(index)
|
||||
.copied()
|
||||
.unwrap_or([0.0; 3]),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2359,19 +2359,7 @@ impl Pipeline {
|
||||
// and alpha blending both depend on it. Scissor and mesh-edge stay
|
||||
// grouping keys because the draw loop sets one scissor per batch and
|
||||
// skips whole mesh-edge batches in shaded modes.
|
||||
// A 3D mesh entity (PolyfaceMesh / PolygonMesh) emits its face fill and
|
||||
// its outline edges as *separate* WireModels sharing the entity handle
|
||||
// (`name`): the fill carries `fill_tris` + a non-empty `fill_tris_low`
|
||||
// (real 3D depth, same test face3d uses); the edge carries `points`.
|
||||
// Flag the edge wire as `is_3d_mesh_edge` so the draw loop can hide it in
|
||||
// clean-shaded modes and draw it black in filled-with-edges modes.
|
||||
let mesh_names: rustc_hash::FxHashSet<&str> = wires
|
||||
.iter()
|
||||
.filter(|w| !w.fill_tris.is_empty() && !w.fill_tris_low.is_empty())
|
||||
.map(|w| w.name.as_str())
|
||||
.collect();
|
||||
let is_mesh_edge =
|
||||
|w: &WireModel| !w.points.is_empty() && mesh_names.contains(w.name.as_str());
|
||||
let is_mesh_edge = |w: &WireModel| !w.points.is_empty() && w.fill_is_3d;
|
||||
let mut batches: Vec<WireGpu> = Vec::new();
|
||||
let mut block_wires: Vec<&WireModel> = Vec::new();
|
||||
let mut i = 0;
|
||||
@@ -2403,7 +2391,6 @@ impl Pipeline {
|
||||
device,
|
||||
&block_wires,
|
||||
depth_map,
|
||||
&mesh_names,
|
||||
None,
|
||||
&self.block_wire_const_bgl,
|
||||
);
|
||||
@@ -2516,12 +2503,10 @@ impl Pipeline {
|
||||
self.wire_const_bgl.as_ref(),
|
||||
));
|
||||
self.gpu_selected_wires = gpu;
|
||||
let mesh_names = rustc_hash::FxHashSet::default();
|
||||
let mut block_gpu = BlockWireGpu::from_wires(
|
||||
device,
|
||||
&selected_blocks,
|
||||
depth_map,
|
||||
&mesh_names,
|
||||
Some(WireModel::SELECTED),
|
||||
&self.block_wire_const_bgl,
|
||||
);
|
||||
@@ -2529,7 +2514,6 @@ impl Pipeline {
|
||||
device,
|
||||
&hover_blocks,
|
||||
depth_map,
|
||||
&mesh_names,
|
||||
Some(WireModel::HOVER),
|
||||
&self.block_wire_const_bgl,
|
||||
));
|
||||
@@ -4046,7 +4030,11 @@ impl Pipeline {
|
||||
// pipeline in HiddenLine so wires hidden behind them disappear.
|
||||
// 2D fills (text greek, MultiLeader bg) always draw with colour.
|
||||
if let Some(ref fill) = self.gpu_face3d_fill {
|
||||
if !fill.chunks_3d.is_empty() || !fill.chunks_2d.is_empty() {
|
||||
if !fill.chunks_3d.is_empty()
|
||||
|| !fill.chunks_2d.is_empty()
|
||||
|| !fill.block_chunks_3d.is_empty()
|
||||
|| !fill.block_chunks_2d.is_empty()
|
||||
{
|
||||
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: Some("face3d.render_pass"),
|
||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||
|
||||
@@ -127,11 +127,9 @@ fn handle_of(w: &WireModel) -> Option<Handle> {
|
||||
crate::scene::Scene::handle_from_wire_name(&w.name)
|
||||
}
|
||||
|
||||
/// True when `w`'s edge segments belong to a mesh/solid whose fill is drawn in a
|
||||
/// separate pass — such wires need the draw loop's mesh-edge treatment, so they
|
||||
/// go in their own arena. `mesh_names` are the entities that emit a fill.
|
||||
pub fn is_mesh_edge(w: &WireModel, mesh_names: &rustc_hash::FxHashSet<u64>) -> bool {
|
||||
!w.points.is_empty() && handle_of(w).map_or(false, |h| mesh_names.contains(&h.value()))
|
||||
/// True when `w` needs the shaded-mode edge treatment.
|
||||
pub fn is_mesh_edge(w: &WireModel, _mesh_names: &rustc_hash::FxHashSet<u64>) -> bool {
|
||||
!w.points.is_empty() && w.fill_is_3d
|
||||
}
|
||||
|
||||
/// True when appending a new entity at the tail could change the image, so the
|
||||
|
||||
@@ -646,7 +646,6 @@ impl BlockWireGpu {
|
||||
device: &wgpu::Device,
|
||||
wires: &[&WireModel],
|
||||
depth_map: &rustc_hash::FxHashMap<u64, [f32; 2]>,
|
||||
mesh_names: &rustc_hash::FxHashSet<&str>,
|
||||
color_override: Option<[f32; 4]>,
|
||||
const_bgl: &wgpu::BindGroupLayout,
|
||||
) -> Vec<Self> {
|
||||
@@ -662,7 +661,7 @@ impl BlockWireGpu {
|
||||
if wire.points.len() < 2 {
|
||||
continue;
|
||||
}
|
||||
let mesh_edge = mesh_names.contains(wire.name.as_str());
|
||||
let mesh_edge = color_override.is_none() && wire.fill_is_3d;
|
||||
let key = (instance.source_id, mesh_edge);
|
||||
let slot = *slots.entry(key).or_insert_with(|| {
|
||||
let slot = groups.len();
|
||||
|
||||
Reference in new issue
Block a user