Viewport: a soft ground shadow under the model, seen from above (ui groundShadow, on by default)
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
This commit is contained in:
1 parent
54c7690271
commit
1970b8c680
2 files changed
+50
-1
No files matched your search
@@ -88,8 +88,10 @@ pub struct UiState {
|
||||
pub pick_off: Vec<String>,
|
||||
/// A click on a face picks its whole body.
|
||||
pub pick_bodies: bool,
|
||||
/// 0: shaded with edges, 1: shaded, 2: wireframe.
|
||||
/// 0: shaded with edges, 1: shaded, 2: wireframe, 3: shaded with hidden edges.
|
||||
pub visual_style: u8,
|
||||
/// A soft shadow on the ground under the model (seen from above).
|
||||
pub ground_shadow: bool,
|
||||
/// Sketches hidden one by one, and finished sketches shown although a feature uses them.
|
||||
pub hidden_sketches: Vec<u64>,
|
||||
pub shown_sketches: Vec<u64>,
|
||||
@@ -118,6 +120,7 @@ impl Default for UiState {
|
||||
pick_off: Vec::new(),
|
||||
pick_bodies: false,
|
||||
visual_style: 0,
|
||||
ground_shadow: true,
|
||||
hidden_sketches: Vec::new(),
|
||||
shown_sketches: Vec::new(),
|
||||
hidden_profiles: Vec::new(),
|
||||
|
||||
@@ -162,6 +162,8 @@ fn scene_key(app: &SolveApp) -> u64 {
|
||||
app.session.revision.hash(&mut h);
|
||||
app.ui.show_grid.hash(&mut h);
|
||||
app.ui.visual_style.hash(&mut h);
|
||||
app.ui.ground_shadow.hash(&mut h);
|
||||
(app.cam.pitch > 0.0).hash(&mut h);
|
||||
app.ui.show_sketches.hash(&mut h);
|
||||
app.ui.hidden_bodies.hash(&mut h);
|
||||
app.ui.hidden_sketches.hash(&mut h);
|
||||
@@ -270,6 +272,9 @@ fn build_scene(app: &SolveApp) -> GpuScene {
|
||||
}
|
||||
}
|
||||
}
|
||||
if app.ui.ground_shadow && app.ui.visual_style != 2 && app.cam.pitch > 0.0 {
|
||||
ground_shadow(&mut sc, app, &st);
|
||||
}
|
||||
for sid in visible_sketches(app) {
|
||||
let Some(ss) = st.sketch(sid) else { continue };
|
||||
let active = s.active_sketch == Some(sid);
|
||||
@@ -301,6 +306,47 @@ fn build_scene(app: &SolveApp) -> GpuScene {
|
||||
sc
|
||||
}
|
||||
|
||||
/// A soft dark ellipse on the ground under the shown bodies (darkest in the middle).
|
||||
fn ground_shadow(sc: &mut GpuScene, app: &SolveApp, st: &solvecraft_engine::doc::ModelState) {
|
||||
let mut b = solvecraft_engine::geom::Aabb3::EMPTY;
|
||||
for x in st.bodies.iter().filter(|x| !app.ui.hidden_bodies.contains(&x.name)) {
|
||||
b = b.union(&x.mesh().bounds());
|
||||
}
|
||||
if b.is_empty() {
|
||||
return;
|
||||
}
|
||||
let size = b.size();
|
||||
let c = b.center();
|
||||
let z = b.min.z - 1e-3 * (1.0 + b.diagonal());
|
||||
let (rx, ry) = (size.x * 0.62 + size.z * 0.15, size.y * 0.62 + size.z * 0.15);
|
||||
if !(rx > 0.0 && ry > 0.0) {
|
||||
return;
|
||||
}
|
||||
let dark = if crate::theme::is_dark() { 150 } else { 80 };
|
||||
// Rings from the middle out, fading to nothing.
|
||||
let rings = [(0.0, dark), (0.55, dark * 3 / 4), (0.85, dark / 3), (1.0, 0)];
|
||||
let n = 48;
|
||||
let at = |r: f64, k: usize| {
|
||||
let a = k as f64 / n as f64 * std::f64::consts::TAU;
|
||||
Vec3::new(c.x + rx * r * a.cos(), c.y + ry * r * a.sin(), z).to_f32()
|
||||
};
|
||||
for w in rings.windows(2) {
|
||||
let ((r0, a0), (r1, a1)) = (w[0], w[1]);
|
||||
let (c0, c1) = ([0, 0, 0, a0 as u8], [0, 0, 0, a1 as u8]);
|
||||
for k in 0..n {
|
||||
let (p00, p01, p10, p11) = (at(r0, k), at(r0, k + 1), at(r1, k), at(r1, k + 1));
|
||||
sc.trans_tri(p00, [0.0; 3], c0);
|
||||
sc.trans_tri(p10, [0.0; 3], c1);
|
||||
sc.trans_tri(p11, [0.0; 3], c1);
|
||||
if r0 > 0.0 {
|
||||
sc.trans_tri(p00, [0.0; 3], c0);
|
||||
sc.trans_tri(p11, [0.0; 3], c1);
|
||||
sc.trans_tri(p01, [0.0; 3], c0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The drawn pieces of a polyline in a dash pattern (on, off, on, off… lengths).
|
||||
pub(crate) fn dashes(pts: &[Vec3], pattern: &[f64]) -> Vec<(Vec3, Vec3)> {
|
||||
let mut out = Vec::new();
|
||||
|
||||
Reference in new issue
Block a user