S7 Implementation Reference — Multi-layer glass, environment mapping, and shadow enhancements
The 3D viewer renders realistic window previews using Three.js r0.160.0. S7 added four enhancements to make glass rendering physically accurate:
RoomEnvironment PMREM provides soft, realistic reflections on glass and frame surfaces.
Parses composition strings into stacked glass layers with metallic spacer bars.
Stronger floor shadow (0.25 opacity) plus radial-gradient contact shadow blob.
12 glass material types with physically-based optical properties (IOR, transmission, roughness).
src/js/3d-engine.js (1415 lines) — single file, all changes within WindowRenderer class.
Three.js MeshPhysicalMaterial with transmission needs an environment map for realistic refraction and reflection. Without it, glass appears flat.
The sigma = 0.04 parameter produces slightly blurred reflections — premium and soft rather than mirror-sharp.
Real insulating glass units (IGU) have 2–3 glass panes separated by gas-filled gaps with metallic spacer bars.
Real glass is 4mm thick — invisible at window scale. A visual scale factor of 3.0 is applied:
| Real Thickness | Visual Thickness | Element |
|---|---|---|
| 4 mm | 12 mm (0.012m) | Glass layer |
| 16 mm | 48 mm (0.048m) | Argon gap |
| 24 mm total | 72 mm total | Full stack |
| Type | Color | Material |
|---|---|---|
| Standard spacer | 0x888888 | Silver aluminium (metalness 0.9) |
| Warm Edge (we) | 0x333333 | Dark composite (better thermal insulation) |
parseGlassComposition(str) converts WinArhi catalog strings into structured data.
(we) or (Ag, we) → set warmEdge flag- delimiter331 = 3+3+1 = 7mm){ layers, gaps, warmEdge }| Input | Layers | Gaps | Notes |
|---|---|---|---|
4LowE-16Ag-4Float | 4mm LowE + 4mm Float | 16mm Argon | Standard double |
331-12Aer-331Sablat | 7mm Float + 7mm Sablat | 12mm Air | Laminate + frosted |
4LowE-14Ag-4R. Clear | 4mm LowE + 4mm Clear | 14mm Argon | Dot/space in name |
331LowE-10Ag-4F-12Ag-4LowE | 7mm + 4mm + 4mm | 10mm + 12mm Ag | Triple pane |
4LowE-16Ag-4Float (we) | 4mm + 4mm | 16mm Ag | Warm Edge = dark spacers |
6Float | 6mm Float | none | Single pane |
Each glass layer gets a MeshPhysicalMaterial with physically-based properties. Materials are cached in materialCache.
| Type | Color | Transmission | Roughness | Visual |
|---|---|---|---|---|
| LowE | 0x88ccdd | 0.90 | 0.0 | Blue-green tint |
| Float / Clear | 0xeeeeff | 0.92 | 0.0 | Neutral transparent |
| Planitherm | 0x99ccdd | 0.88 | 0.0 | Premium blue |
| Sablat (frosted) | 0xdddddd | 0.40 | 0.8 | Diffuse white |
| Krizet | 0xdddddd | 0.50 | 0.6 | Textured pattern |
| Securizat | 0x99aacc | 0.88 | 0.0 | Tempered blue |
| Screen | 0xaabbaa | 0.30 | 0.1 | Solar control green |
| Bronze | 0xcc9966 | 0.35 | 0.05 | Reflective warm |
| Oglinda (mirror) | 0xcccccc | 0.10 | 0.0 | Near-opaque |
| Lacobel | 0x334455 | 0.05 | 0.1 | Painted back |
| Ornament | 0xdddddd | 0.55 | 0.7 | Decorative rough |
All materials: ior: 1.52, DoubleSide, polygonOffset: true, clearcoat: 1 (frosted types → 0.2).
ShadowMaterial opacity increased 0.1 → 0.25 for a more pronounced ground shadow.
| Metric | Value | Notes |
|---|---|---|
| Triangles per panel (double) | ~72 | 2 layers + 4 spacers |
| Triangles per panel (triple) | ~132 | 3 layers + 8 spacers |
| 4-panel triple window | ~528 | Negligible |
| Environment map | One-time ~16ms | Not per-frame |
| Material cache | Shared | Same type reused across panels |
| Pixel ratio cap | 2.0 | Prevents 4K overdraw |
Touch devices with viewport < 768px: multi-layer glass disabled, falls back to single PlaneGeometry.
this._useSimpleGlass = ('ontouchstart' in window && window.innerWidth < 768);
| Method | Purpose |
|---|---|
updateWindow(config) | Rebuild with new config. If glazingDef.composition exists, triggers multi-layer. |
toggleWireframe() | Toggles wireframe on all materials including cached glass layers. |
toggleCrossSection() | Profile cross-section view. |
fitToView() | Auto-positions camera. Also resizes contact shadow. |
dispose() | Cleans up all GPU resources. |
renderer.updateWindow({
width: 1.2, // meters
height: 1.4,
panels: 2,
openings: ['obd', 'ds'],
glazingDef: {
id: '24mm, 4LowE-16Ag-4Float',
composition: '4LowE-16Ag-4Float', // triggers multi-layer
type: 'double', // 'single' skips it
thickness: 24 // mm, fallback material
},
colorDef: { hex: '#FFFFFF', tip: 'solid' },
handleColor: '#C0C0C0'
});
| # | Test | Expected Result |
|---|---|---|
| 1 | Select double LowE glass | Two glass layers visible in profile view |
| 2 | Check spacer bars | Silver metallic bars at gap edges |
| 3 | Select warm edge (we) | Spacer bars change to dark grey |
| 4 | Select triple pane | 3 layers + 2 sets of spacers |
| 5 | Select Sablat (frosted) | Visible roughness on glass |
| 6 | Check reflections | Soft environment reflections on glass |
| 7 | Check floor shadow | Darker shadow + contact shadow blob |
| 8 | Resize window config | Contact shadow resizes |
| 9 | Mobile viewport (<768px) | Falls back to flat PlaneGeometry |
| 10 | Toggle wireframe | All glass layers show wireframe |
| 11 | Change glass repeatedly | No console errors (disposal correct) |
| 12 | Double-click to open panel | Multi-layer glass animates with sash |