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