* View-dependent display refinement: bodies seen up close are drawn from finer display plans (#1320) Each frame the viewport works out every shown body's screen-space error (the display quality's chord tolerance in pixels where the body is nearest the eye) and picks a refinement step past the chosen display quality, each halving the chord, with hysteresis. Steps are planned off the UI thread and swapped in when ready, within a triangle budget and a cache size. Faces (GPU plan or CPU mesh), edges, silhouettes and highlights of a refined body all come from the refined plan, so a highlight stays on the drawn triangles. Planned bodies are chunked by content on the GPU, so a refinement re-evaluates only its own chunk. Display only: the reference mesh, the B-rep and exports never change. Co-Authored-By: Claude Opus 5.5 <[email protected]> * Display refinement: only collect finished plans while the view stands still, time the choice, keep the web planning one step a frame Co-Authored-By: Claude Opus 5.5 <[email protected]> * Format Co-Authored-By: Claude Opus 5.5 <[email protected]> * Keep the Display quality note as it was (the longer one pushed the Colour vision list off the Graphics page) Co-Authored-By: Claude Opus 5.5 <[email protected]> --------- Co-authored-by: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
8b97b9ed62
commit
d43c414b7b
7 files changed
+805
-14
No files matched your search
@@ -126,6 +126,25 @@ impl ModelBody {
|
||||
.clone()
|
||||
}
|
||||
|
||||
/// The display plan and its mesh `k` steps finer than `q` (view-dependent refinement, #1320;
|
||||
/// see [`crate::display_quality::refinement_for`]). Step 0 is the cached plan at `q`; finer
|
||||
/// steps are made on each call and kept by the viewport, which evicts them when it runs over
|
||||
/// its budget. `None` when the body has no plan at that step.
|
||||
pub fn refined_display(&self, q: crate::display_quality::DisplayQuality, k: u8) -> Option<(Arc<TessPlan>, Arc<Mesh>)> {
|
||||
if k == 0 {
|
||||
return Some((self.display_plan_at(q)?, self.plan_mesh_at(q)?));
|
||||
}
|
||||
let plan = match self.body.display_plan_angular(q.refined_chord(self.body.size(), k), q.refined_angle(k)) {
|
||||
Ok(plan) => plan,
|
||||
Err(e) => {
|
||||
log::debug!("{}: no display plan refined {k} steps ({e})", self.name);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let mesh = self.body.display_mesh_of(&plan).ok()?;
|
||||
Some((Arc::new(plan), Arc::new(mesh)))
|
||||
}
|
||||
|
||||
/// The display mesh's chord tolerance: 1/1000 of the body's size.
|
||||
fn display_tol(&self) -> f64 {
|
||||
(self.body.size() * 1e-3).max(1e-3)
|
||||
|
||||
Reference in new issue
Block a user