@needle-tools/gltf-progressive 3.6.0-alpha.1 → 3.6.0-alpha.2
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/CHANGELOG.md +5 -0
- package/gltf-progressive.js +493 -464
- package/gltf-progressive.min.js +9 -9
- package/gltf-progressive.umd.cjs +9 -9
- package/lib/extension.d.ts +4 -1
- package/lib/extension.js +10 -5
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/lods.manager.d.ts +25 -12
- package/lib/lods.manager.js +149 -134
- package/lib/version.js +1 -1
- package/package.json +1 -1
package/lib/lods.manager.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Camera, Color, Material, Object3D, Scene, Texture, Vector3, WebGLRenderer } from "three";
|
|
1
|
+
import { Box3, BufferGeometry, Camera, Color, Material, Matrix4, Object3D, Scene, Texture, Vector3, WebGLRenderer } from "three";
|
|
2
2
|
import { NEEDLE_progressive_plugin } from "./plugins/plugin.js";
|
|
3
3
|
import { PromiseGroupOptions } from "./lods.promise.js";
|
|
4
4
|
export type LODManagerContext = {
|
|
@@ -9,6 +9,28 @@ export declare type LOD_Results = {
|
|
|
9
9
|
texture_lod: number;
|
|
10
10
|
};
|
|
11
11
|
export declare const lodDebugColors: number[];
|
|
12
|
+
export type MeshLODSelectionOptions = {
|
|
13
|
+
geometry: BufferGeometry;
|
|
14
|
+
matrixWorld: Matrix4;
|
|
15
|
+
camera: Camera;
|
|
16
|
+
projectionScreenMatrix: Matrix4;
|
|
17
|
+
desiredDensity: number;
|
|
18
|
+
canvasHeight?: number;
|
|
19
|
+
currentLevel?: number;
|
|
20
|
+
boundingBox?: Box3 | null;
|
|
21
|
+
xrEnabled?: boolean;
|
|
22
|
+
debugDrawLine?: (a: Vector3, b: Vector3, color: number) => void;
|
|
23
|
+
warnMissingPrimitiveDensities?: boolean;
|
|
24
|
+
target?: MeshLODSelectionResult;
|
|
25
|
+
};
|
|
26
|
+
export type MeshLODSelectionResult = {
|
|
27
|
+
level: number;
|
|
28
|
+
primitiveIndex: number;
|
|
29
|
+
screenCoverage: number;
|
|
30
|
+
screenspaceVolume: Vector3;
|
|
31
|
+
centrality: number;
|
|
32
|
+
};
|
|
33
|
+
export declare function calculateMeshLODLevel(options: MeshLODSelectionOptions): MeshLODSelectionResult;
|
|
12
34
|
declare type LODChangedEventListener = (args: {
|
|
13
35
|
type: "mesh" | "texture";
|
|
14
36
|
level: number;
|
|
@@ -130,6 +152,8 @@ export declare class LODsManager {
|
|
|
130
152
|
awaited_count: number;
|
|
131
153
|
resolved_count: number;
|
|
132
154
|
}>;
|
|
155
|
+
/** Track LOD work started outside this manager so {@link awaitLoading} waits for it too. */
|
|
156
|
+
trackLoadingPromise<T>(type: "mesh" | "texture", object: object, promise: Promise<T>): Promise<T>;
|
|
133
157
|
private _postprocessPromiseGroups;
|
|
134
158
|
private readonly _lodchangedlisteners;
|
|
135
159
|
/**
|
|
@@ -199,18 +223,7 @@ export declare class LODsManager {
|
|
|
199
223
|
*/
|
|
200
224
|
private loadProgressiveMeshes;
|
|
201
225
|
private readonly _sphere;
|
|
202
|
-
private readonly _tempBox;
|
|
203
|
-
private readonly _tempBox2;
|
|
204
|
-
private readonly tempMatrix;
|
|
205
226
|
private readonly _tempWorldPosition;
|
|
206
|
-
private readonly _tempBoxSize;
|
|
207
|
-
private readonly _tempBox2Size;
|
|
208
|
-
private static corner0;
|
|
209
|
-
private static corner1;
|
|
210
|
-
private static corner2;
|
|
211
|
-
private static corner3;
|
|
212
|
-
private static readonly _tempPtInside;
|
|
213
|
-
private static isInside;
|
|
214
227
|
private static skinnedMeshBoundsFrameOffsetCounter;
|
|
215
228
|
private static $skinnedMeshBoundsOffset;
|
|
216
229
|
private calculateLodLevel;
|
package/lib/lods.manager.js
CHANGED
|
@@ -48,6 +48,131 @@ export const lodDebugColors = [
|
|
|
48
48
|
0x4d908e,
|
|
49
49
|
0x555555,
|
|
50
50
|
];
|
|
51
|
+
const _meshLODWorldBox = new Box3();
|
|
52
|
+
const _meshLODProjectedBox = new Box3();
|
|
53
|
+
const _meshLODCameraSpaceBox = new Box3();
|
|
54
|
+
const _meshLODBoxSize = new Vector3();
|
|
55
|
+
const _meshLODCameraSpaceBoxSize = new Vector3();
|
|
56
|
+
const _meshLODProjectionInverse = new Matrix4();
|
|
57
|
+
const _meshLODCorner0 = new Vector3();
|
|
58
|
+
const _meshLODCorner1 = new Vector3();
|
|
59
|
+
const _meshLODCorner2 = new Vector3();
|
|
60
|
+
const _meshLODCorner3 = new Vector3();
|
|
61
|
+
function isInsideProjectedBox(box, projectionScreenMatrix) {
|
|
62
|
+
const min = box.min;
|
|
63
|
+
const max = box.max;
|
|
64
|
+
const centerx = (min.x + max.x) * 0.5;
|
|
65
|
+
const centery = (min.y + max.y) * 0.5;
|
|
66
|
+
const point = _meshLODCorner0.set(centerx, centery, min.z).applyMatrix4(projectionScreenMatrix);
|
|
67
|
+
return point.z < 0;
|
|
68
|
+
}
|
|
69
|
+
export function calculateMeshLODLevel(options) {
|
|
70
|
+
const { geometry, matrixWorld, camera, projectionScreenMatrix, desiredDensity, canvasHeight = 0, currentLevel = -1, xrEnabled = false, debugDrawLine, warnMissingPrimitiveDensities = false, } = options;
|
|
71
|
+
const meshLods = NEEDLE_progressive.getMeshLODExtension(geometry)?.lods;
|
|
72
|
+
const primitiveIndex = NEEDLE_progressive.getPrimitiveIndex(geometry);
|
|
73
|
+
const result = options.target ?? {
|
|
74
|
+
level: currentLevel,
|
|
75
|
+
primitiveIndex,
|
|
76
|
+
screenCoverage: 0,
|
|
77
|
+
screenspaceVolume: new Vector3(),
|
|
78
|
+
centrality: 1,
|
|
79
|
+
};
|
|
80
|
+
result.level = currentLevel;
|
|
81
|
+
result.primitiveIndex = primitiveIndex;
|
|
82
|
+
result.screenCoverage = 0;
|
|
83
|
+
result.screenspaceVolume.set(0, 0, 0);
|
|
84
|
+
result.centrality = 1;
|
|
85
|
+
if (!meshLods?.length)
|
|
86
|
+
return result;
|
|
87
|
+
let boundingBox = options.boundingBox ?? geometry.boundingBox;
|
|
88
|
+
if (!boundingBox) {
|
|
89
|
+
geometry.computeBoundingBox();
|
|
90
|
+
boundingBox = geometry.boundingBox;
|
|
91
|
+
}
|
|
92
|
+
if (!boundingBox)
|
|
93
|
+
return result;
|
|
94
|
+
_meshLODWorldBox.copy(boundingBox).applyMatrix4(matrixWorld);
|
|
95
|
+
if (camera.isPerspectiveCamera && isInsideProjectedBox(_meshLODWorldBox, projectionScreenMatrix)) {
|
|
96
|
+
result.level = 0;
|
|
97
|
+
result.screenCoverage = Infinity;
|
|
98
|
+
result.screenspaceVolume.set(Infinity, Infinity, Infinity);
|
|
99
|
+
return result;
|
|
100
|
+
}
|
|
101
|
+
_meshLODProjectedBox.copy(_meshLODWorldBox).applyMatrix4(projectionScreenMatrix);
|
|
102
|
+
if (xrEnabled && camera.isPerspectiveCamera && camera.fov > 70) {
|
|
103
|
+
const min = _meshLODProjectedBox.min;
|
|
104
|
+
const max = _meshLODProjectedBox.max;
|
|
105
|
+
let minX = min.x;
|
|
106
|
+
let minY = min.y;
|
|
107
|
+
let maxX = max.x;
|
|
108
|
+
let maxY = max.y;
|
|
109
|
+
const enlargementFactor = 2.0;
|
|
110
|
+
const centerBoost = 1.5;
|
|
111
|
+
const centerX = (min.x + max.x) * 0.5;
|
|
112
|
+
const centerY = (min.y + max.y) * 0.5;
|
|
113
|
+
minX = (minX - centerX) * enlargementFactor + centerX;
|
|
114
|
+
minY = (minY - centerY) * enlargementFactor + centerY;
|
|
115
|
+
maxX = (maxX - centerX) * enlargementFactor + centerX;
|
|
116
|
+
maxY = (maxY - centerY) * enlargementFactor + centerY;
|
|
117
|
+
const xCentrality = minX < 0 && maxX > 0 ? 0 : Math.min(Math.abs(min.x), Math.abs(max.x));
|
|
118
|
+
const yCentrality = minY < 0 && maxY > 0 ? 0 : Math.min(Math.abs(min.y), Math.abs(max.y));
|
|
119
|
+
const centrality = Math.max(xCentrality, yCentrality);
|
|
120
|
+
result.centrality = (centerBoost - centrality) * (centerBoost - centrality) * (centerBoost - centrality);
|
|
121
|
+
}
|
|
122
|
+
const boxSize = _meshLODProjectedBox.getSize(_meshLODBoxSize);
|
|
123
|
+
boxSize.multiplyScalar(0.5);
|
|
124
|
+
if (globalThis.screen?.availHeight > 0 && canvasHeight > 0) {
|
|
125
|
+
boxSize.multiplyScalar(canvasHeight / globalThis.screen.availHeight);
|
|
126
|
+
}
|
|
127
|
+
if (camera.isPerspectiveCamera) {
|
|
128
|
+
boxSize.x *= camera.aspect;
|
|
129
|
+
}
|
|
130
|
+
_meshLODCameraSpaceBox.copy(boundingBox).applyMatrix4(matrixWorld).applyMatrix4(camera.matrixWorldInverse);
|
|
131
|
+
const cameraSpaceSize = _meshLODCameraSpaceBox.getSize(_meshLODCameraSpaceBoxSize);
|
|
132
|
+
const screenMax = Math.max(boxSize.x, boxSize.y);
|
|
133
|
+
const cameraSpaceMax = Math.max(cameraSpaceSize.x, cameraSpaceSize.y);
|
|
134
|
+
if (screenMax !== 0 && cameraSpaceMax !== 0) {
|
|
135
|
+
boxSize.z = cameraSpaceSize.z / cameraSpaceMax * screenMax;
|
|
136
|
+
}
|
|
137
|
+
const screenCoverage = Math.max(boxSize.x, boxSize.y, boxSize.z) * result.centrality;
|
|
138
|
+
result.screenCoverage = screenCoverage;
|
|
139
|
+
result.screenspaceVolume.copy(boxSize);
|
|
140
|
+
if (screenCoverage <= 0)
|
|
141
|
+
return result;
|
|
142
|
+
if (debugDrawLine) {
|
|
143
|
+
const mat = _meshLODProjectionInverse.copy(projectionScreenMatrix);
|
|
144
|
+
mat.invert();
|
|
145
|
+
_meshLODCorner0.copy(_meshLODProjectedBox.min);
|
|
146
|
+
_meshLODCorner1.copy(_meshLODProjectedBox.max);
|
|
147
|
+
_meshLODCorner1.x = _meshLODCorner0.x;
|
|
148
|
+
_meshLODCorner2.copy(_meshLODProjectedBox.max);
|
|
149
|
+
_meshLODCorner2.y = _meshLODCorner0.y;
|
|
150
|
+
_meshLODCorner3.copy(_meshLODProjectedBox.max);
|
|
151
|
+
const z = (_meshLODCorner0.z + _meshLODCorner3.z) * 0.5;
|
|
152
|
+
_meshLODCorner0.z = _meshLODCorner1.z = _meshLODCorner2.z = _meshLODCorner3.z = z;
|
|
153
|
+
_meshLODCorner0.applyMatrix4(mat);
|
|
154
|
+
_meshLODCorner1.applyMatrix4(mat);
|
|
155
|
+
_meshLODCorner2.applyMatrix4(mat);
|
|
156
|
+
_meshLODCorner3.applyMatrix4(mat);
|
|
157
|
+
debugDrawLine(_meshLODCorner0, _meshLODCorner1, 0x0000ff);
|
|
158
|
+
debugDrawLine(_meshLODCorner0, _meshLODCorner2, 0x0000ff);
|
|
159
|
+
debugDrawLine(_meshLODCorner1, _meshLODCorner3, 0x0000ff);
|
|
160
|
+
debugDrawLine(_meshLODCorner2, _meshLODCorner3, 0x0000ff);
|
|
161
|
+
}
|
|
162
|
+
for (let i = 0; i < meshLods.length; i++) {
|
|
163
|
+
const lod = meshLods[i];
|
|
164
|
+
const density = lod.densities?.[primitiveIndex] || lod.density || .00001;
|
|
165
|
+
if (primitiveIndex > 0 && warnMissingPrimitiveDensities && isDevelopmentServer() && !lod.densities && !globalThis["NEEDLE:MISSING_LOD_PRIMITIVE_DENSITIES"]) {
|
|
166
|
+
globalThis["NEEDLE:MISSING_LOD_PRIMITIVE_DENSITIES"] = true;
|
|
167
|
+
console.warn(`[Needle Progressive] Detected usage of mesh without primitive densities. This might cause incorrect LOD level selection: Consider re-optimizing your model by updating your Needle Integration, Needle glTF Pipeline or running optimization again on Needle Cloud.`);
|
|
168
|
+
}
|
|
169
|
+
if (density / screenCoverage < desiredDensity) {
|
|
170
|
+
result.level = i;
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return result;
|
|
175
|
+
}
|
|
51
176
|
/**
|
|
52
177
|
* The LODsManager class is responsible for managing the LODs and progressive assets in the scene. It will automatically update the LODs based on the camera position, screen coverage and mesh density of the objects.
|
|
53
178
|
* It must be enabled by calling the `enable` method.
|
|
@@ -196,6 +321,11 @@ export class LODsManager {
|
|
|
196
321
|
});
|
|
197
322
|
return newGroup.ready;
|
|
198
323
|
}
|
|
324
|
+
/** Track LOD work started outside this manager so {@link awaitLoading} waits for it too. */
|
|
325
|
+
trackLoadingPromise(type, object, promise) {
|
|
326
|
+
PromiseGroup.addPromise(type, object, promise, this._newPromiseGroups);
|
|
327
|
+
return promise;
|
|
328
|
+
}
|
|
199
329
|
_postprocessPromiseGroups() {
|
|
200
330
|
if (this._newPromiseGroups.length === 0)
|
|
201
331
|
return;
|
|
@@ -545,25 +675,7 @@ export class LODsManager {
|
|
|
545
675
|
}
|
|
546
676
|
// private testIfLODLevelsAreAvailable() {
|
|
547
677
|
_sphere = new Sphere();
|
|
548
|
-
_tempBox = new Box3();
|
|
549
|
-
_tempBox2 = new Box3();
|
|
550
|
-
tempMatrix = new Matrix4();
|
|
551
678
|
_tempWorldPosition = new Vector3();
|
|
552
|
-
_tempBoxSize = new Vector3();
|
|
553
|
-
_tempBox2Size = new Vector3();
|
|
554
|
-
static corner0 = new Vector3();
|
|
555
|
-
static corner1 = new Vector3();
|
|
556
|
-
static corner2 = new Vector3();
|
|
557
|
-
static corner3 = new Vector3();
|
|
558
|
-
static _tempPtInside = new Vector3();
|
|
559
|
-
static isInside(box, matrix) {
|
|
560
|
-
const min = box.min;
|
|
561
|
-
const max = box.max;
|
|
562
|
-
const centerx = (min.x + max.x) * 0.5;
|
|
563
|
-
const centery = (min.y + max.y) * 0.5;
|
|
564
|
-
const pt1 = this._tempPtInside.set(centerx, centery, min.z).applyMatrix4(matrix);
|
|
565
|
-
return pt1.z < 0;
|
|
566
|
-
}
|
|
567
679
|
static skinnedMeshBoundsFrameOffsetCounter = 0;
|
|
568
680
|
static $skinnedMeshBoundsOffset = Symbol("gltf-progressive-skinnedMeshBoundsOffset");
|
|
569
681
|
// #region calculateLodLevel
|
|
@@ -635,7 +747,6 @@ export class LODsManager {
|
|
|
635
747
|
boundingBox = skinnedMesh.boundingBox;
|
|
636
748
|
}
|
|
637
749
|
if (boundingBox) {
|
|
638
|
-
const cam = camera;
|
|
639
750
|
// hack: if the mesh has vertex colors, has less than 100 vertices we always select the highest LOD
|
|
640
751
|
if (mesh.geometry.attributes.color && mesh.geometry.attributes.color.count < 100) {
|
|
641
752
|
if (mesh.geometry.boundingSphere) {
|
|
@@ -649,126 +760,30 @@ export class LODsManager {
|
|
|
649
760
|
}
|
|
650
761
|
}
|
|
651
762
|
}
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
763
|
+
const selection = calculateMeshLODLevel({
|
|
764
|
+
geometry: mesh.geometry,
|
|
765
|
+
matrixWorld: mesh.matrixWorld,
|
|
766
|
+
camera,
|
|
767
|
+
projectionScreenMatrix: this.projectionScreenMatrix,
|
|
768
|
+
desiredDensity,
|
|
769
|
+
canvasHeight,
|
|
770
|
+
currentLevel: state.lastLodLevel_Mesh,
|
|
771
|
+
boundingBox,
|
|
772
|
+
xrEnabled: this.renderer.xr.enabled,
|
|
773
|
+
debugDrawLine: debugProgressiveLoading ? LODsManager.debugDrawLine : undefined,
|
|
774
|
+
warnMissingPrimitiveDensities: true,
|
|
775
|
+
});
|
|
776
|
+
state.lastCentrality = selection.centrality;
|
|
777
|
+
state.lastScreenCoverage = selection.screenCoverage;
|
|
778
|
+
state.lastScreenspaceVolume.copy(selection.screenspaceVolume);
|
|
779
|
+
if (selection.screenCoverage === Infinity) {
|
|
663
780
|
result.mesh_lod = 0;
|
|
664
781
|
result.texture_lod = 0;
|
|
665
782
|
return;
|
|
666
783
|
}
|
|
667
|
-
|
|
668
|
-
// TODO might need to be adjusted for cameras that are rendered during an XR session but are
|
|
669
|
-
// actually not XR cameras (e.g. a render texture)
|
|
670
|
-
if (this.renderer.xr.enabled && (cam.isPerspectiveCamera) && cam.fov > 70) {
|
|
671
|
-
// calculate centrality of the bounding box - how close is it to the screen center
|
|
672
|
-
const min = this._tempBox.min;
|
|
673
|
-
const max = this._tempBox.max;
|
|
674
|
-
let minX = min.x;
|
|
675
|
-
let minY = min.y;
|
|
676
|
-
let maxX = max.x;
|
|
677
|
-
let maxY = max.y;
|
|
678
|
-
// enlarge
|
|
679
|
-
const enlargementFactor = 2.0;
|
|
680
|
-
const centerBoost = 1.5;
|
|
681
|
-
const centerX = (min.x + max.x) * 0.5;
|
|
682
|
-
const centerY = (min.y + max.y) * 0.5;
|
|
683
|
-
minX = (minX - centerX) * enlargementFactor + centerX;
|
|
684
|
-
minY = (minY - centerY) * enlargementFactor + centerY;
|
|
685
|
-
maxX = (maxX - centerX) * enlargementFactor + centerX;
|
|
686
|
-
maxY = (maxY - centerY) * enlargementFactor + centerY;
|
|
687
|
-
const xCentrality = minX < 0 && maxX > 0 ? 0 : Math.min(Math.abs(min.x), Math.abs(max.x));
|
|
688
|
-
const yCentrality = minY < 0 && maxY > 0 ? 0 : Math.min(Math.abs(min.y), Math.abs(max.y));
|
|
689
|
-
const centrality = Math.max(xCentrality, yCentrality);
|
|
690
|
-
// heuristically determined to lower quality for objects at the edges of vision
|
|
691
|
-
state.lastCentrality = (centerBoost - centrality) * (centerBoost - centrality) * (centerBoost - centrality);
|
|
692
|
-
}
|
|
693
|
-
else {
|
|
694
|
-
state.lastCentrality = 1;
|
|
695
|
-
}
|
|
696
|
-
const boxSize = this._tempBox.getSize(this._tempBoxSize);
|
|
697
|
-
boxSize.multiplyScalar(0.5); // goes from -1..1, we want -0.5..0.5 for coverage in percent
|
|
698
|
-
if (screen.availHeight > 0) {
|
|
699
|
-
// correct for size of context on screen
|
|
700
|
-
if (canvasHeight > 0)
|
|
701
|
-
boxSize.multiplyScalar(canvasHeight / screen.availHeight);
|
|
702
|
-
}
|
|
703
|
-
if (camera.isPerspectiveCamera) {
|
|
704
|
-
boxSize.x *= camera.aspect;
|
|
705
|
-
}
|
|
706
|
-
else if (camera.isOrthographicCamera) {
|
|
707
|
-
// const cam = camera as OrthographicCamera;
|
|
708
|
-
// boxSize.x *= cam.zoom * .01;
|
|
709
|
-
}
|
|
710
|
-
const matView = camera.matrixWorldInverse;
|
|
711
|
-
const box2 = this._tempBox2;
|
|
712
|
-
box2.copy(boundingBox);
|
|
713
|
-
box2.applyMatrix4(mesh.matrixWorld);
|
|
714
|
-
box2.applyMatrix4(matView);
|
|
715
|
-
const boxSize2 = box2.getSize(this._tempBox2Size);
|
|
716
|
-
// approximate depth coverage in relation to screenspace size
|
|
717
|
-
const max2 = Math.max(boxSize2.x, boxSize2.y);
|
|
718
|
-
const max1 = Math.max(boxSize.x, boxSize.y);
|
|
719
|
-
if (max1 != 0 && max2 != 0)
|
|
720
|
-
boxSize.z = boxSize2.z / Math.max(boxSize2.x, boxSize2.y) * Math.max(boxSize.x, boxSize.y);
|
|
721
|
-
state.lastScreenCoverage = Math.max(boxSize.x, boxSize.y, boxSize.z);
|
|
722
|
-
state.lastScreenspaceVolume.copy(boxSize);
|
|
723
|
-
state.lastScreenCoverage *= state.lastCentrality;
|
|
724
|
-
// draw screen size box
|
|
725
|
-
if (debugProgressiveLoading && LODsManager.debugDrawLine) {
|
|
726
|
-
const mat = this.tempMatrix.copy(this.projectionScreenMatrix);
|
|
727
|
-
mat.invert();
|
|
728
|
-
const corner0 = LODsManager.corner0;
|
|
729
|
-
const corner1 = LODsManager.corner1;
|
|
730
|
-
const corner2 = LODsManager.corner2;
|
|
731
|
-
const corner3 = LODsManager.corner3;
|
|
732
|
-
// get box corners, transform with camera space, and draw as quad lines
|
|
733
|
-
corner0.copy(this._tempBox.min);
|
|
734
|
-
corner1.copy(this._tempBox.max);
|
|
735
|
-
corner1.x = corner0.x;
|
|
736
|
-
corner2.copy(this._tempBox.max);
|
|
737
|
-
corner2.y = corner0.y;
|
|
738
|
-
corner3.copy(this._tempBox.max);
|
|
739
|
-
// draw outlines at the center of the box
|
|
740
|
-
const z = (corner0.z + corner3.z) * 0.5;
|
|
741
|
-
// all outlines should have the same depth in screen space
|
|
742
|
-
corner0.z = corner1.z = corner2.z = corner3.z = z;
|
|
743
|
-
corner0.applyMatrix4(mat);
|
|
744
|
-
corner1.applyMatrix4(mat);
|
|
745
|
-
corner2.applyMatrix4(mat);
|
|
746
|
-
corner3.applyMatrix4(mat);
|
|
747
|
-
LODsManager.debugDrawLine(corner0, corner1, 0x0000ff);
|
|
748
|
-
LODsManager.debugDrawLine(corner0, corner2, 0x0000ff);
|
|
749
|
-
LODsManager.debugDrawLine(corner1, corner3, 0x0000ff);
|
|
750
|
-
LODsManager.debugDrawLine(corner2, corner3, 0x0000ff);
|
|
751
|
-
}
|
|
752
|
-
let expectedLevel = 999;
|
|
753
|
-
// const framerate = this.context.time.smoothedFps;
|
|
754
|
-
if (mesh_lods && state.lastScreenCoverage > 0) {
|
|
755
|
-
for (let l = 0; l < mesh_lods.length; l++) {
|
|
756
|
-
const lod = mesh_lods[l];
|
|
757
|
-
const densityForThisLevel = lod.densities?.[primitive_index] || lod.density || .00001;
|
|
758
|
-
const resultingDensity = densityForThisLevel / state.lastScreenCoverage;
|
|
759
|
-
if (primitive_index > 0 && isDevelopmentServer() && !lod.densities && !globalThis["NEEDLE:MISSING_LOD_PRIMITIVE_DENSITIES"]) {
|
|
760
|
-
window["NEEDLE:MISSING_LOD_PRIMITIVE_DENSITIES"] = true;
|
|
761
|
-
console.warn(`[Needle Progressive] Detected usage of mesh without primitive densities. This might cause incorrect LOD level selection: Consider re-optimizing your model by updating your Needle Integration, Needle glTF Pipeline or running optimization again on Needle Cloud.`);
|
|
762
|
-
}
|
|
763
|
-
if (resultingDensity < desiredDensity) {
|
|
764
|
-
expectedLevel = l;
|
|
765
|
-
break;
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
}
|
|
769
|
-
const isLowerLod = expectedLevel < mesh_level;
|
|
784
|
+
const isLowerLod = selection.level >= 0 && selection.level < mesh_level;
|
|
770
785
|
if (isLowerLod) {
|
|
771
|
-
mesh_level =
|
|
786
|
+
mesh_level = selection.level;
|
|
772
787
|
mesh_level_calculated = true;
|
|
773
788
|
}
|
|
774
789
|
}
|
package/lib/version.js
CHANGED
package/package.json
CHANGED