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
package/src/scene/objectgroup.ts
CHANGED
|
@@ -99,10 +99,20 @@ class ObjectGroup extends THREE.Group {
|
|
|
99
99
|
vertexFocusSize: number;
|
|
100
100
|
edgeFocusWidth: number;
|
|
101
101
|
shapeGeometry?: THREE.BufferGeometry | null;
|
|
102
|
+
/** Material tag from shapes data, used for Studio mode material lookup */
|
|
103
|
+
materialTag: string;
|
|
102
104
|
minZ?: number;
|
|
103
105
|
height?: number;
|
|
104
106
|
private _zebra: ZebraTool | null;
|
|
105
107
|
|
|
108
|
+
// Studio mode state
|
|
109
|
+
private _cadFrontMaterial: ColoredMaterial | null;
|
|
110
|
+
private _cadBackMaterial: ColoredMaterial | null;
|
|
111
|
+
private _cadOriginalColor: THREE.Color | null;
|
|
112
|
+
private _cadOriginalBackColor: THREE.Color | null;
|
|
113
|
+
private _isStudioMode: boolean;
|
|
114
|
+
private _cadEdgesVisible: boolean | null;
|
|
115
|
+
|
|
106
116
|
/**
|
|
107
117
|
* Create an ObjectGroup for managing a CAD object's visual representation.
|
|
108
118
|
* @param opacity - Default opacity value (0.0 to 1.0).
|
|
@@ -145,6 +155,15 @@ class ObjectGroup extends THREE.Group {
|
|
|
145
155
|
this.edgeFocusWidth = 5; // Size of the edges when highlighted
|
|
146
156
|
|
|
147
157
|
this._zebra = null; // Lazy-initialized zebra tool
|
|
158
|
+
this.materialTag = "";
|
|
159
|
+
|
|
160
|
+
// Studio mode state
|
|
161
|
+
this._cadFrontMaterial = null;
|
|
162
|
+
this._cadBackMaterial = null;
|
|
163
|
+
this._cadOriginalColor = null;
|
|
164
|
+
this._cadOriginalBackColor = null;
|
|
165
|
+
this._isStudioMode = false;
|
|
166
|
+
this._cadEdgesVisible = null;
|
|
148
167
|
}
|
|
149
168
|
|
|
150
169
|
/**
|
|
@@ -157,6 +176,13 @@ class ObjectGroup extends THREE.Group {
|
|
|
157
176
|
return this._zebra;
|
|
158
177
|
}
|
|
159
178
|
|
|
179
|
+
/**
|
|
180
|
+
* Whether this ObjectGroup is currently in Studio mode.
|
|
181
|
+
*/
|
|
182
|
+
get isStudioMode(): boolean {
|
|
183
|
+
return this._isStudioMode;
|
|
184
|
+
}
|
|
185
|
+
|
|
160
186
|
/**
|
|
161
187
|
* Dispose of all resources and clean up memory.
|
|
162
188
|
* Releases geometry, materials, children, and zebra tool.
|
|
@@ -175,6 +201,13 @@ class ObjectGroup extends THREE.Group {
|
|
|
175
201
|
this._zebra.dispose();
|
|
176
202
|
this._zebra = null;
|
|
177
203
|
}
|
|
204
|
+
// Release studio material references (do NOT dispose -- NestedGroup owns them)
|
|
205
|
+
this._cadFrontMaterial = null;
|
|
206
|
+
this._cadBackMaterial = null;
|
|
207
|
+
this._cadOriginalColor = null;
|
|
208
|
+
this._cadOriginalBackColor = null;
|
|
209
|
+
this._isStudioMode = false;
|
|
210
|
+
this._cadEdgesVisible = null;
|
|
178
211
|
}
|
|
179
212
|
|
|
180
213
|
/**
|
|
@@ -427,7 +460,11 @@ class ObjectGroup extends THREE.Group {
|
|
|
427
460
|
setBlackEdges(flag: boolean): void {
|
|
428
461
|
if (this.edgeMaterial && !this.edgeMaterial.vertexColors) {
|
|
429
462
|
const color = flag ? 0x000000 : this.edge_color;
|
|
430
|
-
|
|
463
|
+
// Only update originalColor for edge-only objects (no face mesh).
|
|
464
|
+
// For face+edge objects, originalColor tracks the face color.
|
|
465
|
+
if (!this.front) {
|
|
466
|
+
this.originalColor = new THREE.Color(color);
|
|
467
|
+
}
|
|
431
468
|
this.edgeMaterial.color = new THREE.Color(color);
|
|
432
469
|
this.edgeMaterial.needsUpdate = true;
|
|
433
470
|
}
|
|
@@ -469,7 +506,12 @@ class ObjectGroup extends THREE.Group {
|
|
|
469
506
|
*/
|
|
470
507
|
setShapeVisible(flag: boolean): void {
|
|
471
508
|
if (this.front) {
|
|
472
|
-
this.
|
|
509
|
+
if (this._isStudioMode) {
|
|
510
|
+
// Studio materials are shared — use mesh.visible for per-object visibility
|
|
511
|
+
this.front.visible = flag;
|
|
512
|
+
} else {
|
|
513
|
+
this.front.material.visible = flag;
|
|
514
|
+
}
|
|
473
515
|
}
|
|
474
516
|
for (const clippingGroup of this.clipping.values()) {
|
|
475
517
|
const child0 = clippingGroup.children[0];
|
|
@@ -488,7 +530,11 @@ class ObjectGroup extends THREE.Group {
|
|
|
488
530
|
}
|
|
489
531
|
}
|
|
490
532
|
if (this.back && this.renderback) {
|
|
491
|
-
this.
|
|
533
|
+
if (this._isStudioMode) {
|
|
534
|
+
this.back.visible = flag;
|
|
535
|
+
} else {
|
|
536
|
+
this.back.material.visible = flag;
|
|
537
|
+
}
|
|
492
538
|
}
|
|
493
539
|
}
|
|
494
540
|
|
|
@@ -508,12 +554,17 @@ class ObjectGroup extends THREE.Group {
|
|
|
508
554
|
* Set visibility of back faces.
|
|
509
555
|
*/
|
|
510
556
|
setBackVisible(flag: boolean): void {
|
|
511
|
-
if (
|
|
512
|
-
this.
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
557
|
+
if (this.back && this.front) {
|
|
558
|
+
const frontVisible = this._isStudioMode
|
|
559
|
+
? this.front.visible
|
|
560
|
+
: this.front.material.visible;
|
|
561
|
+
if (frontVisible) {
|
|
562
|
+
if (this._isStudioMode) {
|
|
563
|
+
this.back.visible = this.renderback || flag;
|
|
564
|
+
} else {
|
|
565
|
+
this.back.material.visible = this.renderback || flag;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
517
568
|
}
|
|
518
569
|
}
|
|
519
570
|
|
|
@@ -522,10 +573,13 @@ class ObjectGroup extends THREE.Group {
|
|
|
522
573
|
*/
|
|
523
574
|
getVisibility(): boolean {
|
|
524
575
|
if (this.front) {
|
|
576
|
+
const frontVisible = this._isStudioMode
|
|
577
|
+
? this.front.visible
|
|
578
|
+
: this.front.material.visible;
|
|
525
579
|
if (this.edgeMaterial) {
|
|
526
|
-
return
|
|
580
|
+
return frontVisible || this.edgeMaterial.visible;
|
|
527
581
|
} else {
|
|
528
|
-
return
|
|
582
|
+
return frontVisible;
|
|
529
583
|
}
|
|
530
584
|
} else if (this.edgeMaterial) {
|
|
531
585
|
return this.edgeMaterial.visible;
|
|
@@ -677,6 +731,127 @@ class ObjectGroup extends THREE.Group {
|
|
|
677
731
|
setZebraMappingMode(value: ZebraMappingMode): void {
|
|
678
732
|
this.zebra.setMappingMode(value);
|
|
679
733
|
}
|
|
734
|
+
|
|
735
|
+
// ===========================================================================
|
|
736
|
+
// Studio Mode
|
|
737
|
+
// ===========================================================================
|
|
738
|
+
|
|
739
|
+
/**
|
|
740
|
+
* Enter Studio mode: swap CAD materials for pre-built Studio materials.
|
|
741
|
+
*
|
|
742
|
+
* The caller (NestedGroup) is responsible for resolving material tags and
|
|
743
|
+
* building MeshPhysicalMaterial instances via MaterialFactory. ObjectGroup
|
|
744
|
+
* just receives the finished materials and performs the swap.
|
|
745
|
+
*
|
|
746
|
+
* On first call, saves the current CAD material references so they can be
|
|
747
|
+
* restored by `leaveStudioMode()`. Copies the `material.visible` flag from
|
|
748
|
+
* CAD to Studio material to preserve tree-view hide/show state. Updates
|
|
749
|
+
* `originalColor` / `originalBackColor` so highlight/unhighlight works
|
|
750
|
+
* correctly in Studio mode.
|
|
751
|
+
*
|
|
752
|
+
* @param studioFront - Studio material for front face, or null if this object has no front mesh
|
|
753
|
+
* @param studioBack - Studio material for back face, or null if back face should not be swapped
|
|
754
|
+
*/
|
|
755
|
+
enterStudioMode(
|
|
756
|
+
studioFront: THREE.MeshPhysicalMaterial | null,
|
|
757
|
+
studioBack: THREE.MeshPhysicalMaterial | null,
|
|
758
|
+
): void {
|
|
759
|
+
if (this._isStudioMode) return;
|
|
760
|
+
|
|
761
|
+
// --- Save CAD state ---
|
|
762
|
+
if (this.front) {
|
|
763
|
+
this._cadFrontMaterial = this.front.material;
|
|
764
|
+
}
|
|
765
|
+
if (this.back) {
|
|
766
|
+
this._cadBackMaterial = this.back.material;
|
|
767
|
+
}
|
|
768
|
+
// Save original colors used by highlight/unhighlight
|
|
769
|
+
this._cadOriginalColor = this.originalColor ? this.originalColor.clone() : null;
|
|
770
|
+
this._cadOriginalBackColor = this.originalBackColor ? this.originalBackColor.clone() : null;
|
|
771
|
+
|
|
772
|
+
// Save edge visibility state
|
|
773
|
+
this._cadEdgesVisible = this.edgeMaterial ? this.edgeMaterial.visible : null;
|
|
774
|
+
|
|
775
|
+
// --- Swap front material ---
|
|
776
|
+
if (this.front && studioFront) {
|
|
777
|
+
// Transfer per-object visibility to mesh.visible (NOT material.visible)
|
|
778
|
+
// because studio materials are shared across objects via cache.
|
|
779
|
+
// Writing to a shared material's .visible would affect all users.
|
|
780
|
+
this.front.visible = this.front.material.visible;
|
|
781
|
+
this.front.material = studioFront;
|
|
782
|
+
// Update originalColor to studio material's color for correct highlight
|
|
783
|
+
this.originalColor = studioFront.color;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
// --- Swap back material ---
|
|
787
|
+
if (this.back && studioBack && this.renderback) {
|
|
788
|
+
// Same: per-object visibility via mesh.visible, not shared material
|
|
789
|
+
this.back.visible = this.back.material.visible;
|
|
790
|
+
this.back.material = studioBack;
|
|
791
|
+
// Update originalBackColor for correct highlight on back face
|
|
792
|
+
this.originalBackColor = studioBack.color;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
this._isStudioMode = true;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
/**
|
|
799
|
+
* Leave Studio mode: restore CAD materials.
|
|
800
|
+
*
|
|
801
|
+
* Copies `material.visible` from Studio back to CAD material to preserve
|
|
802
|
+
* any visibility changes made while in Studio mode (e.g., tree-view toggle).
|
|
803
|
+
* Restores `originalColor` / `originalBackColor` to CAD material colors.
|
|
804
|
+
* Restores edge visibility to the state saved when entering Studio mode.
|
|
805
|
+
*/
|
|
806
|
+
leaveStudioMode(): void {
|
|
807
|
+
if (!this._isStudioMode) return;
|
|
808
|
+
|
|
809
|
+
// --- Restore front material ---
|
|
810
|
+
if (this.front && this._cadFrontMaterial) {
|
|
811
|
+
// Copy visibility from mesh.visible back to CAD material
|
|
812
|
+
// (studio mode uses mesh.visible for per-object visibility)
|
|
813
|
+
this._cadFrontMaterial.visible = this.front.visible;
|
|
814
|
+
this.front.material = this._cadFrontMaterial;
|
|
815
|
+
this.front.visible = true; // Reset mesh visibility
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
// --- Restore back material ---
|
|
819
|
+
if (this.back && this._cadBackMaterial && this.renderback) {
|
|
820
|
+
// Copy visibility from mesh.visible back to CAD material
|
|
821
|
+
this._cadBackMaterial.visible = this.back.visible;
|
|
822
|
+
this.back.material = this._cadBackMaterial;
|
|
823
|
+
this.back.visible = true; // Reset mesh visibility
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
// --- Restore original colors for highlight ---
|
|
827
|
+
if (this._cadOriginalColor) {
|
|
828
|
+
this.originalColor = this._cadOriginalColor.clone();
|
|
829
|
+
}
|
|
830
|
+
if (this._cadOriginalBackColor) {
|
|
831
|
+
this.originalBackColor = this._cadOriginalBackColor.clone();
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
// --- Restore edge visibility ---
|
|
835
|
+
if (this.edgeMaterial && this._cadEdgesVisible !== null) {
|
|
836
|
+
this.edgeMaterial.visible = this._cadEdgesVisible;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
this._isStudioMode = false;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
/**
|
|
843
|
+
* Toggle edge visibility while in Studio mode.
|
|
844
|
+
*
|
|
845
|
+
* Only affects edges (not vertices). Should only be called while in
|
|
846
|
+
* Studio mode; the saved CAD edge visibility is not affected.
|
|
847
|
+
*
|
|
848
|
+
* @param visible - Whether edges should be visible
|
|
849
|
+
*/
|
|
850
|
+
setStudioShowEdges(visible: boolean): void {
|
|
851
|
+
if (this.edgeMaterial) {
|
|
852
|
+
this.edgeMaterial.visible = visible;
|
|
853
|
+
}
|
|
854
|
+
}
|
|
680
855
|
}
|
|
681
856
|
|
|
682
857
|
/**
|
package/src/scene/orientation.ts
CHANGED
|
@@ -191,8 +191,20 @@ class OrientationMarker {
|
|
|
191
191
|
*/
|
|
192
192
|
render(renderer: THREE.WebGLRenderer): void {
|
|
193
193
|
if (this.ready && this.scene && this.camera) {
|
|
194
|
+
// Rendering the corner marker mutates renderer state (viewport/scissor/scissor test).
|
|
195
|
+
// Preserve and restore those values so downstream renders are not clipped or offset.
|
|
196
|
+
const prevViewport = renderer.getViewport(new THREE.Vector4());
|
|
197
|
+
const prevScissor = renderer.getScissor(new THREE.Vector4());
|
|
198
|
+
const prevScissorTest = renderer.getScissorTest();
|
|
199
|
+
|
|
200
|
+
// Draw marker in its small corner viewport.
|
|
194
201
|
renderer.setViewport(0, 0, this.width, this.height);
|
|
195
202
|
renderer.render(this.scene, this.camera);
|
|
203
|
+
|
|
204
|
+
// Restore previous state for the main scene / shared render pipeline.
|
|
205
|
+
renderer.setViewport(prevViewport);
|
|
206
|
+
renderer.setScissor(prevScissor);
|
|
207
|
+
renderer.setScissorTest(prevScissorTest);
|
|
196
208
|
}
|
|
197
209
|
}
|
|
198
210
|
|
|
@@ -167,6 +167,7 @@ class ShapeRenderer {
|
|
|
167
167
|
}
|
|
168
168
|
const vertices = shape.vertices;
|
|
169
169
|
const normals = shape.normals;
|
|
170
|
+
const uvs = shape.uvs instanceof Float32Array ? shape.uvs : null;
|
|
170
171
|
// Determine format and validate
|
|
171
172
|
let current = 0;
|
|
172
173
|
if (hasTrianglesPerFace(shape)) {
|
|
@@ -186,6 +187,7 @@ class ShapeRenderer {
|
|
|
186
187
|
|
|
187
188
|
const vecs = new Float32Array(triangles.length * 3);
|
|
188
189
|
const norms = new Float32Array(triangles.length * 3);
|
|
190
|
+
const uvArr = uvs ? new Float32Array(triangles.length * 2) : null;
|
|
189
191
|
for (let i = 0; i < triangles.length; i++) {
|
|
190
192
|
const s = triangles[i];
|
|
191
193
|
vecs[3 * i] = vertices[3 * s];
|
|
@@ -194,6 +196,22 @@ class ShapeRenderer {
|
|
|
194
196
|
norms[3 * i] = normals[3 * s];
|
|
195
197
|
norms[3 * i + 1] = normals[3 * s + 1];
|
|
196
198
|
norms[3 * i + 2] = normals[3 * s + 2];
|
|
199
|
+
if (uvs && uvArr) {
|
|
200
|
+
uvArr[2 * i] = uvs[2 * s];
|
|
201
|
+
uvArr[2 * i + 1] = uvs[2 * s + 1];
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
const newShapeObj: Shape = {
|
|
205
|
+
triangles: [...Array(triangles.length).keys()],
|
|
206
|
+
vertices: Array.from(vecs),
|
|
207
|
+
normals: Array.from(norms),
|
|
208
|
+
edges: [],
|
|
209
|
+
obj_vertices: [],
|
|
210
|
+
edge_types: [],
|
|
211
|
+
face_types: [shape.face_types[j]],
|
|
212
|
+
};
|
|
213
|
+
if (uvArr) {
|
|
214
|
+
newShapeObj.uvs = Array.from(uvArr);
|
|
197
215
|
}
|
|
198
216
|
const new_shape: Shapes = {
|
|
199
217
|
version: 2,
|
|
@@ -206,23 +224,18 @@ class ShapeRenderer {
|
|
|
206
224
|
type: "shapes",
|
|
207
225
|
color: part.color,
|
|
208
226
|
alpha: part.alpha,
|
|
209
|
-
renderback:
|
|
227
|
+
renderback: part.subtype !== "solid",
|
|
210
228
|
state: [1, 3],
|
|
211
229
|
accuracy: part.accuracy,
|
|
212
230
|
bb: null,
|
|
213
|
-
shape:
|
|
214
|
-
triangles: [...Array(triangles.length).keys()],
|
|
215
|
-
vertices: Array.from(vecs),
|
|
216
|
-
normals: Array.from(norms),
|
|
217
|
-
edges: [],
|
|
218
|
-
obj_vertices: [],
|
|
219
|
-
edge_types: [],
|
|
220
|
-
face_types: [shape.face_types[j]],
|
|
221
|
-
},
|
|
231
|
+
shape: newShapeObj,
|
|
222
232
|
};
|
|
223
233
|
if (part.texture) {
|
|
224
234
|
new_shape.texture = part.texture;
|
|
225
235
|
}
|
|
236
|
+
if (part.material) {
|
|
237
|
+
new_shape.material = part.material;
|
|
238
|
+
}
|
|
226
239
|
new_shape.geomtype = shape.face_types[j];
|
|
227
240
|
new_shape.subtype = part.subtype;
|
|
228
241
|
new_shape.exploded = true;
|
|
@@ -241,6 +254,7 @@ class ShapeRenderer {
|
|
|
241
254
|
|
|
242
255
|
const vecs = new Float32Array(triangles.length * 3);
|
|
243
256
|
const norms = new Float32Array(triangles.length * 3);
|
|
257
|
+
const uvArr = uvs ? new Float32Array(triangles.length * 2) : null;
|
|
244
258
|
for (let i = 0; i < triangles.length; i++) {
|
|
245
259
|
const s = triangles[i];
|
|
246
260
|
vecs[3 * i] = vertices[3 * s];
|
|
@@ -249,6 +263,22 @@ class ShapeRenderer {
|
|
|
249
263
|
norms[3 * i] = normals[3 * s];
|
|
250
264
|
norms[3 * i + 1] = normals[3 * s + 1];
|
|
251
265
|
norms[3 * i + 2] = normals[3 * s + 2];
|
|
266
|
+
if (uvs && uvArr) {
|
|
267
|
+
uvArr[2 * i] = uvs[2 * s];
|
|
268
|
+
uvArr[2 * i + 1] = uvs[2 * s + 1];
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
const newShapeObj2: Shape = {
|
|
272
|
+
triangles: [...Array(triangles.length).keys()],
|
|
273
|
+
vertices: Array.from(vecs),
|
|
274
|
+
normals: Array.from(norms),
|
|
275
|
+
edges: [],
|
|
276
|
+
obj_vertices: [],
|
|
277
|
+
edge_types: [],
|
|
278
|
+
face_types: [shape.face_types[j]],
|
|
279
|
+
};
|
|
280
|
+
if (uvArr) {
|
|
281
|
+
newShapeObj2.uvs = Array.from(uvArr);
|
|
252
282
|
}
|
|
253
283
|
const new_shape: Shapes = {
|
|
254
284
|
version: 2,
|
|
@@ -261,23 +291,18 @@ class ShapeRenderer {
|
|
|
261
291
|
type: "shapes",
|
|
262
292
|
color: part.color,
|
|
263
293
|
alpha: part.alpha,
|
|
264
|
-
renderback:
|
|
294
|
+
renderback: part.subtype !== "solid",
|
|
265
295
|
state: [1, 3],
|
|
266
296
|
accuracy: part.accuracy,
|
|
267
297
|
bb: null,
|
|
268
|
-
shape:
|
|
269
|
-
triangles: [...Array(triangles.length).keys()],
|
|
270
|
-
vertices: Array.from(vecs),
|
|
271
|
-
normals: Array.from(norms),
|
|
272
|
-
edges: [],
|
|
273
|
-
obj_vertices: [],
|
|
274
|
-
edge_types: [],
|
|
275
|
-
face_types: [shape.face_types[j]],
|
|
276
|
-
},
|
|
298
|
+
shape: newShapeObj2,
|
|
277
299
|
};
|
|
278
300
|
if (part.texture) {
|
|
279
301
|
new_shape.texture = part.texture;
|
|
280
302
|
}
|
|
303
|
+
if (part.material) {
|
|
304
|
+
new_shape.material = part.material;
|
|
305
|
+
}
|
|
281
306
|
new_shape.geomtype = shape.face_types[j];
|
|
282
307
|
new_shape.subtype = part.subtype;
|
|
283
308
|
new_shape.exploded = true;
|
|
@@ -468,6 +493,7 @@ class ShapeRenderer {
|
|
|
468
493
|
edge_types: number[] | Uint8Array | Uint32Array;
|
|
469
494
|
triangles_per_face?: number[] | Uint32Array;
|
|
470
495
|
segments_per_edge?: number[] | Uint32Array;
|
|
496
|
+
uvs?: number[] | Float32Array;
|
|
471
497
|
}
|
|
472
498
|
|
|
473
499
|
// Shape interface matches MutableShape - we cast to allow reassignment
|
|
@@ -490,9 +516,12 @@ class ShapeRenderer {
|
|
|
490
516
|
// Only flatten if it's actually nested (no segments_per_edge means nested format)
|
|
491
517
|
if (s.edges != null && !(s.edges instanceof Float32Array)) {
|
|
492
518
|
if (s.segments_per_edge !== undefined) {
|
|
493
|
-
// Binary format with flat edges - convert directly
|
|
494
519
|
if (!Array.isArray(s.edges[0])) {
|
|
520
|
+
// Flat number[] — convert directly
|
|
495
521
|
s.edges = new Float32Array(s.edges as number[]);
|
|
522
|
+
} else {
|
|
523
|
+
// Nested number[][] with segments_per_edge — flatten then convert
|
|
524
|
+
s.edges = new Float32Array(flatten(s.edges as number[][], 1));
|
|
496
525
|
}
|
|
497
526
|
}
|
|
498
527
|
// If no segments_per_edge, leave as number[][] for _decompose
|
|
@@ -522,6 +551,11 @@ class ShapeRenderer {
|
|
|
522
551
|
s.obj_vertices = new Float32Array(s.obj_vertices as number[]);
|
|
523
552
|
}
|
|
524
553
|
|
|
554
|
+
// uvs: flat number[] -> Float32Array (2 floats per vertex)
|
|
555
|
+
if (s.uvs != null && !(s.uvs instanceof Float32Array)) {
|
|
556
|
+
s.uvs = new Float32Array(s.uvs as number[]);
|
|
557
|
+
}
|
|
558
|
+
|
|
525
559
|
// face_types: number[] -> Uint32Array
|
|
526
560
|
if (s.face_types != null && !(s.face_types instanceof Uint32Array)) {
|
|
527
561
|
s.face_types = new Uint32Array(s.face_types);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal type declarations for n8ao.
|
|
3
|
+
*
|
|
4
|
+
* n8ao does not ship TypeScript types. This provides just enough
|
|
5
|
+
* typing to suppress TS7016 during builds while keeping the actual
|
|
6
|
+
* N8AOPostPass usage typed as `any` (the API is untyped upstream).
|
|
7
|
+
*/
|
|
8
|
+
declare module "n8ao" {
|
|
9
|
+
import type { Scene, Camera } from "three";
|
|
10
|
+
|
|
11
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
12
|
+
export class N8AOPostPass {
|
|
13
|
+
enabled: boolean;
|
|
14
|
+
camera: Camera;
|
|
15
|
+
configuration: {
|
|
16
|
+
aoRadius: number;
|
|
17
|
+
distanceFalloff: number;
|
|
18
|
+
intensity: number;
|
|
19
|
+
halfRes: boolean;
|
|
20
|
+
depthAwareUpsampling: boolean;
|
|
21
|
+
gammaCorrection: boolean;
|
|
22
|
+
[key: string]: unknown;
|
|
23
|
+
};
|
|
24
|
+
constructor(scene: Scene, camera: Camera, width: number, height: number);
|
|
25
|
+
setQualityMode(mode: "Low" | "Medium" | "High" | "Ultra"): void;
|
|
26
|
+
setSize(width: number, height: number): void;
|
|
27
|
+
}
|
|
28
|
+
}
|