feat(solid3d): ISOLINES and silhouettes on sphere and torus faces
Extends the curved-face wireframe treatment from cones to spheres and tori, so a solid built from those faces reads the way a cylinder already did. ISOLINES: sphere faces get meridian lines across the face's colatitude span at evenly spaced longitudes; torus faces get minor cross-section circles at evenly spaced revolution angles. Both clip to the face's own parametric window (from the boundary polygon via a shared `angular_span` gap-finder), so a partial sphere or torus arc doesn't draw lines out over the missing part. Silhouettes (DISPSILH): `CurvedGen` becomes an enum. A sphere silhouettes as the great circle perpendicular to the view, clipped to the face window; a torus as the two curves where the tube turns edge-on, traced around the revolution. The silhouette now uses the camera's view *direction* alone, not the eye position — a single parallel direction for the whole scene — so the outline follows the view angle, holds still under pan, and doesn't foreshorten, which is the orthographic silhouette a CAD wireframe expects. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
ae5231427b
commit
8c72a06790
4 changed files with 458 additions and 128 deletions
|
|
@ -62,6 +62,10 @@ pub struct ViewportData {
|
|||
pub(in crate::scene) images: Arc<Vec<ImageModel>>,
|
||||
pub(in crate::scene) meshes: Arc<Vec<MeshLodSet>>,
|
||||
pub(in crate::scene) uniforms: Uniforms,
|
||||
/// World-space camera forward — the parallel view direction. DISPSILH
|
||||
/// silhouettes use this alone (not the eye position), so the outline follows
|
||||
/// the view angle and doesn't shift with pan / perspective foreshortening.
|
||||
pub(in crate::scene) view_dir: glam::Vec3,
|
||||
/// Camera rotation matrix derived from the quaternion.
|
||||
/// Used by the ViewCube pipeline — no gimbal lock.
|
||||
pub(in crate::scene) cam_rotation: Mat4,
|
||||
|
|
@ -562,9 +566,9 @@ impl shader::Primitive for Primitive {
|
|||
// default, so this is a no-op unless the drawing enables it). Only
|
||||
// in modes that draw edges — pure shaded hides them.
|
||||
if vp.display_silhouette && (vp.view_wireframe || vp.show_3d_edges) {
|
||||
inner.upload_silhouettes(device, &vp.meshes[..], eye);
|
||||
inner.upload_silhouettes(device, &vp.meshes[..], vp.view_dir);
|
||||
} else {
|
||||
inner.upload_silhouettes(device, &[], eye);
|
||||
inner.upload_silhouettes(device, &[], vp.view_dir);
|
||||
}
|
||||
inner.compute_wire_scissors(view_rot, eye, clip_size.width, clip_size.height);
|
||||
inner.compute_wipeout_scissors(view_rot, eye, clip_size.width, clip_size.height);
|
||||
|
|
@ -1361,6 +1365,7 @@ impl Scene {
|
|||
images,
|
||||
meshes,
|
||||
uniforms,
|
||||
view_dir: (inst.camera.rotation * glam::Vec3::NEG_Z).normalize_or(glam::Vec3::NEG_Z),
|
||||
cam_rotation: inst.camera.view_rotation_mat() * self.viewcube_ucs_mat(),
|
||||
compass_rotation: inst.camera.view_rotation_mat(),
|
||||
// Only the active viewport gets the hovered-region highlight.
|
||||
|
|
|
|||
Loading…
Reference in a new issue