three-cad-viewer 4.1.2 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Readme.md +12 -5
- package/dist/camera/camera.d.ts +14 -2
- package/dist/core/studio-manager.d.ts +91 -0
- package/dist/core/types.d.ts +260 -9
- package/dist/core/viewer-state.d.ts +28 -2
- package/dist/core/viewer.d.ts +200 -6
- package/dist/index.d.ts +7 -2
- package/dist/rendering/environment.d.ts +239 -0
- package/dist/rendering/light-detection.d.ts +44 -0
- package/dist/rendering/material-factory.d.ts +77 -2
- package/dist/rendering/material-presets.d.ts +32 -0
- package/dist/rendering/room-environment.d.ts +13 -0
- package/dist/rendering/studio-composer.d.ts +130 -0
- package/dist/rendering/studio-floor.d.ts +53 -0
- package/dist/rendering/texture-cache.d.ts +142 -0
- package/dist/rendering/triplanar.d.ts +37 -0
- package/dist/scene/animation.d.ts +1 -1
- package/dist/scene/clipping.d.ts +31 -0
- package/dist/scene/nestedgroup.d.ts +64 -27
- package/dist/scene/objectgroup.d.ts +47 -0
- package/dist/three-cad-viewer.css +339 -29
- package/dist/three-cad-viewer.esm.js +27567 -11874
- package/dist/three-cad-viewer.esm.js.map +1 -1
- package/dist/three-cad-viewer.esm.min.js +10 -4
- package/dist/three-cad-viewer.js +27486 -11787
- package/dist/three-cad-viewer.min.js +10 -4
- package/dist/ui/display.d.ts +147 -0
- package/dist/utils/decode-instances.d.ts +60 -0
- package/dist/utils/utils.d.ts +10 -0
- package/package.json +4 -2
- package/src/_version.ts +1 -1
- package/src/camera/camera.ts +27 -10
- package/src/core/studio-manager.ts +682 -0
- package/src/core/types.ts +328 -9
- package/src/core/viewer-state.ts +84 -4
- package/src/core/viewer.ts +453 -22
- package/src/index.ts +25 -1
- package/src/rendering/environment.ts +840 -0
- package/src/rendering/light-detection.ts +327 -0
- package/src/rendering/material-factory.ts +456 -2
- package/src/rendering/material-presets.ts +303 -0
- package/src/rendering/raycast.ts +2 -2
- package/src/rendering/room-environment.ts +192 -0
- package/src/rendering/studio-composer.ts +577 -0
- package/src/rendering/studio-floor.ts +108 -0
- package/src/rendering/texture-cache.ts +1020 -0
- package/src/rendering/triplanar.ts +329 -0
- package/src/scene/animation.ts +3 -2
- package/src/scene/clipping.ts +59 -0
- package/src/scene/nestedgroup.ts +399 -0
- package/src/scene/objectgroup.ts +186 -11
- package/src/scene/orientation.ts +12 -0
- package/src/scene/render-shape.ts +55 -21
- package/src/types/n8ao.d.ts +28 -0
- package/src/ui/display.ts +1032 -27
- package/src/ui/index.html +181 -44
- package/src/utils/decode-instances.ts +233 -0
- package/src/utils/utils.ts +33 -20
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in material presets for Studio mode.
|
|
3
|
+
*
|
|
4
|
+
* 31 presets organized by category: metals (polished & matte/brushed),
|
|
5
|
+
* plastics, glass & transparent, rubber & elastomers, painted surfaces,
|
|
6
|
+
* and natural/other materials.
|
|
7
|
+
*
|
|
8
|
+
* These are pure data definitions — no textures, no runtime cost.
|
|
9
|
+
* The `builtin` field is intentionally omitted; it is used by user-defined
|
|
10
|
+
* materials to reference these presets, not by presets themselves.
|
|
11
|
+
*
|
|
12
|
+
* All color values are in sRGB color space (0-1 per channel).
|
|
13
|
+
* The material factory converts sRGB to linear when creating Three.js materials.
|
|
14
|
+
* Presets with neutral color (plastics, paints) rely on the leaf node's
|
|
15
|
+
* color field for the actual tint via fallback in the material factory.
|
|
16
|
+
*
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import type { MaterialAppearance } from "../core/types.js";
|
|
20
|
+
|
|
21
|
+
// =============================================================================
|
|
22
|
+
// Preset Dictionary
|
|
23
|
+
// =============================================================================
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Built-in material presets keyed by preset name.
|
|
27
|
+
*
|
|
28
|
+
* Usage: look up a preset by the `material` tag on a leaf node, or via
|
|
29
|
+
* `"builtin:<name>"` strings in the materials table.
|
|
30
|
+
*/
|
|
31
|
+
export const MATERIAL_PRESETS: Record<string, MaterialAppearance> = {
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
// Metals -- Polished
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
|
|
36
|
+
"chrome": {
|
|
37
|
+
name: "Chrome",
|
|
38
|
+
color: [0.98, 0.98, 0.98, 1],
|
|
39
|
+
metalness: 1.0,
|
|
40
|
+
roughness: 0.05,
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
"polished-steel": {
|
|
44
|
+
name: "Polished Steel",
|
|
45
|
+
color: [0.91, 0.91, 0.92, 1],
|
|
46
|
+
metalness: 1.0,
|
|
47
|
+
roughness: 0.1,
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
"polished-aluminum": {
|
|
51
|
+
name: "Polished Aluminum",
|
|
52
|
+
color: [0.916, 0.923, 0.924, 1],
|
|
53
|
+
metalness: 1.0,
|
|
54
|
+
roughness: 0.1,
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
"gold": {
|
|
58
|
+
name: "Gold",
|
|
59
|
+
color: [1, 0.93, 0, 1],
|
|
60
|
+
metalness: 1.0,
|
|
61
|
+
roughness: 0.1,
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
"copper": {
|
|
65
|
+
name: "Copper",
|
|
66
|
+
color: [0.98, 0.82, 0.76, 1],
|
|
67
|
+
metalness: 1.0,
|
|
68
|
+
roughness: 0.15,
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
"brass": {
|
|
72
|
+
name: "Brass",
|
|
73
|
+
color: [0.95, 0.9, 0.7, 1],
|
|
74
|
+
metalness: 1.0,
|
|
75
|
+
roughness: 0.15,
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
// ---------------------------------------------------------------------------
|
|
79
|
+
// Metals -- Matte / Brushed
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
|
|
82
|
+
"stainless-steel": {
|
|
83
|
+
name: "Stainless Steel",
|
|
84
|
+
color: [0.91, 0.91, 0.92, 1],
|
|
85
|
+
metalness: 1.0,
|
|
86
|
+
roughness: 0.4,
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
"brushed-aluminum": {
|
|
90
|
+
name: "Brushed Aluminum",
|
|
91
|
+
color: [0.916, 0.923, 0.924, 1],
|
|
92
|
+
metalness: 1.0,
|
|
93
|
+
roughness: 0.35,
|
|
94
|
+
anisotropy: 0.5,
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
"cast-iron": {
|
|
98
|
+
name: "Cast Iron",
|
|
99
|
+
color: [0.68, 0.68, 0.69, 1],
|
|
100
|
+
metalness: 0.9,
|
|
101
|
+
roughness: 0.7,
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
"titanium": {
|
|
105
|
+
name: "Titanium",
|
|
106
|
+
color: [0.81, 0.79, 0.77, 1],
|
|
107
|
+
metalness: 1.0,
|
|
108
|
+
roughness: 0.45,
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
"galvanized": {
|
|
112
|
+
name: "Galvanized",
|
|
113
|
+
color: [0.88, 0.88, 0.9, 1],
|
|
114
|
+
metalness: 0.8,
|
|
115
|
+
roughness: 0.5,
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
// Plastics
|
|
120
|
+
// ---------------------------------------------------------------------------
|
|
121
|
+
|
|
122
|
+
"plastic-glossy": {
|
|
123
|
+
name: "Plastic (Glossy)",
|
|
124
|
+
color: [0.91, 0.91, 0.91, 1],
|
|
125
|
+
metalness: 0.0,
|
|
126
|
+
roughness: 0.4,
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
"plastic-matte": {
|
|
130
|
+
name: "Plastic (Matte)",
|
|
131
|
+
color: [0.91, 0.91, 0.91, 1],
|
|
132
|
+
metalness: 0.0,
|
|
133
|
+
roughness: 0.6,
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
"abs-black": {
|
|
137
|
+
name: "ABS Black",
|
|
138
|
+
color: [0.25, 0.25, 0.25, 1],
|
|
139
|
+
metalness: 0.0,
|
|
140
|
+
roughness: 0.4,
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
"nylon": {
|
|
144
|
+
name: "Nylon",
|
|
145
|
+
color: [0.95, 0.94, 0.92, 1],
|
|
146
|
+
metalness: 0.0,
|
|
147
|
+
roughness: 0.55,
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
"acrylic-clear": {
|
|
151
|
+
name: "Acrylic (Clear)",
|
|
152
|
+
color: [1, 1, 1, 1],
|
|
153
|
+
metalness: 0.0,
|
|
154
|
+
roughness: 0.0,
|
|
155
|
+
transmission: 0.95,
|
|
156
|
+
ior: 1.49,
|
|
157
|
+
},
|
|
158
|
+
|
|
159
|
+
// ---------------------------------------------------------------------------
|
|
160
|
+
// Glass & Transparent
|
|
161
|
+
// ---------------------------------------------------------------------------
|
|
162
|
+
|
|
163
|
+
"glass-clear": {
|
|
164
|
+
name: "Glass (Clear)",
|
|
165
|
+
color: [1, 1, 1, 1],
|
|
166
|
+
metalness: 0.0,
|
|
167
|
+
roughness: 0.0,
|
|
168
|
+
transmission: 1.0,
|
|
169
|
+
ior: 1.52,
|
|
170
|
+
thickness: 2.0,
|
|
171
|
+
},
|
|
172
|
+
|
|
173
|
+
"glass-tinted": {
|
|
174
|
+
name: "Glass (Tinted)",
|
|
175
|
+
color: [0.8, 0.91, 0.95, 1],
|
|
176
|
+
metalness: 0.0,
|
|
177
|
+
roughness: 0.0,
|
|
178
|
+
transmission: 0.9,
|
|
179
|
+
ior: 1.52,
|
|
180
|
+
thickness: 3.0,
|
|
181
|
+
},
|
|
182
|
+
|
|
183
|
+
"glass-frosted": {
|
|
184
|
+
name: "Glass (Frosted)",
|
|
185
|
+
color: [1, 1, 1, 1],
|
|
186
|
+
metalness: 0.0,
|
|
187
|
+
roughness: 0.3,
|
|
188
|
+
transmission: 0.85,
|
|
189
|
+
ior: 1.52,
|
|
190
|
+
thickness: 2.0,
|
|
191
|
+
},
|
|
192
|
+
|
|
193
|
+
// ---------------------------------------------------------------------------
|
|
194
|
+
// Rubber & Elastomers
|
|
195
|
+
// ---------------------------------------------------------------------------
|
|
196
|
+
|
|
197
|
+
"rubber-black": {
|
|
198
|
+
name: "Rubber (Black)",
|
|
199
|
+
color: [0.31, 0.31, 0.31, 1],
|
|
200
|
+
metalness: 0.0,
|
|
201
|
+
roughness: 0.9,
|
|
202
|
+
},
|
|
203
|
+
|
|
204
|
+
"rubber-gray": {
|
|
205
|
+
name: "Rubber (Gray)",
|
|
206
|
+
color: [0.63, 0.63, 0.63, 1],
|
|
207
|
+
metalness: 0.0,
|
|
208
|
+
roughness: 0.85,
|
|
209
|
+
},
|
|
210
|
+
|
|
211
|
+
"rubber-red": {
|
|
212
|
+
name: "Rubber (Red)",
|
|
213
|
+
color: [0.85, 0.35, 0.35, 1],
|
|
214
|
+
metalness: 0.0,
|
|
215
|
+
roughness: 0.8,
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
// ---------------------------------------------------------------------------
|
|
219
|
+
// Painted Surfaces
|
|
220
|
+
// ---------------------------------------------------------------------------
|
|
221
|
+
|
|
222
|
+
"paint-matte": {
|
|
223
|
+
name: "Paint (Matte)",
|
|
224
|
+
color: [0.91, 0.91, 0.91, 1],
|
|
225
|
+
metalness: 0.0,
|
|
226
|
+
roughness: 0.7,
|
|
227
|
+
},
|
|
228
|
+
|
|
229
|
+
"paint-glossy": {
|
|
230
|
+
name: "Paint (Glossy)",
|
|
231
|
+
color: [0.91, 0.91, 0.91, 1],
|
|
232
|
+
metalness: 0.0,
|
|
233
|
+
roughness: 0.15,
|
|
234
|
+
},
|
|
235
|
+
|
|
236
|
+
"paint-metallic": {
|
|
237
|
+
name: "Paint (Metallic)",
|
|
238
|
+
color: [0.91, 0.91, 0.91, 1],
|
|
239
|
+
metalness: 0.5,
|
|
240
|
+
roughness: 0.25,
|
|
241
|
+
},
|
|
242
|
+
|
|
243
|
+
"car-paint": {
|
|
244
|
+
name: "Car Paint",
|
|
245
|
+
color: [0.91, 0, 0, 1],
|
|
246
|
+
metalness: 0.5,
|
|
247
|
+
roughness: 0.2,
|
|
248
|
+
clearcoat: 1.0,
|
|
249
|
+
clearcoatRoughness: 0.03,
|
|
250
|
+
},
|
|
251
|
+
|
|
252
|
+
// ---------------------------------------------------------------------------
|
|
253
|
+
// Natural / Other
|
|
254
|
+
// ---------------------------------------------------------------------------
|
|
255
|
+
|
|
256
|
+
"wood-light": {
|
|
257
|
+
name: "Wood (Light)",
|
|
258
|
+
color: [0.89, 0.8, 0.68, 1],
|
|
259
|
+
metalness: 0.0,
|
|
260
|
+
roughness: 0.6,
|
|
261
|
+
},
|
|
262
|
+
|
|
263
|
+
"wood-dark": {
|
|
264
|
+
name: "Wood (Dark)",
|
|
265
|
+
color: [0.63, 0.51, 0.38, 1],
|
|
266
|
+
metalness: 0.0,
|
|
267
|
+
roughness: 0.55,
|
|
268
|
+
},
|
|
269
|
+
|
|
270
|
+
"ceramic-white": {
|
|
271
|
+
name: "Ceramic (White)",
|
|
272
|
+
color: [0.98, 0.98, 0.97, 1],
|
|
273
|
+
metalness: 0.0,
|
|
274
|
+
roughness: 0.1,
|
|
275
|
+
},
|
|
276
|
+
|
|
277
|
+
"carbon-fiber": {
|
|
278
|
+
name: "Carbon Fiber",
|
|
279
|
+
color: [0.25, 0.25, 0.25, 1],
|
|
280
|
+
metalness: 0.3,
|
|
281
|
+
roughness: 0.35,
|
|
282
|
+
anisotropy: 0.3,
|
|
283
|
+
},
|
|
284
|
+
|
|
285
|
+
"concrete": {
|
|
286
|
+
name: "Concrete",
|
|
287
|
+
color: [0.83, 0.82, 0.8, 1],
|
|
288
|
+
metalness: 0.0,
|
|
289
|
+
roughness: 0.85,
|
|
290
|
+
},
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
// =============================================================================
|
|
294
|
+
// Sorted Name List
|
|
295
|
+
// =============================================================================
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Sorted list of all built-in material preset names.
|
|
299
|
+
*
|
|
300
|
+
* Useful for UI dropdowns, validation, and programmatic enumeration.
|
|
301
|
+
* Derived from MATERIAL_PRESETS keys at module load time.
|
|
302
|
+
*/
|
|
303
|
+
export const MATERIAL_PRESET_NAMES: string[] = Object.keys(MATERIAL_PRESETS).sort();
|
package/src/rendering/raycast.ts
CHANGED
|
@@ -181,7 +181,7 @@ class Raycaster {
|
|
|
181
181
|
const object = obj.object;
|
|
182
182
|
// Accept Mesh (faces), Points (vertices), and Line (edges)
|
|
183
183
|
const isValidType = isMesh(object) || isPoints(object) || isLine(object);
|
|
184
|
-
if (isValidType && !Array.isArray(object.material) && object.material.visible) {
|
|
184
|
+
if (isValidType && object.visible && !Array.isArray(object.material) && object.material.visible) {
|
|
185
185
|
validObjs.push(obj);
|
|
186
186
|
}
|
|
187
187
|
}
|
|
@@ -202,7 +202,7 @@ class Raycaster {
|
|
|
202
202
|
// Accept Mesh (faces), Points (vertices), and Line (edges)
|
|
203
203
|
const isValidType = isMesh(obj) || isPoints(obj) || isLine(obj);
|
|
204
204
|
if (!isValidType) continue;
|
|
205
|
-
if (Array.isArray(obj.material) || !obj.material.visible) continue;
|
|
205
|
+
if (!obj.visible || Array.isArray(obj.material) || !obj.material.visible) continue;
|
|
206
206
|
|
|
207
207
|
const objectGroup = object.object.parent;
|
|
208
208
|
if (!isObjectGroup(objectGroup)) continue;
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clean room environment for Studio mode PMREM generation.
|
|
3
|
+
*
|
|
4
|
+
* Based on Three.js RoomEnvironment (which is based on Google model-viewer's
|
|
5
|
+
* EnvironmentScene), but with the 6 decorative boxes removed and an infinity
|
|
6
|
+
* cove (quarter-cylinder) at all wall-floor junctions for a clean cyclorama.
|
|
7
|
+
*/
|
|
8
|
+
import {
|
|
9
|
+
BackSide,
|
|
10
|
+
BoxGeometry,
|
|
11
|
+
BufferGeometry,
|
|
12
|
+
Float32BufferAttribute,
|
|
13
|
+
Mesh,
|
|
14
|
+
MeshLambertMaterial,
|
|
15
|
+
MeshStandardMaterial,
|
|
16
|
+
PointLight,
|
|
17
|
+
Scene,
|
|
18
|
+
} from "three";
|
|
19
|
+
|
|
20
|
+
class CleanRoomEnvironment extends Scene {
|
|
21
|
+
constructor() {
|
|
22
|
+
super();
|
|
23
|
+
|
|
24
|
+
this.name = "CleanRoomEnvironment";
|
|
25
|
+
this.position.y = -3.5;
|
|
26
|
+
// Pre-rotate 45° so the cleanest wall/floor edge faces the default camera
|
|
27
|
+
this.rotation.y = (45 * Math.PI) / 180;
|
|
28
|
+
|
|
29
|
+
const geometry = new BoxGeometry();
|
|
30
|
+
geometry.deleteAttribute("uv");
|
|
31
|
+
|
|
32
|
+
const roomMaterial = new MeshStandardMaterial({ side: BackSide });
|
|
33
|
+
|
|
34
|
+
const mainLight = new PointLight(0xffffff, 900, 28, 2);
|
|
35
|
+
mainLight.position.set(0.418, 16.199, 0.3);
|
|
36
|
+
this.add(mainLight);
|
|
37
|
+
|
|
38
|
+
const room = new Mesh(geometry, roomMaterial);
|
|
39
|
+
room.position.set(-0.757, 13.219, 0.717);
|
|
40
|
+
room.scale.set(31.713, 28.305, 28.591);
|
|
41
|
+
this.add(room);
|
|
42
|
+
|
|
43
|
+
// Infinity cove (quarter-cylinder sweep) at all 4 wall-floor junctions.
|
|
44
|
+
// Eliminates the sharp 90° corner visible in reflections.
|
|
45
|
+
//
|
|
46
|
+
// Room bounds (inner faces of BackSide box):
|
|
47
|
+
const cx = -0.757, cy = 13.219, cz = 0.717;
|
|
48
|
+
const hx = 31.713 / 2, hy = 28.305 / 2, hz = 28.591 / 2;
|
|
49
|
+
const floorY = cy - hy; // ≈ -0.93
|
|
50
|
+
const wallMinX = cx - hx; // ≈ -16.61
|
|
51
|
+
const wallMinZ = cz - hz; // ≈ -13.58
|
|
52
|
+
const R = 6;
|
|
53
|
+
|
|
54
|
+
// Single infinity cove on the -z wall (faces default camera after 45° rotation).
|
|
55
|
+
const cove = new Mesh(createCove(hx * 2, R, 12, "-z"), roomMaterial);
|
|
56
|
+
cove.position.set(wallMinX, floorY, wallMinZ + R);
|
|
57
|
+
this.add(cove);
|
|
58
|
+
|
|
59
|
+
// Area lights on walls and ceiling
|
|
60
|
+
|
|
61
|
+
// -x right
|
|
62
|
+
const light1 = new Mesh(geometry, createAreaLightMaterial(50));
|
|
63
|
+
light1.position.set(-16.116, 14.37, 8.208);
|
|
64
|
+
light1.scale.set(0.1, 2.428, 2.739);
|
|
65
|
+
this.add(light1);
|
|
66
|
+
|
|
67
|
+
// -x left
|
|
68
|
+
const light2 = new Mesh(geometry, createAreaLightMaterial(50));
|
|
69
|
+
light2.position.set(-16.109, 18.021, -8.207);
|
|
70
|
+
light2.scale.set(0.1, 2.425, 2.751);
|
|
71
|
+
this.add(light2);
|
|
72
|
+
|
|
73
|
+
// +x
|
|
74
|
+
const light3 = new Mesh(geometry, createAreaLightMaterial(17));
|
|
75
|
+
light3.position.set(14.904, 12.198, -1.832);
|
|
76
|
+
light3.scale.set(0.15, 4.265, 6.331);
|
|
77
|
+
this.add(light3);
|
|
78
|
+
|
|
79
|
+
// +z
|
|
80
|
+
const light4 = new Mesh(geometry, createAreaLightMaterial(43));
|
|
81
|
+
light4.position.set(-0.462, 8.89, 14.52);
|
|
82
|
+
light4.scale.set(4.38, 5.441, 0.088);
|
|
83
|
+
this.add(light4);
|
|
84
|
+
|
|
85
|
+
// -z
|
|
86
|
+
const light5 = new Mesh(geometry, createAreaLightMaterial(20));
|
|
87
|
+
light5.position.set(3.235, 11.486, -12.541);
|
|
88
|
+
light5.scale.set(2.5, 2.0, 0.1);
|
|
89
|
+
this.add(light5);
|
|
90
|
+
|
|
91
|
+
// +y (ceiling)
|
|
92
|
+
const light6 = new Mesh(geometry, createAreaLightMaterial(100));
|
|
93
|
+
light6.position.set(0.0, 20.0, 0.0);
|
|
94
|
+
light6.scale.set(1.0, 0.1, 1.0);
|
|
95
|
+
this.add(light6);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
dispose(): void {
|
|
99
|
+
const resources = new Set<{ dispose(): void }>();
|
|
100
|
+
this.traverse((object) => {
|
|
101
|
+
if ("isMesh" in object && object.isMesh) {
|
|
102
|
+
const mesh = object as Mesh;
|
|
103
|
+
resources.add(mesh.geometry);
|
|
104
|
+
if (!Array.isArray(mesh.material)) {
|
|
105
|
+
resources.add(mesh.material);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
for (const resource of resources) {
|
|
110
|
+
resource.dispose();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Quarter-cylinder for infinity cove — no rotation needed.
|
|
117
|
+
*
|
|
118
|
+
* @param length Extrusion length along the wall edge
|
|
119
|
+
* @param radius Cove radius
|
|
120
|
+
* @param segments Arc subdivisions
|
|
121
|
+
* @param wall Which wall: "-x"|"+x"|"-z"|"+z"
|
|
122
|
+
*
|
|
123
|
+
* The arc sweeps from floor-tangent (horizontal) to wall-tangent (vertical).
|
|
124
|
+
* Winding is set so BackSide material renders the concave interior.
|
|
125
|
+
*/
|
|
126
|
+
function createCove(
|
|
127
|
+
length: number, radius: number, segments: number,
|
|
128
|
+
wall: "-x" | "+x" | "-z" | "+z",
|
|
129
|
+
): BufferGeometry {
|
|
130
|
+
const positions: number[] = [];
|
|
131
|
+
const normals: number[] = [];
|
|
132
|
+
const indices: number[] = [];
|
|
133
|
+
|
|
134
|
+
// sign: which direction the arc curves toward the wall
|
|
135
|
+
// axis: 0 = arc in XY extruded along Z, 1 = arc in ZY extruded along X
|
|
136
|
+
const axis = wall === "-x" || wall === "+x" ? 0 : 1;
|
|
137
|
+
const sign = wall === "-x" || wall === "-z" ? -1 : 1;
|
|
138
|
+
|
|
139
|
+
for (let i = 0; i <= segments; i++) {
|
|
140
|
+
const angle = (i / segments) * Math.PI / 2;
|
|
141
|
+
const h = sign * radius * Math.sin(angle); // horizontal offset toward wall
|
|
142
|
+
const y = radius * (1 - Math.cos(angle)); // vertical offset above floor
|
|
143
|
+
const nh = sign * Math.sin(angle); // normal toward wall
|
|
144
|
+
const ny = -Math.cos(angle); // normal downward
|
|
145
|
+
|
|
146
|
+
if (axis === 0) {
|
|
147
|
+
// Arc in XY, extruded along Z (for ±x walls)
|
|
148
|
+
positions.push(h, y, 0);
|
|
149
|
+
normals.push(nh, ny, 0);
|
|
150
|
+
positions.push(h, y, length);
|
|
151
|
+
normals.push(nh, ny, 0);
|
|
152
|
+
} else {
|
|
153
|
+
// Arc in ZY, extruded along X (for ±z walls)
|
|
154
|
+
positions.push(0, y, h);
|
|
155
|
+
normals.push(0, ny, nh);
|
|
156
|
+
positions.push(length, y, h);
|
|
157
|
+
normals.push(0, ny, nh);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
for (let i = 0; i < segments; i++) {
|
|
162
|
+
const a = i * 2;
|
|
163
|
+
const b = a + 1;
|
|
164
|
+
const c = a + 2;
|
|
165
|
+
const d = a + 3;
|
|
166
|
+
// Winding: front face must point toward corner for BackSide to show
|
|
167
|
+
// concave interior. Extruding along X (axis=1) flips the cross product
|
|
168
|
+
// vs extruding along Z (axis=0), so we XOR the conditions.
|
|
169
|
+
const flip = (sign > 0) !== (axis === 1);
|
|
170
|
+
if (flip) {
|
|
171
|
+
indices.push(a, c, b, b, c, d);
|
|
172
|
+
} else {
|
|
173
|
+
indices.push(a, b, c, b, d, c);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const geom = new BufferGeometry();
|
|
178
|
+
geom.setAttribute("position", new Float32BufferAttribute(positions, 3));
|
|
179
|
+
geom.setAttribute("normal", new Float32BufferAttribute(normals, 3));
|
|
180
|
+
geom.setIndex(indices);
|
|
181
|
+
return geom;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function createAreaLightMaterial(intensity: number): MeshLambertMaterial {
|
|
185
|
+
return new MeshLambertMaterial({
|
|
186
|
+
color: 0x000000,
|
|
187
|
+
emissive: 0xffffff,
|
|
188
|
+
emissiveIntensity: intensity,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export { CleanRoomEnvironment };
|