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:
HakanandClaude Opus 4.7 committed 2026-05-14 14:49:59 +03:00
1 parent c5ed83c752
commit 242e8870c3
1 file changed
+67 -1
+67 -1
View File
@@ -3901,7 +3901,8 @@ fn tessellate_entity(
if let Some(wpp) = world_per_pixel {
let w = (ab[2] - ab[0]).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![];
}
}
@@ -4102,6 +4103,71 @@ fn tessellate_entity(
}
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(
document,
h,