@nebula-spatial/viewer 0.3.0 → 0.4.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/CHANGELOG.md +93 -49
- package/README.md +593 -218
- package/dist/assets/types.d.ts +234 -0
- package/dist/cad/types.d.ts +16 -26
- package/dist/index-Lsk3kHNe.js +6718 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +4 -4924
- package/dist/mujoco-runtime-s85kwjo7.js +208 -0
- package/dist/plugins.d.ts +47 -3
- package/dist/session-B_UiRctl.js +762 -0
- package/dist/session-CGaj14lM.js +93 -0
- package/dist/stage-BxROW_dP.js +421 -0
- package/dist/types.d.ts +24 -2
- package/dist/ui/types.d.ts +45 -0
- package/dist/usd-session-Dcd20Z6G.js +522 -0
- package/package.json +7 -4
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { Quaternion as y, Vector3 as M, Group as P, Box3 as T } from "three";
|
|
2
|
+
import { DRACOLoader as x } from "three/examples/jsm/loaders/DRACOLoader.js";
|
|
3
|
+
import { GLTFLoader as D } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
4
|
+
import { S as E, d as w } from "./stage-BxROW_dP.js";
|
|
5
|
+
const G = new y().setFromAxisAngle(new M(1, 0, 0), Math.PI / 2), R = new y();
|
|
6
|
+
function S(r) {
|
|
7
|
+
return r === "y" ? G : R;
|
|
8
|
+
}
|
|
9
|
+
function b(r, n) {
|
|
10
|
+
const t = S(n);
|
|
11
|
+
return t.equals(r.quaternion) ? !1 : (r.quaternion.copy(t), r.updateMatrixWorld(!0), !0);
|
|
12
|
+
}
|
|
13
|
+
function z(r, n) {
|
|
14
|
+
let t = !1, i = null, e = null, d = "z", f;
|
|
15
|
+
const l = new x(), p = new D(), m = () => {
|
|
16
|
+
t = !0;
|
|
17
|
+
}, a = (async () => {
|
|
18
|
+
d = n.options.upAxis ?? "z", n.options.dracoDecoderPath && l.setDecoderPath(n.options.dracoDecoderPath), p.setDRACOLoader(l);
|
|
19
|
+
let o = null;
|
|
20
|
+
try {
|
|
21
|
+
if (t || n.signal.aborted) throw h();
|
|
22
|
+
const s = await p.loadAsync(r.url ?? await r.resolve(r.entryPath ?? ""));
|
|
23
|
+
o = new P(), o.name = "viewer-model-root";
|
|
24
|
+
const u = s.scenes.filter((c) => c !== s.scene);
|
|
25
|
+
if (o.add(s.scene), t || n.signal.aborted) {
|
|
26
|
+
for (const c of u) o.add(c);
|
|
27
|
+
throw h();
|
|
28
|
+
}
|
|
29
|
+
b(o, d), g(o);
|
|
30
|
+
const A = new E(o, n.options.simulationTheme, void 0, "model");
|
|
31
|
+
i = o, e = A, o = null;
|
|
32
|
+
} finally {
|
|
33
|
+
o && w(o), l.dispose();
|
|
34
|
+
}
|
|
35
|
+
})();
|
|
36
|
+
return a.catch(() => {
|
|
37
|
+
}), {
|
|
38
|
+
id: `model-${Math.random().toString(36).slice(2)}`,
|
|
39
|
+
opened: a,
|
|
40
|
+
get root() {
|
|
41
|
+
return (e == null ? void 0 : e.root) ?? null;
|
|
42
|
+
},
|
|
43
|
+
getFitBounds() {
|
|
44
|
+
return (e == null ? void 0 : e.getModelBounds()) ?? null;
|
|
45
|
+
},
|
|
46
|
+
beforeRender(o, s, u) {
|
|
47
|
+
return e == null ? void 0 : e.beforeRender(o, s, u);
|
|
48
|
+
},
|
|
49
|
+
capabilities: { canPlay: !1, canPause: !1, canReset: !1, hasPhysics: !1, canReorientUpAxis: !0, canToggleGround: !0 },
|
|
50
|
+
// Session presentation overrides are only consulted for `interactionMode`
|
|
51
|
+
// and `fitPolicy`; the UI group comes from the loader descriptor. Keep the
|
|
52
|
+
// two in sync so the override never reads as a contradictory value.
|
|
53
|
+
presentation: { preferredViewMode: "3d", interactionMode: "object", uiProfile: "model", fitPolicy: "fit-on-ready" },
|
|
54
|
+
getUpAxis() {
|
|
55
|
+
return i ? d : null;
|
|
56
|
+
},
|
|
57
|
+
setTheme(o) {
|
|
58
|
+
e == null || e.setTheme(o);
|
|
59
|
+
},
|
|
60
|
+
setGroundVisible(o) {
|
|
61
|
+
e == null || e.setGroundVisible(o);
|
|
62
|
+
},
|
|
63
|
+
getGroundVisible() {
|
|
64
|
+
return (e == null ? void 0 : e.getGroundVisible()) ?? !0;
|
|
65
|
+
},
|
|
66
|
+
setUpAxis(o) {
|
|
67
|
+
if (t || !i || !e || !b(i, o)) return;
|
|
68
|
+
d = o, e.reseatGround();
|
|
69
|
+
const s = e.getModelBounds();
|
|
70
|
+
n.requestRender(), n.fit(s, { padding: 1.15 });
|
|
71
|
+
},
|
|
72
|
+
beginDispose: m,
|
|
73
|
+
dispose() {
|
|
74
|
+
return m(), f ?? (f = a.catch(() => {
|
|
75
|
+
}).then(() => {
|
|
76
|
+
e == null || e.dispose(), e = null, i && w(i), i = null;
|
|
77
|
+
})), f;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function g(r) {
|
|
82
|
+
r.updateMatrixWorld(!0);
|
|
83
|
+
const n = new T().setFromObject(r);
|
|
84
|
+
if (n.isEmpty()) throw new Error("模型不包含可显示的几何内容。");
|
|
85
|
+
const t = n.getSize(new M()), i = Math.max(t.x, t.y, t.z);
|
|
86
|
+
if (!Number.isFinite(i) || i <= 0) throw new Error("模型尺寸无效。");
|
|
87
|
+
}
|
|
88
|
+
function h() {
|
|
89
|
+
return Object.assign(new Error("Model load aborted."), { name: "AbortError", code: "E_ABORTED" });
|
|
90
|
+
}
|
|
91
|
+
export {
|
|
92
|
+
z as createModelSession
|
|
93
|
+
};
|
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
var v = Object.defineProperty;
|
|
2
|
+
var y = (c, e, t) => e in c ? v(c, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : c[e] = t;
|
|
3
|
+
var a = (c, e, t) => y(c, typeof e != "symbol" ? e + "" : e, t);
|
|
4
|
+
import * as o from "three";
|
|
5
|
+
import { V as p } from "./index-Lsk3kHNe.js";
|
|
6
|
+
const x = 1, b = (
|
|
7
|
+
/* glsl */
|
|
8
|
+
`
|
|
9
|
+
uniform mat4 textureMatrix;
|
|
10
|
+
varying vec4 vReflectionUv;
|
|
11
|
+
varying vec3 vWorldPosition;
|
|
12
|
+
|
|
13
|
+
void main() {
|
|
14
|
+
vec4 worldPosition = modelMatrix * vec4(position, 1.0);
|
|
15
|
+
vWorldPosition = worldPosition.xyz;
|
|
16
|
+
vReflectionUv = textureMatrix * vec4(position, 1.0);
|
|
17
|
+
// Match Three.js built-in materials: transform to view space before projection.
|
|
18
|
+
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
|
|
19
|
+
gl_Position = projectionMatrix * mvPosition;
|
|
20
|
+
}
|
|
21
|
+
`
|
|
22
|
+
), M = (
|
|
23
|
+
/* glsl */
|
|
24
|
+
`
|
|
25
|
+
uniform sampler2D tDiffuse;
|
|
26
|
+
uniform vec2 resolution;
|
|
27
|
+
uniform vec3 fineGridColor;
|
|
28
|
+
uniform vec3 coarseGridColor;
|
|
29
|
+
uniform float blurIntensity;
|
|
30
|
+
uniform float reflectionMix;
|
|
31
|
+
uniform float gridOpacity;
|
|
32
|
+
uniform float gridScale;
|
|
33
|
+
uniform vec2 groundCenter;
|
|
34
|
+
uniform float maxRadius;
|
|
35
|
+
uniform float fadeSoftness;
|
|
36
|
+
|
|
37
|
+
varying vec4 vReflectionUv;
|
|
38
|
+
varying vec3 vWorldPosition;
|
|
39
|
+
|
|
40
|
+
vec4 blur9(sampler2D image, vec2 uv, vec2 res, float radius) {
|
|
41
|
+
vec4 color = vec4(0.0);
|
|
42
|
+
vec2 stepSize = radius / res;
|
|
43
|
+
color += texture2D(image, uv + vec2(-stepSize.x, -stepSize.y)) * 0.0625;
|
|
44
|
+
color += texture2D(image, uv + vec2(0.0, -stepSize.y)) * 0.125;
|
|
45
|
+
color += texture2D(image, uv + vec2(stepSize.x, -stepSize.y)) * 0.0625;
|
|
46
|
+
color += texture2D(image, uv + vec2(-stepSize.x, 0.0)) * 0.125;
|
|
47
|
+
color += texture2D(image, uv) * 0.25;
|
|
48
|
+
color += texture2D(image, uv + vec2(stepSize.x, 0.0)) * 0.125;
|
|
49
|
+
color += texture2D(image, uv + vec2(-stepSize.x, stepSize.y)) * 0.0625;
|
|
50
|
+
color += texture2D(image, uv + vec2(0.0, stepSize.y)) * 0.125;
|
|
51
|
+
color += texture2D(image, uv + vec2(stepSize.x, stepSize.y)) * 0.0625;
|
|
52
|
+
return color;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
float gridLine(vec2 position, float scale) {
|
|
56
|
+
vec2 coordinate = position / scale;
|
|
57
|
+
vec2 width = max(fwidth(coordinate), vec2(0.0001));
|
|
58
|
+
vec2 distanceToLine = abs(fract(coordinate - 0.5) - 0.5) / width;
|
|
59
|
+
return 1.0 - min(min(distanceToLine.x, distanceToLine.y), 1.0);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
void main() {
|
|
63
|
+
vec2 groundPosition = vWorldPosition.xy;
|
|
64
|
+
float edgeDistance = length(groundPosition - groundCenter);
|
|
65
|
+
float edgeFade = 1.0 - smoothstep(maxRadius - fadeSoftness, maxRadius, edgeDistance);
|
|
66
|
+
|
|
67
|
+
float fineLine = gridLine(groundPosition, gridScale);
|
|
68
|
+
float coarseLine = gridLine(groundPosition, gridScale * 10.0);
|
|
69
|
+
float gridAlpha = max(fineLine * 0.16, coarseLine * 0.42) * gridOpacity * edgeFade;
|
|
70
|
+
vec3 gridColor = mix(fineGridColor, coarseGridColor, coarseLine);
|
|
71
|
+
|
|
72
|
+
vec2 reflectionUv = vReflectionUv.xy / vReflectionUv.w;
|
|
73
|
+
bool validReflection = reflectionUv.x >= 0.0 && reflectionUv.x <= 1.0
|
|
74
|
+
&& reflectionUv.y >= 0.0 && reflectionUv.y <= 1.0;
|
|
75
|
+
vec4 reflection = validReflection
|
|
76
|
+
? blur9(tDiffuse, reflectionUv, resolution, blurIntensity)
|
|
77
|
+
: vec4(0.0);
|
|
78
|
+
float reflectionAlpha = reflectionMix * edgeFade * (validReflection ? 1.0 : 0.0);
|
|
79
|
+
|
|
80
|
+
float alpha = reflectionAlpha + gridAlpha * (1.0 - reflectionAlpha);
|
|
81
|
+
if (alpha <= 0.001) discard;
|
|
82
|
+
vec3 color = mix(reflection.rgb, gridColor, gridAlpha / max(alpha, 0.001));
|
|
83
|
+
gl_FragColor = vec4(color, alpha);
|
|
84
|
+
#include <tonemapping_fragment>
|
|
85
|
+
#include <colorspace_fragment>
|
|
86
|
+
}
|
|
87
|
+
`
|
|
88
|
+
);
|
|
89
|
+
class w extends o.Mesh {
|
|
90
|
+
constructor({ size: t = 20, textureWidth: i = 512, textureHeight: r = 512 } = {}) {
|
|
91
|
+
const s = new o.Matrix4(), n = new o.WebGLRenderTarget(i, r, {
|
|
92
|
+
type: o.HalfFloatType,
|
|
93
|
+
minFilter: o.LinearFilter,
|
|
94
|
+
magFilter: o.LinearFilter,
|
|
95
|
+
format: o.RGBAFormat,
|
|
96
|
+
depthBuffer: !0,
|
|
97
|
+
samples: 0
|
|
98
|
+
}), l = new o.ShaderMaterial({
|
|
99
|
+
uniforms: {
|
|
100
|
+
tDiffuse: { value: n.texture },
|
|
101
|
+
textureMatrix: { value: s },
|
|
102
|
+
resolution: { value: new o.Vector2(i, r) },
|
|
103
|
+
fineGridColor: { value: new o.Color(2502702) },
|
|
104
|
+
coarseGridColor: { value: new o.Color(7897726) },
|
|
105
|
+
blurIntensity: { value: 1.7 },
|
|
106
|
+
reflectionMix: { value: 0.07 },
|
|
107
|
+
gridOpacity: { value: 1 },
|
|
108
|
+
gridScale: { value: 0.2 },
|
|
109
|
+
groundCenter: { value: new o.Vector2() },
|
|
110
|
+
maxRadius: { value: t * 0.5 },
|
|
111
|
+
fadeSoftness: { value: t * 0.325 }
|
|
112
|
+
},
|
|
113
|
+
vertexShader: b,
|
|
114
|
+
fragmentShader: M,
|
|
115
|
+
transparent: !0,
|
|
116
|
+
depthWrite: !1,
|
|
117
|
+
toneMapped: !0,
|
|
118
|
+
fog: !1
|
|
119
|
+
});
|
|
120
|
+
super(new o.PlaneGeometry(t, t), l);
|
|
121
|
+
a(this, "renderTarget");
|
|
122
|
+
a(this, "textureMatrix");
|
|
123
|
+
a(this, "virtualCamera");
|
|
124
|
+
a(this, "clipBias");
|
|
125
|
+
a(this, "reflectorPlane");
|
|
126
|
+
a(this, "normal");
|
|
127
|
+
a(this, "reflectorWorldPosition");
|
|
128
|
+
a(this, "cameraWorldPosition");
|
|
129
|
+
a(this, "rotationMatrix");
|
|
130
|
+
a(this, "lookAtPosition");
|
|
131
|
+
a(this, "clipPlane");
|
|
132
|
+
a(this, "view");
|
|
133
|
+
a(this, "target");
|
|
134
|
+
a(this, "q");
|
|
135
|
+
this.renderTarget = n, this.textureMatrix = s, this.virtualCamera = new o.PerspectiveCamera(), this.virtualCamera.layers.set(x), this.clipBias = 3e-3, this.frustumCulled = !1, this.renderOrder = 1, this.position.z = 2e-3, this.reflectorPlane = new o.Plane(), this.normal = new o.Vector3(), this.reflectorWorldPosition = new o.Vector3(), this.cameraWorldPosition = new o.Vector3(), this.rotationMatrix = new o.Matrix4(), this.lookAtPosition = new o.Vector3(0, 0, -1), this.clipPlane = new o.Vector4(), this.view = new o.Vector3(), this.target = new o.Vector3(), this.q = new o.Vector4();
|
|
136
|
+
}
|
|
137
|
+
renderReflection(t, i, r) {
|
|
138
|
+
if (this.reflectorWorldPosition.setFromMatrixPosition(this.matrixWorld), this.cameraWorldPosition.setFromMatrixPosition(r.matrixWorld), this.rotationMatrix.extractRotation(this.matrixWorld), this.normal.set(0, 0, 1).applyMatrix4(this.rotationMatrix), this.view.subVectors(this.reflectorWorldPosition, this.cameraWorldPosition), this.view.dot(this.normal) > 0) return;
|
|
139
|
+
this.view.reflect(this.normal).negate().add(this.reflectorWorldPosition), this.rotationMatrix.extractRotation(r.matrixWorld), this.lookAtPosition.set(0, 0, -1).applyMatrix4(this.rotationMatrix).add(this.cameraWorldPosition), this.target.subVectors(this.reflectorWorldPosition, this.lookAtPosition).reflect(this.normal).negate().add(this.reflectorWorldPosition), this.virtualCamera.position.copy(this.view), this.virtualCamera.up.set(0, 1, 0).applyMatrix4(this.rotationMatrix).reflect(this.normal), this.virtualCamera.lookAt(this.target), this.virtualCamera.near = r.near, this.virtualCamera.far = r.far, this.virtualCamera.updateMatrixWorld(), this.virtualCamera.projectionMatrix.copy(r.projectionMatrix), this.textureMatrix.set(
|
|
140
|
+
0.5,
|
|
141
|
+
0,
|
|
142
|
+
0,
|
|
143
|
+
0.5,
|
|
144
|
+
0,
|
|
145
|
+
0.5,
|
|
146
|
+
0,
|
|
147
|
+
0.5,
|
|
148
|
+
0,
|
|
149
|
+
0,
|
|
150
|
+
0.5,
|
|
151
|
+
0.5,
|
|
152
|
+
0,
|
|
153
|
+
0,
|
|
154
|
+
0,
|
|
155
|
+
1
|
|
156
|
+
).multiply(this.virtualCamera.projectionMatrix).multiply(this.virtualCamera.matrixWorldInverse).multiply(this.matrixWorld), this.reflectorPlane.setFromNormalAndCoplanarPoint(this.normal, this.reflectorWorldPosition).applyMatrix4(this.virtualCamera.matrixWorldInverse), this.clipPlane.set(
|
|
157
|
+
this.reflectorPlane.normal.x,
|
|
158
|
+
this.reflectorPlane.normal.y,
|
|
159
|
+
this.reflectorPlane.normal.z,
|
|
160
|
+
this.reflectorPlane.constant
|
|
161
|
+
);
|
|
162
|
+
const s = this.virtualCamera.projectionMatrix;
|
|
163
|
+
this.q.set(
|
|
164
|
+
(Math.sign(this.clipPlane.x) + s.elements[8]) / s.elements[0],
|
|
165
|
+
(Math.sign(this.clipPlane.y) + s.elements[9]) / s.elements[5],
|
|
166
|
+
-1,
|
|
167
|
+
(1 + s.elements[10]) / s.elements[14]
|
|
168
|
+
), this.clipPlane.multiplyScalar(2 / this.clipPlane.dot(this.q)), s.elements[2] = this.clipPlane.x, s.elements[6] = this.clipPlane.y, s.elements[10] = this.clipPlane.z + 1 - this.clipBias, s.elements[14] = this.clipPlane.w, this.virtualCamera.projectionMatrixInverse.copy(s).invert();
|
|
169
|
+
const n = t.getRenderTarget(), l = t.xr.enabled, u = t.shadowMap.autoUpdate, d = t.shadowMap.enabled;
|
|
170
|
+
try {
|
|
171
|
+
t.xr.enabled = !1, t.shadowMap.enabled = !1, t.shadowMap.autoUpdate = !1, t.setRenderTarget(this.renderTarget), t.state.buffers.depth.setMask(!0), t.clear(), t.render(i, this.virtualCamera);
|
|
172
|
+
} finally {
|
|
173
|
+
t.setRenderTarget(n), t.xr.enabled = l, t.shadowMap.enabled = d, t.shadowMap.autoUpdate = u;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
setRenderSize(t, i) {
|
|
177
|
+
this.renderTarget.setSize(t, i), this.material.uniforms.resolution.value.set(t, i);
|
|
178
|
+
}
|
|
179
|
+
// Radius is in world units; the outer 65% fades before the square mesh edge.
|
|
180
|
+
setRadius(t, i, r = this.material.uniforms.groundCenter.value) {
|
|
181
|
+
this.scale.setScalar(t * 2 / this.geometry.parameters.width), this.position.x = r.x, this.position.y = r.y, this.material.uniforms.groundCenter.value.set(r.x, r.y), this.material.uniforms.gridScale.value = i, this.material.uniforms.maxRadius.value = t, this.material.uniforms.fadeSoftness.value = t * 0.65;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
const g = {
|
|
185
|
+
light: {
|
|
186
|
+
background: p.light,
|
|
187
|
+
fineGrid: 5859168,
|
|
188
|
+
coarseGrid: 3427136,
|
|
189
|
+
gridOpacity: 0.85,
|
|
190
|
+
reflectionMix: 0.06
|
|
191
|
+
},
|
|
192
|
+
dark: {
|
|
193
|
+
background: p.dark,
|
|
194
|
+
fineGrid: 7375236,
|
|
195
|
+
coarseGrid: 5552554,
|
|
196
|
+
gridOpacity: 0.9,
|
|
197
|
+
reflectionMix: 0.06
|
|
198
|
+
}
|
|
199
|
+
}, P = {
|
|
200
|
+
simulation: 0.68,
|
|
201
|
+
model: 1.4
|
|
202
|
+
};
|
|
203
|
+
function C(c) {
|
|
204
|
+
const e = /* @__PURE__ */ new Set(), t = /* @__PURE__ */ new Set(), i = /* @__PURE__ */ new Set(), r = /* @__PURE__ */ new Set();
|
|
205
|
+
c.traverse((s) => {
|
|
206
|
+
var l;
|
|
207
|
+
const n = s;
|
|
208
|
+
n.geometry && e.add(n.geometry);
|
|
209
|
+
for (const u of Array.isArray(n.material) ? n.material : [n.material])
|
|
210
|
+
if (u) {
|
|
211
|
+
t.add(u);
|
|
212
|
+
for (const d of Object.values(u)) {
|
|
213
|
+
if (!S(d)) continue;
|
|
214
|
+
i.add(d);
|
|
215
|
+
const h = (l = d.source) == null ? void 0 : l.data;
|
|
216
|
+
h && typeof h.close == "function" && r.add(h);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
for (const s of e) s.dispose();
|
|
221
|
+
for (const s of t) s.dispose();
|
|
222
|
+
for (const s of i) s.dispose();
|
|
223
|
+
for (const s of r) s.close();
|
|
224
|
+
}
|
|
225
|
+
function S(c) {
|
|
226
|
+
return !!(c && typeof c == "object" && c.isTexture);
|
|
227
|
+
}
|
|
228
|
+
const f = 2213822, G = 6000111, R = 6;
|
|
229
|
+
function L(c, e, t) {
|
|
230
|
+
e.updateMatrixWorld();
|
|
231
|
+
const i = new o.Vector3();
|
|
232
|
+
return e.getWorldDirection(i).normalize(), c.setFromNormalAndCoplanarPoint(i, t);
|
|
233
|
+
}
|
|
234
|
+
class F {
|
|
235
|
+
constructor(e, t = "dark", i, r = "simulation") {
|
|
236
|
+
a(this, "root", new o.Group());
|
|
237
|
+
a(this, "reflector", new w({ size: 100, textureWidth: 256, textureHeight: 256 }));
|
|
238
|
+
a(this, "values");
|
|
239
|
+
a(this, "fog");
|
|
240
|
+
a(this, "raycaster", new o.Raycaster());
|
|
241
|
+
a(this, "pointer", new o.Vector2());
|
|
242
|
+
a(this, "dragPlane", new o.Plane());
|
|
243
|
+
a(this, "dragTarget", new o.Vector3());
|
|
244
|
+
a(this, "dragIntersection", new o.Vector3());
|
|
245
|
+
a(this, "dragOffset", new o.Vector3());
|
|
246
|
+
a(this, "bodyGroups", /* @__PURE__ */ new Map());
|
|
247
|
+
a(this, "auxiliaries", /* @__PURE__ */ new Set());
|
|
248
|
+
a(this, "forceLine");
|
|
249
|
+
a(this, "forceBoosted", !1);
|
|
250
|
+
a(this, "grabCanvas", null);
|
|
251
|
+
a(this, "previousCursor", "");
|
|
252
|
+
a(this, "size", "");
|
|
253
|
+
a(this, "groundVisible");
|
|
254
|
+
a(this, "disposed", !1);
|
|
255
|
+
this.model = e, this.runtime = i, this.presentation = r, this.values = g[t];
|
|
256
|
+
const s = this.values, n = new o.Box3().setFromObject(e), l = Math.max(...n.getSize(new o.Vector3()).toArray());
|
|
257
|
+
if (!Number.isFinite(l) || l <= 0) throw new Error("Empty simulation geometry.");
|
|
258
|
+
this.root.add(e), this.forceLine = this.createForceLine(), this.root.add(this.forceLine), e.traverse((m) => {
|
|
259
|
+
m instanceof o.Mesh && m.layers.enable(x);
|
|
260
|
+
}), this.root.add(this.reflector);
|
|
261
|
+
const u = Math.max(n.getSize(new o.Vector3()).length() * 0.5, 0.02), d = this.reflector.material.uniforms;
|
|
262
|
+
d.fineGridColor.value.setHex(s.fineGrid), d.coarseGridColor.value.setHex(s.coarseGrid), d.gridOpacity.value = s.gridOpacity, d.reflectionMix.value = s.reflectionMix, this.layoutGround(n, u), this.groundVisible = r === "simulation", this.setGroundVisible(this.groundVisible);
|
|
263
|
+
const h = u / Math.sin(o.MathUtils.degToRad(38) / 2) * 1.25;
|
|
264
|
+
this.fog = new o.Fog(s.background, h * 2.5, h * 8);
|
|
265
|
+
}
|
|
266
|
+
setTheme(e) {
|
|
267
|
+
if (this.disposed) return;
|
|
268
|
+
const t = this.values = g[e], i = this.reflector.material.uniforms;
|
|
269
|
+
i.fineGridColor.value.setHex(t.fineGrid), i.coarseGridColor.value.setHex(t.coarseGrid), i.gridOpacity.value = t.gridOpacity, i.reflectionMix.value = t.reflectionMix, this.fog.color.setHex(t.background);
|
|
270
|
+
}
|
|
271
|
+
layoutGround(e, t) {
|
|
272
|
+
this.reflector.setRadius(t * 8, Math.pow(10, Math.floor(Math.log10(Math.max(t, 0.01)))), e.getCenter(new o.Vector3()));
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Re-fits the ground disc and reflection to the model's current world bounds.
|
|
276
|
+
* Model previews call this after re-orienting the asset's authored up axis:
|
|
277
|
+
* an axis-aligned bounding box is not rotation invariant, so the floor that
|
|
278
|
+
* was sized to a wide-flat footprint can end up clipping an upright model.
|
|
279
|
+
*/
|
|
280
|
+
reseatGround() {
|
|
281
|
+
if (this.disposed) return;
|
|
282
|
+
this.root.updateMatrixWorld(!0);
|
|
283
|
+
const e = new o.Box3().setFromObject(this.model);
|
|
284
|
+
e.isEmpty() || this.layoutGround(e, Math.max(e.getSize(new o.Vector3()).length() * 0.5, 0.02));
|
|
285
|
+
}
|
|
286
|
+
createForceLine() {
|
|
287
|
+
const e = new o.BufferGeometry().setFromPoints([
|
|
288
|
+
new o.Vector3(),
|
|
289
|
+
new o.Vector3()
|
|
290
|
+
]), t = new o.LineBasicMaterial({
|
|
291
|
+
color: f,
|
|
292
|
+
depthTest: !1,
|
|
293
|
+
transparent: !0
|
|
294
|
+
}), i = new o.Line(e, t);
|
|
295
|
+
return i.renderOrder = 1e3, i.visible = !1, i;
|
|
296
|
+
}
|
|
297
|
+
findBodyGroup(e) {
|
|
298
|
+
var i;
|
|
299
|
+
let t = e;
|
|
300
|
+
for (; t && t !== this.model && t !== this.root; ) {
|
|
301
|
+
if (typeof ((i = t.userData) == null ? void 0 : i.bodyId) == "number") return t;
|
|
302
|
+
t = t.parent;
|
|
303
|
+
}
|
|
304
|
+
return null;
|
|
305
|
+
}
|
|
306
|
+
getBodyGroup(e) {
|
|
307
|
+
let t = this.bodyGroups.get(e);
|
|
308
|
+
return t || this.model.traverse((i) => {
|
|
309
|
+
var r;
|
|
310
|
+
((r = i.userData) == null ? void 0 : r.bodyId) === e && (t = i, this.bodyGroups.set(e, i));
|
|
311
|
+
}), t;
|
|
312
|
+
}
|
|
313
|
+
pointerRay(e, t, i) {
|
|
314
|
+
const r = i.getBoundingClientRect();
|
|
315
|
+
this.pointer.set(
|
|
316
|
+
(e.clientX - r.left) / r.width * 2 - 1,
|
|
317
|
+
-((e.clientY - r.top) / r.height) * 2 + 1
|
|
318
|
+
), this.raycaster.setFromCamera(this.pointer, t);
|
|
319
|
+
}
|
|
320
|
+
setForceBoost(e) {
|
|
321
|
+
var t;
|
|
322
|
+
!((t = this.runtime) != null && t.grab) || e === this.forceBoosted || (this.forceBoosted = e, this.runtime.updateGrabStrength(e ? R : 1), this.forceLine.material.color.setHex(e ? G : f));
|
|
323
|
+
}
|
|
324
|
+
beginGrab(e, t, i) {
|
|
325
|
+
if (!this.runtime || this.disposed) return !1;
|
|
326
|
+
this.pointerRay(e, t, i);
|
|
327
|
+
const r = this.raycaster.intersectObject(this.model, !0).find((u) => u.object.isMesh);
|
|
328
|
+
if (!r) return !1;
|
|
329
|
+
const s = this.findBodyGroup(r.object);
|
|
330
|
+
if (!s) return !1;
|
|
331
|
+
const n = s.worldToLocal(r.point.clone());
|
|
332
|
+
this.dragTarget.copy(r.point), L(this.dragPlane, t, r.point), this.dragOffset.set(0, 0, 0);
|
|
333
|
+
const l = this.root.worldToLocal(r.point.clone());
|
|
334
|
+
return this.bodyGroups.set(s.userData.bodyId, s), this.runtime.beginGrab({
|
|
335
|
+
bodyId: s.userData.bodyId,
|
|
336
|
+
localPoint: [n.x, n.y, n.z],
|
|
337
|
+
target: [l.x, l.y, l.z]
|
|
338
|
+
}), this.forceBoosted = !1, this.setForceBoost(e.shiftKey), this.forceLine.visible = !0, this.updateForceLine(), this.grabCanvas = i, i != null && i.style && (this.previousCursor = i.style.cursor, i.style.cursor = "grabbing"), !0;
|
|
339
|
+
}
|
|
340
|
+
moveGrab(e, t, i) {
|
|
341
|
+
var s;
|
|
342
|
+
if (!((s = this.runtime) != null && s.grab)) return;
|
|
343
|
+
if (this.pointerRay(e, t, i), this.setForceBoost(e.shiftKey), i != null && i.style && i.style.cursor !== "grabbing" && (i.style.cursor = "grabbing"), this.raycaster.ray.intersectPlane(this.dragPlane, this.dragIntersection))
|
|
344
|
+
this.dragTarget.copy(this.dragIntersection).add(this.dragOffset);
|
|
345
|
+
else
|
|
346
|
+
return;
|
|
347
|
+
const r = this.root.worldToLocal(this.dragTarget.clone());
|
|
348
|
+
this.runtime.updateGrabTarget([r.x, r.y, r.z]), this.updateForceLine();
|
|
349
|
+
}
|
|
350
|
+
endGrab() {
|
|
351
|
+
var e;
|
|
352
|
+
this.runtime && (this.runtime.endGrab(), this.forceBoosted = !1, this.forceLine.visible = !1, this.forceLine.material.color.setHex(f), (e = this.grabCanvas) != null && e.style && (this.grabCanvas.style.cursor = this.previousCursor), this.grabCanvas = null);
|
|
353
|
+
}
|
|
354
|
+
updateForceLine() {
|
|
355
|
+
var l;
|
|
356
|
+
const e = (l = this.runtime) == null ? void 0 : l.grab;
|
|
357
|
+
if (!e) return;
|
|
358
|
+
const t = this.getBodyGroup(e.bodyId);
|
|
359
|
+
if (!t) return;
|
|
360
|
+
const i = new o.Vector3().fromArray(e.localPoint), r = t.localToWorld(i), s = this.root.worldToLocal(r), n = this.forceLine.geometry.attributes.position;
|
|
361
|
+
n.setXYZ(0, s.x, s.y, s.z), n.setXYZ(1, e.target[0], e.target[1], e.target[2]), n.needsUpdate = !0;
|
|
362
|
+
}
|
|
363
|
+
beforeRender(e, t, i) {
|
|
364
|
+
var n;
|
|
365
|
+
const r = {
|
|
366
|
+
tone: e.toneMapping,
|
|
367
|
+
exposure: e.toneMappingExposure,
|
|
368
|
+
color: e.outputColorSpace,
|
|
369
|
+
environment: t.environment,
|
|
370
|
+
fog: t.fog,
|
|
371
|
+
background: t.background
|
|
372
|
+
}, s = () => {
|
|
373
|
+
e.toneMapping = r.tone, e.toneMappingExposure = r.exposure, e.outputColorSpace = r.color, t.environment = r.environment, t.fog = r.fog, t.background = r.background;
|
|
374
|
+
};
|
|
375
|
+
if (this.disposed) return s;
|
|
376
|
+
try {
|
|
377
|
+
(n = this.runtime) != null && n.grab && this.updateForceLine(), e.toneMapping = o.ACESFilmicToneMapping, e.toneMappingExposure = P[this.presentation], e.outputColorSpace = o.SRGBColorSpace, t.background = new o.Color(this.values.background), t.fog = this.fog;
|
|
378
|
+
const l = e.getSize(new o.Vector2()), u = `${l.x}:${l.y}`;
|
|
379
|
+
return u !== this.size && (this.size = u, this.reflector.setRenderSize(Math.max(1, Math.floor(l.x * 0.35)), Math.max(1, Math.floor(l.y * 0.35)))), t.updateMatrixWorld(!0), i.updateMatrixWorld(!0), this.groundVisible && i instanceof o.PerspectiveCamera && this.reflector.renderReflection(e, t, i), s;
|
|
380
|
+
} catch (l) {
|
|
381
|
+
throw s(), l;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* The reflector mesh carries both the grid lines and the reflection. Hiding
|
|
386
|
+
* it also skips the reflection render pass, which only feeds its shader.
|
|
387
|
+
*/
|
|
388
|
+
setGroundVisible(e) {
|
|
389
|
+
this.groundVisible = e, this.reflector.visible = e;
|
|
390
|
+
}
|
|
391
|
+
getGroundVisible() {
|
|
392
|
+
return this.groundVisible;
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Adds a debug/auxiliary object next to the model rather than inside it.
|
|
396
|
+
* The model subtree is what the reflector pass and `getModelBounds` measure,
|
|
397
|
+
* so nesting hidden aids (collision meshes, which are far larger than the
|
|
398
|
+
* visual shell) would inflate both the reflection extent and the camera fit.
|
|
399
|
+
*/
|
|
400
|
+
attachAuxiliary(e) {
|
|
401
|
+
this.auxiliaries.add(e), this.root.add(e);
|
|
402
|
+
}
|
|
403
|
+
getModelBounds() {
|
|
404
|
+
this.root.updateMatrixWorld(!0);
|
|
405
|
+
const e = new o.Box3().setFromObject(this.model);
|
|
406
|
+
if (!e.isEmpty()) return e;
|
|
407
|
+
const t = new o.Box3();
|
|
408
|
+
return t.min.set(-5e3, -5e3, -5e3), t.max.set(5e3, 5e3, 5e3), t;
|
|
409
|
+
}
|
|
410
|
+
dispose() {
|
|
411
|
+
if (!this.disposed) {
|
|
412
|
+
this.disposed = !0, this.endGrab(), this.model.removeFromParent();
|
|
413
|
+
for (const e of this.auxiliaries) e.removeFromParent();
|
|
414
|
+
this.auxiliaries.clear(), this.root.removeFromParent(), this.reflector.renderTarget.dispose(), C(this.root);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
export {
|
|
419
|
+
F as S,
|
|
420
|
+
C as d
|
|
421
|
+
};
|
package/dist/types.d.ts
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import type { Box3, ColorRepresentation, Object3D, Vector3 } from 'three';
|
|
2
|
-
import type { CadViewerCapability, CameraStateStore, ViewerUiOptions } from './cad/types';
|
|
3
|
-
|
|
2
|
+
import type { CadViewerCapability, CameraStateStore, ViewerUiOptions, ViewerUiTheme } from './cad/types';
|
|
3
|
+
import type { AssetChangeEvent, AssetControlChangeEvent, AssetErrorEvent, AssetPreview, AssetSource, OpenAssetOptions, ViewerAssetOptions } from './assets/types';
|
|
4
|
+
export type { CadBlockModel, CadDocumentHandle, CadDocumentUnits, CadFontResolver, CadFontRequest, CadResolvedFont, CadResolvedTextFont, CadTextWarmupOptions, CadHudModel, CadHudSnapshot, CadInspectorModel, CadInspectorSnapshot, CadLayerModel, CadLayerRow, CadBlockUsageRow, CadSessionPhase, CadWorldBounds, CadScaleRulerState, CadInsertDetails, CadInsertSelection, CadInsertSelectionId, CadTextDetails, CadTextSelection, CadTextSelectionId, CadSelection, CadHit, CadViewerSnapshot, CadLoadProgress, CadViewerErrorCode, CadViewerErrorEvent, CadLoadSource, CadOpenOptions, CadSessionLoadTiming, RenderDebugBreakdownEntry, SplitBlockLayerDetail, CadViewerCapability, ResolveTextFont, CadViewerEventMap, CameraStateStore, ViewerCadUiKeyboardOptions, ViewerUiOptions, ViewerCadUiParts, ViewerCadUiOptions, ViewerUiPreset, ViewerCadUiStateStore, ViewerUiTheme, ViewerUiTokens, } from './cad/types';
|
|
4
5
|
export type ViewerViewMode = '2d' | '3d';
|
|
5
6
|
export type CadInteractionMode = 'managed' | 'manual' | 'disabled';
|
|
7
|
+
/**
|
|
8
|
+
* Which 3D navigation implementation the runtime drives.
|
|
9
|
+
* `viewer` is the CAD path; `preview` is the model/simulation particle viewer
|
|
10
|
+
* matching sim-studio. Kept as its own union so the viewer's public surface
|
|
11
|
+
* does not re-export the runtime package's type.
|
|
12
|
+
*/
|
|
13
|
+
export type ViewerNavigationPolicy = 'legacy' | 'viewer' | 'preview';
|
|
6
14
|
export type CameraChangeReason = 'pointer' | 'wheel' | 'fit' | 'restore' | 'api' | 'view-mode';
|
|
7
15
|
export type ViewerEnvironment = 'room' | {
|
|
8
16
|
/** Load an external equirectangular HDR texture for image-based lighting. */
|
|
@@ -72,6 +80,8 @@ export interface ViewerOptions {
|
|
|
72
80
|
/** Max delay for merged viewport demands while the interaction is active. Default 160ms. */
|
|
73
81
|
viewportDemandCoalesceMs?: number;
|
|
74
82
|
ui?: ViewerUiOptions;
|
|
83
|
+
assets?: ViewerAssetOptions;
|
|
84
|
+
onCleanupError?: (event: AssetErrorEvent) => void;
|
|
75
85
|
}
|
|
76
86
|
export interface ViewerFitViewOptions {
|
|
77
87
|
padding?: number;
|
|
@@ -126,6 +136,9 @@ export interface ViewerEventMap {
|
|
|
126
136
|
'view-mode-change': {
|
|
127
137
|
viewMode: ViewerViewMode;
|
|
128
138
|
};
|
|
139
|
+
'theme-change': {
|
|
140
|
+
theme: ViewerUiTheme;
|
|
141
|
+
};
|
|
129
142
|
resize: {
|
|
130
143
|
resized: boolean;
|
|
131
144
|
};
|
|
@@ -156,6 +169,9 @@ export interface ViewerEventMap {
|
|
|
156
169
|
layerPanelOpen: boolean;
|
|
157
170
|
propertyPanelOpen: boolean;
|
|
158
171
|
};
|
|
172
|
+
'asset-change': AssetChangeEvent;
|
|
173
|
+
'asset-error': AssetErrorEvent;
|
|
174
|
+
'asset-control-change': AssetControlChangeEvent;
|
|
159
175
|
}
|
|
160
176
|
export interface Viewer {
|
|
161
177
|
readonly viewport: HTMLElement;
|
|
@@ -184,12 +200,16 @@ export interface Viewer {
|
|
|
184
200
|
execute(id: string, args?: unknown): boolean;
|
|
185
201
|
has(id: string): boolean;
|
|
186
202
|
};
|
|
203
|
+
openAsset(source: AssetSource, options?: OpenAssetOptions): AssetPreview;
|
|
204
|
+
closeAsset(): Promise<void>;
|
|
187
205
|
addObject(object: Object3D, options?: ViewerObjectOptions): void;
|
|
188
206
|
removeObject(object: Object3D): boolean;
|
|
189
207
|
setVisible(object: Object3D, visible: boolean): void;
|
|
190
208
|
setViewMode(mode: ViewerViewMode, options?: {
|
|
191
209
|
preserveOrbit?: boolean;
|
|
192
210
|
}): void;
|
|
211
|
+
/** Switches the UI and active preview stage theme at runtime. */
|
|
212
|
+
setTheme(theme: ViewerUiTheme): boolean;
|
|
193
213
|
fitView(target?: Object3D | Box3, options?: ViewerFitViewOptions): boolean;
|
|
194
214
|
fitAll(options?: ViewerFitViewOptions): boolean;
|
|
195
215
|
screenToWorldOnPlane(clientX: number, clientY: number, planeZ?: number): Vector3 | null;
|
|
@@ -199,6 +219,8 @@ export interface Viewer {
|
|
|
199
219
|
on<K extends keyof ViewerEventMap>(type: K, listener: (event: ViewerEventMap[K]) => void): () => void;
|
|
200
220
|
resize(): boolean;
|
|
201
221
|
requestRender(): void;
|
|
222
|
+
getActiveCamera(): import('three').Camera;
|
|
223
|
+
setNavigationEnabled(enabled: boolean): void;
|
|
202
224
|
dispose(): void;
|
|
203
225
|
use(plugins: readonly import('./plugins').ViewerPlugin[], options?: {
|
|
204
226
|
replace?: boolean;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { ViewerCadUiOptions } from '../cad/types';
|
|
2
|
+
/** Theme shared by every package-owned UI group. */
|
|
3
|
+
export type ViewerUiTheme = 'dark' | 'light';
|
|
4
|
+
/** Which built-in UI groups the viewer registers. */
|
|
5
|
+
export type ViewerUiPreset = 'auto' | 'cad-readonly' | 'none';
|
|
6
|
+
/** Options for the built-in model/simulation scene UI group. */
|
|
7
|
+
export interface ViewerSceneUiOptions {
|
|
8
|
+
parts?: ViewerSceneUiParts;
|
|
9
|
+
}
|
|
10
|
+
export interface ViewerSceneUiParts {
|
|
11
|
+
filename?: boolean;
|
|
12
|
+
playback?: boolean;
|
|
13
|
+
reset?: boolean;
|
|
14
|
+
fit?: boolean;
|
|
15
|
+
upAxis?: boolean;
|
|
16
|
+
ground?: boolean;
|
|
17
|
+
collision?: boolean;
|
|
18
|
+
theme?: boolean;
|
|
19
|
+
}
|
|
20
|
+
/** Shared UI configuration; asset-specific controls live in their named groups. */
|
|
21
|
+
export interface ViewerUiOptions {
|
|
22
|
+
root: HTMLElement;
|
|
23
|
+
preset?: ViewerUiPreset;
|
|
24
|
+
/** Single initial theme source; built-in buttons switch it internally at runtime. */
|
|
25
|
+
theme?: ViewerUiTheme;
|
|
26
|
+
tokens?: ViewerUiTokens;
|
|
27
|
+
style?: string | ((root: ShadowRoot) => void);
|
|
28
|
+
locale?: string;
|
|
29
|
+
messages?: Readonly<Record<string, string>>;
|
|
30
|
+
messageResolver?: (key: string, params?: Readonly<Record<string, string | number>>) => string | undefined;
|
|
31
|
+
/** Defaults to the viewport; 'none' only broadcasts layout changes. */
|
|
32
|
+
insetTarget?: HTMLElement | 'none';
|
|
33
|
+
cad?: ViewerCadUiOptions;
|
|
34
|
+
/** Shared scene controls for model and simulation assets, gated by capabilities. */
|
|
35
|
+
scene?: ViewerSceneUiOptions;
|
|
36
|
+
}
|
|
37
|
+
export interface ViewerUiTokens {
|
|
38
|
+
accent?: string;
|
|
39
|
+
panelBackground?: string;
|
|
40
|
+
background?: string;
|
|
41
|
+
text?: string;
|
|
42
|
+
textDim?: string;
|
|
43
|
+
border?: string;
|
|
44
|
+
hudBackground?: string;
|
|
45
|
+
}
|