forked from 1b-agent/opencadstudio-upstream
feat(render): double-single fills for the face3d pipeline
Table / PolyfaceMesh / greek-text / mleader-background fills go through the face3d pipeline; their vertices were single f32 and quantized at UTM scale. WireModel now carries a fill_tris_low residual (filled by the tessellate Lines path), Face3DVertex gains position_low (location 3), and face3d.wgsl reconstructs the eye-relative position from the pair. 3DFACE quads built from key_vertices use a zero residual (no low source). Co-Authored-By: Claude Opus 4.7 <[email protected]>
This commit is contained in:
1 parent
bd12cc2f5a
commit
c0f3d0de5e
41 files changed
+107
-28
No files matched your search
Vendored
+1
@@ -1130,6 +1130,7 @@ impl Batches {
|
||||
plinegen: b.plinegen,
|
||||
vp_scissor: None,
|
||||
fill_tris: b.fill_tris,
|
||||
fill_tris_low: Vec::new(),
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
|
||||
@@ -239,6 +239,7 @@ pub fn tessellate(
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -278,6 +279,7 @@ pub fn tessellate(
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
});
|
||||
}
|
||||
return out;
|
||||
@@ -324,6 +326,7 @@ pub fn tessellate(
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
}];
|
||||
}
|
||||
_ => {}
|
||||
@@ -358,6 +361,7 @@ pub fn tessellate(
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
}];
|
||||
}
|
||||
}
|
||||
@@ -390,6 +394,7 @@ pub fn tessellate(
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
}];
|
||||
}
|
||||
}
|
||||
@@ -409,11 +414,7 @@ pub fn tessellate(
|
||||
.into_iter()
|
||||
.map(|[x, y, z]| [(x - ox) as f32, (y - oy) as f32, (z - oz) as f32])
|
||||
.collect();
|
||||
let fill_tris: Vec<[f32; 3]> = te
|
||||
.fill_tris
|
||||
.into_iter()
|
||||
.map(|[x, y, z]| [(x - ox) as f32, (y - oy) as f32, (z - oz) as f32])
|
||||
.collect();
|
||||
let (fill_tris, fill_tris_low) = offset_to_ds(te.fill_tris, world_offset);
|
||||
return vec![WireModel {
|
||||
name,
|
||||
points: local_pts,
|
||||
@@ -431,6 +432,7 @@ pub fn tessellate(
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris,
|
||||
fill_tris_low,
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -460,6 +462,7 @@ pub fn tessellate(
|
||||
vp_scissor: None,
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -501,6 +504,7 @@ pub fn tessellate(
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
}]
|
||||
}
|
||||
|
||||
|
||||
@@ -8210,6 +8210,7 @@ fn tessellate_entity(
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
};
|
||||
|
||||
if let Some(cache) = block_cache {
|
||||
@@ -8422,6 +8423,7 @@ fn tessellate_entity(
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
}];
|
||||
}
|
||||
if h_px < 5.0 && aabb != WireModel::UNBOUNDED_AABB {
|
||||
@@ -8460,6 +8462,7 @@ fn tessellate_entity(
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris,
|
||||
fill_tris_low: Vec::new(),
|
||||
}];
|
||||
}
|
||||
}
|
||||
@@ -8569,6 +8572,7 @@ fn lod_stub_wire(
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8628,6 +8632,7 @@ fn lod_stub_wire_3d(
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -79,6 +79,9 @@ pub struct WireModel {
|
||||
/// Pre-triangulated solid fill: flat vertex list, 3 per triangle (world-offset applied).
|
||||
/// Non-empty only for PolyfaceMesh / PolygonMesh entities.
|
||||
pub fill_tris: Vec<[f32; 3]>,
|
||||
/// Low residual paired with [`fill_tris`] (double-single). Empty = all-zero;
|
||||
/// tessellation from CAD f64 fills it so fills stay precise at UTM scale.
|
||||
pub fill_tris_low: Vec<[f32; 3]>,
|
||||
}
|
||||
|
||||
impl WireModel {
|
||||
@@ -114,6 +117,7 @@ impl WireModel {
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,6 +241,7 @@ impl Default for WireModel {
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: Vec::new(),
|
||||
fill_tris_low: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,30 +33,40 @@ pub struct Face3DVertex {
|
||||
/// applied as a small clip-z bias in the shader. 0.0 for true 3D mesh
|
||||
/// faces (PolyfaceMesh / PolygonMesh) so their real depth is preserved.
|
||||
pub draw_depth: f32,
|
||||
/// Double-single low residual of `position` so fills stay precise at
|
||||
/// UTM-scale coordinates (zero for 3DFACE quads built from key_vertices,
|
||||
/// which don't carry a residual).
|
||||
pub position_low: [f32; 3],
|
||||
}
|
||||
|
||||
impl Face3DVertex {
|
||||
pub fn layout<'a>() -> wgpu::VertexBufferLayout<'a> {
|
||||
const ATTRS: &[wgpu::VertexAttribute] = &[
|
||||
wgpu::VertexAttribute {
|
||||
offset: std::mem::offset_of!(Face3DVertex, position) as u64,
|
||||
shader_location: 0,
|
||||
format: wgpu::VertexFormat::Float32x3,
|
||||
},
|
||||
wgpu::VertexAttribute {
|
||||
offset: std::mem::offset_of!(Face3DVertex, color) as u64,
|
||||
shader_location: 1,
|
||||
format: wgpu::VertexFormat::Float32x4,
|
||||
},
|
||||
wgpu::VertexAttribute {
|
||||
offset: std::mem::offset_of!(Face3DVertex, draw_depth) as u64,
|
||||
shader_location: 2,
|
||||
format: wgpu::VertexFormat::Float32,
|
||||
},
|
||||
wgpu::VertexAttribute {
|
||||
offset: std::mem::offset_of!(Face3DVertex, position_low) as u64,
|
||||
shader_location: 3,
|
||||
format: wgpu::VertexFormat::Float32x3,
|
||||
},
|
||||
];
|
||||
wgpu::VertexBufferLayout {
|
||||
array_stride: std::mem::size_of::<Face3DVertex>() 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::Float32x4,
|
||||
},
|
||||
wgpu::VertexAttribute {
|
||||
offset: 28,
|
||||
shader_location: 2,
|
||||
format: wgpu::VertexFormat::Float32,
|
||||
},
|
||||
],
|
||||
attributes: ATTRS,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -120,6 +130,7 @@ impl Face3DGpu {
|
||||
position: p[i],
|
||||
color: fill_color,
|
||||
draw_depth: depth,
|
||||
position_low: [0.0; 3],
|
||||
};
|
||||
verts_3d.push(v(0));
|
||||
verts_3d.push(v(1));
|
||||
@@ -153,21 +164,23 @@ impl Face3DGpu {
|
||||
let fill_color = [r * 0.45, g * 0.45, b * 0.45, a];
|
||||
// True 3D surface: keep real depth (no draw-order bias) so
|
||||
// hidden-surface shading is preserved.
|
||||
for &position in &wire.fill_tris {
|
||||
for (i, &position) in wire.fill_tris.iter().enumerate() {
|
||||
verts_3d.push(Face3DVertex {
|
||||
position,
|
||||
color: fill_color,
|
||||
draw_depth: 0.0,
|
||||
position_low: wire.fill_tris_low.get(i).copied().unwrap_or([0.0; 3]),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
let fill_color = [r, g, b, a];
|
||||
let depth = depth_of(wire);
|
||||
for &position in &wire.fill_tris {
|
||||
for (i, &position) in wire.fill_tris.iter().enumerate() {
|
||||
verts_2d.push(Face3DVertex {
|
||||
position,
|
||||
color: fill_color,
|
||||
draw_depth: depth,
|
||||
position_low: wire.fill_tris_low.get(i).copied().unwrap_or([0.0; 3]),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,6 +224,7 @@ pub fn apply_along(
|
||||
plinegen: true,
|
||||
vp_scissor: None,
|
||||
fill_tris: vec![],
|
||||
fill_tris_low: Vec::new(),
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user