perf(scene): greek top-level Text/MText below 4px height
When a Text/MText entity's anno-scaled glyph height projects to fewer than 4 screen pixels, drop the per-glyph stroke tessellation and emit a single filled rectangle in the text's color instead. The user still sees "text lives here" at the original color and footprint, but the expensive font-stroke generation is skipped for thousands of unreadable labels at fit-all / zoom-out views. Pre-boosts the fill color to compensate for the 0.45 ambient-occlusion dim the face3d pipeline applies (it's meant for 3D-shaded mesh solids, not 2D text greeking). Note: applies only to top-level entities; Text/MText *inside* block defs is already tessellated into the block cache at build time, so greeking those would require either a cache rebuild on zoom or a parallel "low-detail" cache. Left for later if real-world test suggests it's needed. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
c5ed83c752
commit
242e8870c3
1 changed files with 67 additions and 1 deletions
|
|
@ -3901,7 +3901,8 @@ fn tessellate_entity(
|
||||||
if let Some(wpp) = world_per_pixel {
|
if let Some(wpp) = world_per_pixel {
|
||||||
let w = (ab[2] - ab[0]).abs();
|
let w = (ab[2] - ab[0]).abs();
|
||||||
let h = (ab[3] - ab[1]).abs();
|
let h = (ab[3] - ab[1]).abs();
|
||||||
if w.max(h) / wpp < 0.5 {
|
// Keep in sync with `block_cache::MIN_PIXEL_SIZE`.
|
||||||
|
if w.max(h) / wpp < 5.0 {
|
||||||
return vec![];
|
return vec![];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4102,6 +4103,71 @@ fn tessellate_entity(
|
||||||
}
|
}
|
||||||
|
|
||||||
let aabb = entity_aabb(e, world_offset);
|
let aabb = entity_aabb(e, world_offset);
|
||||||
|
|
||||||
|
// Text greeking: when a Text/MText entity's projected glyph height
|
||||||
|
// drops below a readable size, replace the per-glyph stroke geometry
|
||||||
|
// with a single filled rectangle in the text's color. Same visual
|
||||||
|
// hint ("text lives here") at a fraction of the tessellation cost.
|
||||||
|
if let Some(wpp) = world_per_pixel {
|
||||||
|
let text_height: Option<f64> = match e {
|
||||||
|
EntityType::Text(t) => Some(t.height * anno_scale as f64),
|
||||||
|
EntityType::MText(m) => Some(m.height * anno_scale as f64),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
if let Some(h_world) = text_height {
|
||||||
|
let h_px = (h_world as f32) / wpp;
|
||||||
|
// < 4 px: glyphs aren't readable; emit a greeked rect instead.
|
||||||
|
// We still drew through the LOD floor (entity AABB > 2 px), so
|
||||||
|
// this rect is bigger than 2 px in at least one dimension.
|
||||||
|
if h_px < 4.0 && aabb != WireModel::UNBOUNDED_AABB {
|
||||||
|
let [x0, y0, x1, y1] = aabb;
|
||||||
|
let z = match e {
|
||||||
|
EntityType::Text(t) => (t.insertion_point.z - world_offset[2]) as f32,
|
||||||
|
EntityType::MText(m) => (m.insertion_point.z - world_offset[2]) as f32,
|
||||||
|
_ => 0.0,
|
||||||
|
};
|
||||||
|
// Two CCW triangles spanning the AABB.
|
||||||
|
let fill_tris = vec![
|
||||||
|
[x0, y0, z],
|
||||||
|
[x1, y0, z],
|
||||||
|
[x1, y1, z],
|
||||||
|
[x0, y0, z],
|
||||||
|
[x1, y1, z],
|
||||||
|
[x0, y1, z],
|
||||||
|
];
|
||||||
|
// The face3d pipeline dims fill_tris colors to 45% to fake
|
||||||
|
// ambient occlusion on PolyfaceMesh / 3DFACE solids. Greeked
|
||||||
|
// text doesn't want that shading — pre-boost the color so it
|
||||||
|
// emerges close to the original text color after the dim.
|
||||||
|
let boost = 1.0 / 0.45;
|
||||||
|
let [r, g, b, a] = entity_color;
|
||||||
|
let greek_color = [
|
||||||
|
(r * boost).min(1.0),
|
||||||
|
(g * boost).min(1.0),
|
||||||
|
(b * boost).min(1.0),
|
||||||
|
a,
|
||||||
|
];
|
||||||
|
return vec![WireModel {
|
||||||
|
name: h.value().to_string(),
|
||||||
|
points: vec![],
|
||||||
|
color: greek_color,
|
||||||
|
selected: sel,
|
||||||
|
aci,
|
||||||
|
pattern_length: 0.0,
|
||||||
|
pattern: [0.0; 8],
|
||||||
|
line_weight_px: 1.0,
|
||||||
|
snap_pts: vec![],
|
||||||
|
tangent_geoms: vec![],
|
||||||
|
key_vertices: vec![],
|
||||||
|
aabb,
|
||||||
|
plinegen: true,
|
||||||
|
vp_scissor: None,
|
||||||
|
fill_tris,
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut base = tessellate::tessellate(
|
let mut base = tessellate::tessellate(
|
||||||
document,
|
document,
|
||||||
h,
|
h,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue