@d5techs/3dgs-lib 1.4.70 → 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 -258
- package/dist/3dgs-lib.cjs.map +1 -1
- package/dist/3dgs-lib.js +7 -258
- 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,61 +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: camera-centered, height-independent projection ---
|
|
2250
|
-
let dyClamped = min(d.y, -0.0001);
|
|
2251
|
-
let ratio = d.x / dyClamped;
|
|
2252
|
-
let ratioZ = d.z / dyClamped;
|
|
2253
|
-
|
|
2254
|
-
// K = captureH controls ground spread (smaller = more horizon, larger = more nadir)
|
|
2255
|
-
let groundDir = normalize(vec3(-ratio, -captureH, -ratioZ));
|
|
2256
|
-
let groundUv = dirToUv(groundDir);
|
|
2257
|
-
|
|
2258
|
-
// --- sample both (uniform control flow) ---
|
|
2259
|
-
let skyColor = textureSample(envTexture, envSampler, skyUv).rgb;
|
|
2260
|
-
let groundColor = textureSample(envTexture, envSampler, groundUv).rgb;
|
|
2261
|
-
|
|
2262
|
-
// Sharp blend at horizon — cy is always > 0 so no aboveGround check needed
|
|
2263
|
-
let horizonBlend = smoothstep(0.002, -0.002, d.y);
|
|
2264
|
-
let c = mix(skyColor, groundColor, horizonBlend);
|
|
2265
|
-
|
|
2266
|
-
// Reinhard tone mapping + gamma
|
|
2267
|
-
let mapped = c / (c + vec3(1.));
|
|
2268
|
-
let gamma = pow(mapped, vec3(1./2.2));
|
|
2269
|
-
return vec4(gamma, 1.);
|
|
2270
|
-
}`
|
|
2271
|
-
);
|
|
2272
2120
|
class SkyboxRenderer {
|
|
2273
2121
|
constructor(device, format, depthFormat) {
|
|
2274
2122
|
__publicField(this, "device");
|
|
@@ -2277,14 +2125,10 @@ class SkyboxRenderer {
|
|
|
2277
2125
|
__publicField(this, "uniformData", new Float32Array(16));
|
|
2278
2126
|
__publicField(this, "cubePipeline");
|
|
2279
2127
|
__publicField(this, "cubeBindGroupLayout");
|
|
2280
|
-
__publicField(this, "equirectPipeline");
|
|
2281
|
-
__publicField(this, "equirectBindGroupLayout");
|
|
2282
2128
|
__publicField(this, "texture", null);
|
|
2283
2129
|
__publicField(this, "bindGroup", null);
|
|
2284
2130
|
__publicField(this, "frameReady", false);
|
|
2285
|
-
__publicField(this, "
|
|
2286
|
-
/** Virtual HDR capture height (world units). Controls ground texture spread. */
|
|
2287
|
-
__publicField(this, "groundRadius", 50);
|
|
2131
|
+
__publicField(this, "active", false);
|
|
2288
2132
|
this.device = device;
|
|
2289
2133
|
const depthStencil = {
|
|
2290
2134
|
format: depthFormat,
|
|
@@ -2305,20 +2149,6 @@ class SkyboxRenderer {
|
|
|
2305
2149
|
primitive: { topology: "triangle-list", cullMode: "none" },
|
|
2306
2150
|
depthStencil
|
|
2307
2151
|
});
|
|
2308
|
-
this.equirectBindGroupLayout = device.createBindGroupLayout({
|
|
2309
|
-
entries: [
|
|
2310
|
-
{ binding: 0, visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT, buffer: { type: "uniform" } },
|
|
2311
|
-
{ binding: 1, visibility: GPUShaderStage.FRAGMENT, sampler: { type: "filtering" } },
|
|
2312
|
-
{ binding: 2, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: "float", viewDimension: "2d" } }
|
|
2313
|
-
]
|
|
2314
|
-
});
|
|
2315
|
-
this.equirectPipeline = device.createRenderPipeline({
|
|
2316
|
-
layout: device.createPipelineLayout({ bindGroupLayouts: [this.equirectBindGroupLayout] }),
|
|
2317
|
-
vertex: { module: device.createShaderModule({ code: EQUIRECT_WGSL }), entryPoint: "vs" },
|
|
2318
|
-
fragment: { module: device.createShaderModule({ code: EQUIRECT_WGSL }), entryPoint: "fs", targets: [{ format }] },
|
|
2319
|
-
primitive: { topology: "triangle-list", cullMode: "none" },
|
|
2320
|
-
depthStencil
|
|
2321
|
-
});
|
|
2322
2152
|
this.uniformBuffer = device.createBuffer({
|
|
2323
2153
|
size: 64,
|
|
2324
2154
|
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
|
|
@@ -2326,9 +2156,8 @@ class SkyboxRenderer {
|
|
|
2326
2156
|
this.sampler = device.createSampler({ magFilter: "linear", minFilter: "linear" });
|
|
2327
2157
|
}
|
|
2328
2158
|
get isActive() {
|
|
2329
|
-
return this.
|
|
2159
|
+
return this.active && this.texture !== null && this.bindGroup !== null;
|
|
2330
2160
|
}
|
|
2331
|
-
// ---- cubemap ----
|
|
2332
2161
|
async loadCubemap(faceUrls) {
|
|
2333
2162
|
this.clear();
|
|
2334
2163
|
const bitmaps = await Promise.all(
|
|
@@ -2369,41 +2198,9 @@ class SkyboxRenderer {
|
|
|
2369
2198
|
]
|
|
2370
2199
|
});
|
|
2371
2200
|
this.texture = tex;
|
|
2372
|
-
this.
|
|
2373
|
-
}
|
|
2374
|
-
// ---- equirectangular HDR ----
|
|
2375
|
-
async loadEquirectangular(url) {
|
|
2376
|
-
this.clear();
|
|
2377
|
-
const hdr = await loadHdr(url);
|
|
2378
|
-
const pixelCount = hdr.width * hdr.height * 4;
|
|
2379
|
-
const f16 = new Uint16Array(pixelCount);
|
|
2380
|
-
for (let i = 0; i < pixelCount; i++) {
|
|
2381
|
-
f16[i] = float32ToFloat16(hdr.data[i]);
|
|
2382
|
-
}
|
|
2383
|
-
const tex = this.device.createTexture({
|
|
2384
|
-
size: [hdr.width, hdr.height],
|
|
2385
|
-
format: "rgba16float",
|
|
2386
|
-
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST
|
|
2387
|
-
});
|
|
2388
|
-
this.device.queue.writeTexture(
|
|
2389
|
-
{ texture: tex },
|
|
2390
|
-
f16.buffer,
|
|
2391
|
-
{ bytesPerRow: hdr.width * 8, rowsPerImage: hdr.height },
|
|
2392
|
-
{ width: hdr.width, height: hdr.height }
|
|
2393
|
-
);
|
|
2394
|
-
this.bindGroup = this.device.createBindGroup({
|
|
2395
|
-
layout: this.equirectBindGroupLayout,
|
|
2396
|
-
entries: [
|
|
2397
|
-
{ binding: 0, resource: { buffer: this.uniformBuffer } },
|
|
2398
|
-
{ binding: 1, resource: this.sampler },
|
|
2399
|
-
{ binding: 2, resource: tex.createView() }
|
|
2400
|
-
]
|
|
2401
|
-
});
|
|
2402
|
-
this.texture = tex;
|
|
2403
|
-
this.mode = "equirect";
|
|
2201
|
+
this.active = true;
|
|
2404
2202
|
}
|
|
2405
|
-
|
|
2406
|
-
prepareFrame(viewMatrix, projectionMatrix, cameraPosition) {
|
|
2203
|
+
prepareFrame(viewMatrix, projectionMatrix) {
|
|
2407
2204
|
if (!this.isActive) {
|
|
2408
2205
|
this.frameReady = false;
|
|
2409
2206
|
return;
|
|
@@ -2421,17 +2218,12 @@ class SkyboxRenderer {
|
|
|
2421
2218
|
ud[9] = viewMatrix[9];
|
|
2422
2219
|
ud[10] = viewMatrix[10];
|
|
2423
2220
|
ud[11] = 0;
|
|
2424
|
-
ud[12] = cameraPosition ? cameraPosition[0] : 0;
|
|
2425
|
-
ud[13] = cameraPosition ? cameraPosition[1] : 0;
|
|
2426
|
-
ud[14] = cameraPosition ? cameraPosition[2] : 0;
|
|
2427
|
-
ud[15] = this.groundRadius;
|
|
2428
2221
|
this.device.queue.writeBuffer(this.uniformBuffer, 0, ud);
|
|
2429
2222
|
this.frameReady = true;
|
|
2430
2223
|
}
|
|
2431
2224
|
draw(pass) {
|
|
2432
2225
|
if (!this.frameReady || !this.bindGroup) return;
|
|
2433
|
-
|
|
2434
|
-
pass.setPipeline(pipeline);
|
|
2226
|
+
pass.setPipeline(this.cubePipeline);
|
|
2435
2227
|
pass.setBindGroup(0, this.bindGroup);
|
|
2436
2228
|
pass.draw(3);
|
|
2437
2229
|
}
|
|
@@ -2442,7 +2234,7 @@ class SkyboxRenderer {
|
|
|
2442
2234
|
}
|
|
2443
2235
|
this.bindGroup = null;
|
|
2444
2236
|
this.frameReady = false;
|
|
2445
|
-
this.
|
|
2237
|
+
this.active = false;
|
|
2446
2238
|
}
|
|
2447
2239
|
destroy() {
|
|
2448
2240
|
this.clear();
|
|
@@ -19061,36 +18853,9 @@ class App {
|
|
|
19061
18853
|
this.updateAdaptivePerformance();
|
|
19062
18854
|
this.hotspotManager.updateBillboards();
|
|
19063
18855
|
if ((_a2 = this.skyboxRenderer) == null ? void 0 : _a2.isActive) {
|
|
19064
|
-
const cam = this.camera.position;
|
|
19065
|
-
let groundLevel = 0;
|
|
19066
|
-
const gsRendererForGround = this.sceneManager.getGSRenderer();
|
|
19067
|
-
const bbox = (gsRendererForGround == null ? void 0 : gsRendererForGround.getBoundingBox()) ?? null;
|
|
19068
|
-
if (bbox) {
|
|
19069
|
-
const m = gsRendererForGround.getModelMatrix();
|
|
19070
|
-
groundLevel = m[5] * bbox.min[1] + m[13];
|
|
19071
|
-
}
|
|
19072
|
-
if (!this._hdrDebugLogged) {
|
|
19073
|
-
this._hdrDebugLogged = true;
|
|
19074
|
-
console.log(
|
|
19075
|
-
"[HDR Ground Debug]",
|
|
19076
|
-
"hasGsRenderer:",
|
|
19077
|
-
!!gsRendererForGround,
|
|
19078
|
-
"hasBbox:",
|
|
19079
|
-
!!bbox,
|
|
19080
|
-
"bbox:",
|
|
19081
|
-
bbox ? { min: [...bbox.min], max: [...bbox.max], center: [...bbox.center] } : null,
|
|
19082
|
-
"groundLevel:",
|
|
19083
|
-
groundLevel,
|
|
19084
|
-
"cam:",
|
|
19085
|
-
[cam[0].toFixed(2), cam[1].toFixed(2), cam[2].toFixed(2)]
|
|
19086
|
-
);
|
|
19087
|
-
}
|
|
19088
|
-
const camH = cam[1] - groundLevel;
|
|
19089
|
-
this.skyboxRenderer.groundRadius = 0.3;
|
|
19090
18856
|
this.skyboxRenderer.prepareFrame(
|
|
19091
18857
|
this.camera.viewMatrix,
|
|
19092
|
-
this.camera.projectionMatrix
|
|
19093
|
-
[cam[0], camH, cam[2]]
|
|
18858
|
+
this.camera.projectionMatrix
|
|
19094
18859
|
);
|
|
19095
18860
|
}
|
|
19096
18861
|
const pass = this.renderer.beginFrame();
|
|
@@ -19275,21 +19040,6 @@ class App {
|
|
|
19275
19040
|
faceUrls.negZ
|
|
19276
19041
|
]);
|
|
19277
19042
|
}
|
|
19278
|
-
async setHdrBackground(url) {
|
|
19279
|
-
if (!this.skyboxRenderer) {
|
|
19280
|
-
this.skyboxRenderer = new SkyboxRenderer(
|
|
19281
|
-
this.renderer.device,
|
|
19282
|
-
this.renderer.format,
|
|
19283
|
-
"depth24plus"
|
|
19284
|
-
);
|
|
19285
|
-
}
|
|
19286
|
-
await this.skyboxRenderer.loadEquirectangular(url);
|
|
19287
|
-
}
|
|
19288
|
-
setHdrGroundRadius(radius) {
|
|
19289
|
-
if (this.skyboxRenderer) {
|
|
19290
|
-
this.skyboxRenderer.groundRadius = radius;
|
|
19291
|
-
}
|
|
19292
|
-
}
|
|
19293
19043
|
clearSkybox() {
|
|
19294
19044
|
var _a2;
|
|
19295
19045
|
(_a2 = this.skyboxRenderer) == null ? void 0 : _a2.clear();
|
|
@@ -19781,7 +19531,6 @@ exports.exportEditedPLY = exportEditedPLY;
|
|
|
19781
19531
|
exports.getRecommendedDPR = getRecommendedDPR;
|
|
19782
19532
|
exports.isMobileDevice = isMobileDevice;
|
|
19783
19533
|
exports.isWebGPUSupported = isWebGPUSupported;
|
|
19784
|
-
exports.loadHdr = loadHdr;
|
|
19785
19534
|
exports.loadPLY = loadPLY;
|
|
19786
19535
|
exports.loadPLYMobile = loadPLYMobile;
|
|
19787
19536
|
exports.loadSOG = loadSOG;
|