3D-Ansicht: neuer Darstellungsmodus "Schattiert mit Kanten" (BIM-Look)

Neuer RenderStyle::ShadedEdges in render3d: wie "shaded" (echte Bauteilfarben,
beleuchtet), zusätzlich dunkle Modell-Kanten obenauf wie bei "hidden" — der
typische Revit/ArchiCAD-Look, der bisher fehlte (nur reines Weiss+Kanten via
"hidden" oder reine Bauteilfarben ohne Kanten via "shaded" waren möglich).
Nutzt dieselbe tiefengebiaste Flächen-Pipeline wie "hidden", damit die Kanten
sauber obenauf liegen (kein Z-Fighting). +6 Rust-Tests (--features render,
83/83 grün). Als neue Option "shaded-edges" in beiden Darstellungsart-
Dropdowns der 3D-Oberleiste; Three.js-Fallback ignoriert den Wert graceful
(fällt auf shaded zurück, bekommt bewusst keine neuen Features).
This commit is contained in:
2026-07-12 18:59:05 +02:00
parent 6b89ad5bdb
commit a84dc7ac73
5 changed files with 80 additions and 7 deletions
+68 -4
View File
@@ -46,6 +46,11 @@ pub enum RenderStyle {
/// Hidden-Line: flach-weisse Flaechen (fuellen den Depth-Buffer) + dunkle
/// Kanten obenauf, tiefengetestet -> nur sichtbare Kanten erscheinen.
Hidden,
/// "Schattiert mit Kanten" (typischer BIM-Look, z. B. Revit/ArchiCAD): wie
/// `Shaded` (echte Bauteilfarben, beleuchtet), ZUSAETZLICH die dunklen
/// Modell-Kanten obenauf (wie bei `Hidden`, aber mit Material- statt
/// Weiss-Flaechen).
ShadedEdges,
}
impl RenderStyle {
@@ -56,18 +61,20 @@ impl RenderStyle {
"textured" => RenderStyle::Textured,
"wireframe" => RenderStyle::Wireframe,
"hidden" => RenderStyle::Hidden,
"shaded-edges" => RenderStyle::ShadedEdges,
_ => RenderStyle::Shaded,
}
}
/// `mode.x`-Wert fuer den Mesh-Shader (siehe shaders.rs): 0 = Material/shaded
/// (auch textured), 1 = weiss/Clay, 2 = flach-weisse Hidden-Line-Flaechen.
/// (auch textured/shaded-edges), 1 = weiss/Clay, 2 = flach-weisse
/// Hidden-Line-Flaechen.
fn mesh_mode(self) -> f32 {
match self {
RenderStyle::White => 1.0,
RenderStyle::Hidden => 2.0,
// Shaded, Textured, Wireframe (Flaechen werden bei Wireframe eh nicht
// gezeichnet) -> Material.
// gezeichnet), ShadedEdges -> Material.
_ => 0.0,
}
}
@@ -79,7 +86,19 @@ impl RenderStyle {
/// Werden in diesem Stil Modell-Kanten gezeichnet?
fn draws_edges(self) -> bool {
matches!(self, RenderStyle::Wireframe | RenderStyle::Hidden)
matches!(
self,
RenderStyle::Wireframe | RenderStyle::Hidden | RenderStyle::ShadedEdges
)
}
/// Braucht dieser Stil die leicht nach hinten gebiaste Flaechen-Pipeline,
/// damit die (tiefengetesteten) Kanten sauber obenauf liegen, statt mit den
/// Flaechen zu flackern (Z-Fighting)? Gilt fuer alle Stile, die BEIDES
/// zeichnen (Flaechen + Kanten) — bislang nur `Hidden`, jetzt auch
/// `ShadedEdges`.
fn needs_biased_face_pipeline(self) -> bool {
matches!(self, RenderStyle::Hidden | RenderStyle::ShadedEdges)
}
}
@@ -1343,7 +1362,7 @@ impl Renderer {
pass.draw_indexed(0..t.index_count, 0, 0..1);
}
} else if let Some(m) = &self.mesh {
let face_pipeline = if self.style == RenderStyle::Hidden {
let face_pipeline = if self.style.needs_biased_face_pipeline() {
&self.hidden_face_pipeline
} else {
&self.pipeline
@@ -1418,3 +1437,48 @@ impl Renderer {
queue.submit(std::iter::once(encoder.finish()));
}
}
#[cfg(test)]
mod render_style_tests {
use super::RenderStyle;
#[test]
fn shaded_edges_parses_from_api_string() {
assert_eq!(
RenderStyle::from_str_or_shaded("shaded-edges"),
RenderStyle::ShadedEdges
);
}
#[test]
fn unknown_style_falls_back_to_shaded() {
assert_eq!(RenderStyle::from_str_or_shaded("bogus"), RenderStyle::Shaded);
}
#[test]
fn shaded_edges_uses_material_colors_like_shaded() {
// mode.x = 0.0 -> Material/Bauteilfarben, NICHT weiss (1.0) oder
// Hidden-Line-Flaechen (2.0) — der BIM-Look behaelt echte Farben.
assert_eq!(RenderStyle::ShadedEdges.mesh_mode(), 0.0);
assert_eq!(RenderStyle::Shaded.mesh_mode(), RenderStyle::ShadedEdges.mesh_mode());
}
#[test]
fn shaded_edges_draws_both_faces_and_edges() {
assert!(RenderStyle::ShadedEdges.draws_faces());
assert!(RenderStyle::ShadedEdges.draws_edges());
}
#[test]
fn shaded_edges_needs_biased_face_pipeline_like_hidden() {
assert!(RenderStyle::ShadedEdges.needs_biased_face_pipeline());
assert!(RenderStyle::Hidden.needs_biased_face_pipeline());
assert!(!RenderStyle::Shaded.needs_biased_face_pipeline());
}
#[test]
fn plain_shaded_style_unaffected_by_new_variant() {
assert!(!RenderStyle::Shaded.draws_edges());
assert!(RenderStyle::Shaded.draws_faces());
}
}
+3
View File
@@ -389,6 +389,9 @@ impl WebModelRenderer {
/// - `"wireframe"`— nur Modell-Kanten (Feature-Edges), keine Flaechen.
/// - `"hidden"` — Hidden-Line: flach-weisse Flaechen fuellen den Depth-
/// Buffer, dunkle Kanten liegen tiefengetestet obenauf (nur sichtbare).
/// - `"shaded-edges"` — "Schattiert mit Kanten" (typischer BIM-Look): wie
/// `"shaded"` (echte Bauteilfarben), ZUSAETZLICH dunkle Modell-Kanten
/// obenauf wie bei `"hidden"`.
/// Unbekannte Werte fallen auf `"shaded"` zurueck. Wirkt erst beim naechsten
/// `render`. Loest `set_render_mode_white` ab (das bleibt kompatibel).
pub fn set_render_style(&mut self, style: &str) -> Result<(), JsValue> {
+1
View File
@@ -84,6 +84,7 @@ export const de = {
"display.style.color": "Farbig",
"display.style.mono": "Schwarz-Weiss",
"display.style.shaded": "Schattiert",
"display.style.shadedEdges": "Schattiert mit Kanten",
"display.style.white": "Weiss",
"display.style.textured": "Texturiert",
"display.style.wireframe": "Drahtgitter",
+1
View File
@@ -83,6 +83,7 @@ export const en: Record<TranslationKey, string> = {
"display.style.color": "Color",
"display.style.mono": "Black & white",
"display.style.shaded": "Shaded",
"display.style.shadedEdges": "Shaded with edges",
"display.style.white": "White",
"display.style.textured": "Textured",
"display.style.wireframe": "Wireframe",
+7 -3
View File
@@ -50,15 +50,17 @@ export type DetailLevel = "grob" | "mittel" | "fein";
/**
* Render-/Anzeigemodus der 3D-Ansicht: schattiert, einheitlich weiss (Clay-Look),
* texturiert (echte PBR-Materialien je Bauteil), Drahtgitter, Verdeckte Kanten
* (Hidden-Line). Wirkt nur in der Perspektive. Der Slot section" (Schnitt-
* schraffur, Welle B) ist bewusst freigelassen.
* (Hidden-Line), Schattiert mit Kanten (typischer BIM-Look: Bauteilfarben +
* Modell-Kanten obenauf). Wirkt nur in der Perspektive. Der Slot section"
* (Schnittschraffur, Welle B) ist bewusst freigelassen.
*/
export type RenderMode =
| "shaded"
| "white"
| "textured"
| "wireframe"
| "hidden";
| "hidden"
| "shaded-edges";
/**
* Kanonischer Blickwinkel der 3D-Ansicht (Vectorworks/DOSSIER-Stil). front"/
@@ -1591,6 +1593,7 @@ export function ViewRibbonTab({
title={t("display.style.hint")}
options={[
{ value: "shaded", label: t("display.style.shaded") },
{ value: "shaded-edges", label: t("display.style.shadedEdges") },
{ value: "white", label: t("display.style.white") },
{ value: "textured", label: t("display.style.textured") },
{ value: "wireframe", label: t("display.style.wireframe") },
@@ -1796,6 +1799,7 @@ export function Ribbon3dTab({
title={t("display.style.hint")}
options={[
{ value: "shaded", label: t("display.style.shaded") },
{ value: "shaded-edges", label: t("display.style.shadedEdges") },
{ value: "white", label: t("display.style.white") },
{ value: "textured", label: t("display.style.textured") },
{ value: "wireframe", label: t("display.style.wireframe") },