@d5techs/3dgs-lib 1.4.53 → 1.4.55
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 +82 -13
- package/dist/3dgs-lib.cjs.map +1 -1
- package/dist/3dgs-lib.js +82 -13
- package/dist/3dgs-lib.js.map +1 -1
- package/dist/App.d.ts +1 -0
- package/dist/core/SkyboxRenderer.d.ts +3 -1
- package/package.json +1 -1
package/dist/3dgs-lib.cjs
CHANGED
|
@@ -2183,10 +2183,22 @@ function decodeScanline(bytes, pos, width) {
|
|
|
2183
2183
|
}
|
|
2184
2184
|
return { pixels, newPos: pos };
|
|
2185
2185
|
}
|
|
2186
|
+
const f32Buf = new Float32Array(1);
|
|
2187
|
+
const u32Buf = new Uint32Array(f32Buf.buffer);
|
|
2188
|
+
function float32ToFloat16(val) {
|
|
2189
|
+
f32Buf[0] = val;
|
|
2190
|
+
const f = u32Buf[0];
|
|
2191
|
+
const sign = f >> 16 & 32768;
|
|
2192
|
+
const exp = (f >> 23 & 255) - 127 + 15;
|
|
2193
|
+
const frac = f >> 13 & 1023;
|
|
2194
|
+
if (exp <= 0) return sign;
|
|
2195
|
+
if (exp >= 31) return sign | 31744;
|
|
2196
|
+
return sign | exp << 10 | frac;
|
|
2197
|
+
}
|
|
2186
2198
|
const CUBE_WGSL = (
|
|
2187
2199
|
/* wgsl */
|
|
2188
2200
|
`
|
|
2189
|
-
struct Uniforms { col0: vec4<f32>, col1: vec4<f32>, col2: vec4<f32> };
|
|
2201
|
+
struct Uniforms { col0: vec4<f32>, col1: vec4<f32>, col2: vec4<f32>, extra: vec4<f32> };
|
|
2190
2202
|
@group(0) @binding(0) var<uniform> u: Uniforms;
|
|
2191
2203
|
@group(0) @binding(1) var cubeSampler: sampler;
|
|
2192
2204
|
@group(0) @binding(2) var cubeTexture: texture_cube<f32>;
|
|
@@ -2205,12 +2217,17 @@ struct V { @builtin(position) pos: vec4<f32>, @location(0) dir: vec3<f32> };
|
|
|
2205
2217
|
const EQUIRECT_WGSL = (
|
|
2206
2218
|
/* wgsl */
|
|
2207
2219
|
`
|
|
2208
|
-
struct Uniforms { col0: vec4<f32>, col1: vec4<f32>, col2: vec4<f32> };
|
|
2220
|
+
struct Uniforms { col0: vec4<f32>, col1: vec4<f32>, col2: vec4<f32>, extra: vec4<f32> };
|
|
2209
2221
|
@group(0) @binding(0) var<uniform> u: Uniforms;
|
|
2210
2222
|
@group(0) @binding(1) var envSampler: sampler;
|
|
2211
2223
|
@group(0) @binding(2) var envTexture: texture_2d<f32>;
|
|
2212
2224
|
struct V { @builtin(position) pos: vec4<f32>, @location(0) dir: vec3<f32> };
|
|
2213
2225
|
const PI: f32 = 3.14159265358979;
|
|
2226
|
+
|
|
2227
|
+
fn dirToUv(d: vec3<f32>) -> vec2<f32> {
|
|
2228
|
+
return vec2(atan2(d.z, d.x) / (2.*PI) + .5, 1. - (asin(clamp(d.y,-1.,1.)) / PI + .5));
|
|
2229
|
+
}
|
|
2230
|
+
|
|
2214
2231
|
@vertex fn vs(@builtin(vertex_index) vi: u32) -> V {
|
|
2215
2232
|
let ps = array<vec2<f32>,3>(vec2(-1.,-1.),vec2(3.,-1.),vec2(-1.,3.));
|
|
2216
2233
|
var o: V; let p = ps[vi]; o.pos = vec4(p, 0., 1.);
|
|
@@ -2218,10 +2235,44 @@ const PI: f32 = 3.14159265358979;
|
|
|
2218
2235
|
o.dir = vec3(dot(u.col0.xyz,e), dot(u.col1.xyz,e), dot(u.col2.xyz,e));
|
|
2219
2236
|
return o;
|
|
2220
2237
|
}
|
|
2238
|
+
|
|
2221
2239
|
@fragment fn fs(i: V) -> @location(0) vec4<f32> {
|
|
2222
2240
|
let d = normalize(i.dir);
|
|
2223
|
-
let
|
|
2224
|
-
let
|
|
2241
|
+
let camY = u.extra.x;
|
|
2242
|
+
let sphereR = u.extra.y;
|
|
2243
|
+
|
|
2244
|
+
// --- sky UV (always computed) ---
|
|
2245
|
+
let skyUv = dirToUv(d);
|
|
2246
|
+
|
|
2247
|
+
// --- ground projection UV (always computed to satisfy uniform control flow) ---
|
|
2248
|
+
// ray-plane intersection: camera at height camY, plane y=0
|
|
2249
|
+
let dySafe = select(d.y, -0.0001, d.y > -0.0001);
|
|
2250
|
+
let t = -camY / dySafe;
|
|
2251
|
+
let hitX = t * d.x;
|
|
2252
|
+
let hitZ = t * d.z;
|
|
2253
|
+
let hitDist2 = hitX * hitX + hitZ * hitZ;
|
|
2254
|
+
let R2 = sphereR * sphereR;
|
|
2255
|
+
// clamp hit to sphere radius to avoid extreme stretching at edges
|
|
2256
|
+
let needClamp = hitDist2 > R2;
|
|
2257
|
+
let clampScale = select(1.0, sphereR / sqrt(max(hitDist2, 0.0001)), needClamp);
|
|
2258
|
+
let pX = hitX * clampScale;
|
|
2259
|
+
let pZ = hitZ * clampScale;
|
|
2260
|
+
// project back onto sphere: y = -sqrt(R^2 - x^2 - z^2)
|
|
2261
|
+
let projY = -sqrt(max(R2 - pX * pX - pZ * pZ, 0.0));
|
|
2262
|
+
let groundDir = normalize(vec3(pX, projY, pZ));
|
|
2263
|
+
let groundUv = dirToUv(groundDir);
|
|
2264
|
+
|
|
2265
|
+
// --- sample both (unconditional = uniform control flow) ---
|
|
2266
|
+
let skyColor = textureSample(envTexture, envSampler, skyUv).rgb;
|
|
2267
|
+
let groundColor = textureSample(envTexture, envSampler, groundUv).rgb;
|
|
2268
|
+
|
|
2269
|
+
// blend near horizon for smooth transition
|
|
2270
|
+
let blend = smoothstep(0.0, -0.08, d.y);
|
|
2271
|
+
let mixed = mix(skyColor, groundColor, blend);
|
|
2272
|
+
let useGround = d.y < 0.0 && camY > 0.01;
|
|
2273
|
+
let c = select(skyColor, mixed, useGround);
|
|
2274
|
+
|
|
2275
|
+
// Reinhard tone mapping + gamma
|
|
2225
2276
|
let mapped = c / (c + vec3(1.));
|
|
2226
2277
|
let gamma = pow(mapped, vec3(1./2.2));
|
|
2227
2278
|
return vec4(gamma, 1.);
|
|
@@ -2232,7 +2283,7 @@ class SkyboxRenderer {
|
|
|
2232
2283
|
__publicField(this, "device");
|
|
2233
2284
|
__publicField(this, "uniformBuffer");
|
|
2234
2285
|
__publicField(this, "sampler");
|
|
2235
|
-
__publicField(this, "uniformData", new Float32Array(
|
|
2286
|
+
__publicField(this, "uniformData", new Float32Array(16));
|
|
2236
2287
|
__publicField(this, "cubePipeline");
|
|
2237
2288
|
__publicField(this, "cubeBindGroupLayout");
|
|
2238
2289
|
__publicField(this, "equirectPipeline");
|
|
@@ -2241,6 +2292,8 @@ class SkyboxRenderer {
|
|
|
2241
2292
|
__publicField(this, "bindGroup", null);
|
|
2242
2293
|
__publicField(this, "frameReady", false);
|
|
2243
2294
|
__publicField(this, "mode", "none");
|
|
2295
|
+
/** Ground projection sphere radius (world units). Larger = ground extends further. */
|
|
2296
|
+
__publicField(this, "groundRadius", 32);
|
|
2244
2297
|
this.device = device;
|
|
2245
2298
|
const depthStencil = {
|
|
2246
2299
|
format: depthFormat,
|
|
@@ -2249,7 +2302,7 @@ class SkyboxRenderer {
|
|
|
2249
2302
|
};
|
|
2250
2303
|
this.cubeBindGroupLayout = device.createBindGroupLayout({
|
|
2251
2304
|
entries: [
|
|
2252
|
-
{ binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: "uniform" } },
|
|
2305
|
+
{ binding: 0, visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT, buffer: { type: "uniform" } },
|
|
2253
2306
|
{ binding: 1, visibility: GPUShaderStage.FRAGMENT, sampler: { type: "filtering" } },
|
|
2254
2307
|
{ binding: 2, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: "float", viewDimension: "cube" } }
|
|
2255
2308
|
]
|
|
@@ -2263,7 +2316,7 @@ class SkyboxRenderer {
|
|
|
2263
2316
|
});
|
|
2264
2317
|
this.equirectBindGroupLayout = device.createBindGroupLayout({
|
|
2265
2318
|
entries: [
|
|
2266
|
-
{ binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: "uniform" } },
|
|
2319
|
+
{ binding: 0, visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT, buffer: { type: "uniform" } },
|
|
2267
2320
|
{ binding: 1, visibility: GPUShaderStage.FRAGMENT, sampler: { type: "filtering" } },
|
|
2268
2321
|
{ binding: 2, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: "float", viewDimension: "2d" } }
|
|
2269
2322
|
]
|
|
@@ -2276,7 +2329,7 @@ class SkyboxRenderer {
|
|
|
2276
2329
|
depthStencil
|
|
2277
2330
|
});
|
|
2278
2331
|
this.uniformBuffer = device.createBuffer({
|
|
2279
|
-
size:
|
|
2332
|
+
size: 64,
|
|
2280
2333
|
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
|
|
2281
2334
|
});
|
|
2282
2335
|
this.sampler = device.createSampler({ magFilter: "linear", minFilter: "linear" });
|
|
@@ -2331,15 +2384,20 @@ class SkyboxRenderer {
|
|
|
2331
2384
|
async loadEquirectangular(url) {
|
|
2332
2385
|
this.clear();
|
|
2333
2386
|
const hdr = await loadHdr(url);
|
|
2387
|
+
const pixelCount = hdr.width * hdr.height * 4;
|
|
2388
|
+
const f16 = new Uint16Array(pixelCount);
|
|
2389
|
+
for (let i = 0; i < pixelCount; i++) {
|
|
2390
|
+
f16[i] = float32ToFloat16(hdr.data[i]);
|
|
2391
|
+
}
|
|
2334
2392
|
const tex = this.device.createTexture({
|
|
2335
2393
|
size: [hdr.width, hdr.height],
|
|
2336
|
-
format: "
|
|
2394
|
+
format: "rgba16float",
|
|
2337
2395
|
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST
|
|
2338
2396
|
});
|
|
2339
2397
|
this.device.queue.writeTexture(
|
|
2340
2398
|
{ texture: tex },
|
|
2341
|
-
|
|
2342
|
-
{ bytesPerRow: hdr.width *
|
|
2399
|
+
f16.buffer,
|
|
2400
|
+
{ bytesPerRow: hdr.width * 8, rowsPerImage: hdr.height },
|
|
2343
2401
|
{ width: hdr.width, height: hdr.height }
|
|
2344
2402
|
);
|
|
2345
2403
|
this.bindGroup = this.device.createBindGroup({
|
|
@@ -2354,7 +2412,7 @@ class SkyboxRenderer {
|
|
|
2354
2412
|
this.mode = "equirect";
|
|
2355
2413
|
}
|
|
2356
2414
|
// ---- common ----
|
|
2357
|
-
prepareFrame(viewMatrix, projectionMatrix) {
|
|
2415
|
+
prepareFrame(viewMatrix, projectionMatrix, cameraPosition) {
|
|
2358
2416
|
if (!this.isActive) {
|
|
2359
2417
|
this.frameReady = false;
|
|
2360
2418
|
return;
|
|
@@ -2372,6 +2430,10 @@ class SkyboxRenderer {
|
|
|
2372
2430
|
ud[9] = viewMatrix[9];
|
|
2373
2431
|
ud[10] = viewMatrix[10];
|
|
2374
2432
|
ud[11] = 0;
|
|
2433
|
+
ud[12] = cameraPosition ? cameraPosition[1] : 0;
|
|
2434
|
+
ud[13] = this.groundRadius;
|
|
2435
|
+
ud[14] = 0;
|
|
2436
|
+
ud[15] = 0;
|
|
2375
2437
|
this.device.queue.writeBuffer(this.uniformBuffer, 0, ud);
|
|
2376
2438
|
this.frameReady = true;
|
|
2377
2439
|
}
|
|
@@ -19008,9 +19070,11 @@ class App {
|
|
|
19008
19070
|
this.updateAdaptivePerformance();
|
|
19009
19071
|
this.hotspotManager.updateBillboards();
|
|
19010
19072
|
if ((_a2 = this.skyboxRenderer) == null ? void 0 : _a2.isActive) {
|
|
19073
|
+
const cam = this.camera.position;
|
|
19011
19074
|
this.skyboxRenderer.prepareFrame(
|
|
19012
19075
|
this.camera.viewMatrix,
|
|
19013
|
-
this.camera.projectionMatrix
|
|
19076
|
+
this.camera.projectionMatrix,
|
|
19077
|
+
[cam[0], cam[1], cam[2]]
|
|
19014
19078
|
);
|
|
19015
19079
|
}
|
|
19016
19080
|
const pass = this.renderer.beginFrame();
|
|
@@ -19205,6 +19269,11 @@ class App {
|
|
|
19205
19269
|
}
|
|
19206
19270
|
await this.skyboxRenderer.loadEquirectangular(url);
|
|
19207
19271
|
}
|
|
19272
|
+
setHdrGroundRadius(radius) {
|
|
19273
|
+
if (this.skyboxRenderer) {
|
|
19274
|
+
this.skyboxRenderer.groundRadius = radius;
|
|
19275
|
+
}
|
|
19276
|
+
}
|
|
19208
19277
|
clearSkybox() {
|
|
19209
19278
|
var _a2;
|
|
19210
19279
|
(_a2 = this.skyboxRenderer) == null ? void 0 : _a2.clear();
|