forked from 1b-agent/opencadstudio-upstream
fix(solid): use kernel geometry
Derive extrusion, bounds, edges, and fill from cadkernel while preserving precise view filtering and stable GPU uploads.
This commit is contained in:
1 parent
17dc0aff39
commit
ee89458f8a
5 files changed
+225
-104
No files matched your search
+158
-74
@@ -1,12 +1,4 @@
|
|||||||
// SOLID entity — 2D filled quadrilateral (or triangle when p3 == p4).
|
// SOLID geometry comes from the kernel; entity coordinates stay in WCS here.
|
||||||
//
|
|
||||||
// Wireframe: the 4 perimeter edges as RenderObject::Lines.
|
|
||||||
// Filled: boundary triangles on `fill_tris`, plus the top and side faces for
|
|
||||||
// non-zero thickness. The full WCS plane is preserved both at top
|
|
||||||
// level and through block expansion. The scene keeps a separate 2-D
|
|
||||||
// HatchModel only for plot projection; screen rendering filters that
|
|
||||||
// flattened copy out.
|
|
||||||
// Grips: 4 corner grip points.
|
|
||||||
|
|
||||||
use acadrust::entities::Solid;
|
use acadrust::entities::Solid;
|
||||||
use crate::t;
|
use crate::t;
|
||||||
@@ -18,6 +10,14 @@ use crate::scene::convert::acad_to_render::{RenderEntity, RenderObject};
|
|||||||
use crate::scene::model::object::{GripApply, GripDef, PropSection};
|
use crate::scene::model::object::{GripApply, GripDef, PropSection};
|
||||||
use crate::scene::model::wire_model::SnapHint;
|
use crate::scene::model::wire_model::SnapHint;
|
||||||
|
|
||||||
|
type Edge = ([f64; 3], [f64; 3]);
|
||||||
|
|
||||||
|
struct SolidGeometry {
|
||||||
|
edges: Vec<Edge>,
|
||||||
|
fill_tris: Vec<[f64; 3]>,
|
||||||
|
extruded: bool,
|
||||||
|
}
|
||||||
|
|
||||||
fn normal_tuple(solid: &Solid) -> (f64, f64, f64) {
|
fn normal_tuple(solid: &Solid) -> (f64, f64, f64) {
|
||||||
let normal = glam::DVec3::new(solid.normal.x, solid.normal.y, solid.normal.z)
|
let normal = glam::DVec3::new(solid.normal.x, solid.normal.y, solid.normal.z)
|
||||||
.normalize_or(glam::DVec3::Z);
|
.normalize_or(glam::DVec3::Z);
|
||||||
@@ -64,87 +64,171 @@ fn push_edge(lines: &mut Vec<[f64; 3]>, start: [f64; 3], end: [f64; 3]) {
|
|||||||
lines.extend([start, end, [f64::NAN; 3]]);
|
lines.extend([start, end, [f64::NAN; 3]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_fan(triangles: &mut Vec<[f64; 3]>, points: &[[f64; 3]], reverse: bool) {
|
fn boundary(solid: &Solid) -> Vec<[f64; 3]> {
|
||||||
for index in 1..points.len() - 1 {
|
let corners = wcs_corners(solid);
|
||||||
if reverse {
|
if solid.is_triangle() {
|
||||||
triangles.extend([points[0], points[index + 1], points[index]]);
|
vec![corners[0], corners[1], corners[2]]
|
||||||
} else {
|
} else {
|
||||||
triangles.extend([points[0], points[index], points[index + 1]]);
|
vec![corners[0], corners[1], corners[3], corners[2]]
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn boundary_edges(points: &[[f64; 3]]) -> Vec<Edge> {
|
||||||
|
(0..points.len())
|
||||||
|
.map(|index| (points[index], points[(index + 1) % points.len()]))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn kernel_tolerance(points: &[[f64; 3]]) -> f64 {
|
||||||
|
cadkernel::space::coplanarity_tolerance(points).max(1.0e-12)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extrusion_body(
|
||||||
|
solid: &Solid,
|
||||||
|
base: &[[f64; 3]],
|
||||||
|
tolerance: f64,
|
||||||
|
profile_valid: bool,
|
||||||
|
) -> Option<cadkernel::brep::Body> {
|
||||||
|
if solid.thickness.abs() <= 1.0e-10 || !profile_valid {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let normal = glam::DVec3::new(solid.normal.x, solid.normal.y, solid.normal.z)
|
||||||
|
.normalize_or(glam::DVec3::Z);
|
||||||
|
let origin = glam::DVec3::from_array(base[0]);
|
||||||
|
let axis = base
|
||||||
|
.iter()
|
||||||
|
.skip(1)
|
||||||
|
.map(|point| glam::DVec3::from_array(*point) - origin)
|
||||||
|
.find(|axis| axis.length() > tolerance)?;
|
||||||
|
let plane = cadkernel::space::Plane::orthonormal(
|
||||||
|
base[0],
|
||||||
|
axis.to_array(),
|
||||||
|
normal.to_array(),
|
||||||
|
)?;
|
||||||
|
if base
|
||||||
|
.iter()
|
||||||
|
.any(|point| !plane.contains(*point, tolerance))
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let projected = base
|
||||||
|
.iter()
|
||||||
|
.map(|point| plane.project(*point))
|
||||||
|
.collect::<Option<Vec<_>>>()?;
|
||||||
|
let profile = (0..projected.len())
|
||||||
|
.map(|index| {
|
||||||
|
cadkernel::geom2d::Curve::Line(cadkernel::geom2d::Line {
|
||||||
|
start: projected[index],
|
||||||
|
end: projected[(index + 1) % projected.len()],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
cadkernel::brep::extrude(
|
||||||
|
plane,
|
||||||
|
&profile,
|
||||||
|
(normal * solid.thickness).to_array(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solid_geometry(solid: &Solid) -> Option<SolidGeometry> {
|
||||||
|
let base = boundary(solid);
|
||||||
|
let tolerance = kernel_tolerance(&base);
|
||||||
|
let fill_tris = cadkernel::space::polygon::triangulate(
|
||||||
|
&base,
|
||||||
|
cadkernel::geom2d::Tolerance::new(tolerance),
|
||||||
|
);
|
||||||
|
if solid.thickness.abs() <= 1.0e-10 {
|
||||||
|
return Some(SolidGeometry {
|
||||||
|
edges: boundary_edges(&base),
|
||||||
|
fill_tris,
|
||||||
|
extruded: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let Some(body) = extrusion_body(solid, &base, tolerance, !fill_tris.is_empty()) else {
|
||||||
|
return Some(SolidGeometry {
|
||||||
|
edges: boundary_edges(&base),
|
||||||
|
fill_tris: Vec::new(),
|
||||||
|
extruded: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
let mesh = cadkernel::brep::mesh::tessellate(
|
||||||
|
&body,
|
||||||
|
cadkernel::brep::mesh::TessellationTolerance::new(
|
||||||
|
cadkernel::tessellation::DEFAULT_ANGLE,
|
||||||
|
tolerance,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if !mesh.missing_faces.is_empty() || mesh.mesh.is_empty() {
|
||||||
|
return Some(SolidGeometry {
|
||||||
|
edges: boundary_edges(&base),
|
||||||
|
fill_tris: Vec::new(),
|
||||||
|
extruded: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let edges = mesh
|
||||||
|
.edges
|
||||||
|
.iter()
|
||||||
|
.flat_map(|edge| edge.positions.windows(2).map(|pair| (pair[0], pair[1])))
|
||||||
|
.collect();
|
||||||
|
let mut fill_tris = Vec::with_capacity(mesh.mesh.triangles.len() * 3);
|
||||||
|
for triangle in mesh.mesh.triangles {
|
||||||
|
fill_tris.extend(triangle.map(|index| mesh.mesh.positions[index]));
|
||||||
|
}
|
||||||
|
Some(SolidGeometry {
|
||||||
|
edges,
|
||||||
|
fill_tris,
|
||||||
|
extruded: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn wcs_bounds(solid: &Solid) -> Option<cadkernel::brep::Aabb> {
|
||||||
|
let base = boundary(solid);
|
||||||
|
let tolerance = kernel_tolerance(&base);
|
||||||
|
let profile_valid = !cadkernel::space::polygon::triangulate(
|
||||||
|
&base,
|
||||||
|
cadkernel::geom2d::Tolerance::new(tolerance),
|
||||||
|
)
|
||||||
|
.is_empty();
|
||||||
|
extrusion_body(solid, &base, tolerance, profile_valid)
|
||||||
|
.and_then(|body| cadkernel::brep::body_bounds(&body))
|
||||||
|
.or_else(|| cadkernel::brep::Aabb::around(base))
|
||||||
|
}
|
||||||
|
|
||||||
impl RenderConvertible for Solid {
|
impl RenderConvertible for Solid {
|
||||||
fn to_render(&self, _document: &acadrust::CadDocument) -> Option<RenderEntity> {
|
fn to_render(&self, _document: &acadrust::CadDocument) -> Option<RenderEntity> {
|
||||||
// SOLID corners are OCS and the last two are stored in Z order. Preserve
|
let geometry = solid_geometry(self)?;
|
||||||
// that ordering exactly: it is part of the entity geometry and can
|
|
||||||
// intentionally describe a crossing shape.
|
|
||||||
let corners = wcs_corners(self);
|
|
||||||
let base = if self.is_triangle() {
|
|
||||||
vec![corners[0], corners[1], corners[2]]
|
|
||||||
} else {
|
|
||||||
vec![corners[0], corners[1], corners[3], corners[2]]
|
|
||||||
};
|
|
||||||
let normal = glam::DVec3::new(self.normal.x, self.normal.y, self.normal.z)
|
|
||||||
.normalize_or(glam::DVec3::Z);
|
|
||||||
let extruded = self.thickness.abs() > 1.0e-10;
|
|
||||||
let top: Vec<[f64; 3]> = base
|
|
||||||
.iter()
|
|
||||||
.map(|point| {
|
|
||||||
(glam::DVec3::from_array(*point) + normal * self.thickness).to_array()
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let mut lines = Vec::new();
|
let mut lines = Vec::new();
|
||||||
for index in 0..base.len() {
|
for &(start, end) in &geometry.edges {
|
||||||
push_edge(&mut lines, base[index], base[(index + 1) % base.len()]);
|
push_edge(&mut lines, start, end);
|
||||||
}
|
}
|
||||||
if extruded {
|
let mut nodes = Vec::new();
|
||||||
for index in 0..top.len() {
|
for &(start, end) in &geometry.edges {
|
||||||
push_edge(&mut lines, top[index], top[(index + 1) % top.len()]);
|
for point in [start, end] {
|
||||||
push_edge(&mut lines, base[index], top[index]);
|
if !nodes.contains(&point) {
|
||||||
|
nodes.push(point);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let mut snap = Vec::with_capacity(nodes.len() * 2 + geometry.edges.len());
|
||||||
let mut fill_tris = Vec::new();
|
for point in nodes {
|
||||||
push_fan(&mut fill_tris, &base, false);
|
snap.push((dvec3(point), SnapHint::Node));
|
||||||
if extruded {
|
snap.push((dvec3(point), SnapHint::Endpoint));
|
||||||
push_fan(&mut fill_tris, &top, true);
|
|
||||||
for index in 0..base.len() {
|
|
||||||
let next = (index + 1) % base.len();
|
|
||||||
fill_tris.extend([
|
|
||||||
base[index],
|
|
||||||
base[next],
|
|
||||||
top[next],
|
|
||||||
base[index],
|
|
||||||
top[next],
|
|
||||||
top[index],
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
snap.extend(geometry.edges.iter().map(|(start, end)| {
|
||||||
let mut snap_points = base.clone();
|
((dvec3(*start) + dvec3(*end)) * 0.5, SnapHint::Midpoint)
|
||||||
if extruded {
|
}));
|
||||||
snap_points.extend(top.iter().copied());
|
let pick_tris = geometry
|
||||||
}
|
.extruded
|
||||||
let snap = snap_points
|
.then(|| geometry.fill_tris.clone())
|
||||||
.iter()
|
.unwrap_or_default();
|
||||||
.copied()
|
|
||||||
.map(|point| (dvec3(point), SnapHint::Node))
|
|
||||||
.collect();
|
|
||||||
let pick_tris = if extruded {
|
|
||||||
fill_tris.clone()
|
|
||||||
} else {
|
|
||||||
Vec::new()
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(RenderEntity {
|
Some(RenderEntity {
|
||||||
pick_tris,
|
pick_tris,
|
||||||
object: RenderObject::Lines(lines),
|
object: RenderObject::Lines(lines),
|
||||||
snap_pts: snap,
|
snap_pts: snap,
|
||||||
tangent_geoms: vec![],
|
tangent_geoms: vec![],
|
||||||
key_vertices: snap_points,
|
key_vertices: Vec::new(),
|
||||||
fill_tris,
|
fill_tris: geometry.fill_tris,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1657,12 +1657,25 @@ pub(crate) fn set_wire_aabb(w: &mut WireModel, entity_box: [f32; 4]) {
|
|||||||
w.aabb = out;
|
w.aabb = out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn entity_bounds(e: &acadrust::EntityType) -> ([f64; 3], [f64; 3]) {
|
||||||
|
if let acadrust::EntityType::Solid(solid) = e {
|
||||||
|
if let Some(bounds) = crate::entities::solid::wcs_bounds(solid) {
|
||||||
|
return (bounds.min, bounds.max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let bounds = e.as_entity().bounding_box();
|
||||||
|
(
|
||||||
|
[bounds.min.x, bounds.min.y, bounds.min.z],
|
||||||
|
[bounds.max.x, bounds.max.y, bounds.max.z],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn entity_aabb(e: &acadrust::EntityType) -> [f32; 4] {
|
pub(crate) fn entity_aabb(e: &acadrust::EntityType) -> [f32; 4] {
|
||||||
let bbox = e.as_entity().bounding_box();
|
let (min, max) = entity_bounds(e);
|
||||||
let min_x = (bbox.min.x) as f32;
|
let min_x = min[0] as f32;
|
||||||
let min_y = (bbox.min.y) as f32;
|
let min_y = min[1] as f32;
|
||||||
let max_x = (bbox.max.x) as f32;
|
let max_x = max[0] as f32;
|
||||||
let max_y = (bbox.max.y) as f32;
|
let max_y = max[1] as f32;
|
||||||
// The all-zero box is bounding_box()'s Default — returned by entities with
|
// The all-zero box is bounding_box()'s Default — returned by entities with
|
||||||
// no usable box (unimplemented) — so treat it as UNBOUNDED (never
|
// no usable box (unimplemented) — so treat it as UNBOUNDED (never
|
||||||
// pre-rejected). A genuinely zero-size box *away* from the origin (e.g. a
|
// pre-rejected). A genuinely zero-size box *away* from the origin (e.g. a
|
||||||
@@ -1680,8 +1693,8 @@ pub(crate) fn entity_aabb(e: &acadrust::EntityType) -> [f32; 4] {
|
|||||||
/// indexing uses this so changing `world_offset` doesn't invalidate
|
/// indexing uses this so changing `world_offset` doesn't invalidate
|
||||||
/// the index.
|
/// the index.
|
||||||
pub(crate) fn entity_world_aabb_f64(e: &acadrust::EntityType) -> Option<[f64; 4]> {
|
pub(crate) fn entity_world_aabb_f64(e: &acadrust::EntityType) -> Option<[f64; 4]> {
|
||||||
let bbox = e.as_entity().bounding_box();
|
let (min, max) = entity_bounds(e);
|
||||||
let (xmin, ymin, xmax, ymax) = (bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y);
|
let (xmin, ymin, xmax, ymax) = (min[0], min[1], max[0], max[1]);
|
||||||
if xmin == xmax && ymin == ymax {
|
if xmin == xmax && ymin == ymax {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,20 +22,48 @@ use crate::scene::model::wire_model::WireModel;
|
|||||||
use iced::wgpu;
|
use iced::wgpu;
|
||||||
use iced::wgpu::util::DeviceExt;
|
use iced::wgpu::util::DeviceExt;
|
||||||
|
|
||||||
fn planar_solid_faces_view(wire: &WireModel, view_dir: glam::Vec3) -> bool {
|
pub(crate) fn planar_solid_faces_view(wire: &WireModel, view_dir: glam::Vec3) -> bool {
|
||||||
if !wire.fill_is_2d_solid || wire.fill_is_3d {
|
if !wire.fill_is_2d_solid || wire.fill_is_3d {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
let view = view_dir.normalize_or_zero();
|
let view = view_dir.as_dvec3().normalize_or_zero();
|
||||||
wire.fill_tris.chunks_exact(3).any(|triangle| {
|
let point = |index: usize| {
|
||||||
let first = glam::Vec3::from_array(triangle[0]);
|
let high = wire.fill_tris[index];
|
||||||
let second = glam::Vec3::from_array(triangle[1]);
|
let low = wire
|
||||||
let third = glam::Vec3::from_array(triangle[2]);
|
.fill_tris_low
|
||||||
|
.get(index)
|
||||||
|
.copied()
|
||||||
|
.unwrap_or([0.0; 3]);
|
||||||
|
glam::DVec3::new(
|
||||||
|
high[0] as f64 + low[0] as f64,
|
||||||
|
high[1] as f64 + low[1] as f64,
|
||||||
|
high[2] as f64 + low[2] as f64,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
(0..wire.fill_tris.len() / 3).any(|triangle| {
|
||||||
|
let first = point(triangle * 3);
|
||||||
|
let second = point(triangle * 3 + 1);
|
||||||
|
let third = point(triangle * 3 + 2);
|
||||||
let normal = (second - first).cross(third - first).normalize_or_zero();
|
let normal = (second - first).cross(third - first).normalize_or_zero();
|
||||||
normal.length_squared() > 0.0 && normal.dot(view).abs() >= 1.0 - 1.0e-5
|
normal.length_squared() > 0.0 && normal.dot(view).abs() >= 1.0 - 1.0e-5
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn planar_solid_visibility_key(
|
||||||
|
wires: &[WireModel],
|
||||||
|
view_dir: glam::Vec3,
|
||||||
|
) -> u64 {
|
||||||
|
let mut key = 0xcbf29ce484222325_u64;
|
||||||
|
for wire in wires
|
||||||
|
.iter()
|
||||||
|
.filter(|wire| wire.fill_is_2d_solid && !wire.fill_is_3d)
|
||||||
|
{
|
||||||
|
key ^= planar_solid_faces_view(wire, view_dir) as u64;
|
||||||
|
key = key.wrapping_mul(0x100000001b3);
|
||||||
|
}
|
||||||
|
key
|
||||||
|
}
|
||||||
|
|
||||||
// ── Vertex layout ──────────────────────────────────────────────────────────
|
// ── Vertex layout ──────────────────────────────────────────────────────────
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
@@ -88,8 +116,8 @@ impl Face3DVertex {
|
|||||||
// ── GPU handle ─────────────────────────────────────────────────────────────
|
// ── GPU handle ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
/// One vertex buffer + draw count. Fill data is split into as many chunks
|
/// One vertex buffer + draw count. Fill data is split into as many chunks
|
||||||
/// as the device's `max_buffer_size` requires: a mesh-heavy DWG (e.g. a
|
/// as the device's `max_buffer_size` requires: a mesh-heavy drawing can hold
|
||||||
/// Navisworks import) can hold tens of millions of fill triangles, and at
|
/// tens of millions of fill triangles, and at
|
||||||
/// 44 B/vertex a single batched buffer blows past the default 256 MB limit
|
/// 44 B/vertex a single batched buffer blows past the default 256 MB limit
|
||||||
/// once enough layers are thawed — wgpu then raises an uncaptured
|
/// once enough layers are thawed — wgpu then raises an uncaptured
|
||||||
/// validation error and aborts the process (#358). Same scheme as the
|
/// validation error and aborts the process (#358). Same scheme as the
|
||||||
|
|||||||
@@ -312,12 +312,8 @@ pub struct Pipeline {
|
|||||||
/// a pick bumps only `selection_generation`, refreshing the overlay without
|
/// a pick bumps only `selection_generation`, refreshing the overlay without
|
||||||
/// touching the main wire buffers.
|
/// touching the main wire buffers.
|
||||||
pub cached_selection: (u64, u64),
|
pub cached_selection: (u64, u64),
|
||||||
/// `(wire_content_id, face3d_fill_active, show_2d_solid_fills, view_dir)` the Face3D
|
/// Face upload key; keeps the resident wire Arc uniquely owned by Scene.
|
||||||
/// edge/fill buffers were uploaded for. A stable content id avoids retaining
|
pub cached_face3d_key: (u64, bool, bool, u64),
|
||||||
/// the resident wire Arc:
|
|
||||||
/// that Arc must stay uniquely owned by Scene so a small edit can splice it
|
|
||||||
/// in place instead of rebuilding the whole drawing.
|
|
||||||
pub cached_face3d_key: (u64, bool, bool, [u32; 3]),
|
|
||||||
/// Handle → indices into the resident wire set, built once per wire upload
|
/// Handle → indices into the resident wire set, built once per wire upload
|
||||||
/// (when `cached_wire_id` changes). Lets the selection/hover xray overlay
|
/// (when `cached_wire_id` changes). Lets the selection/hover xray overlay
|
||||||
/// gather just the highlighted entity's wires (`O(highlighted)`) instead of
|
/// gather just the highlighted entity's wires (`O(highlighted)`) instead of
|
||||||
@@ -2323,7 +2319,7 @@ impl Pipeline {
|
|||||||
cached_epoch: (u64::MAX, u64::MAX, u64::MAX),
|
cached_epoch: (u64::MAX, u64::MAX, u64::MAX),
|
||||||
cached_wire_id: u64::MAX,
|
cached_wire_id: u64::MAX,
|
||||||
cached_selection: (u64::MAX, u64::MAX),
|
cached_selection: (u64::MAX, u64::MAX),
|
||||||
cached_face3d_key: (u64::MAX, false, false, [u32::MAX; 3]),
|
cached_face3d_key: (u64::MAX, false, false, u64::MAX),
|
||||||
wire_handle_index: std::sync::Arc::new(rustc_hash::FxHashMap::default()),
|
wire_handle_index: std::sync::Arc::new(rustc_hash::FxHashMap::default()),
|
||||||
render_sig: u64::MAX,
|
render_sig: u64::MAX,
|
||||||
skip_geometry: false,
|
skip_geometry: false,
|
||||||
|
|||||||
@@ -378,7 +378,7 @@ impl shader::Primitive for Primitive {
|
|||||||
inner.cached_wire_id = u64::MAX;
|
inner.cached_wire_id = u64::MAX;
|
||||||
inner.cached_selection = (u64::MAX, u64::MAX);
|
inner.cached_selection = (u64::MAX, u64::MAX);
|
||||||
inner.cached_mesh_content_id = u64::MAX;
|
inner.cached_mesh_content_id = u64::MAX;
|
||||||
inner.cached_face3d_key = (u64::MAX, false, false, [u32::MAX; 3]);
|
inner.cached_face3d_key = (u64::MAX, false, false, u64::MAX);
|
||||||
inner.cached_hatch_source = None;
|
inner.cached_hatch_source = None;
|
||||||
inner.cached_preview_hatch_source = None;
|
inner.cached_preview_hatch_source = None;
|
||||||
inner.cached_wipeout_source = None;
|
inner.cached_wipeout_source = None;
|
||||||
@@ -485,11 +485,11 @@ impl shader::Primitive for Primitive {
|
|||||||
// the Wireframe overlay style.
|
// the Wireframe overlay style.
|
||||||
let face3d_fill_active = fill_mode && !vp.view_wireframe;
|
let face3d_fill_active = fill_mode && !vp.view_wireframe;
|
||||||
let solid_fill_active = fill_mode && vp.show_2d_solid_fills;
|
let solid_fill_active = fill_mode && vp.show_2d_solid_fills;
|
||||||
let view_dir_key = [
|
let solid_visibility_key =
|
||||||
vp.view_dir.x.to_bits(),
|
crate::scene::pipeline::face3d_gpu::planar_solid_visibility_key(
|
||||||
vp.view_dir.y.to_bits(),
|
&vp_wires,
|
||||||
vp.view_dir.z.to_bits(),
|
vp.view_dir,
|
||||||
];
|
);
|
||||||
let fill_changed = inner.cached_fill_mode != fill_mode;
|
let fill_changed = inner.cached_fill_mode != fill_mode;
|
||||||
let hatch_changed = inner
|
let hatch_changed = inner
|
||||||
.cached_hatch_source
|
.cached_hatch_source
|
||||||
@@ -581,7 +581,7 @@ impl shader::Primitive for Primitive {
|
|||||||
if face3d_changed
|
if face3d_changed
|
||||||
|| face3d_fill_active != inner.cached_face3d_key.1
|
|| face3d_fill_active != inner.cached_face3d_key.1
|
||||||
|| solid_fill_active != inner.cached_face3d_key.2
|
|| solid_fill_active != inner.cached_face3d_key.2
|
||||||
|| view_dir_key != inner.cached_face3d_key.3
|
|| solid_visibility_key != inner.cached_face3d_key.3
|
||||||
{
|
{
|
||||||
inner.upload_face3d(
|
inner.upload_face3d(
|
||||||
device,
|
device,
|
||||||
@@ -599,7 +599,7 @@ impl shader::Primitive for Primitive {
|
|||||||
vp.wire_content_id,
|
vp.wire_content_id,
|
||||||
face3d_fill_active,
|
face3d_fill_active,
|
||||||
solid_fill_active,
|
solid_fill_active,
|
||||||
view_dir_key,
|
solid_visibility_key,
|
||||||
);
|
);
|
||||||
// Wire buffers are world-space, so a camera move alone doesn't
|
// Wire buffers are world-space, so a camera move alone doesn't
|
||||||
// change them — only the view_proj uniform (uploaded every frame).
|
// change them — only the view_proj uniform (uploaded every frame).
|
||||||
|
|||||||
Reference in new issue
Block a user