@d5techs/3dgs-lib 1.4.69 → 1.4.71
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 +7 -259
- package/dist/3dgs-lib.cjs.map +1 -1
- package/dist/3dgs-lib.js +7 -259
- package/dist/3dgs-lib.js.map +1 -1
- package/dist/App.d.ts +0 -2
- package/dist/core/SkyboxRenderer.d.ts +2 -7
- package/dist/index.d.ts +0 -2
- package/package.json +1 -1
- package/dist/loaders/HdrLoader.d.ts +0 -6
package/dist/3dgs-lib.cjs
CHANGED
|
@@ -2098,103 +2098,6 @@ class SceneAidsRenderer {
|
|
|
2098
2098
|
this.axesBindGroup = null;
|
|
2099
2099
|
}
|
|
2100
2100
|
}
|
|
2101
|
-
async function loadHdr(url) {
|
|
2102
|
-
const res = await fetch(url);
|
|
2103
|
-
if (!res.ok) throw new Error(`HdrLoader: fetch failed ${url} (${res.status})`);
|
|
2104
|
-
const buf = await res.arrayBuffer();
|
|
2105
|
-
return parseHdr(new Uint8Array(buf));
|
|
2106
|
-
}
|
|
2107
|
-
function parseHdr(bytes) {
|
|
2108
|
-
let pos = 0;
|
|
2109
|
-
const readLine = () => {
|
|
2110
|
-
let line = "";
|
|
2111
|
-
while (pos < bytes.length) {
|
|
2112
|
-
const c = bytes[pos++];
|
|
2113
|
-
if (c === 10) return line;
|
|
2114
|
-
line += String.fromCharCode(c);
|
|
2115
|
-
}
|
|
2116
|
-
return line;
|
|
2117
|
-
};
|
|
2118
|
-
const magic = readLine();
|
|
2119
|
-
if (!magic.startsWith("#?")) throw new Error("HdrLoader: not a Radiance HDR file");
|
|
2120
|
-
while (pos < bytes.length) {
|
|
2121
|
-
const line = readLine();
|
|
2122
|
-
if (line.length === 0) break;
|
|
2123
|
-
}
|
|
2124
|
-
const resLine = readLine();
|
|
2125
|
-
const m = resLine.match(/-Y\s+(\d+)\s+\+X\s+(\d+)/);
|
|
2126
|
-
if (!m) throw new Error("HdrLoader: unsupported resolution format: " + resLine);
|
|
2127
|
-
const height = parseInt(m[1], 10);
|
|
2128
|
-
const width = parseInt(m[2], 10);
|
|
2129
|
-
const rgbe = new Uint8Array(width * height * 4);
|
|
2130
|
-
for (let y = 0; y < height; y++) {
|
|
2131
|
-
const scanline = decodeScanline(bytes, pos, width);
|
|
2132
|
-
pos = scanline.newPos;
|
|
2133
|
-
rgbe.set(scanline.pixels, y * width * 4);
|
|
2134
|
-
}
|
|
2135
|
-
const data = new Float32Array(width * height * 4);
|
|
2136
|
-
for (let i = 0; i < width * height; i++) {
|
|
2137
|
-
const r = rgbe[i * 4];
|
|
2138
|
-
const g = rgbe[i * 4 + 1];
|
|
2139
|
-
const b = rgbe[i * 4 + 2];
|
|
2140
|
-
const e = rgbe[i * 4 + 3];
|
|
2141
|
-
if (e === 0) {
|
|
2142
|
-
data[i * 4] = 0;
|
|
2143
|
-
data[i * 4 + 1] = 0;
|
|
2144
|
-
data[i * 4 + 2] = 0;
|
|
2145
|
-
} else {
|
|
2146
|
-
const scale = Math.pow(2, e - 128 - 8);
|
|
2147
|
-
data[i * 4] = r * scale;
|
|
2148
|
-
data[i * 4 + 1] = g * scale;
|
|
2149
|
-
data[i * 4 + 2] = b * scale;
|
|
2150
|
-
}
|
|
2151
|
-
data[i * 4 + 3] = 1;
|
|
2152
|
-
}
|
|
2153
|
-
return { width, height, data };
|
|
2154
|
-
}
|
|
2155
|
-
function decodeScanline(bytes, pos, width) {
|
|
2156
|
-
const pixels = new Uint8Array(width * 4);
|
|
2157
|
-
if (width < 8 || width > 32767) {
|
|
2158
|
-
for (let i = 0; i < width * 4; i++) pixels[i] = bytes[pos++];
|
|
2159
|
-
return { pixels, newPos: pos };
|
|
2160
|
-
}
|
|
2161
|
-
const b0 = bytes[pos], b1 = bytes[pos + 1], b22 = bytes[pos + 2], b3 = bytes[pos + 3];
|
|
2162
|
-
if (b0 !== 2 || b1 !== 2 || (b22 & 128) !== 0) {
|
|
2163
|
-
for (let i = 0; i < width * 4; i++) pixels[i] = bytes[pos++];
|
|
2164
|
-
return { pixels, newPos: pos };
|
|
2165
|
-
}
|
|
2166
|
-
const lineWidth = b22 << 8 | b3;
|
|
2167
|
-
if (lineWidth !== width) throw new Error("HdrLoader: scanline width mismatch");
|
|
2168
|
-
pos += 4;
|
|
2169
|
-
for (let ch = 0; ch < 4; ch++) {
|
|
2170
|
-
let x = 0;
|
|
2171
|
-
while (x < width) {
|
|
2172
|
-
const code = bytes[pos++];
|
|
2173
|
-
if (code > 128) {
|
|
2174
|
-
const count = code - 128;
|
|
2175
|
-
const val = bytes[pos++];
|
|
2176
|
-
for (let i = 0; i < count; i++) pixels[(x + i) * 4 + ch] = val;
|
|
2177
|
-
x += count;
|
|
2178
|
-
} else {
|
|
2179
|
-
for (let i = 0; i < code; i++) pixels[(x + i) * 4 + ch] = bytes[pos++];
|
|
2180
|
-
x += code;
|
|
2181
|
-
}
|
|
2182
|
-
}
|
|
2183
|
-
}
|
|
2184
|
-
return { pixels, newPos: pos };
|
|
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
|
-
}
|
|
2198
2101
|
const CUBE_WGSL = (
|
|
2199
2102
|
/* wgsl */
|
|
2200
2103
|
`
|
|
@@ -2214,62 +2117,6 @@ struct V { @builtin(position) pos: vec4<f32>, @location(0) dir: vec3<f32> };
|
|
|
2214
2117
|
return vec4(textureSample(cubeTexture, cubeSampler, normalize(i.dir)).rgb, 1.);
|
|
2215
2118
|
}`
|
|
2216
2119
|
);
|
|
2217
|
-
const EQUIRECT_WGSL = (
|
|
2218
|
-
/* wgsl */
|
|
2219
|
-
`
|
|
2220
|
-
struct Uniforms { col0: vec4<f32>, col1: vec4<f32>, col2: vec4<f32>, cam: vec4<f32> };
|
|
2221
|
-
@group(0) @binding(0) var<uniform> u: Uniforms;
|
|
2222
|
-
@group(0) @binding(1) var envSampler: sampler;
|
|
2223
|
-
@group(0) @binding(2) var envTexture: texture_2d<f32>;
|
|
2224
|
-
struct V { @builtin(position) pos: vec4<f32>, @location(0) dir: vec3<f32> };
|
|
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
|
-
|
|
2231
|
-
@vertex fn vs(@builtin(vertex_index) vi: u32) -> V {
|
|
2232
|
-
let ps = array<vec2<f32>,3>(vec2(-1.,-1.),vec2(3.,-1.),vec2(-1.,3.));
|
|
2233
|
-
var o: V; let p = ps[vi]; o.pos = vec4(p, 0., 1.);
|
|
2234
|
-
let e = vec3(p.x*u.col0.w, p.y*u.col1.w, -1.);
|
|
2235
|
-
o.dir = vec3(dot(u.col0.xyz,e), dot(u.col1.xyz,e), dot(u.col2.xyz,e));
|
|
2236
|
-
return o;
|
|
2237
|
-
}
|
|
2238
|
-
|
|
2239
|
-
@fragment fn fs(i: V) -> @location(0) vec4<f32> {
|
|
2240
|
-
let d = normalize(i.dir);
|
|
2241
|
-
let cx = u.cam.x;
|
|
2242
|
-
let cy = max(u.cam.y, 0.1); // clamp: camera always above ground
|
|
2243
|
-
let cz = u.cam.z;
|
|
2244
|
-
let captureH = u.cam.w;
|
|
2245
|
-
|
|
2246
|
-
// --- sky: sample HDR with original direction ---
|
|
2247
|
-
let skyUv = dirToUv(d);
|
|
2248
|
-
|
|
2249
|
-
// --- ground: ray→plane at Y=0, camera-centered (no world XZ offset) ---
|
|
2250
|
-
let dyClamped = min(d.y, -0.0001);
|
|
2251
|
-
let t = -cy / dyClamped;
|
|
2252
|
-
let hitX = t * d.x;
|
|
2253
|
-
let hitZ = t * d.z;
|
|
2254
|
-
|
|
2255
|
-
// Direction from virtual capture point to ground hit point
|
|
2256
|
-
let groundDir = normalize(vec3(hitX, -captureH, hitZ));
|
|
2257
|
-
let groundUv = dirToUv(groundDir);
|
|
2258
|
-
|
|
2259
|
-
// --- sample both (uniform control flow) ---
|
|
2260
|
-
let skyColor = textureSample(envTexture, envSampler, skyUv).rgb;
|
|
2261
|
-
let groundColor = textureSample(envTexture, envSampler, groundUv).rgb;
|
|
2262
|
-
|
|
2263
|
-
// Sharp blend at horizon — cy is always > 0 so no aboveGround check needed
|
|
2264
|
-
let horizonBlend = smoothstep(0.002, -0.002, d.y);
|
|
2265
|
-
let c = mix(skyColor, groundColor, horizonBlend);
|
|
2266
|
-
|
|
2267
|
-
// Reinhard tone mapping + gamma
|
|
2268
|
-
let mapped = c / (c + vec3(1.));
|
|
2269
|
-
let gamma = pow(mapped, vec3(1./2.2));
|
|
2270
|
-
return vec4(gamma, 1.);
|
|
2271
|
-
}`
|
|
2272
|
-
);
|
|
2273
2120
|
class SkyboxRenderer {
|
|
2274
2121
|
constructor(device, format, depthFormat) {
|
|
2275
2122
|
__publicField(this, "device");
|
|
@@ -2278,14 +2125,10 @@ class SkyboxRenderer {
|
|
|
2278
2125
|
__publicField(this, "uniformData", new Float32Array(16));
|
|
2279
2126
|
__publicField(this, "cubePipeline");
|
|
2280
2127
|
__publicField(this, "cubeBindGroupLayout");
|
|
2281
|
-
__publicField(this, "equirectPipeline");
|
|
2282
|
-
__publicField(this, "equirectBindGroupLayout");
|
|
2283
2128
|
__publicField(this, "texture", null);
|
|
2284
2129
|
__publicField(this, "bindGroup", null);
|
|
2285
2130
|
__publicField(this, "frameReady", false);
|
|
2286
|
-
__publicField(this, "
|
|
2287
|
-
/** Virtual HDR capture height (world units). Controls ground texture spread. */
|
|
2288
|
-
__publicField(this, "groundRadius", 50);
|
|
2131
|
+
__publicField(this, "active", false);
|
|
2289
2132
|
this.device = device;
|
|
2290
2133
|
const depthStencil = {
|
|
2291
2134
|
format: depthFormat,
|
|
@@ -2306,20 +2149,6 @@ class SkyboxRenderer {
|
|
|
2306
2149
|
primitive: { topology: "triangle-list", cullMode: "none" },
|
|
2307
2150
|
depthStencil
|
|
2308
2151
|
});
|
|
2309
|
-
this.equirectBindGroupLayout = device.createBindGroupLayout({
|
|
2310
|
-
entries: [
|
|
2311
|
-
{ binding: 0, visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT, buffer: { type: "uniform" } },
|
|
2312
|
-
{ binding: 1, visibility: GPUShaderStage.FRAGMENT, sampler: { type: "filtering" } },
|
|
2313
|
-
{ binding: 2, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: "float", viewDimension: "2d" } }
|
|
2314
|
-
]
|
|
2315
|
-
});
|
|
2316
|
-
this.equirectPipeline = device.createRenderPipeline({
|
|
2317
|
-
layout: device.createPipelineLayout({ bindGroupLayouts: [this.equirectBindGroupLayout] }),
|
|
2318
|
-
vertex: { module: device.createShaderModule({ code: EQUIRECT_WGSL }), entryPoint: "vs" },
|
|
2319
|
-
fragment: { module: device.createShaderModule({ code: EQUIRECT_WGSL }), entryPoint: "fs", targets: [{ format }] },
|
|
2320
|
-
primitive: { topology: "triangle-list", cullMode: "none" },
|
|
2321
|
-
depthStencil
|
|
2322
|
-
});
|
|
2323
2152
|
this.uniformBuffer = device.createBuffer({
|
|
2324
2153
|
size: 64,
|
|
2325
2154
|
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
|
|
@@ -2327,9 +2156,8 @@ class SkyboxRenderer {
|
|
|
2327
2156
|
this.sampler = device.createSampler({ magFilter: "linear", minFilter: "linear" });
|
|
2328
2157
|
}
|
|
2329
2158
|
get isActive() {
|
|
2330
|
-
return this.
|
|
2159
|
+
return this.active && this.texture !== null && this.bindGroup !== null;
|
|
2331
2160
|
}
|
|
2332
|
-
// ---- cubemap ----
|
|
2333
2161
|
async loadCubemap(faceUrls) {
|
|
2334
2162
|
this.clear();
|
|
2335
2163
|
const bitmaps = await Promise.all(
|
|
@@ -2370,41 +2198,9 @@ class SkyboxRenderer {
|
|
|
2370
2198
|
]
|
|
2371
2199
|
});
|
|
2372
2200
|
this.texture = tex;
|
|
2373
|
-
this.
|
|
2374
|
-
}
|
|
2375
|
-
// ---- equirectangular HDR ----
|
|
2376
|
-
async loadEquirectangular(url) {
|
|
2377
|
-
this.clear();
|
|
2378
|
-
const hdr = await loadHdr(url);
|
|
2379
|
-
const pixelCount = hdr.width * hdr.height * 4;
|
|
2380
|
-
const f16 = new Uint16Array(pixelCount);
|
|
2381
|
-
for (let i = 0; i < pixelCount; i++) {
|
|
2382
|
-
f16[i] = float32ToFloat16(hdr.data[i]);
|
|
2383
|
-
}
|
|
2384
|
-
const tex = this.device.createTexture({
|
|
2385
|
-
size: [hdr.width, hdr.height],
|
|
2386
|
-
format: "rgba16float",
|
|
2387
|
-
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST
|
|
2388
|
-
});
|
|
2389
|
-
this.device.queue.writeTexture(
|
|
2390
|
-
{ texture: tex },
|
|
2391
|
-
f16.buffer,
|
|
2392
|
-
{ bytesPerRow: hdr.width * 8, rowsPerImage: hdr.height },
|
|
2393
|
-
{ width: hdr.width, height: hdr.height }
|
|
2394
|
-
);
|
|
2395
|
-
this.bindGroup = this.device.createBindGroup({
|
|
2396
|
-
layout: this.equirectBindGroupLayout,
|
|
2397
|
-
entries: [
|
|
2398
|
-
{ binding: 0, resource: { buffer: this.uniformBuffer } },
|
|
2399
|
-
{ binding: 1, resource: this.sampler },
|
|
2400
|
-
{ binding: 2, resource: tex.createView() }
|
|
2401
|
-
]
|
|
2402
|
-
});
|
|
2403
|
-
this.texture = tex;
|
|
2404
|
-
this.mode = "equirect";
|
|
2201
|
+
this.active = true;
|
|
2405
2202
|
}
|
|
2406
|
-
|
|
2407
|
-
prepareFrame(viewMatrix, projectionMatrix, cameraPosition) {
|
|
2203
|
+
prepareFrame(viewMatrix, projectionMatrix) {
|
|
2408
2204
|
if (!this.isActive) {
|
|
2409
2205
|
this.frameReady = false;
|
|
2410
2206
|
return;
|
|
@@ -2422,17 +2218,12 @@ class SkyboxRenderer {
|
|
|
2422
2218
|
ud[9] = viewMatrix[9];
|
|
2423
2219
|
ud[10] = viewMatrix[10];
|
|
2424
2220
|
ud[11] = 0;
|
|
2425
|
-
ud[12] = cameraPosition ? cameraPosition[0] : 0;
|
|
2426
|
-
ud[13] = cameraPosition ? cameraPosition[1] : 0;
|
|
2427
|
-
ud[14] = cameraPosition ? cameraPosition[2] : 0;
|
|
2428
|
-
ud[15] = this.groundRadius;
|
|
2429
2221
|
this.device.queue.writeBuffer(this.uniformBuffer, 0, ud);
|
|
2430
2222
|
this.frameReady = true;
|
|
2431
2223
|
}
|
|
2432
2224
|
draw(pass) {
|
|
2433
2225
|
if (!this.frameReady || !this.bindGroup) return;
|
|
2434
|
-
|
|
2435
|
-
pass.setPipeline(pipeline);
|
|
2226
|
+
pass.setPipeline(this.cubePipeline);
|
|
2436
2227
|
pass.setBindGroup(0, this.bindGroup);
|
|
2437
2228
|
pass.draw(3);
|
|
2438
2229
|
}
|
|
@@ -2443,7 +2234,7 @@ class SkyboxRenderer {
|
|
|
2443
2234
|
}
|
|
2444
2235
|
this.bindGroup = null;
|
|
2445
2236
|
this.frameReady = false;
|
|
2446
|
-
this.
|
|
2237
|
+
this.active = false;
|
|
2447
2238
|
}
|
|
2448
2239
|
destroy() {
|
|
2449
2240
|
this.clear();
|
|
@@ -19062,36 +18853,9 @@ class App {
|
|
|
19062
18853
|
this.updateAdaptivePerformance();
|
|
19063
18854
|
this.hotspotManager.updateBillboards();
|
|
19064
18855
|
if ((_a2 = this.skyboxRenderer) == null ? void 0 : _a2.isActive) {
|
|
19065
|
-
const cam = this.camera.position;
|
|
19066
|
-
let groundLevel = 0;
|
|
19067
|
-
const gsRendererForGround = this.sceneManager.getGSRenderer();
|
|
19068
|
-
const bbox = (gsRendererForGround == null ? void 0 : gsRendererForGround.getBoundingBox()) ?? null;
|
|
19069
|
-
if (bbox) {
|
|
19070
|
-
const m = gsRendererForGround.getModelMatrix();
|
|
19071
|
-
groundLevel = m[5] * bbox.min[1] + m[13];
|
|
19072
|
-
}
|
|
19073
|
-
if (!this._hdrDebugLogged) {
|
|
19074
|
-
this._hdrDebugLogged = true;
|
|
19075
|
-
console.log(
|
|
19076
|
-
"[HDR Ground Debug]",
|
|
19077
|
-
"hasGsRenderer:",
|
|
19078
|
-
!!gsRendererForGround,
|
|
19079
|
-
"hasBbox:",
|
|
19080
|
-
!!bbox,
|
|
19081
|
-
"bbox:",
|
|
19082
|
-
bbox ? { min: [...bbox.min], max: [...bbox.max], center: [...bbox.center] } : null,
|
|
19083
|
-
"groundLevel:",
|
|
19084
|
-
groundLevel,
|
|
19085
|
-
"cam:",
|
|
19086
|
-
[cam[0].toFixed(2), cam[1].toFixed(2), cam[2].toFixed(2)]
|
|
19087
|
-
);
|
|
19088
|
-
}
|
|
19089
|
-
const camH = cam[1] - groundLevel;
|
|
19090
|
-
this.skyboxRenderer.groundRadius = 50;
|
|
19091
18856
|
this.skyboxRenderer.prepareFrame(
|
|
19092
18857
|
this.camera.viewMatrix,
|
|
19093
|
-
this.camera.projectionMatrix
|
|
19094
|
-
[cam[0], camH, cam[2]]
|
|
18858
|
+
this.camera.projectionMatrix
|
|
19095
18859
|
);
|
|
19096
18860
|
}
|
|
19097
18861
|
const pass = this.renderer.beginFrame();
|
|
@@ -19276,21 +19040,6 @@ class App {
|
|
|
19276
19040
|
faceUrls.negZ
|
|
19277
19041
|
]);
|
|
19278
19042
|
}
|
|
19279
|
-
async setHdrBackground(url) {
|
|
19280
|
-
if (!this.skyboxRenderer) {
|
|
19281
|
-
this.skyboxRenderer = new SkyboxRenderer(
|
|
19282
|
-
this.renderer.device,
|
|
19283
|
-
this.renderer.format,
|
|
19284
|
-
"depth24plus"
|
|
19285
|
-
);
|
|
19286
|
-
}
|
|
19287
|
-
await this.skyboxRenderer.loadEquirectangular(url);
|
|
19288
|
-
}
|
|
19289
|
-
setHdrGroundRadius(radius) {
|
|
19290
|
-
if (this.skyboxRenderer) {
|
|
19291
|
-
this.skyboxRenderer.groundRadius = radius;
|
|
19292
|
-
}
|
|
19293
|
-
}
|
|
19294
19043
|
clearSkybox() {
|
|
19295
19044
|
var _a2;
|
|
19296
19045
|
(_a2 = this.skyboxRenderer) == null ? void 0 : _a2.clear();
|
|
@@ -19782,7 +19531,6 @@ exports.exportEditedPLY = exportEditedPLY;
|
|
|
19782
19531
|
exports.getRecommendedDPR = getRecommendedDPR;
|
|
19783
19532
|
exports.isMobileDevice = isMobileDevice;
|
|
19784
19533
|
exports.isWebGPUSupported = isWebGPUSupported;
|
|
19785
|
-
exports.loadHdr = loadHdr;
|
|
19786
19534
|
exports.loadPLY = loadPLY;
|
|
19787
19535
|
exports.loadPLYMobile = loadPLYMobile;
|
|
19788
19536
|
exports.loadSOG = loadSOG;
|