@d5techs/3dgs-lib 1.4.44 → 1.4.46
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/dist/3dgs-lib.cjs +96 -21
- package/dist/3dgs-lib.cjs.map +1 -1
- package/dist/3dgs-lib.js +96 -21
- package/dist/3dgs-lib.js.map +1 -1
- package/dist/App.d.ts +1 -0
- package/dist/core/OrbitControls.d.ts +2 -0
- package/dist/core/SkyboxRenderer.d.ts +5 -3
- package/package.json +1 -1
package/dist/3dgs-lib.js
CHANGED
|
@@ -737,7 +737,7 @@ const _OrbitControls = class _OrbitControls {
|
|
|
737
737
|
*/
|
|
738
738
|
panByScreenDelta(deltaX, deltaY) {
|
|
739
739
|
const { right, up } = this.getCameraAxes();
|
|
740
|
-
const scale = this.panSpeed * this.
|
|
740
|
+
const scale = this.panSpeed * this.getEffectiveZoomDist();
|
|
741
741
|
const dx = -deltaX * scale;
|
|
742
742
|
const dy = deltaY * scale;
|
|
743
743
|
if (this.enableDamping) {
|
|
@@ -825,7 +825,7 @@ const _OrbitControls = class _OrbitControls {
|
|
|
825
825
|
const m = this.camera.viewMatrix;
|
|
826
826
|
const right = [m[0], m[4], m[8]];
|
|
827
827
|
const forward = [-m[2], -m[6], -m[10]];
|
|
828
|
-
const speed = this.moveSpeed * this.
|
|
828
|
+
const speed = this.moveSpeed * this.getEffectiveZoomDist();
|
|
829
829
|
let dx = 0, dy = 0, dz = 0;
|
|
830
830
|
if (this.pressedKeys.has("w") || this.pressedKeys.has("arrowup")) {
|
|
831
831
|
dx += forward[0] * speed;
|
|
@@ -960,7 +960,7 @@ const _OrbitControls = class _OrbitControls {
|
|
|
960
960
|
const deltaX = currentCenter.x - this.lastTouchCenter.x;
|
|
961
961
|
const deltaY = currentCenter.y - this.lastTouchCenter.y;
|
|
962
962
|
const { right, up } = this.getCameraAxes();
|
|
963
|
-
const scale = this.touchPanSpeed * this.
|
|
963
|
+
const scale = this.touchPanSpeed * this.getEffectiveZoomDist();
|
|
964
964
|
const dx = -deltaX * scale;
|
|
965
965
|
const dy = deltaY * scale;
|
|
966
966
|
if (this.enableDamping) {
|
|
@@ -1013,6 +1013,12 @@ const _OrbitControls = class _OrbitControls {
|
|
|
1013
1013
|
this.camera.position[2] = this.camera.target[2] + this.distance * sinPhi * cosTheta;
|
|
1014
1014
|
this.camera.updateMatrix();
|
|
1015
1015
|
}
|
|
1016
|
+
get modelCenter() {
|
|
1017
|
+
return [this._modelCenter[0], this._modelCenter[1], this._modelCenter[2]];
|
|
1018
|
+
}
|
|
1019
|
+
get modelRadius() {
|
|
1020
|
+
return this.zoomDistanceCap;
|
|
1021
|
+
}
|
|
1016
1022
|
/**
|
|
1017
1023
|
* 旋转速度缩放:当 target 远离模型时降低旋转灵敏度,
|
|
1018
1024
|
* 使模型在屏幕上的视觉运动速度保持一致。
|
|
@@ -2097,6 +2103,7 @@ struct Uniforms {
|
|
|
2097
2103
|
col0: vec4<f32>,
|
|
2098
2104
|
col1: vec4<f32>,
|
|
2099
2105
|
col2: vec4<f32>,
|
|
2106
|
+
extra: vec4<f32>,
|
|
2100
2107
|
};
|
|
2101
2108
|
|
|
2102
2109
|
@group(0) @binding(0) var<uniform> u: Uniforms;
|
|
@@ -2108,6 +2115,12 @@ struct VSOut {
|
|
|
2108
2115
|
@location(0) dir: vec3<f32>,
|
|
2109
2116
|
};
|
|
2110
2117
|
|
|
2118
|
+
fn rotateX(d: vec3<f32>, angle: f32) -> vec3<f32> {
|
|
2119
|
+
let c = cos(angle);
|
|
2120
|
+
let s = sin(angle);
|
|
2121
|
+
return vec3<f32>(d.x, c * d.y - s * d.z, s * d.y + c * d.z);
|
|
2122
|
+
}
|
|
2123
|
+
|
|
2111
2124
|
@vertex
|
|
2112
2125
|
fn vs(@builtin(vertex_index) vi: u32) -> VSOut {
|
|
2113
2126
|
let positions = array<vec2<f32>, 3>(
|
|
@@ -2119,15 +2132,17 @@ fn vs(@builtin(vertex_index) vi: u32) -> VSOut {
|
|
|
2119
2132
|
let p = positions[vi];
|
|
2120
2133
|
out.position = vec4<f32>(p, 0.0, 1.0);
|
|
2121
2134
|
|
|
2122
|
-
// col0.w = 1/proj[0] (aspect*tan(fov/2)), col1.w = 1/proj[5] (tan(fov/2))
|
|
2123
2135
|
let eyeDir = vec3<f32>(p.x * u.col0.w, p.y * u.col1.w, -1.0);
|
|
2124
2136
|
|
|
2125
|
-
|
|
2126
|
-
out.dir = vec3<f32>(
|
|
2137
|
+
var worldDir = vec3<f32>(
|
|
2127
2138
|
dot(u.col0.xyz, eyeDir),
|
|
2128
2139
|
dot(u.col1.xyz, eyeDir),
|
|
2129
2140
|
dot(u.col2.xyz, eyeDir),
|
|
2130
2141
|
);
|
|
2142
|
+
|
|
2143
|
+
worldDir = rotateX(worldDir, u.extra.x);
|
|
2144
|
+
|
|
2145
|
+
out.dir = worldDir;
|
|
2131
2146
|
return out;
|
|
2132
2147
|
}
|
|
2133
2148
|
|
|
@@ -2145,31 +2160,57 @@ class SkyboxRenderer {
|
|
|
2145
2160
|
__publicField(this, "uniformBuffer");
|
|
2146
2161
|
__publicField(this, "sampler");
|
|
2147
2162
|
__publicField(this, "bindGroupLayout");
|
|
2148
|
-
__publicField(this, "uniformData", new Float32Array(
|
|
2163
|
+
__publicField(this, "uniformData", new Float32Array(16));
|
|
2149
2164
|
__publicField(this, "cubeTexture", null);
|
|
2150
2165
|
__publicField(this, "cubeBindGroup", null);
|
|
2151
2166
|
__publicField(this, "frameReady", false);
|
|
2167
|
+
__publicField(this, "alignToGround", true);
|
|
2152
2168
|
this.device = device;
|
|
2153
2169
|
const shaderModule = device.createShaderModule({ code: WGSL });
|
|
2154
2170
|
this.bindGroupLayout = device.createBindGroupLayout({
|
|
2155
2171
|
entries: [
|
|
2156
|
-
{
|
|
2157
|
-
|
|
2158
|
-
|
|
2172
|
+
{
|
|
2173
|
+
binding: 0,
|
|
2174
|
+
visibility: GPUShaderStage.VERTEX,
|
|
2175
|
+
buffer: { type: "uniform" }
|
|
2176
|
+
},
|
|
2177
|
+
{
|
|
2178
|
+
binding: 1,
|
|
2179
|
+
visibility: GPUShaderStage.FRAGMENT,
|
|
2180
|
+
sampler: { type: "filtering" }
|
|
2181
|
+
},
|
|
2182
|
+
{
|
|
2183
|
+
binding: 2,
|
|
2184
|
+
visibility: GPUShaderStage.FRAGMENT,
|
|
2185
|
+
texture: { sampleType: "float", viewDimension: "cube" }
|
|
2186
|
+
}
|
|
2159
2187
|
]
|
|
2160
2188
|
});
|
|
2161
2189
|
this.pipeline = device.createRenderPipeline({
|
|
2162
|
-
layout: device.createPipelineLayout({
|
|
2190
|
+
layout: device.createPipelineLayout({
|
|
2191
|
+
bindGroupLayouts: [this.bindGroupLayout]
|
|
2192
|
+
}),
|
|
2163
2193
|
vertex: { module: shaderModule, entryPoint: "vs" },
|
|
2164
|
-
fragment: {
|
|
2194
|
+
fragment: {
|
|
2195
|
+
module: shaderModule,
|
|
2196
|
+
entryPoint: "fs",
|
|
2197
|
+
targets: [{ format }]
|
|
2198
|
+
},
|
|
2165
2199
|
primitive: { topology: "triangle-list", cullMode: "none" },
|
|
2166
|
-
depthStencil: {
|
|
2200
|
+
depthStencil: {
|
|
2201
|
+
format: depthFormat,
|
|
2202
|
+
depthWriteEnabled: false,
|
|
2203
|
+
depthCompare: "always"
|
|
2204
|
+
}
|
|
2167
2205
|
});
|
|
2168
2206
|
this.uniformBuffer = device.createBuffer({
|
|
2169
|
-
size:
|
|
2207
|
+
size: 64,
|
|
2170
2208
|
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
|
|
2171
2209
|
});
|
|
2172
|
-
this.sampler = device.createSampler({
|
|
2210
|
+
this.sampler = device.createSampler({
|
|
2211
|
+
magFilter: "linear",
|
|
2212
|
+
minFilter: "linear"
|
|
2213
|
+
});
|
|
2173
2214
|
}
|
|
2174
2215
|
get isActive() {
|
|
2175
2216
|
return this.cubeTexture !== null && this.cubeBindGroup !== null;
|
|
@@ -2179,7 +2220,10 @@ class SkyboxRenderer {
|
|
|
2179
2220
|
const bitmaps = await Promise.all(
|
|
2180
2221
|
faceUrls.map(async (url) => {
|
|
2181
2222
|
const res = await fetch(url);
|
|
2182
|
-
if (!res.ok)
|
|
2223
|
+
if (!res.ok)
|
|
2224
|
+
throw new Error(
|
|
2225
|
+
`SkyboxRenderer: failed to fetch ${url} (${res.status})`
|
|
2226
|
+
);
|
|
2183
2227
|
return createImageBitmap(await res.blob());
|
|
2184
2228
|
})
|
|
2185
2229
|
);
|
|
@@ -2188,7 +2232,9 @@ class SkyboxRenderer {
|
|
|
2188
2232
|
for (let i = 1; i < 6; i++) {
|
|
2189
2233
|
if (bitmaps[i].width !== width || bitmaps[i].height !== height) {
|
|
2190
2234
|
bitmaps.forEach((b) => b.close());
|
|
2191
|
-
throw new Error(
|
|
2235
|
+
throw new Error(
|
|
2236
|
+
"SkyboxRenderer: all cubemap faces must share the same dimensions"
|
|
2237
|
+
);
|
|
2192
2238
|
}
|
|
2193
2239
|
}
|
|
2194
2240
|
const tex = this.device.createTexture({
|
|
@@ -2216,10 +2262,11 @@ class SkyboxRenderer {
|
|
|
2216
2262
|
this.cubeTexture = tex;
|
|
2217
2263
|
}
|
|
2218
2264
|
/**
|
|
2219
|
-
* Write uniforms BEFORE beginFrame().
|
|
2220
|
-
*
|
|
2265
|
+
* Write uniforms BEFORE beginFrame().
|
|
2266
|
+
* pitchOffset: radians to rotate sampling direction around world X axis,
|
|
2267
|
+
* used to align skybox horizon with model ground plane.
|
|
2221
2268
|
*/
|
|
2222
|
-
prepareFrame(viewMatrix, projectionMatrix) {
|
|
2269
|
+
prepareFrame(viewMatrix, projectionMatrix, pitchOffset = 0) {
|
|
2223
2270
|
if (!this.isActive) {
|
|
2224
2271
|
this.frameReady = false;
|
|
2225
2272
|
return;
|
|
@@ -2237,6 +2284,10 @@ class SkyboxRenderer {
|
|
|
2237
2284
|
ud[9] = viewMatrix[9];
|
|
2238
2285
|
ud[10] = viewMatrix[10];
|
|
2239
2286
|
ud[11] = 0;
|
|
2287
|
+
ud[12] = pitchOffset;
|
|
2288
|
+
ud[13] = 0;
|
|
2289
|
+
ud[14] = 0;
|
|
2290
|
+
ud[15] = 0;
|
|
2240
2291
|
this.device.queue.writeBuffer(this.uniformBuffer, 0, ud);
|
|
2241
2292
|
this.frameReady = true;
|
|
2242
2293
|
}
|
|
@@ -18871,7 +18922,26 @@ class App {
|
|
|
18871
18922
|
this.updateAdaptivePerformance();
|
|
18872
18923
|
this.hotspotManager.updateBillboards();
|
|
18873
18924
|
if ((_a2 = this.skyboxRenderer) == null ? void 0 : _a2.isActive) {
|
|
18874
|
-
|
|
18925
|
+
let pitchOffset = 0;
|
|
18926
|
+
if (this.skyboxRenderer.alignToGround) {
|
|
18927
|
+
const cam = this.camera.position;
|
|
18928
|
+
const mc = this.controls.modelCenter;
|
|
18929
|
+
const mr = this.controls.modelRadius;
|
|
18930
|
+
if (mr !== Infinity) {
|
|
18931
|
+
const groundY = mc[1] - mr;
|
|
18932
|
+
const heightAboveGround = cam[1] - groundY;
|
|
18933
|
+
const dx = cam[0] - mc[0];
|
|
18934
|
+
const dz = cam[2] - mc[2];
|
|
18935
|
+
const hDist = Math.sqrt(dx * dx + dz * dz);
|
|
18936
|
+
const raw = Math.atan2(heightAboveGround, Math.max(hDist, 0.01));
|
|
18937
|
+
pitchOffset = Math.max(-1.2, Math.min(1.2, raw));
|
|
18938
|
+
}
|
|
18939
|
+
}
|
|
18940
|
+
this.skyboxRenderer.prepareFrame(
|
|
18941
|
+
this.camera.viewMatrix,
|
|
18942
|
+
this.camera.projectionMatrix,
|
|
18943
|
+
pitchOffset
|
|
18944
|
+
);
|
|
18875
18945
|
}
|
|
18876
18946
|
const pass = this.renderer.beginFrame();
|
|
18877
18947
|
if ((_b2 = this.skyboxRenderer) == null ? void 0 : _b2.isActive) {
|
|
@@ -19063,6 +19133,11 @@ class App {
|
|
|
19063
19133
|
var _a2;
|
|
19064
19134
|
return ((_a2 = this.skyboxRenderer) == null ? void 0 : _a2.isActive) ?? false;
|
|
19065
19135
|
}
|
|
19136
|
+
setSkyboxAlignToGround(value) {
|
|
19137
|
+
if (this.skyboxRenderer) {
|
|
19138
|
+
this.skyboxRenderer.alignToGround = value;
|
|
19139
|
+
}
|
|
19140
|
+
}
|
|
19066
19141
|
// ============================================
|
|
19067
19142
|
// Gizmo(委托给 GizmoManager)
|
|
19068
19143
|
// ============================================
|