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