From cbc5551312992d3e822ed1eae1db9d39659918bd Mon Sep 17 00:00:00 2001 From: Patrick Ryan Date: Fri, 26 Jun 2026 11:49:51 -0700 Subject: [PATCH 1/2] feat(standard): opt-in skeleton/vcolor/uvOffset deform features + in-code scene231 (port onto upstream #300) Reuses the validated integration of the Standard skeleton, vertex-color and uvOffset deform features onto the current upstream base (0a556d36, #300), plus the in-code scene231 parity scene (programmatic bone animation, MAD 0.000). Branches cleanly off upstream (yesterday's local commit is not an ancestor). Byte-neutrality: the enableStandard* opt-ins are exposed via the deep module path (babylon-lite/material/standard/enable-standard-mesh-features.js), NOT re-exported through the index.ts barrel. Re-exporting through the barrel perturbed Rollup/terser export-name mangling in shared chunks, adding ~10 bytes to every scene (incl. non-Standard scenes); the deep import keeps index.ts byte-identical to upstream so non-feature scenes don't shift. The remaining ~0.1KB shift on a few Standard scenes is the inherent terser shift from the in-pipeline hooks (folds the feature code, but the source edit nudges mangling) and is offset by the fog optimization in the next commit. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- lab/lite/babylon-ref-scene231.html | 15 ++ lab/lite/bundle-scene231.html | 16 ++ lab/lite/scene231.html | 16 ++ lab/lite/src/bjs/scene231.ts | 122 +++++++++ lab/lite/src/lite/scene231.ts | 102 ++++++++ lab/lite/src/shared/scene231-skin.ts | 236 ++++++++++++++++++ .../pbr/fragments/skeleton-fragment.ts | 74 +----- .../standard/enable-standard-mesh-features.ts | 53 ++++ .../fragments/std-skeleton-fragment.ts | 56 +++++ .../fragments/std-vertex-color-fragment.ts | 44 ++++ .../src/material/standard/standard-flags.ts | 16 +- .../standard/standard-geometry-renderable.ts | 24 +- .../standard/standard-group-builder.ts | 33 +++ .../material/standard/standard-material.ts | 5 + .../material/standard/standard-pipeline.ts | 26 +- .../material/standard/standard-renderable.ts | 60 ++++- .../material/standard/std-feature-hooks.ts | 34 +++ .../src/shader/fragments/skeleton-fragment.ts | 78 ++++++ scene-config.json | 9 + .../scene231-standard-deform-features.spec.ts | 31 +++ 20 files changed, 962 insertions(+), 88 deletions(-) create mode 100644 lab/lite/babylon-ref-scene231.html create mode 100644 lab/lite/bundle-scene231.html create mode 100644 lab/lite/scene231.html create mode 100644 lab/lite/src/bjs/scene231.ts create mode 100644 lab/lite/src/lite/scene231.ts create mode 100644 lab/lite/src/shared/scene231-skin.ts create mode 100644 packages/babylon-lite/src/material/standard/enable-standard-mesh-features.ts create mode 100644 packages/babylon-lite/src/material/standard/fragments/std-skeleton-fragment.ts create mode 100644 packages/babylon-lite/src/material/standard/fragments/std-vertex-color-fragment.ts create mode 100644 packages/babylon-lite/src/material/standard/std-feature-hooks.ts create mode 100644 packages/babylon-lite/src/shader/fragments/skeleton-fragment.ts create mode 100644 tests/lite/parity/scenes/scene231-standard-deform-features.spec.ts diff --git a/lab/lite/babylon-ref-scene231.html b/lab/lite/babylon-ref-scene231.html new file mode 100644 index 0000000000..caa4d8d9a9 --- /dev/null +++ b/lab/lite/babylon-ref-scene231.html @@ -0,0 +1,15 @@ + + + + + BJS Reference — Scene 231: StandardMaterial Deform Features + + + + + + + diff --git a/lab/lite/bundle-scene231.html b/lab/lite/bundle-scene231.html new file mode 100644 index 0000000000..9d5748d212 --- /dev/null +++ b/lab/lite/bundle-scene231.html @@ -0,0 +1,16 @@ + + + + + Babylon Lite — Scene 231: StandardMaterial Deform Features (Bundle) + + + + + + + + diff --git a/lab/lite/scene231.html b/lab/lite/scene231.html new file mode 100644 index 0000000000..ec3d810363 --- /dev/null +++ b/lab/lite/scene231.html @@ -0,0 +1,16 @@ + + + + + Babylon Lite — Scene 231: StandardMaterial Deform Features + + + + + + + + diff --git a/lab/lite/src/bjs/scene231.ts b/lab/lite/src/bjs/scene231.ts new file mode 100644 index 0000000000..3bcca27619 --- /dev/null +++ b/lab/lite/src/bjs/scene231.ts @@ -0,0 +1,122 @@ +// BJS reference for Scene 231 — StandardMaterial deform features (per-vertex +// color + skeletal skinning + UV offset) on an in-code beam with programmatically +// animated bones. Mirrors lab/lite/src/lite/scene231.ts exactly: the geometry, +// vertex colors, skin weights, checker texture, and per-frame bone matrices all +// come from the shared engine-agnostic module so the two engines stay in lockstep. + +import { ArcRotateCamera } from "@babylonjs/core/Cameras/arcRotateCamera"; +import { WebGPUEngine } from "@babylonjs/core/Engines/webgpuEngine"; +import { HemisphericLight } from "@babylonjs/core/Lights/hemisphericLight"; +import "@babylonjs/core/Materials/standardMaterial"; +import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial"; +import { RawTexture } from "@babylonjs/core/Materials/Textures/rawTexture"; +import { Texture } from "@babylonjs/core/Materials/Textures/texture"; +import { Color3, Color4 } from "@babylonjs/core/Maths/math.color"; +import { Matrix, Vector3 } from "@babylonjs/core/Maths/math.vector"; +import { Mesh } from "@babylonjs/core/Meshes/mesh"; +import { VertexData } from "@babylonjs/core/Meshes/mesh.vertexData"; +import { Bone } from "@babylonjs/core/Bones/bone"; +import { Skeleton } from "@babylonjs/core/Bones/skeleton"; +import { Scene } from "@babylonjs/core/scene"; +import { boneMatrixData, buildBeamData, buildCheckerPixels, CHECKER_SIZE, UV_OFFSET } from "../shared/scene231-skin.js"; + +(async function () { + const __initStart = performance.now(); + const canvas = document.getElementById("renderCanvas") as HTMLCanvasElement; + const engine = new WebGPUEngine(canvas, { antialias: true, adaptToDeviceRatio: true }); + await engine.initAsync(); + engine.displayLoadingUI = function () {}; + + const scene = new Scene(engine); + scene.clearColor = new Color4(0.145, 0.165, 0.21, 1); + + const camera = new ArcRotateCamera("camera", -Math.PI / 2, 1.1, 5.5, new Vector3(0, 0, 0), scene); + camera.fov = 0.72; + camera.minZ = 0.1; + camera.maxZ = 100; + camera.attachControl(canvas, true); + scene.activeCamera = camera; + + const light = new HemisphericLight("hemi", new Vector3(0, 1, 0), scene); + light.intensity = 0.9; + + const beam = buildBeamData(); + + // Build the mesh from the shared geometry, including per-vertex color and skin attributes. + const mesh = new Mesh("scene231-beam", scene); + const vd = new VertexData(); + vd.positions = beam.positions; + vd.normals = beam.normals; + vd.uvs = beam.uvs; + vd.colors = beam.colors; + vd.indices = beam.indices; + vd.matricesIndices = Array.from(beam.joints); + vd.matricesWeights = Array.from(beam.weights); + vd.applyToMesh(mesh); + mesh.numBoneInfluencers = 4; + mesh.hasVertexAlpha = false; + mesh.useVertexColors = true; + + // Two independent bones (root + upper), bound at identity so the per-frame + // local matrices become the skin palette directly (matching Lite's bone texture). + const skeleton = new Skeleton("scene231-skeleton", "scene231-skeleton", scene); + const root = new Bone("root", skeleton, null, Matrix.Identity()); + const upper = new Bone("upper", skeleton, null, Matrix.Identity()); + mesh.skeleton = skeleton; + + const checker = RawTexture.CreateRGBATexture(buildCheckerPixels(), CHECKER_SIZE, CHECKER_SIZE, scene, false, false, Texture.NEAREST_SAMPLINGMODE); + checker.wrapU = Texture.WRAP_ADDRESSMODE; + checker.wrapV = Texture.WRAP_ADDRESSMODE; + checker.uOffset = UV_OFFSET[0]; + checker.vOffset = UV_OFFSET[1]; + + const material = new StandardMaterial("scene231-mat", scene); + material.diffuseColor = new Color3(1, 1, 1); + material.diffuseTexture = checker; + mesh.material = material; + + // Per-frame programmatic bone animation: recompute the bone matrices as a pure + // function of the frame index and push them as the bones' local transforms. + const boneData = boneMatrixData(0); + const m0 = Matrix.Identity(); + const m1 = Matrix.Identity(); + const params = new URLSearchParams(window.location.search); + const seek = parseFloat(params.get("seekTime") || ""); + const freezeFrame = isNaN(seek) ? -1 : Math.round(seek * 60); + let frame = 0; + let frozen = false; + + const applyBones = (): void => { + Matrix.FromArrayToRef(boneData, 0, m0); + Matrix.FromArrayToRef(boneData, 16, m1); + root.updateMatrix(m0, false, true); + upper.updateMatrix(m1, false, true); + }; + applyBones(); + + scene.onBeforeRenderObservable.add(() => { + if (frozen) { + return; + } + frame++; + boneMatrixData(frame, boneData); + applyBones(); + if (freezeFrame >= 0 && frame >= freezeFrame) { + frozen = true; + canvas.dataset.animationFrozen = "true"; + } + }); + + engine.getDeltaTime = function () { + return 16; + }; + scene.useConstantAnimationDeltaTime = true; + + await scene.whenReadyAsync(); + engine.runRenderLoop(() => scene.render()); + window.addEventListener("resize", () => engine.resize()); + + await new Promise((resolve) => scene.onAfterRenderObservable.addOnce(() => resolve())); + canvas.dataset.initMs = String(performance.now() - __initStart); + canvas.dataset.ready = "true"; +})().catch(console.error); diff --git a/lab/lite/src/lite/scene231.ts b/lab/lite/src/lite/scene231.ts new file mode 100644 index 0000000000..b99683d670 --- /dev/null +++ b/lab/lite/src/lite/scene231.ts @@ -0,0 +1,102 @@ +// Scene 231 — StandardMaterial deform features (in-code, no glTF): +// per-vertex color + skeletal skinning + UV offset on a procedurally built beam, +// with bones animated programmatically (per-frame updates, no animation system). +// +// The beam is a tall box (4 vertically-subdivided side faces + caps) skinned to a +// 2-bone skeleton: a fixed root bone and an upper bone that swings about the beam +// origin. The pose is a pure function of the frame index, so freezing at a known +// frame (via ?seekTime) is deterministic and matches the Babylon.js reference. + +import { + addToScene, + attachControl, + createArcRotateCamera, + createEngine, + createHemisphericLight, + createSceneContext, + createStandardMaterial, + createTexture2DFromPixels, + onBeforeRender, + registerScene, + startEngine, +} from "babylon-lite"; +import type { ArcRotateCamera } from "babylon-lite"; +import { enableStandardSkeleton, enableStandardUvOffset, enableStandardVertexColor } from "babylon-lite/material/standard/enable-standard-mesh-features.js"; +import { createMeshFromData } from "babylon-lite/mesh/mesh-factories.js"; +import { createSkeleton } from "babylon-lite/skeleton/create-skeleton.js"; +import { boneMatrixData, buildBeamData, buildCheckerPixels, CHECKER_SIZE, SKELETON_BONE_COUNT, UV_OFFSET } from "../shared/scene231-skin.js"; + +async function main(): Promise { + const __initStart = performance.now(); + const canvas = document.getElementById("renderCanvas") as HTMLCanvasElement; + const engine = await createEngine(canvas); + const scene = createSceneContext(engine); + scene.clearColor = { r: 0.145, g: 0.165, b: 0.21, a: 1 }; + + // Opt in to the Standard deform/vertex features used by this scene. Plain + // Standard scenes that never call these stay byte-identical to upstream. + enableStandardVertexColor(); + enableStandardSkeleton(); + enableStandardUvOffset(); + + const camera = createArcRotateCamera(-Math.PI / 2, 1.1, 5.5, { x: 0, y: 0, z: 0 }); + camera.fov = 0.72; + camera.nearPlane = 0.1; + camera.farPlane = 100; + scene.camera = camera; + attachControl(camera as ArcRotateCamera, canvas, scene); + + addToScene(scene, createHemisphericLight([0, 1, 0], 0.9)); + + const beam = buildBeamData(); + const mesh = createMeshFromData(engine, "scene231-beam", beam.positions, beam.normals, beam.indices, beam.uvs, undefined, undefined, beam.colors); + + const material = createStandardMaterial(); + material.diffuseColor = [1, 1, 1]; + material.diffuseTexture = createTexture2DFromPixels(engine, buildCheckerPixels(), CHECKER_SIZE, CHECKER_SIZE, { addressModeU: "repeat", addressModeV: "repeat" }); + material.uvOffset = UV_OFFSET; + mesh.material = material; + + const boneData = boneMatrixData(0); + mesh.skeleton = createSkeleton(engine, beam.joints, beam.weights, SKELETON_BONE_COUNT, boneData); + addToScene(scene, mesh); + + // Per-frame programmatic bone animation: recompute the bone matrices as a pure + // function of the frame index and re-upload them to the skeleton's bone texture. + const boneTexWidth = SKELETON_BONE_COUNT * 4; + const boneTexture = mesh.skeleton.boneTexture; + scene.fixedDeltaMs = 16.0; + + const params = new URLSearchParams(window.location.search); + const seek = parseFloat(params.get("seekTime") || ""); + const freezeFrame = isNaN(seek) ? -1 : Math.round(seek * 60); + let frame = 0; + let frozen = false; + + onBeforeRender(scene, () => { + if (frozen) { + return; + } + frame++; + boneMatrixData(frame, boneData); + engine._device.queue.writeTexture({ texture: boneTexture }, boneData.buffer as ArrayBuffer, { bytesPerRow: boneTexWidth * 16 }, { width: boneTexWidth, height: 1 }); + if (freezeFrame >= 0 && frame >= freezeFrame) { + frozen = true; + canvas.dataset.animationFrozen = "true"; + } + }); + + await registerScene(scene); + await startEngine(engine); + canvas.dataset.drawCalls = String(engine.drawCallCount); + canvas.dataset.initMs = String(performance.now() - __initStart); + canvas.dataset.ready = "true"; +} + +main().catch((error: unknown) => { + const canvas = document.getElementById("renderCanvas") as HTMLCanvasElement | null; + if (canvas) { + canvas.dataset.error = error instanceof Error ? error.message : String(error); + } + console.error(error); +}); diff --git a/lab/lite/src/shared/scene231-skin.ts b/lab/lite/src/shared/scene231-skin.ts new file mode 100644 index 0000000000..ec790febf0 --- /dev/null +++ b/lab/lite/src/shared/scene231-skin.ts @@ -0,0 +1,236 @@ +// Shared, engine-agnostic data for Scene 231 (StandardMaterial deform features: +// per-vertex color + skeletal skinning + UV offset, with programmatically +// animated bones). +// +// Both the Lite scene (scene231.ts) and the Babylon.js reference (bjs/scene231.ts) +// import this module so the geometry, per-vertex colors, skin weights, checker +// texture, and per-frame bone matrices are byte-for-byte identical. Nothing here +// depends on either engine — only plain typed arrays — so neither bundle pulls in +// the other engine, and parity is guaranteed by construction. + +/** Procedural beam mesh: 4 vertically-subdivided side faces + 2 end caps. */ +export interface BeamData { + positions: Float32Array; // xyz per vertex + normals: Float32Array; // xyz per vertex + uvs: Float32Array; // uv per vertex + indices: Uint32Array; + colors: Float32Array; // rgba per vertex + joints: Uint16Array; // 4 bone indices per vertex + weights: Float32Array; // 4 bone weights per vertex + vertexCount: number; +} + +const HALF_W = 0.25; // half width (x) +const HALF_D = 0.25; // half depth (z) +const HALF_H = 1.0; // half height (y) -> beam spans y in [-1, 1] +const SEGMENTS = 16; // height subdivisions per side face (smooth bend) +const BONE_COUNT = 2; + +/** Normalized height 0..1 (bottom..top) from a y in [-HALF_H, HALF_H]. */ +function heightT(y: number): number { + return (y + HALF_H) / (2 * HALF_H); +} + +/** Smooth bone-1 (upper) influence as a function of normalized height. + * Bottom ~20% rides the root bone; top ~20% rides the upper bone; smooth between. */ +function upperWeight(t: number): number { + const k = (t - 0.2) / 0.6; + const c = k < 0 ? 0 : k > 1 ? 1 : k; + return c * c * (3 - 2 * c); // smoothstep +} + +/** A simple bottom->top rainbow so the bend reads clearly. */ +function heightColor(t: number, out: Float32Array, o: number): void { + // HSV-ish sweep red -> green -> blue across the height. + const h = t; // 0..1 + const r = Math.max(0, 1 - Math.abs(h - 0.0) * 2); + const g = Math.max(0, 1 - Math.abs(h - 0.5) * 2); + const b = Math.max(0, 1 - Math.abs(h - 1.0) * 2); + out[o] = 0.25 + 0.75 * r; + out[o + 1] = 0.25 + 0.75 * g; + out[o + 2] = 0.25 + 0.75 * b; + out[o + 3] = 1; +} + +/** Build the beam geometry + per-vertex color + skin weights. */ +export function buildBeamData(): BeamData { + const positions: number[] = []; + const normals: number[] = []; + const uvs: number[] = []; + const colors: number[] = []; + const joints: number[] = []; + const weights: number[] = []; + const indices: number[] = []; + + const pushVertex = (x: number, y: number, z: number, nx: number, ny: number, nz: number, u: number, v: number): void => { + positions.push(x, y, z); + normals.push(nx, ny, nz); + uvs.push(u, v); + const t = heightT(y); + const c = new Float32Array(4); + heightColor(t, c, 0); + colors.push(c[0]!, c[1]!, c[2]!, c[3]!); + const w1 = upperWeight(t); + const w0 = 1 - w1; + joints.push(0, 1, 0, 0); + weights.push(w0, w1, 0, 0); + }; + + // Four side faces, each a vertical strip subdivided SEGMENTS times. + // Each face: outward normal, two columns (the face's two vertical edges). + interface Face { + // corner a (left edge) and b (right edge) in the XZ plane, plus outward normal + ax: number; + az: number; + bx: number; + bz: number; + nx: number; + nz: number; + } + const faces: Face[] = [ + { ax: -HALF_W, az: HALF_D, bx: HALF_W, bz: HALF_D, nx: 0, nz: 1 }, // +Z + { ax: HALF_W, az: HALF_D, bx: HALF_W, bz: -HALF_D, nx: 1, nz: 0 }, // +X + { ax: HALF_W, az: -HALF_D, bx: -HALF_W, bz: -HALF_D, nx: 0, nz: -1 }, // -Z + { ax: -HALF_W, az: -HALF_D, bx: -HALF_W, bz: HALF_D, nx: -1, nz: 0 }, // -X + ]; + + for (const f of faces) { + const base = positions.length / 3; + for (let i = 0; i <= SEGMENTS; i++) { + const v = i / SEGMENTS; + const y = -HALF_H + v * (2 * HALF_H); + pushVertex(f.ax, y, f.az, f.nx, 0, f.nz, 0, v); + pushVertex(f.bx, y, f.bz, f.nx, 0, f.nz, 1, v); + } + for (let i = 0; i < SEGMENTS; i++) { + const a = base + i * 2; + const b = a + 1; + const c = a + 2; + const d = a + 3; + indices.push(a, c, b, b, c, d); + } + } + + // End caps (single quads). Winding chosen so the outward normal faces ±Y. + const addCap = (y: number, ny: number): void => { + const base = positions.length / 3; + const corners: [number, number][] = [ + [-HALF_W, -HALF_D], + [HALF_W, -HALF_D], + [HALF_W, HALF_D], + [-HALF_W, HALF_D], + ]; + for (const [x, z] of corners) { + pushVertex(x, y, z, 0, ny, 0, x / (2 * HALF_W) + 0.5, z / (2 * HALF_D) + 0.5); + } + if (ny > 0) { + indices.push(base, base + 1, base + 2, base, base + 2, base + 3); + } else { + indices.push(base, base + 2, base + 1, base, base + 3, base + 2); + } + }; + addCap(HALF_H, 1); + addCap(-HALF_H, -1); + + return { + positions: new Float32Array(positions), + normals: new Float32Array(normals), + uvs: new Float32Array(uvs), + indices: new Uint32Array(indices), + colors: new Float32Array(colors), + joints: new Uint16Array(joints), + weights: new Float32Array(weights), + vertexCount: positions.length / 3, + }; +} + +export const SKELETON_BONE_COUNT = BONE_COUNT; + +/** Animation period (frames) and swing amplitude (radians) for the upper bone. */ +const PERIOD_FRAMES = 120; +const SWING_AMPLITUDE = 0.6; + +/** Bend angle (radians) of the upper bone at a given frame — a pure function of + * the frame index, so both engines reproduce the identical pose when frozen. */ +export function bendAngle(frame: number): number { + return SWING_AMPLITUDE * Math.sin((frame / PERIOD_FRAMES) * Math.PI * 2); +} + +/** Per-frame bone matrices as a packed Float32Array (BONE_COUNT * 16), in + * Babylon row-major layout (translation at indices 12,13,14 of each block). + * Bone 0 = identity (root). Bone 1 = rotation about Z by bendAngle, pivoting at + * the beam origin (y = 0), so the upper part swings side to side. */ +export function boneMatrixData(frame: number, out?: Float32Array): Float32Array { + const m = out ?? new Float32Array(BONE_COUNT * 16); + // Bone 0: identity + m[0] = 1; + m[1] = 0; + m[2] = 0; + m[3] = 0; + m[4] = 0; + m[5] = 1; + m[6] = 0; + m[7] = 0; + m[8] = 0; + m[9] = 0; + m[10] = 1; + m[11] = 0; + m[12] = 0; + m[13] = 0; + m[14] = 0; + m[15] = 1; + // Bone 1: rotation about Z (Babylon RotationZ row-major layout) + const a = bendAngle(frame); + const c = Math.cos(a); + const s = Math.sin(a); + m[16] = c; + m[17] = s; + m[18] = 0; + m[19] = 0; + m[20] = -s; + m[21] = c; + m[22] = 0; + m[23] = 0; + m[24] = 0; + m[25] = 0; + m[26] = 1; + m[27] = 0; + m[28] = 0; + m[29] = 0; + m[30] = 0; + m[31] = 1; + return m; +} + +// ---- Checker texture (for the UV-offset feature) --------------------------- + +export const CHECKER_SIZE = 256; +const CHECKER_CELLS = 8; + +/** A grey/orange checker, RGBA8, CHECKER_SIZE square. Identical pixels feed both + * engines so the UV-offset shift compares exactly. */ +export function buildCheckerPixels(): Uint8Array { + const n = CHECKER_SIZE; + const data = new Uint8Array(n * n * 4); + const cell = n / CHECKER_CELLS; + for (let y = 0; y < n; y++) { + for (let x = 0; x < n; x++) { + const odd = ((Math.floor(x / cell) + Math.floor(y / cell)) & 1) === 1; + const o = (y * n + x) * 4; + if (odd) { + data[o] = 235; + data[o + 1] = 145; + data[o + 2] = 40; + } else { + data[o] = 60; + data[o + 1] = 64; + data[o + 2] = 74; + } + data[o + 3] = 255; + } + } + return data; +} + +/** Static UV offset applied to the diffuse texture (demonstrates the feature). */ +export const UV_OFFSET: [number, number] = [0.13, 0.07]; diff --git a/packages/babylon-lite/src/material/pbr/fragments/skeleton-fragment.ts b/packages/babylon-lite/src/material/pbr/fragments/skeleton-fragment.ts index 8715105cc6..2e29c27bc7 100644 --- a/packages/babylon-lite/src/material/pbr/fragments/skeleton-fragment.ts +++ b/packages/babylon-lite/src/material/pbr/fragments/skeleton-fragment.ts @@ -1,73 +1,17 @@ /** - * Skeleton Fragment + * Skeleton Fragment (PBR ext wrapper) * - * Vertex-stage skeletal animation: bone texture sampling + skinning matrix. - * Only bundled when a scene has skeletal animation. - * Supports 4-bone and 8-bone skinning. + * Re-exports the shared, material-agnostic skeleton fragment and wraps it in a + * PBR extension (`PbrExt`) so the PBR composer can detect/bind skinning. + * The shared `createSkeletonFragment` lives in `shader/fragments/skeleton-fragment.ts` + * and is reused by the Standard material side without pulling in this wrapper. + * PBR keeps the default `"vertex"` binding style (bone texture placed before base + * bindings) — behaviour identical to before the move. */ -import type { ShaderFragment, VertexAttribute } from "../../../shader/fragment-types.js"; +import { createSkeletonFragment } from "../../../shader/fragments/skeleton-fragment.js"; -// WebGPU shader stage constants -const STAGE_VERTEX = 0x1; - -const SKELETON_HELPERS = ` -fn readMatrixFromRawSampler(smp: texture_2d, index: f32) -> mat4x4 { -let offset = i32(index) * 4; -let m0 = textureLoad(smp, vec2(offset + 0, 0), 0); -let m1 = textureLoad(smp, vec2(offset + 1, 0), 0); -let m2 = textureLoad(smp, vec2(offset + 2, 0), 0); -let m3 = textureLoad(smp, vec2(offset + 3, 0), 0); -return mat4x4f(m0, m1, m2, m3); -} -`; - -function makeSkinningCode(has8Bones: boolean): string { - let code = `var influence: mat4x4 = readMatrixFromRawSampler(boneSampler, f32(joints[0])) * weights[0]; -influence = influence + readMatrixFromRawSampler(boneSampler, f32(joints[1])) * weights[1]; -influence = influence + readMatrixFromRawSampler(boneSampler, f32(joints[2])) * weights[2]; -influence = influence + readMatrixFromRawSampler(boneSampler, f32(joints[3])) * weights[3];`; - if (has8Bones) { - code += ` -influence = influence + readMatrixFromRawSampler(boneSampler, f32(joints1[0])) * weights1[0]; -influence = influence + readMatrixFromRawSampler(boneSampler, f32(joints1[1])) * weights1[1]; -influence = influence + readMatrixFromRawSampler(boneSampler, f32(joints1[2])) * weights1[2]; -influence = influence + readMatrixFromRawSampler(boneSampler, f32(joints1[3])) * weights1[3];`; - } - code += `\nfinalWorld = mesh.world * influence;`; - return code; -} - -/** - * Create a skeleton fragment. - * @param has8Bones - Whether to use 8-bone skinning (joints1/weights1). - */ -export function createSkeletonFragment(has8Bones: boolean): ShaderFragment { - return { - _id: "skeleton", - - _vertexAttributes: [ - { _name: "joints", _type: "vec4", _gpuFormat: "uint32x4" as GPUVertexFormat, _arrayStride: 16 }, - { _name: "weights", _type: "vec4", _gpuFormat: "float32x4" as GPUVertexFormat, _arrayStride: 16 }, - ...(has8Bones - ? [ - { _name: "joints1", _type: "vec4", _gpuFormat: "uint32x4" as GPUVertexFormat, _arrayStride: 16 }, - { _name: "weights1", _type: "vec4", _gpuFormat: "float32x4" as GPUVertexFormat, _arrayStride: 16 }, - ] - : []), - ] as VertexAttribute[], - - _vertexBindings: [ - { _name: "boneSampler", _type: { _kind: "texture", _textureType: "texture_2d" as const, _sampleType: "unfilterable-float" as const }, _visibility: STAGE_VERTEX }, - ], - - _vertexHelperFunctions: SKELETON_HELPERS, - - _vertexSlots: { - VW: makeSkinningCode(has8Bones), - }, - }; -} +export { createSkeletonFragment }; import type { PbrExt } from "../pbr-flags.js"; import { MSH_HAS_SKELETON, MSH_HAS_SKELETON_8 } from "../../mesh-features.js"; diff --git a/packages/babylon-lite/src/material/standard/enable-standard-mesh-features.ts b/packages/babylon-lite/src/material/standard/enable-standard-mesh-features.ts new file mode 100644 index 0000000000..f5258d06af --- /dev/null +++ b/packages/babylon-lite/src/material/standard/enable-standard-mesh-features.ts @@ -0,0 +1,53 @@ +/** + * Opt-in enablers for the Standard material's deform/vertex mesh features (vertex color, skeleton) + * and UV offset. Each registers a dispatcher into the Standard group-builder's module-local + * `_stdMeshExtDispatch` registry so the group-builder dynamically loads the matching fragment chunk + * when a mesh in the group has the feature (UV offset toggles a pipeline fold flag instead). + * + * This is the **net-neutral fold seam** (same pattern as `enableMaterialStencil`): a scene that + * never calls one of these never imports this module, so the group-builder's dispatch registry and + * the per-feature shader chunks fold completely out of the bundle. Loaders (the FBX loader) and + * in-code scenes that build such meshes call the matching `enableStandard*()`, so only those scenes + * pay for them; plain Standard scenes stay byte-identical to upstream. + * + * Each enabler is idempotent (registers its dispatcher at most once per session). + * + * NOTE: morph targets are integrated automatically by master's `_computeMeshFeatures` path (no + * opt-in needed), and explicit-tangent normal mapping is not yet ported — so no enabler for those. + */ + +import type { Mesh } from "../../mesh/mesh.js"; +import { _registerStdMeshExtDispatch } from "./standard-group-builder.js"; +import { _installStandardUvOffset } from "./standard-pipeline.js"; + +let _vColorEnabled = false; +/** Enable Standard per-vertex color (RGB). Called by loaders/scenes that build vertex-colored meshes. */ +export function enableStandardVertexColor(): void { + if (_vColorEnabled) { + return; + } + _vColorEnabled = true; + _registerStdMeshExtDispatch([(m: Mesh) => !!m._gpu?.colorBuffer, () => import("./fragments/std-vertex-color-fragment.js"), "stdVertexColorExt"]); +} + +let _skeletonEnabled = false; +/** Enable Standard skeletal skinning. Called by loaders/scenes that build skinned meshes. */ +export function enableStandardSkeleton(): void { + if (_skeletonEnabled) { + return; + } + _skeletonEnabled = true; + _registerStdMeshExtDispatch([(m: Mesh) => !!m.skeleton, () => import("./fragments/std-skeleton-fragment.js"), "stdSkeletonExt"]); +} + +let _uvOffsetEnabled = false; +/** Enable Standard UV offset (`material.uvOffset`). Called by loaders/scenes that set a non-zero UV + * translation (the FBX loader, from `uvTranslation`). Without this, the pipeline's UV-offset reads + * fold to a constant 0 so non-offset scenes stay byte-identical. */ +export function enableStandardUvOffset(): void { + if (_uvOffsetEnabled) { + return; + } + _uvOffsetEnabled = true; + _installStandardUvOffset(); +} diff --git a/packages/babylon-lite/src/material/standard/fragments/std-skeleton-fragment.ts b/packages/babylon-lite/src/material/standard/fragments/std-skeleton-fragment.ts new file mode 100644 index 0000000000..ebd2eaf221 --- /dev/null +++ b/packages/babylon-lite/src/material/standard/fragments/std-skeleton-fragment.ts @@ -0,0 +1,56 @@ +/** Standard Skeleton Extension — vertex-stage skeletal (skinning) deformation wired as a + * plain StdExt. Reuses the shared, material-agnostic skeleton fragment (the same + * WGSL/attributes/helper/VW used by PBR) and relocates its single bone-texture binding + * from `_vertexBindings` to `_bindings` (afterBase) so the bone texture lands AFTER the + * base bindings, where the shared StdExt bind loop already runs. Doing the relocation here + * (rather than parameterizing the shared factory) keeps the PBR skeleton chunk byte-identical + * to before the fragment was shared. Gated on the mesh-driven HAS_SKELETON feature bit + * (8-bone via HAS_SKELETON_8). The joints/weights vertex buffers are bound generically + * through `_bindVertexBuffers`, mirroring the PBR draw's skinning vertex-buffer order. */ + +import type { ShaderFragment } from "../../../shader/fragment-types.js"; +import { createSkeletonFragment } from "../../../shader/fragments/skeleton-fragment.js"; +import type { Mesh } from "../../../mesh/mesh.js"; +import type { StandardMaterialProps } from "../standard-material.js"; +import type { StdExt } from "../standard-flags.js"; +import { HAS_SKELETON, HAS_SKELETON_8 } from "../standard-flags.js"; +import { _installStdExtFeature } from "../std-feature-hooks.js"; + +/** Registry extension gated on `HAS_SKELETON`. The bone texture is a vertex-only mesh-driven + * resource, so `_bind` pulls it off the mesh (not the material) and pushes it in the same + * order the composer declares it (afterBase). `_bindVertexBuffers` binds the joints/weights + * (+joints1/weights1 for 8-bone) draw-time vertex buffers in the composer's attribute order. + * No `_textures` — the bone texture is owned by the mesh's skeleton system, not the GPU pool. */ +export const stdSkeletonExt: StdExt = { + _id: "skeleton", + _phase: "mesh", + _feature: HAS_SKELETON, + _frag: (features: number): ShaderFragment => { + // Reuse the shared fragment (PBR's "vertex" placement) and relocate the single bone + // binding to `_bindings` so the Standard composer's trailing ext-bind loop binds it + // after the base bindings — matching `_bind` below. + const frag = createSkeletonFragment((features & HAS_SKELETON_8) !== 0); + return { ...frag, _bindings: frag._vertexBindings, _vertexBindings: undefined }; + }, + _bind(_mat: StandardMaterialProps, entries: GPUBindGroupEntry[], b: number, mesh?: Mesh): number { + entries.push({ binding: b++, resource: mesh!.skeleton!.boneTexture.createView() }); + return b; + }, + _bindVertexBuffers(mesh: Mesh, pass: GPURenderPassEncoder | GPURenderBundleEncoder, slot: number): number { + const s = mesh.skeleton; + if (!s) { + return slot; + } + pass.setVertexBuffer(slot++, s.jointsBuffer); + pass.setVertexBuffer(slot++, s.weightsBuffer); + if (s.joints1Buffer && s.weights1Buffer) { + pass.setVertexBuffer(slot++, s.joints1Buffer); + pass.setVertexBuffer(slot++, s.weights1Buffer); + } + return slot; + }, +}; + +// Loading this chunk wires the skeleton feature bit into the bundle (folds the renderable's +// feature-OR branch in scenes that never enable skinning). See standard-renderable._stdExtBits. +_installStdExtFeature(HAS_SKELETON); diff --git a/packages/babylon-lite/src/material/standard/fragments/std-vertex-color-fragment.ts b/packages/babylon-lite/src/material/standard/fragments/std-vertex-color-fragment.ts new file mode 100644 index 0000000000..d8e2cd265f --- /dev/null +++ b/packages/babylon-lite/src/material/standard/fragments/std-vertex-color-fragment.ts @@ -0,0 +1,44 @@ +/** Standard Vertex-Color Fragment — multiplies baseColor by the per-vertex color before lighting, + * matching BJS StandardMaterial. The `color` attribute is float32x4 RGBA (stride 16) — the + * engine-wide vertex-color layout (glTF/PBR, procedural meshes, node materials, and the FBX loader + * all emit RGBA) — and the rgb is used to modulate base color (vertex alpha is forced to 1.0). */ + +import type { ShaderFragment } from "../../../shader/fragment-types.js"; +import type { StdExt } from "../standard-flags.js"; +import { HAS_VERTEX_COLOR } from "../standard-flags.js"; +import { _installStdExtFeature } from "../std-feature-hooks.js"; + +export function createStdVertexColorFragment(): ShaderFragment { + return { + _id: "std-vcolor", + _vertexAttributes: [{ _name: "color", _type: "vec4", _gpuFormat: "float32x4", _arrayStride: 16 }], + _varyings: [{ _name: "vColor", _type: "vec3" }], + _vertexSlots: { VB: `out.vColor = color.rgb;` }, + // Backtick (not double-quote) so the bundle's WGSL identifier mangler rewrites + // `baseColor` here to match the mangled declaration in the standard template. + _fragmentSlots: { AT: `\nbaseColor = baseColor * input.vColor;` }, + }; +} + +/** Registry extension gated on `HAS_VERTEX_COLOR`. Vertex color is a vertex attribute (not a + * UBO/texture), so there is no group-1 binding — the `_bind`/`_textures` hooks are omitted and + * the shared StdExt bind/texture loops skip it. It DOES contribute a draw-time vertex buffer, + * bound generically via `_bindVertexBuffers` (mirrors the layout the composer emits for the + * `color` attribute). */ +export const stdVertexColorExt: StdExt = { + _id: "std-vcolor", + _phase: "mesh", + _feature: HAS_VERTEX_COLOR, + _frag: () => createStdVertexColorFragment(), + _bindVertexBuffers(mesh, pass, slot) { + const g = mesh._gpu; + if (g.colorBuffer) { + pass.setVertexBuffer(slot++, g.colorBuffer, g._vbLayout?._c?._offset); + } + return slot; + }, +}; + +// Loading this chunk wires the vertex-color feature bit into the bundle (folds the renderable's +// feature-OR branch in scenes that never enable vertex color). See standard-renderable._stdExtBits. +_installStdExtFeature(HAS_VERTEX_COLOR); diff --git a/packages/babylon-lite/src/material/standard/standard-flags.ts b/packages/babylon-lite/src/material/standard/standard-flags.ts index 4e6793b084..92231dc5f8 100644 --- a/packages/babylon-lite/src/material/standard/standard-flags.ts +++ b/packages/babylon-lite/src/material/standard/standard-flags.ts @@ -1,5 +1,6 @@ import type { ShaderFragment } from "../../shader/fragment-types.js"; import type { Texture2D } from "../../texture/texture-2d.js"; +import type { Mesh } from "../../mesh/mesh.js"; import type { StandardMaterialProps } from "./standard-material.js"; // ─── Feature Flags ────────────────────────────────────────────────── @@ -29,6 +30,12 @@ export const GEOMETRY_OUTPUT = 1 << 21; export const LIGHTMAP_SHADOWMAP = 1 << 15; /** Lightmap UVs are V-flipped (BJS Texture.uAng === π → uv'=(u, 1-v)). */ export const LIGHTMAP_FLIP_V = 1 << 22; +/** Mesh carries per-vertex color (RGB modulates baseColor). Opt-in via `enableStandardVertexColor`. */ +export const HAS_VERTEX_COLOR = 1 << 23; +/** Mesh is skinned (bone-texture + joints/weights). Opt-in via `enableStandardSkeleton`. */ +export const HAS_SKELETON = 1 << 26; +/** Skinned mesh uses 8 bones/vertex (joints1/weights1). */ +export const HAS_SKELETON_8 = 1 << 27; // ─── Standard Material Extension Registry ─────────────────────────── @@ -46,8 +53,13 @@ export interface StdExt { readonly _feature: number; /** @internal */ _frag(features: number, shadowLights?: ShadowLightSlotLite[]): ShaderFragment; - /** @internal Push group-1 bind entries starting at binding `b`; return new b. */ - _bind?(mat: StandardMaterialProps, entries: GPUBindGroupEntry[], b: number): number; + /** @internal Push group-1 bind entries starting at binding `b`; return new b. `mesh` is + * forwarded for mesh-driven resources (e.g. the skeleton bone texture); texture exts ignore it. */ + _bind?(mat: StandardMaterialProps, entries: GPUBindGroupEntry[], b: number, mesh?: Mesh): number; + /** @internal Bind draw-time vertex buffers for this feature (e.g. joints/weights, vertex color) + * starting at vertex-buffer `slot`; return the next slot. Called only for mesh-phase deform/vertex + * exts whose feature bit is active. */ + _bindVertexBuffers?(mesh: Mesh, pass: GPURenderPassEncoder | GPURenderBundleEncoder, slot: number): number; /** @internal Enumerate textures for acquire/release. */ _textures?(mat: StandardMaterialProps, out: Texture2D[]): void; } diff --git a/packages/babylon-lite/src/material/standard/standard-geometry-renderable.ts b/packages/babylon-lite/src/material/standard/standard-geometry-renderable.ts index 29bdc47f50..29d1c252ec 100644 --- a/packages/babylon-lite/src/material/standard/standard-geometry-renderable.ts +++ b/packages/babylon-lite/src/material/standard/standard-geometry-renderable.ts @@ -42,7 +42,7 @@ import { syncThinInstanceBuffers } from "../../mesh/thin-instance-gpu.js"; import type { Material } from "../material.js"; import type { StandardMaterialProps } from "./standard-material.js"; import { _getStdExtsSorted, DOUBLE_SIDED, HAS_DIFFUSE_TEXTURE, HAS_OPACITY_TEXTURE, NEEDS_UV, NEEDS_UV2 } from "./standard-flags.js"; -import { writeStdMaterialData } from "./standard-pipeline.js"; +import { writeStdMaterialData, _isStandardUvOffsetEnabled } from "./standard-pipeline.js"; import { composeStandardGeometryShader } from "./standard-geometry-output-shader.js"; import { getSceneBindGroupLayout } from "../../render/scene-helpers.js"; import { collectStdBoundTextures } from "./collect-std-bound-textures.js"; @@ -298,12 +298,18 @@ function _ensureViewResources(view: StandardGeometryMaterialView, engine: Engine const uvData = new F32(4); let scaleX = 1; let scaleY = 1; + let offsetX = 0; let offsetY = 0; if ((features & HAS_DIFFUSE_TEXTURE) !== 0 && source.diffuseTexture) { scaleX = source.uvScale[0]; scaleY = source.uvScale[1]; + // UV offset folds to 0 unless a loader/scene opted in via enableStandardUvOffset. + if (_isStandardUvOffsetEnabled()) { + offsetX = source.uvOffset![0]; + offsetY = source.uvOffset![1]; + } if (source.diffuseTexture.invertY) { - offsetY = scaleY; + offsetY += scaleY; scaleY = -scaleY; } } else if ((features & HAS_OPACITY_TEXTURE) !== 0 && source.opacityTexture?.invertY) { @@ -315,7 +321,7 @@ function _ensureViewResources(view: StandardGeometryMaterialView, engine: Engine } uvData[0] = scaleX; uvData[1] = scaleY; - uvData[2] = 0; + uvData[2] = offsetX; uvData[3] = offsetY; upUBO = createUniformBuffer(engine, uvData); } @@ -339,13 +345,7 @@ function _ensureViewResources(view: StandardGeometryMaterialView, engine: Engine return res; } -function _createGeometryMeshBindGroup( - engine: EngineContext, - view: StandardGeometryMaterialView, - res: StandardGeometryViewResources, - _mesh: Mesh, - meshUBO: GPUBuffer -): GPUBindGroup { +function _createGeometryMeshBindGroup(engine: EngineContext, view: StandardGeometryMaterialView, res: StandardGeometryViewResources, mesh: Mesh, meshUBO: GPUBuffer): GPUBindGroup { const source = view.source as StandardMaterialProps; const features = res._features; let nextBinding = 0; @@ -362,7 +362,9 @@ function _createGeometryMeshBindGroup( } for (const used of res._extFragments) { if (used._ext._bind) { - nextBinding = used._ext._bind(source, entries, nextBinding); + // Geometry-output features never OR in the skeleton/vcolor exts (those are color-pass + // only), so `mesh` is forwarded only for signature parity; texture exts ignore it. + nextBinding = used._ext._bind(source, entries, nextBinding, mesh); } } // Geometry-params `gp` UBO is contributed by the geometry composer as the diff --git a/packages/babylon-lite/src/material/standard/standard-group-builder.ts b/packages/babylon-lite/src/material/standard/standard-group-builder.ts index 7ee5fcc0e2..a37ea81bdd 100644 --- a/packages/babylon-lite/src/material/standard/standard-group-builder.ts +++ b/packages/babylon-lite/src/material/standard/standard-group-builder.ts @@ -1,7 +1,23 @@ import type { EngineContext } from "../../engine/engine.js"; import type { MeshGroupBuilder } from "../../render/renderable.js"; import { _registerStdExt } from "./standard-flags.js"; +import type { StdExt } from "./standard-flags.js"; import type { StandardMaterialProps } from "./standard-material.js"; +import type { Mesh } from "../../mesh/mesh.js"; + +// Mesh-feature → StdExt dispatch registry (resolver-hook fold). Each deform/vertex feature +// (skeleton, vertex color) is installed here ONLY by its `enableStandard*()` opt-in +// (enable-standard-mesh-features.ts), which loaders/scenes call when they create such a mesh. A +// scene that never enables one keeps this `null`, so the dispatch loop below folds entirely out of +// the bundle — the same module-local-proven-null fold the stencil path uses — and non-deform +// Standard scenes (fog/skybox, Sponza, …) stay byte-identical to upstream. +export type StdMeshExtDispatch = readonly [(m: Mesh) => boolean, () => Promise, string | null]; +let _stdMeshExtDispatch: StdMeshExtDispatch[] | null = null; +/** @internal Install a mesh-feature StdExt dispatcher (called only by `enableStandard*` opt-ins). + * `key` names the StdExt export to register, or is `null` for chunks that self-install. */ +export function _registerStdMeshExtDispatch(d: StdMeshExtDispatch): void { + (_stdMeshExtDispatch ??= []).push(d); +} /** Lazy-imports the standard renderable builder and builds the pipeline. */ // Material-property → fragment-module dispatch table. Each entry is a plain @@ -74,6 +90,23 @@ export function getStandardGroupBuilder(): MeshGroupBuilder { }) ); } + // Deform/vertex mesh-feature StdExts (skeleton, vertex color) are dispatched from the + // module-local `_stdMeshExtDispatch` registry, populated only by the `enableStandard*()` + // opt-ins loaders/scenes call. When no feature was enabled the registry is `null` and this + // whole block folds away, so non-deform Standard scenes stay byte-identical. + if (_stdMeshExtDispatch) { + for (const [pred, load, key] of _stdMeshExtDispatch) { + if (meshes.some(pred)) { + imports.push( + load().then((mod) => { + if (key) { + _registerStdExt((mod as Record)[key]!); + } + }) + ); + } + } + } for (const [prop, load, key] of _STD_MAT_EXTS) { if (meshes.some((m) => !!(m.material as any)[prop])) { imports.push(load().then((mod) => _registerStdExt(mod[key]))); diff --git a/packages/babylon-lite/src/material/standard/standard-material.ts b/packages/babylon-lite/src/material/standard/standard-material.ts index 00a84f0ff0..284fb56a10 100644 --- a/packages/babylon-lite/src/material/standard/standard-material.ts +++ b/packages/babylon-lite/src/material/standard/standard-material.ts @@ -97,6 +97,11 @@ export interface StandardMaterialProps extends Material { reflectionCoordMode: 1 | 2; /** UV tiling scale. Default [1, 1]. */ uvScale: [number, number]; + /** UV offset/translation applied after scale (`uv*scale + offset`). Optional; absent (the + * default) behaves as [0, 0] and folds the offset reads out of the bundle. Set only by loaders + * or scenes that need it (the FBX loader, from `uvTranslation`, which also calls + * `enableStandardUvOffset`). Matches BJS `Texture.uOffset`/`vOffset`. */ + uvOffset?: [number, number]; /** Back-face culling. Default true (BJS convention). False = double-sided. */ backFaceCulling: boolean; /** When true, skip all lighting and output emissive * diffuse * baseColor. Default false. */ diff --git a/packages/babylon-lite/src/material/standard/standard-pipeline.ts b/packages/babylon-lite/src/material/standard/standard-pipeline.ts index 5c76d2fe86..e1ff38710e 100644 --- a/packages/babylon-lite/src/material/standard/standard-pipeline.ts +++ b/packages/babylon-lite/src/material/standard/standard-pipeline.ts @@ -14,6 +14,7 @@ import { F32 } from "../../engine/typed-arrays.js"; import type { EngineContext } from "../../engine/engine.js"; import type { RenderTargetSignature } from "../../engine/render-target.js"; import type { StandardMaterialProps } from "./standard-material.js"; +import type { Mesh } from "../../mesh/mesh.js"; import type { ResolvedStencil } from "../stencil-state.js"; import type { StencilState } from "../material.js"; import { _standardFeatureKey } from "./standard-material.js"; @@ -47,6 +48,19 @@ export function _installStandardStencilResolver(resolve: (stencil: StencilState) _stencilResolver = resolve; } +/** UV-offset fold flag, set only by `enableStandardUvOffset`. Module-local with a single exported + * setter: when no scene opts in the setter tree-shakes, the bundler proves this is always `false`, + * and the `material.uvOffset` reads below fold to a constant 0 — non-offset scenes stay byte-identical. */ +let _uvOffsetEnabled = false; +/** @internal Enable Standard UV offset reads (called by `enableStandardUvOffset`). */ +export function _installStandardUvOffset(): void { + _uvOffsetEnabled = true; +} +/** @internal Whether `material.uvOffset` is honored (read by the geometry-output UV path). */ +export function _isStandardUvOffsetEnabled(): boolean { + return _uvOffsetEnabled; +} + // ─── Composer Path (Phase 1) ──────────────────────────────────────── // Converts feature bitmask → StandardTemplateConfig → ComposedShader. // This produces identical WGSL to the old string-builder path but via @@ -257,7 +271,8 @@ export function createStandardMeshBindGroup( meshUBO: GPUBuffer, materialUBO: GPUBuffer, material: StandardMaterialProps, - morphTargets: { deltasBuffer: GPUBuffer; weightsBuffer: GPUBuffer } | null = null + morphTargets: { deltasBuffer: GPUBuffer; weightsBuffer: GPUBuffer } | null = null, + mesh?: Mesh ): GPUBindGroup { const device = engine._device; const features = bindings._features; @@ -288,16 +303,17 @@ export function createStandardMeshBindGroup( const uvData = new F32(4); const scaleX = material.uvScale[0]; let scaleY = material.uvScale[1]; - let offsetY = 0; + // UV offset folds to a constant 0 unless a loader/scene opted in via enableStandardUvOffset. + let offsetY = _uvOffsetEnabled ? material.uvOffset![1] : 0; // Flip V for y-down source data (e.g. basis/compressed textures). // uv * (sx, sy) + (ox, oy) with vFlip becomes uv.xy * (sx, -sy) + (ox, sy+oy). if (material.diffuseTexture?.invertY) { - offsetY = scaleY; + offsetY += scaleY; scaleY = -scaleY; } uvData[0] = scaleX; uvData[1] = scaleY; - uvData[2] = 0; + uvData[2] = _uvOffsetEnabled ? material.uvOffset![0] : 0; uvData[3] = offsetY; entries.push({ binding: nextBinding++, resource: { buffer: createUniformBuffer(engine, uvData) } }); } @@ -314,7 +330,7 @@ export function createStandardMeshBindGroup( const sortedExts = _getStdExtsSorted(); for (const ext of sortedExts) { if (features & ext._feature && ext._bind) { - nextBinding = ext._bind(material, entries, nextBinding); + nextBinding = ext._bind(material, entries, nextBinding, mesh); } } diff --git a/packages/babylon-lite/src/material/standard/standard-renderable.ts b/packages/babylon-lite/src/material/standard/standard-renderable.ts index 8888f84a2f..31b3232a1a 100644 --- a/packages/babylon-lite/src/material/standard/standard-renderable.ts +++ b/packages/babylon-lite/src/material/standard/standard-renderable.ts @@ -15,12 +15,33 @@ import { _computeStandardMaterialFeatures, _standardShaderVariantKey } from "./s import { acquireTexture, releaseTexture, clearSamplerCache } from "../../resource/gpu-pool.js"; import { createUniformBuffer } from "../../resource/gpu-buffers.js"; import { getOrCreateStandardBindings, getOrCreateStandardPipeline, createStandardMeshBindGroup, clearStandardPipelineCache, writeStdMaterialData } from "./standard-pipeline.js"; -import { ESM_SHADOW_OUTPUT, NO_COLOR_OUTPUT, NEEDS_UV, NEEDS_UV2, HAS_OPACITY_TEXTURE, _getStdExts } from "./standard-flags.js"; +import { + ESM_SHADOW_OUTPUT, + NO_COLOR_OUTPUT, + NEEDS_UV, + NEEDS_UV2, + HAS_OPACITY_TEXTURE, + HAS_VERTEX_COLOR, + HAS_SKELETON, + HAS_SKELETON_8, + _getStdExtsSorted, +} from "./standard-flags.js"; +import type { StdExt } from "./standard-flags.js"; +import { _stdExtBits } from "./std-feature-hooks.js"; import type { ShaderFragment } from "../../shader/fragment-types.js"; import type { ShadowGenerator } from "../../shadow/shadow-generator.js"; import { writeMeshLightSelection } from "../../render/lights-ubo.js"; import type { Material, MaterialRenderFeatures } from "../material.js"; -import { _computeMeshFeatures, MSH_HAS_INSTANCE_COLOR, MSH_HAS_MORPH_TARGETS, MSH_HAS_THIN_INSTANCES, MSH_RECEIVE_SHADOWS } from "../mesh-features.js"; +import { + _computeMeshFeatures, + MSH_HAS_INSTANCE_COLOR, + MSH_HAS_MORPH_TARGETS, + MSH_HAS_THIN_INSTANCES, + MSH_HAS_SKELETON, + MSH_HAS_SKELETON_8, + MSH_HAS_VERTEX_COLOR, + MSH_RECEIVE_SHADOWS, +} from "../mesh-features.js"; import { packMat4IntoF32 } from "../../math/pack-mat4-into-f32.js"; /** Scratch buffer for material UBO writes (24 floats = 96 bytes). Reused across @@ -75,10 +96,24 @@ export function buildStandardMeshRenderables(scene: SceneContext, meshes: Mesh[] const mat = (materialOverride ?? mesh.material) as StandardMaterialProps; const renderFeatures = (mat._renderFeatures ??= { features: _computeStandardMaterialFeatures(mat) }) as MaterialRenderFeatures; const isOverride = materialOverride != null; - const features = renderFeatures.features; + let features = renderFeatures.features; const shadowOutput = (features & (NO_COLOR_OUTPUT | ESM_SHADOW_OUTPUT)) !== 0; const receiveShadows = !shadowOutput && mesh.receiveShadows && hasSomeShadows; const meshFeatures = _computeMeshFeatures(mesh, receiveShadows); + // OR in the opt-in deform/vertex feature bits driven by mesh attributes. Gated on + // `_stdExtBits` so a scene that enabled no Standard deform/vertex feature folds this whole + // block (and the downstream vertex-buffer binders) out of the bundle — byte-neutral. + if (_stdExtBits) { + if (_stdExtBits & HAS_VERTEX_COLOR && meshFeatures & MSH_HAS_VERTEX_COLOR) { + features |= HAS_VERTEX_COLOR; + } + if (_stdExtBits & HAS_SKELETON && meshFeatures & MSH_HAS_SKELETON && !(meshFeatures & MSH_HAS_THIN_INSTANCES)) { + features |= HAS_SKELETON; + if (meshFeatures & MSH_HAS_SKELETON_8) { + features |= HAS_SKELETON_8; + } + } + } // Build per-feature fragment list (deduped via pipeline cache). const frags: ShaderFragment[] = []; // Keep morph first: composeStandardShader uses the first fragment's patch @@ -86,12 +121,18 @@ export function buildStandardMeshRenderables(scene: SceneContext, meshes: Mesh[] if (meshFeatures & MSH_HAS_MORPH_TARGETS && morphFragment) { frags.push(morphFragment()); } - for (const ext of _getStdExts().values()) { + // Vertex-buffer binders contributed by active deform/vertex exts (skeleton joints/weights, + // vertex color). Collected here, replayed in the draw closure. Folds with `_stdExtBits`. + const vbBinders: NonNullable[] = []; + for (const ext of _getStdExtsSorted()) { if (features & ext._feature) { const f = ext._frag(features); if (f) { frags.push(f); } + if (_stdExtBits && ext._bindVertexBuffers) { + vbBinders.push(ext._bindVertexBuffers); + } } } let shaderKey = ""; @@ -130,7 +171,7 @@ export function buildStandardMeshRenderables(scene: SceneContext, meshes: Mesh[] const matData = new F32(24); writeStdMaterialData(matData, mat, textureLevel); const materialUBO = createUniformBuffer(engine, matData); - const meshBindGroup = createStandardMeshBindGroup(engine, bindings, meshUBO, materialUBO, mat, mesh.morphTargets ?? null); + const meshBindGroup = createStandardMeshBindGroup(engine, bindings, meshUBO, materialUBO, mat, mesh.morphTargets ?? null, mesh); // Shadow bind group (group 2) — shared across receiving meshes via shadowBGCache. let shadowBindGroup: GPUBindGroup | null = null; @@ -219,6 +260,15 @@ export function buildStandardMeshRenderables(scene: SceneContext, meshes: Mesh[] pass.setVertexBuffer(slot++, g.uv2Buffer, vb?._u2?._offset); } + // Deform/vertex feature vertex buffers (skeleton joints/weights, vertex color), in the + // composer's attribute order (after base attrs, before thin-instance). Folds out when no + // Standard deform/vertex feature was enabled. + if (_stdExtBits) { + for (const bind of vbBinders) { + slot = bind(mesh, pass, slot); + } + } + const ti = hasThinInstances ? mesh.thinInstances : null; if (ti && tiSync) { slot = tiSync(engine, ti, pass, slot, hasInstanceColor, cullBinding?.cullDrawBufs); diff --git a/packages/babylon-lite/src/material/standard/std-feature-hooks.ts b/packages/babylon-lite/src/material/standard/std-feature-hooks.ts new file mode 100644 index 0000000000..d27f55005d --- /dev/null +++ b/packages/babylon-lite/src/material/standard/std-feature-hooks.ts @@ -0,0 +1,34 @@ +/** + * Internal fold-state for the Standard material's deform/vertex + explicit-tangent features. + * + * This module holds the module-local state and its setters and is **only ever named-imported** + * (never namespace-imported / re-exported through a dynamically `await import()`-ed chunk). That is + * the whole point: `standard-renderable.ts` and `normal-map-fragment.ts` are loaded via dynamic + * namespace imports (`await import("./standard-renderable.js")`, `mod.bumpStdExt`), so Rollup must + * retain ALL of their exports. If the setters below lived there, terser could never prove the state + * stays at its initializer, and every gated branch would ship into scenes that don't use the feature. + * + * By keeping the setters here — imported by name into `standard-renderable`/`normal-map-fragment` + * for READING the state, and imported by name into the dynamic feature chunks for WRITING it — a + * scene that loads no feature chunk has no reachable caller of a setter. Terser then proves the + * state constant and folds the feature-OR, the vertex-buffer binder loop, and the tangent path out + * entirely (true byte-neutrality), exactly like the stencil resolver hook. + */ + +import type { ShaderFragment } from "../../shader/fragment-types.js"; + +/** Active deform/vertex StdExt feature bits. Each dynamic feature chunk (std-vertex-color / morph / + * skeleton / normal-tangent fragment) ORs its `HAS_*` bit in via `_installStdExtFeature` on import. */ +export let _stdExtBits = 0; +/** @internal OR a deform/vertex feature bit into the active set (called by feature chunks on load). */ +export function _installStdExtFeature(bit: number): void { + _stdExtBits |= bit; +} + +/** Explicit-tangent normal-map fragment factory, injected by `std-normal-tangent-fragment.ts` on + * import. Stays `null` (and every tangent branch folds) until that chunk loads. */ +export let _tangentFrag: ((features: number) => ShaderFragment) | null = null; +/** @internal Install the explicit-tangent normal-map fragment factory (called by the tangent chunk). */ +export function _installNormalTangentFrag(frag: (features: number) => ShaderFragment): void { + _tangentFrag = frag; +} diff --git a/packages/babylon-lite/src/shader/fragments/skeleton-fragment.ts b/packages/babylon-lite/src/shader/fragments/skeleton-fragment.ts new file mode 100644 index 0000000000..7cc7f02d60 --- /dev/null +++ b/packages/babylon-lite/src/shader/fragments/skeleton-fragment.ts @@ -0,0 +1,78 @@ +/** + * Skeleton Fragment (shared) + * + * Vertex-stage skeletal animation: bone texture sampling + skinning matrix. + * Material-agnostic — used by both the PBR and Standard material composers. + * Only bundled when a scene has skeletal animation. Supports 4-bone and 8-bone + * skinning. + * + * The bone texture is declared as a `_vertexBindings` entry (placed by the + * composer immediately after the mesh UBO, before base bindings) — exactly as + * the PBR path has always done. The Standard side reuses this same fragment and + * relocates the single bone binding to `_bindings` (afterBase) in its own + * wrapper, so no per-call branch lives in this shared module (keeps the PBR + * skeleton chunk byte-identical to before the move). + */ + +import type { ShaderFragment, VertexAttribute } from "../fragment-types.js"; + +// WebGPU shader stage constants +const STAGE_VERTEX = 0x1; + +const SKELETON_HELPERS = ` +fn readMatrixFromRawSampler(smp: texture_2d, index: f32) -> mat4x4 { +let offset = i32(index) * 4; +let m0 = textureLoad(smp, vec2(offset + 0, 0), 0); +let m1 = textureLoad(smp, vec2(offset + 1, 0), 0); +let m2 = textureLoad(smp, vec2(offset + 2, 0), 0); +let m3 = textureLoad(smp, vec2(offset + 3, 0), 0); +return mat4x4f(m0, m1, m2, m3); +} +`; + +function makeSkinningCode(has8Bones: boolean): string { + let code = `var influence: mat4x4 = readMatrixFromRawSampler(boneSampler, f32(joints[0])) * weights[0]; +influence = influence + readMatrixFromRawSampler(boneSampler, f32(joints[1])) * weights[1]; +influence = influence + readMatrixFromRawSampler(boneSampler, f32(joints[2])) * weights[2]; +influence = influence + readMatrixFromRawSampler(boneSampler, f32(joints[3])) * weights[3];`; + if (has8Bones) { + code += ` +influence = influence + readMatrixFromRawSampler(boneSampler, f32(joints1[0])) * weights1[0]; +influence = influence + readMatrixFromRawSampler(boneSampler, f32(joints1[1])) * weights1[1]; +influence = influence + readMatrixFromRawSampler(boneSampler, f32(joints1[2])) * weights1[2]; +influence = influence + readMatrixFromRawSampler(boneSampler, f32(joints1[3])) * weights1[3];`; + } + code += `\nfinalWorld = mesh.world * influence;`; + return code; +} + +/** + * Create a skeleton fragment. + * @param has8Bones - Whether to use 8-bone skinning (joints1/weights1). + */ +export function createSkeletonFragment(has8Bones: boolean): ShaderFragment { + return { + _id: "skeleton", + + _vertexAttributes: [ + { _name: "joints", _type: "vec4", _gpuFormat: "uint32x4" as GPUVertexFormat, _arrayStride: 16 }, + { _name: "weights", _type: "vec4", _gpuFormat: "float32x4" as GPUVertexFormat, _arrayStride: 16 }, + ...(has8Bones + ? [ + { _name: "joints1", _type: "vec4", _gpuFormat: "uint32x4" as GPUVertexFormat, _arrayStride: 16 }, + { _name: "weights1", _type: "vec4", _gpuFormat: "float32x4" as GPUVertexFormat, _arrayStride: 16 }, + ] + : []), + ] as VertexAttribute[], + + _vertexBindings: [ + { _name: "boneSampler", _type: { _kind: "texture", _textureType: "texture_2d" as const, _sampleType: "unfilterable-float" as const }, _visibility: STAGE_VERTEX }, + ], + + _vertexHelperFunctions: SKELETON_HELPERS, + + _vertexSlots: { + VW: makeSkinningCode(has8Bones), + }, + }; +} diff --git a/scene-config.json b/scene-config.json index 0c403fc22c..275d94f287 100644 --- a/scene-config.json +++ b/scene-config.json @@ -2007,6 +2007,15 @@ "tags": ["pbr", "gltf", "non-indexed"], "skipPerf": true }, + { + "id": 231, + "slug": "scene231-standard-deform-features", + "name": "Scene 231 — StandardMaterial Deform Features", + "maxMad": 0.1, + "description": "In-code (no glTF) beam exercising StandardMaterial per-vertex color + skeletal skinning + UV offset, with programmatically animated bones frozen at a deterministic frame. Validates the opt-in Standard deform features against Babylon.js.", + "tags": ["std", "procedural", "skeleton", "vertex-color", "uv-offset", "animated"], + "skipPerf": true + }, { "id": 240, "slug": "scene240-animated-triangle", diff --git a/tests/lite/parity/scenes/scene231-standard-deform-features.spec.ts b/tests/lite/parity/scenes/scene231-standard-deform-features.spec.ts new file mode 100644 index 0000000000..1668587966 --- /dev/null +++ b/tests/lite/parity/scenes/scene231-standard-deform-features.spec.ts @@ -0,0 +1,31 @@ +/** + * Scene 231 — StandardMaterial deform features (per-vertex color + skeletal + * skinning + UV offset) on an in-code beam with programmatically animated bones. + */ +import { test, expect } from "@playwright/test"; +import * as path from "path"; +import { attachCompareArtifacts, captureGolden, compareImages, getSceneConfig } from "../compare-utils"; + +const sceneConfig = getSceneConfig(231); +const REFERENCE_DIR = path.resolve(__dirname, "../../../../reference/lite/scene231-standard-deform-features"); +const GOLDEN_REF = path.join(REFERENCE_DIR, "babylon-ref-golden.png"); + +test.skip(!!sceneConfig.skipParity, "Scene 231 skipped via skipParity in scene-config.json"); + +test("Scene 231 — StandardMaterial deform features match Babylon.js reference", async ({ page }, testInfo) => { + const browser = page.context().browser()!; + await captureGolden(browser, { sceneId: 231, seekTime: 0.5, timeout: 90_000 }); + + await page.goto("/scene231.html?seekTime=0.5"); + await page.waitForFunction(() => document.querySelector("canvas")?.dataset.ready === "true", { timeout: 60_000 }); + await page.waitForFunction(() => document.querySelector("canvas")?.dataset.animationFrozen === "true", { timeout: 60_000 }); + await page.waitForTimeout(500); + + const screenshotPath = path.join(REFERENCE_DIR, "test-actual.png"); + await page.locator("canvas").screenshot({ path: screenshotPath }); + + const full = compareImages(screenshotPath, GOLDEN_REF); + await attachCompareArtifacts(testInfo, screenshotPath, GOLDEN_REF, REFERENCE_DIR); + console.log(`Full image MAD: ${full.mad.toFixed(3)} (limit ${sceneConfig.maxMad})`); + expect(full.mad, `Full image MAD should be <= ${sceneConfig.maxMad}`).toBeLessThanOrEqual(sceneConfig.maxMad); +}); From e142f2e28ad8f58c34fdfe49f2fcd4ad38610710 Mon Sep 17 00:00:00 2001 From: Patrick Ryan Date: Fri, 26 Jun 2026 16:05:01 -0700 Subject: [PATCH 2/2] =?UTF-8?q?feat(standard):=20dynamic=20fog=20WGSL=20?= =?UTF-8?q?=E2=80=94=20non-fog=20Standard=20scenes=20bundle=20zero=20fog?= =?UTF-8?q?=20bytes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ports the dynamic fog gating from the prior Branch A onto upstream #300, mirroring the PBR fog path (pbr-fog-wgsl.ts). The fog `calcFogFactor` helper + blend block move out of the always-included standard-template into a new std-fog-wgsl module that standard-group-builder dynamic-imports ONLY when scene.fog is set; the strings are threaded through the renderable into composeStandardShader (_fogHelper/_fogBlock, "" for non-fog scenes). Effect vs a fresh upstream build (same env): 80+ scenes smaller, total -86 KB; the deform-hook terser shift on non-fog Standard scenes is now offset (the ex-boundary scenes are ~1 KB smaller). Fog scenes pay the dynamic-fog chunk-wrapper overhead (~+0.3 KB), the same tradeoff PBR makes; scene3's ceiling is bumped 54 -> 54.5 to cover it (user-approved). Full visual parity unchanged (418 passed; scene3 fog MAD 0.000); only the 3 machine-sensitive Havok scenes fail as usual. Regenerates the tracked per-scene bundle baseline (lab/public/bundle/manifest/.json) for the 84 scenes whose raw size or runtime chunks moved on this branch, and adds scene231's manifest, per docs/lite/architecture/38-bundle-size-tooling.md ("Commit the regenerated files for any scene whose size or runtime chunks moved"). Removes the accidentally-committed aggregate lab/public/bundle/manifest.json — a gitignored generated artifact that PR #294 replaced with the per-scene files and that must never be committed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- lab/public/bundle/manifest/scene100.json | 7 +++--- lab/public/bundle/manifest/scene101.json | 7 +++--- lab/public/bundle/manifest/scene102.json | 7 +++--- lab/public/bundle/manifest/scene103.json | 7 +++--- lab/public/bundle/manifest/scene104.json | 7 +++--- lab/public/bundle/manifest/scene105.json | 7 +++--- lab/public/bundle/manifest/scene106.json | 7 +++--- lab/public/bundle/manifest/scene110.json | 7 +++--- lab/public/bundle/manifest/scene111.json | 7 +++--- lab/public/bundle/manifest/scene113.json | 7 +++--- lab/public/bundle/manifest/scene115.json | 7 +++--- lab/public/bundle/manifest/scene116.json | 7 +++--- lab/public/bundle/manifest/scene129.json | 7 +++--- lab/public/bundle/manifest/scene141.json | 7 +++--- lab/public/bundle/manifest/scene142.json | 7 +++--- lab/public/bundle/manifest/scene143.json | 4 ++-- lab/public/bundle/manifest/scene145.json | 13 +++++------ lab/public/bundle/manifest/scene15.json | 7 +++--- lab/public/bundle/manifest/scene150.json | 7 +++--- lab/public/bundle/manifest/scene151.json | 7 +++--- lab/public/bundle/manifest/scene154.json | 7 +++--- lab/public/bundle/manifest/scene155.json | 7 +++--- lab/public/bundle/manifest/scene156.json | 7 +++--- lab/public/bundle/manifest/scene16.json | 7 +++--- lab/public/bundle/manifest/scene17.json | 7 +++--- lab/public/bundle/manifest/scene170.json | 7 +++--- lab/public/bundle/manifest/scene171.json | 11 ++++----- lab/public/bundle/manifest/scene172.json | 7 +++--- lab/public/bundle/manifest/scene173.json | 7 +++--- lab/public/bundle/manifest/scene174.json | 11 ++++----- lab/public/bundle/manifest/scene175.json | 11 ++++----- lab/public/bundle/manifest/scene18.json | 7 +++--- lab/public/bundle/manifest/scene2.json | 7 +++--- lab/public/bundle/manifest/scene200.json | 7 +++--- lab/public/bundle/manifest/scene201.json | 7 +++--- lab/public/bundle/manifest/scene202.json | 7 +++--- lab/public/bundle/manifest/scene203.json | 7 +++--- lab/public/bundle/manifest/scene204.json | 7 +++--- lab/public/bundle/manifest/scene205.json | 7 +++--- lab/public/bundle/manifest/scene206.json | 7 +++--- lab/public/bundle/manifest/scene207.json | 7 +++--- lab/public/bundle/manifest/scene209.json | 7 +++--- lab/public/bundle/manifest/scene214.json | 7 +++--- lab/public/bundle/manifest/scene217.json | 7 +++--- lab/public/bundle/manifest/scene22.json | 7 +++--- lab/public/bundle/manifest/scene221.json | 7 +++--- lab/public/bundle/manifest/scene222.json | 7 +++--- lab/public/bundle/manifest/scene223.json | 7 +++--- lab/public/bundle/manifest/scene224.json | 7 +++--- lab/public/bundle/manifest/scene225.json | 7 +++--- lab/public/bundle/manifest/scene227.json | 7 +++--- lab/public/bundle/manifest/scene228.json | 7 +++--- lab/public/bundle/manifest/scene231.json | 12 ++++++++++ lab/public/bundle/manifest/scene24.json | 7 +++--- lab/public/bundle/manifest/scene25.json | 7 +++--- lab/public/bundle/manifest/scene252.json | 7 +++--- lab/public/bundle/manifest/scene261.json | 7 +++--- lab/public/bundle/manifest/scene3.json | 7 +++--- lab/public/bundle/manifest/scene36.json | 7 +++--- lab/public/bundle/manifest/scene38.json | 7 +++--- lab/public/bundle/manifest/scene4.json | 7 +++--- lab/public/bundle/manifest/scene40.json | 7 +++--- lab/public/bundle/manifest/scene41.json | 7 +++--- lab/public/bundle/manifest/scene42.json | 7 +++--- lab/public/bundle/manifest/scene43.json | 7 +++--- lab/public/bundle/manifest/scene44.json | 7 +++--- lab/public/bundle/manifest/scene45.json | 7 +++--- lab/public/bundle/manifest/scene46.json | 7 +++--- lab/public/bundle/manifest/scene47.json | 7 +++--- lab/public/bundle/manifest/scene48.json | 7 +++--- lab/public/bundle/manifest/scene49.json | 7 +++--- lab/public/bundle/manifest/scene52.json | 7 +++--- lab/public/bundle/manifest/scene53.json | 7 +++--- lab/public/bundle/manifest/scene54.json | 7 +++--- lab/public/bundle/manifest/scene56.json | 7 +++--- lab/public/bundle/manifest/scene57.json | 7 +++--- lab/public/bundle/manifest/scene59.json | 7 +++--- lab/public/bundle/manifest/scene75.json | 7 +++--- lab/public/bundle/manifest/scene84.json | 7 +++--- lab/public/bundle/manifest/scene9.json | 4 ++-- lab/public/bundle/manifest/scene90.json | 7 +++--- lab/public/bundle/manifest/scene91.json | 7 +++--- lab/public/bundle/manifest/scene94.json | 7 +++--- lab/public/bundle/manifest/scene95.json | 7 +++--- lab/public/bundle/manifest/scene98.json | 7 +++--- .../standard/standard-group-builder.ts | 14 ++++++++++- .../material/standard/standard-pipeline.ts | 15 ++++++++++-- .../material/standard/standard-renderable.ts | 19 +++++++++++++-- .../material/standard/standard-template.ts | 15 ++++++------ .../src/material/standard/std-fog-wgsl.ts | 23 +++++++++++++++++++ scene-config.json | 2 +- 91 files changed, 347 insertions(+), 353 deletions(-) create mode 100644 lab/public/bundle/manifest/scene231.json create mode 100644 packages/babylon-lite/src/material/standard/std-fog-wgsl.ts diff --git a/lab/public/bundle/manifest/scene100.json b/lab/public/bundle/manifest/scene100.json index 6dad0eeaab..5c04cf6066 100644 --- a/lab/public/bundle/manifest/scene100.json +++ b/lab/public/bundle/manifest/scene100.json @@ -1,10 +1,9 @@ { - "rawKB": 50.4, - "gzipKB": 20.2, + "rawKB": 49.3, + "gzipKB": 19.8, "ignoredRawKB": 0, "runtimeChunks": [ - "scene100-standard-renderable-Buv_s4dX.js", - "scene100-wgsl-helpers-CwHFFXvt.js", + "scene100-standard-renderable-BWKAd75D.js", "scene100.js" ] } diff --git a/lab/public/bundle/manifest/scene101.json b/lab/public/bundle/manifest/scene101.json index 00df96df0f..ae2e877946 100644 --- a/lab/public/bundle/manifest/scene101.json +++ b/lab/public/bundle/manifest/scene101.json @@ -1,10 +1,9 @@ { - "rawKB": 53.8, - "gzipKB": 21.5, + "rawKB": 52.7, + "gzipKB": 21.1, "ignoredRawKB": 0, "runtimeChunks": [ - "scene101-standard-renderable-BAYncetB.js", - "scene101-wgsl-helpers-CwHFFXvt.js", + "scene101-standard-renderable-CVbAyvcw.js", "scene101.js" ] } diff --git a/lab/public/bundle/manifest/scene102.json b/lab/public/bundle/manifest/scene102.json index 4f62fada30..6c06048543 100644 --- a/lab/public/bundle/manifest/scene102.json +++ b/lab/public/bundle/manifest/scene102.json @@ -1,10 +1,9 @@ { - "rawKB": 59.5, - "gzipKB": 23.7, + "rawKB": 58.4, + "gzipKB": 23.3, "ignoredRawKB": 0, "runtimeChunks": [ - "scene102-standard-renderable-VJFYqVqL.js", - "scene102-wgsl-helpers-CwHFFXvt.js", + "scene102-standard-renderable-CPoVoWmd.js", "scene102.js" ] } diff --git a/lab/public/bundle/manifest/scene103.json b/lab/public/bundle/manifest/scene103.json index 56e235280d..14a60b3450 100644 --- a/lab/public/bundle/manifest/scene103.json +++ b/lab/public/bundle/manifest/scene103.json @@ -1,12 +1,11 @@ { - "rawKB": 62.1, - "gzipKB": 24.7, + "rawKB": 61, + "gzipKB": 24.3, "ignoredRawKB": 0, "runtimeChunks": [ - "scene103-standard-renderable-DKLp8FJA.js", + "scene103-standard-renderable-vLQ1_LqS.js", "scene103-thin-instance-fragment-CBn2miAC.js", "scene103-thin-instance-gpu-D2OBjYZH.js", - "scene103-wgsl-helpers-CwHFFXvt.js", "scene103.js" ] } diff --git a/lab/public/bundle/manifest/scene104.json b/lab/public/bundle/manifest/scene104.json index dad93f57d3..0c508b7ab7 100644 --- a/lab/public/bundle/manifest/scene104.json +++ b/lab/public/bundle/manifest/scene104.json @@ -1,15 +1,14 @@ { - "rawKB": 101.7, - "gzipKB": 39.3, + "rawKB": 100.6, + "gzipKB": 38.9, "ignoredRawKB": 0, "runtimeChunks": [ "scene104-generate-mipmaps-BGv6wRC-.js", "scene104-gltf-feature-registry-CE6GMq6X.js", "scene104-gltf-glb-parser-BJfNq64D.js", "scene104-shader-composer-CgJmQyJj.js", - "scene104-standard-renderable-BYZDGzK-.js", + "scene104-standard-renderable-CZ5EuNPw.js", "scene104-std-lightmap-fragment-BtZeffyx.js", - "scene104-wgsl-helpers-CwHFFXvt.js", "scene104.js" ] } diff --git a/lab/public/bundle/manifest/scene105.json b/lab/public/bundle/manifest/scene105.json index d3f2ebb4aa..c1cf221088 100644 --- a/lab/public/bundle/manifest/scene105.json +++ b/lab/public/bundle/manifest/scene105.json @@ -1,15 +1,14 @@ { - "rawKB": 102.3, - "gzipKB": 39.6, + "rawKB": 101.3, + "gzipKB": 39.1, "ignoredRawKB": 0, "runtimeChunks": [ "scene105-generate-mipmaps-Bw7xZIhD.js", "scene105-gltf-feature-registry-DurnsCTb.js", "scene105-gltf-glb-parser-BsWC1iTB.js", "scene105-shader-composer-CgJmQyJj.js", - "scene105-standard-renderable-wWJPvbnz.js", + "scene105-standard-renderable-CVA_VO9o.js", "scene105-std-lightmap-fragment-DJHrjMOe.js", - "scene105-wgsl-helpers-CwHFFXvt.js", "scene105.js" ] } diff --git a/lab/public/bundle/manifest/scene106.json b/lab/public/bundle/manifest/scene106.json index 6b1f944f83..9a0859ba47 100644 --- a/lab/public/bundle/manifest/scene106.json +++ b/lab/public/bundle/manifest/scene106.json @@ -1,10 +1,9 @@ { - "rawKB": 51.4, - "gzipKB": 20.6, + "rawKB": 50.4, + "gzipKB": 20.1, "ignoredRawKB": 0, "runtimeChunks": [ - "scene106-standard-renderable-BZNlFJ4y.js", - "scene106-wgsl-helpers-CwHFFXvt.js", + "scene106-standard-renderable-oiUJ9jpI.js", "scene106.js" ] } diff --git a/lab/public/bundle/manifest/scene110.json b/lab/public/bundle/manifest/scene110.json index f0d9f82749..1ccff775d3 100644 --- a/lab/public/bundle/manifest/scene110.json +++ b/lab/public/bundle/manifest/scene110.json @@ -1,10 +1,9 @@ { - "rawKB": 50.9, - "gzipKB": 19.9, + "rawKB": 49.8, + "gzipKB": 19.5, "ignoredRawKB": 0, "runtimeChunks": [ - "scene110-standard-renderable-D6cO9rrY.js", - "scene110-wgsl-helpers-CwHFFXvt.js", + "scene110-standard-renderable-CZeUI5EB.js", "scene110.js" ] } diff --git a/lab/public/bundle/manifest/scene111.json b/lab/public/bundle/manifest/scene111.json index 1e51e5a1aa..7e88f54164 100644 --- a/lab/public/bundle/manifest/scene111.json +++ b/lab/public/bundle/manifest/scene111.json @@ -1,6 +1,6 @@ { - "rawKB": 134.6, - "gzipKB": 54.3, + "rawKB": 133.5, + "gzipKB": 53.8, "ignoredRawKB": 6.4, "runtimeChunks": [ "scene111-_math-factory-DFVyS8gB.js", @@ -23,11 +23,10 @@ "scene111-shader-composer-CVST0cVc.js", "scene111-shadow-fragment-core-Dbe1xNkt.js", "scene111-shadow-task-C9r4Q-jw.js", - "scene111-standard-renderable-DWURFIF8.js", + "scene111-standard-renderable-BGoErCrE.js", "scene111-std-shadow-fragment-u3x2t2qW.js", "scene111-transform-block-xSHzJVmq.js", "scene111-vertex-output-C7G5u6Y0.js", - "scene111-wgsl-helpers-CwHFFXvt.js", "scene111.js" ] } diff --git a/lab/public/bundle/manifest/scene113.json b/lab/public/bundle/manifest/scene113.json index 24d62211d9..c63319876b 100644 --- a/lab/public/bundle/manifest/scene113.json +++ b/lab/public/bundle/manifest/scene113.json @@ -1,10 +1,9 @@ { - "rawKB": 63, - "gzipKB": 24.3, + "rawKB": 61.9, + "gzipKB": 23.8, "ignoredRawKB": 0, "runtimeChunks": [ - "scene113-standard-renderable-DHQkU9-B.js", - "scene113-wgsl-helpers-CwHFFXvt.js", + "scene113-standard-renderable-gnIr5e1I.js", "scene113.js" ] } diff --git a/lab/public/bundle/manifest/scene115.json b/lab/public/bundle/manifest/scene115.json index 562c8e0e90..7c8e12bb10 100644 --- a/lab/public/bundle/manifest/scene115.json +++ b/lab/public/bundle/manifest/scene115.json @@ -1,6 +1,6 @@ { - "rawKB": 126, - "gzipKB": 51.8, + "rawKB": 125, + "gzipKB": 51.3, "ignoredRawKB": 0, "runtimeChunks": [ "scene115-create-morph-targets-BxcR5t59.js", @@ -20,8 +20,7 @@ "scene115-shader-composer-CgJmQyJj.js", "scene115-singlelight-hemispheric-wgsl-D4qRhfo5.js", "scene115-skeleton-fragment-Wgm6o2IA.js", - "scene115-standard-renderable-BJyVFLpF.js", - "scene115-wgsl-helpers-CwHFFXvt.js", + "scene115-standard-renderable-CJQ3hAVX.js", "scene115.js" ] } diff --git a/lab/public/bundle/manifest/scene116.json b/lab/public/bundle/manifest/scene116.json index 68243428f5..15d0fd9c08 100644 --- a/lab/public/bundle/manifest/scene116.json +++ b/lab/public/bundle/manifest/scene116.json @@ -1,15 +1,14 @@ { - "rawKB": 76.5, - "gzipKB": 31.3, + "rawKB": 75.4, + "gzipKB": 30.8, "ignoredRawKB": 0, "runtimeChunks": [ "scene116-pbr-renderable-RHux3tgC.js", "scene116-shader-composer-Bga-tI-0.js", "scene116-singlelight-hemispheric-wgsl-ziPxL_2u.js", - "scene116-standard-renderable-muHsmIf0.js", + "scene116-standard-renderable-By25_6zA.js", "scene116-std-emissive-fragment-C813VlNk.js", "scene116-unlit-fragment-Bgox5O_g.js", - "scene116-wgsl-helpers-CwHFFXvt.js", "scene116.js" ] } diff --git a/lab/public/bundle/manifest/scene129.json b/lab/public/bundle/manifest/scene129.json index a0958aa133..d0cef60a22 100644 --- a/lab/public/bundle/manifest/scene129.json +++ b/lab/public/bundle/manifest/scene129.json @@ -1,11 +1,10 @@ { - "rawKB": 82.8, - "gzipKB": 31.5, + "rawKB": 81.8, + "gzipKB": 31.1, "ignoredRawKB": 0, "runtimeChunks": [ "scene129-gs-picking-pipeline-wk9cVMav.js", - "scene129-standard-renderable-DT6HMQHE.js", - "scene129-wgsl-helpers-CwHFFXvt.js", + "scene129-standard-renderable-C5XyvMdI.js", "scene129.js" ] } diff --git a/lab/public/bundle/manifest/scene141.json b/lab/public/bundle/manifest/scene141.json index 68c53082c5..eae83679a3 100644 --- a/lab/public/bundle/manifest/scene141.json +++ b/lab/public/bundle/manifest/scene141.json @@ -1,6 +1,6 @@ { - "rawKB": 123.5, - "gzipKB": 50.9, + "rawKB": 122.4, + "gzipKB": 50.5, "ignoredRawKB": 6.4, "runtimeChunks": [ "scene141-_math-factory-DFVyS8gB.js", @@ -21,10 +21,9 @@ "scene141-shadow-fragment-core-Dbe1xNkt.js", "scene141-shadow-task-D7JQvILi.js", "scene141-singlelight-directional-wgsl-CUGOIxSX.js", - "scene141-standard-renderable-CgdKXWAd.js", + "scene141-standard-renderable-yaaDLyBS.js", "scene141-transform-block-DWUOQ_Fz.js", "scene141-vertex-output-C7G5u6Y0.js", - "scene141-wgsl-helpers-CwHFFXvt.js", "scene141.js" ] } diff --git a/lab/public/bundle/manifest/scene142.json b/lab/public/bundle/manifest/scene142.json index 0411fb24c4..025485195f 100644 --- a/lab/public/bundle/manifest/scene142.json +++ b/lab/public/bundle/manifest/scene142.json @@ -1,10 +1,9 @@ { - "rawKB": 61.2, - "gzipKB": 22.9, + "rawKB": 60.1, + "gzipKB": 22.4, "ignoredRawKB": 0, "runtimeChunks": [ - "scene142-standard-renderable-COIztMWN.js", - "scene142-wgsl-helpers-CwHFFXvt.js", + "scene142-standard-renderable-DOOqetWl.js", "scene142.js" ] } diff --git a/lab/public/bundle/manifest/scene143.json b/lab/public/bundle/manifest/scene143.json index 9afe0d63cf..777e485e09 100644 --- a/lab/public/bundle/manifest/scene143.json +++ b/lab/public/bundle/manifest/scene143.json @@ -1,12 +1,12 @@ { "rawKB": 70.3, - "gzipKB": 27.3, + "gzipKB": 27.4, "ignoredRawKB": 0, "runtimeChunks": [ "scene143-generate-mipmaps-CiyhUZPA.js", "scene143-normal-map-fragment-vZfuB--u.js", "scene143-point-light-CHHO5fr1.js", - "scene143-standard-renderable-RDRd4x1P.js", + "scene143-standard-renderable-uju7lWWB.js", "scene143-std-ambient-fragment-CU5U7ir2.js", "scene143-std-opacity-fragment-CbaZz9IY.js", "scene143-std-reflection-fragment-BMQE51J5.js", diff --git a/lab/public/bundle/manifest/scene145.json b/lab/public/bundle/manifest/scene145.json index 9c6fa74db3..a613b4e910 100644 --- a/lab/public/bundle/manifest/scene145.json +++ b/lab/public/bundle/manifest/scene145.json @@ -1,20 +1,20 @@ { - "rawKB": 89, - "gzipKB": 36.3, + "rawKB": 87.8, + "gzipKB": 35.8, "ignoredRawKB": 0, "runtimeChunks": [ "scene145-bake-local-matrix-67U-IT8C.js", "scene145-cube-texture-vbJP4eNk.js", "scene145-generate-mipmaps-Db4M86C8.js", - "scene145-geometry-view-CN4PelFi.js", + "scene145-geometry-view-CKdfj_OV.js", "scene145-mesh-features-Dnub8q45.js", "scene145-mip-count-CdXF1U-X.js", "scene145-parse-camera-BXBDIYdM.js", "scene145-point-light-DuKWngp0.js", "scene145-shader-composer-BLINGJZD.js", - "scene145-standard-material-CVLV5Oh4.js", - "scene145-standard-pipeline-CRbKzlw9.js", - "scene145-standard-renderable-CTmuVKCk.js", + "scene145-standard-material-Ci3gzKk9.js", + "scene145-standard-pipeline-uzw5Rkrm.js", + "scene145-standard-renderable-CQegbxGk.js", "scene145-std-ambient-fragment-Ctnv-tPf.js", "scene145-std-cube-reflection-fragment-BnXcsg5b.js", "scene145-std-opacity-fragment-F2uWm_km.js", @@ -22,7 +22,6 @@ "scene145-thin-instance-fragment-CBn2miAC.js", "scene145-thin-instance-gpu-Du81IUuw.js", "scene145-ubo-layout-Cs5YvLYZ.js", - "scene145-wgsl-helpers-CwHFFXvt.js", "scene145.js" ] } diff --git a/lab/public/bundle/manifest/scene15.json b/lab/public/bundle/manifest/scene15.json index d9eb54de64..f032142af2 100644 --- a/lab/public/bundle/manifest/scene15.json +++ b/lab/public/bundle/manifest/scene15.json @@ -1,10 +1,9 @@ { - "rawKB": 47.4, - "gzipKB": 19, + "rawKB": 46.3, + "gzipKB": 18.5, "ignoredRawKB": 0, "runtimeChunks": [ - "scene15-standard-renderable-DjpuOYV2.js", - "scene15-wgsl-helpers-CwHFFXvt.js", + "scene15-standard-renderable-CgLabYHh.js", "scene15.js" ] } diff --git a/lab/public/bundle/manifest/scene150.json b/lab/public/bundle/manifest/scene150.json index f71e57cd42..24d0f42db6 100644 --- a/lab/public/bundle/manifest/scene150.json +++ b/lab/public/bundle/manifest/scene150.json @@ -1,10 +1,9 @@ { - "rawKB": 55.2, - "gzipKB": 21.6, + "rawKB": 54.1, + "gzipKB": 21.2, "ignoredRawKB": 0, "runtimeChunks": [ - "scene150-standard-renderable-Dwlmn5s3.js", - "scene150-wgsl-helpers-CwHFFXvt.js", + "scene150-standard-renderable-BFX72Lxl.js", "scene150.js" ] } diff --git a/lab/public/bundle/manifest/scene151.json b/lab/public/bundle/manifest/scene151.json index ceef9075cf..ac2c735571 100644 --- a/lab/public/bundle/manifest/scene151.json +++ b/lab/public/bundle/manifest/scene151.json @@ -1,10 +1,9 @@ { - "rawKB": 55.4, - "gzipKB": 21.7, + "rawKB": 54.4, + "gzipKB": 21.2, "ignoredRawKB": 0, "runtimeChunks": [ - "scene151-standard-renderable-C822zhOt.js", - "scene151-wgsl-helpers-CwHFFXvt.js", + "scene151-standard-renderable-BqZ9MeFl.js", "scene151.js" ] } diff --git a/lab/public/bundle/manifest/scene154.json b/lab/public/bundle/manifest/scene154.json index 4168e12411..e1e3c1bf42 100644 --- a/lab/public/bundle/manifest/scene154.json +++ b/lab/public/bundle/manifest/scene154.json @@ -1,10 +1,9 @@ { - "rawKB": 55.6, - "gzipKB": 21.7, + "rawKB": 54.6, + "gzipKB": 21.3, "ignoredRawKB": 0, "runtimeChunks": [ - "scene154-standard-renderable-B0H1CD6L.js", - "scene154-wgsl-helpers-CwHFFXvt.js", + "scene154-standard-renderable-C4iMVyse.js", "scene154.js" ] } diff --git a/lab/public/bundle/manifest/scene155.json b/lab/public/bundle/manifest/scene155.json index cfcceca5cd..bb21bb47c9 100644 --- a/lab/public/bundle/manifest/scene155.json +++ b/lab/public/bundle/manifest/scene155.json @@ -1,10 +1,9 @@ { - "rawKB": 58.1, - "gzipKB": 22.6, + "rawKB": 57, + "gzipKB": 22.1, "ignoredRawKB": 0, "runtimeChunks": [ - "scene155-standard-renderable-CDfPDID1.js", - "scene155-wgsl-helpers-CwHFFXvt.js", + "scene155-standard-renderable-DmH58mw3.js", "scene155.js" ] } diff --git a/lab/public/bundle/manifest/scene156.json b/lab/public/bundle/manifest/scene156.json index 9b393d4929..607b4b03ab 100644 --- a/lab/public/bundle/manifest/scene156.json +++ b/lab/public/bundle/manifest/scene156.json @@ -1,10 +1,9 @@ { - "rawKB": 58.8, - "gzipKB": 22.8, + "rawKB": 57.8, + "gzipKB": 22.4, "ignoredRawKB": 0, "runtimeChunks": [ - "scene156-standard-renderable-DJlsSdaM.js", - "scene156-wgsl-helpers-CwHFFXvt.js", + "scene156-standard-renderable-Bl156GhT.js", "scene156.js" ] } diff --git a/lab/public/bundle/manifest/scene16.json b/lab/public/bundle/manifest/scene16.json index 5613f8b48b..03d1411d31 100644 --- a/lab/public/bundle/manifest/scene16.json +++ b/lab/public/bundle/manifest/scene16.json @@ -1,12 +1,11 @@ { - "rawKB": 48.9, - "gzipKB": 19.6, + "rawKB": 47.8, + "gzipKB": 19.2, "ignoredRawKB": 0, "runtimeChunks": [ - "scene16-standard-renderable-CXUbe7VR.js", + "scene16-standard-renderable-CkJ8UtwR.js", "scene16-thin-instance-fragment-CBn2miAC.js", "scene16-thin-instance-gpu-oR8PF1wB.js", - "scene16-wgsl-helpers-CwHFFXvt.js", "scene16.js" ] } diff --git a/lab/public/bundle/manifest/scene17.json b/lab/public/bundle/manifest/scene17.json index 31b13dc82c..ae53c077be 100644 --- a/lab/public/bundle/manifest/scene17.json +++ b/lab/public/bundle/manifest/scene17.json @@ -1,6 +1,6 @@ { - "rawKB": 85.9, - "gzipKB": 35.7, + "rawKB": 84.8, + "gzipKB": 35.2, "ignoredRawKB": 0, "runtimeChunks": [ "scene17-generate-mipmaps-DdI_QVIx.js", @@ -9,10 +9,9 @@ "scene17-rgbd-decode-aydmE8bD.js", "scene17-shader-composer-Bga-tI-0.js", "scene17-singlelight-hemispheric-wgsl-DXh7-K43.js", - "scene17-standard-renderable-DhjJVqDv.js", + "scene17-standard-renderable-ChlC1inf.js", "scene17-thin-instance-fragment-CBn2miAC.js", "scene17-thin-instance-gpu-BthweFeQ.js", - "scene17-wgsl-helpers-CwHFFXvt.js", "scene17.js" ] } diff --git a/lab/public/bundle/manifest/scene170.json b/lab/public/bundle/manifest/scene170.json index 8da43fbd7e..8008d2e0c9 100644 --- a/lab/public/bundle/manifest/scene170.json +++ b/lab/public/bundle/manifest/scene170.json @@ -1,11 +1,10 @@ { - "rawKB": 51.6, - "gzipKB": 20.4, + "rawKB": 50.5, + "gzipKB": 20, "ignoredRawKB": 1485.2, "runtimeChunks": [ "scene170-recast-navigation-CYBQI-zY-Dry_z7x_.js", - "scene170-standard-renderable-awCOjW3n.js", - "scene170-wgsl-helpers-CwHFFXvt.js", + "scene170-standard-renderable-ZooVi18e.js", "scene170.js" ] } diff --git a/lab/public/bundle/manifest/scene171.json b/lab/public/bundle/manifest/scene171.json index 7f44597238..efb1afc8b8 100644 --- a/lab/public/bundle/manifest/scene171.json +++ b/lab/public/bundle/manifest/scene171.json @@ -1,16 +1,15 @@ { - "rawKB": 96.4, - "gzipKB": 39.2, + "rawKB": 95.3, + "gzipKB": 38.8, "ignoredRawKB": 1485.2, "runtimeChunks": [ - "scene171-generate-mipmaps-DXPozdXM.js", + "scene171-generate-mipmaps-DciVh-Qu.js", "scene171-gltf-glb-parser-COBAbifQ.js", - "scene171-pbr-renderable-U8xtN7DF.js", + "scene171-pbr-renderable-Q1yQ1-Iu.js", "scene171-recast-navigation-CYBQI-zY-Dry_z7x_.js", "scene171-shader-composer-CgJmQyJj.js", "scene171-singlelight-hemispheric-wgsl-CeuKqi92.js", - "scene171-standard-renderable-DBKlvAnr.js", - "scene171-wgsl-helpers-CwHFFXvt.js", + "scene171-standard-renderable-C00icSsM.js", "scene171.js" ] } diff --git a/lab/public/bundle/manifest/scene172.json b/lab/public/bundle/manifest/scene172.json index b545481af6..98c7af850f 100644 --- a/lab/public/bundle/manifest/scene172.json +++ b/lab/public/bundle/manifest/scene172.json @@ -1,11 +1,10 @@ { - "rawKB": 59.9, - "gzipKB": 23.5, + "rawKB": 58.9, + "gzipKB": 23, "ignoredRawKB": 1485.2, "runtimeChunks": [ "scene172-recast-navigation-CYBQI-zY-Dry_z7x_.js", - "scene172-standard-renderable-DKUEOmYA.js", - "scene172-wgsl-helpers-CwHFFXvt.js", + "scene172-standard-renderable-DQ8t6v5m.js", "scene172.js" ] } diff --git a/lab/public/bundle/manifest/scene173.json b/lab/public/bundle/manifest/scene173.json index a9a0d48721..f0c6e4abe0 100644 --- a/lab/public/bundle/manifest/scene173.json +++ b/lab/public/bundle/manifest/scene173.json @@ -1,11 +1,10 @@ { - "rawKB": 62.1, - "gzipKB": 24.2, + "rawKB": 61, + "gzipKB": 23.7, "ignoredRawKB": 1485.2, "runtimeChunks": [ "scene173-recast-navigation-CYBQI-zY-Dry_z7x_.js", - "scene173-standard-renderable-jbBENzb2.js", - "scene173-wgsl-helpers-CwHFFXvt.js", + "scene173-standard-renderable-dFvXDtqw.js", "scene173.js" ] } diff --git a/lab/public/bundle/manifest/scene174.json b/lab/public/bundle/manifest/scene174.json index 1e85a4694c..682cc1b51d 100644 --- a/lab/public/bundle/manifest/scene174.json +++ b/lab/public/bundle/manifest/scene174.json @@ -1,16 +1,15 @@ { - "rawKB": 97, - "gzipKB": 39.6, + "rawKB": 96, + "gzipKB": 39.2, "ignoredRawKB": 1485.2, "runtimeChunks": [ - "scene174-generate-mipmaps-oyz7Zcb3.js", + "scene174-generate-mipmaps-DOk08rXN.js", "scene174-gltf-glb-parser-V10AO6Mf.js", - "scene174-pbr-renderable-FyaqLZqu.js", + "scene174-pbr-renderable-DWCycXIJ.js", "scene174-recast-navigation-CYBQI-zY-Dry_z7x_.js", "scene174-shader-composer-CgJmQyJj.js", "scene174-singlelight-hemispheric-wgsl-STW_78f5.js", - "scene174-standard-renderable-CwcJW6qL.js", - "scene174-wgsl-helpers-CwHFFXvt.js", + "scene174-standard-renderable-B7BOkKqy.js", "scene174.js" ] } diff --git a/lab/public/bundle/manifest/scene175.json b/lab/public/bundle/manifest/scene175.json index d5dec7464a..a3471ce71d 100644 --- a/lab/public/bundle/manifest/scene175.json +++ b/lab/public/bundle/manifest/scene175.json @@ -1,16 +1,15 @@ { - "rawKB": 95.3, - "gzipKB": 38.9, + "rawKB": 94.3, + "gzipKB": 38.5, "ignoredRawKB": 1485.2, "runtimeChunks": [ - "scene175-generate-mipmaps-B-d91NI_.js", + "scene175-generate-mipmaps-C7PmApd7.js", "scene175-gltf-glb-parser-BmlEZ507.js", - "scene175-pbr-renderable-DjBc-dib.js", + "scene175-pbr-renderable-nE57aWWx.js", "scene175-recast-navigation-CYBQI-zY-Dry_z7x_.js", "scene175-shader-composer-CgJmQyJj.js", "scene175-singlelight-hemispheric-wgsl-D-nS_1oq.js", - "scene175-standard-renderable-DmsClrbv.js", - "scene175-wgsl-helpers-CwHFFXvt.js", + "scene175-standard-renderable-CYerlzcF.js", "scene175.js" ] } diff --git a/lab/public/bundle/manifest/scene18.json b/lab/public/bundle/manifest/scene18.json index c688573be6..4ca4cf2b92 100644 --- a/lab/public/bundle/manifest/scene18.json +++ b/lab/public/bundle/manifest/scene18.json @@ -1,15 +1,14 @@ { - "rawKB": 60.7, - "gzipKB": 24.4, + "rawKB": 59.7, + "gzipKB": 23.9, "ignoredRawKB": 0, "runtimeChunks": [ "scene18-generate-mipmaps-CORvzSVx.js", "scene18-material-view-Dua1bl7W.js", "scene18-no-color-view-DPM4VP7h.js", "scene18-shadow-task-t_t6oLxe.js", - "scene18-standard-renderable-M2ivaWTL.js", + "scene18-standard-renderable-HehChBxy.js", "scene18-std-shadow-fragment-pwyXRo4i.js", - "scene18-wgsl-helpers-CwHFFXvt.js", "scene18.js" ] } diff --git a/lab/public/bundle/manifest/scene2.json b/lab/public/bundle/manifest/scene2.json index 9f40d2a040..0f663314b5 100644 --- a/lab/public/bundle/manifest/scene2.json +++ b/lab/public/bundle/manifest/scene2.json @@ -1,10 +1,9 @@ { - "rawKB": 47, - "gzipKB": 18.8, + "rawKB": 46, + "gzipKB": 18.4, "ignoredRawKB": 0, "runtimeChunks": [ - "scene2-standard-renderable-BiFo_CfT.js", - "scene2-wgsl-helpers-CwHFFXvt.js", + "scene2-standard-renderable-CLfaRvJ6.js", "scene2.js" ] } diff --git a/lab/public/bundle/manifest/scene200.json b/lab/public/bundle/manifest/scene200.json index 3f20c4ee26..de8d783acb 100644 --- a/lab/public/bundle/manifest/scene200.json +++ b/lab/public/bundle/manifest/scene200.json @@ -1,10 +1,9 @@ { - "rawKB": 46.8, - "gzipKB": 18.7, + "rawKB": 45.8, + "gzipKB": 18.2, "ignoredRawKB": 0, "runtimeChunks": [ - "scene200-standard-renderable-CmdaDWAN.js", - "scene200-wgsl-helpers-CwHFFXvt.js", + "scene200-standard-renderable-CDg0mS2W.js", "scene200.js" ] } diff --git a/lab/public/bundle/manifest/scene201.json b/lab/public/bundle/manifest/scene201.json index 98c6f467ac..7d45ce52de 100644 --- a/lab/public/bundle/manifest/scene201.json +++ b/lab/public/bundle/manifest/scene201.json @@ -1,13 +1,12 @@ { - "rawKB": 48.6, - "gzipKB": 19.7, + "rawKB": 47.6, + "gzipKB": 19.3, "ignoredRawKB": 0, "runtimeChunks": [ "scene201-_mat4-storage-f64-BubF55_X.js", "scene201-floating-origin-18rYq_DG.js", "scene201-pack-mat4-with-offset-BS-Lz8k7.js", - "scene201-standard-renderable-BT6iqp8p.js", - "scene201-wgsl-helpers-CwHFFXvt.js", + "scene201-standard-renderable-C4YKR7PM.js", "scene201.js" ] } diff --git a/lab/public/bundle/manifest/scene202.json b/lab/public/bundle/manifest/scene202.json index 35695f64a4..e7d7cda21e 100644 --- a/lab/public/bundle/manifest/scene202.json +++ b/lab/public/bundle/manifest/scene202.json @@ -1,13 +1,12 @@ { - "rawKB": 49.4, - "gzipKB": 20, + "rawKB": 48.3, + "gzipKB": 19.6, "ignoredRawKB": 0, "runtimeChunks": [ "scene202-_mat4-storage-f64-Cxw5KwUZ.js", "scene202-floating-origin-BG1gyRgj.js", "scene202-pack-mat4-with-offset-BS-Lz8k7.js", - "scene202-standard-renderable-C6pqEWwQ.js", - "scene202-wgsl-helpers-CwHFFXvt.js", + "scene202-standard-renderable-C0ZdJKYn.js", "scene202.js" ] } diff --git a/lab/public/bundle/manifest/scene203.json b/lab/public/bundle/manifest/scene203.json index b396da646c..cda57e9916 100644 --- a/lab/public/bundle/manifest/scene203.json +++ b/lab/public/bundle/manifest/scene203.json @@ -1,13 +1,12 @@ { - "rawKB": 49.7, - "gzipKB": 20.2, + "rawKB": 48.6, + "gzipKB": 19.7, "ignoredRawKB": 0, "runtimeChunks": [ "scene203-_mat4-storage-f64-C0lTlSaC.js", "scene203-floating-origin-CBr6x8Ml.js", "scene203-pack-mat4-with-offset-BS-Lz8k7.js", - "scene203-standard-renderable-DiimDZpT.js", - "scene203-wgsl-helpers-CwHFFXvt.js", + "scene203-standard-renderable-4vsd-D0F.js", "scene203.js" ] } diff --git a/lab/public/bundle/manifest/scene204.json b/lab/public/bundle/manifest/scene204.json index dbb5ec71cb..076125847b 100644 --- a/lab/public/bundle/manifest/scene204.json +++ b/lab/public/bundle/manifest/scene204.json @@ -1,15 +1,14 @@ { - "rawKB": 51.1, - "gzipKB": 20.9, + "rawKB": 50, + "gzipKB": 20.4, "ignoredRawKB": 0, "runtimeChunks": [ "scene204-_mat4-storage-f64-7Hs0bt2y.js", "scene204-floating-origin-GYPpgH2l.js", "scene204-pack-mat4-with-offset-BS-Lz8k7.js", - "scene204-standard-renderable-CEqz6rMQ.js", + "scene204-standard-renderable-Cfe2uFMQ.js", "scene204-thin-instance-fragment-CBn2miAC.js", "scene204-thin-instance-gpu-BPglyyv5.js", - "scene204-wgsl-helpers-CwHFFXvt.js", "scene204.js" ] } diff --git a/lab/public/bundle/manifest/scene205.json b/lab/public/bundle/manifest/scene205.json index 8507031d65..8834f3e88a 100644 --- a/lab/public/bundle/manifest/scene205.json +++ b/lab/public/bundle/manifest/scene205.json @@ -1,6 +1,6 @@ { - "rawKB": 62, - "gzipKB": 25.5, + "rawKB": 60.9, + "gzipKB": 25, "ignoredRawKB": 0, "runtimeChunks": [ "scene205-_mat4-storage-f64-BubVEbOW.js", @@ -8,8 +8,7 @@ "scene205-floating-origin-BpHUAtCM.js", "scene205-pack-mat4-with-offset-BS-Lz8k7.js", "scene205-scene-uniforms-FTYH6Ct0.js", - "scene205-standard-renderable-BN27SEi1.js", - "scene205-wgsl-helpers-CwHFFXvt.js", + "scene205-standard-renderable-DkLqwmbO.js", "scene205.js" ] } diff --git a/lab/public/bundle/manifest/scene206.json b/lab/public/bundle/manifest/scene206.json index 4a10a76d05..caa750b402 100644 --- a/lab/public/bundle/manifest/scene206.json +++ b/lab/public/bundle/manifest/scene206.json @@ -1,6 +1,6 @@ { - "rawKB": 62.3, - "gzipKB": 25.5, + "rawKB": 61.3, + "gzipKB": 25.1, "ignoredRawKB": 0, "runtimeChunks": [ "scene206-_mat4-storage-f64-FI8ZUjRd.js", @@ -8,8 +8,7 @@ "scene206-floating-origin-B3Cmn-Fn.js", "scene206-pack-mat4-with-offset-BS-Lz8k7.js", "scene206-scene-uniforms-FTYH6Ct0.js", - "scene206-standard-renderable-DLDxk5f_.js", - "scene206-wgsl-helpers-CwHFFXvt.js", + "scene206-standard-renderable-CvjHnnBy.js", "scene206.js" ] } diff --git a/lab/public/bundle/manifest/scene207.json b/lab/public/bundle/manifest/scene207.json index e10639a1bd..53bf0eec62 100644 --- a/lab/public/bundle/manifest/scene207.json +++ b/lab/public/bundle/manifest/scene207.json @@ -1,6 +1,6 @@ { - "rawKB": 59.7, - "gzipKB": 24, + "rawKB": 58.6, + "gzipKB": 23.6, "ignoredRawKB": 0, "runtimeChunks": [ "scene207-_mat4-storage-f64-B_0HYOAx.js", @@ -9,9 +9,8 @@ "scene207-no-color-view-BJnjfxE3.js", "scene207-pack-mat4-with-offset-BS-Lz8k7.js", "scene207-shadow-task-SxovdLRJ.js", - "scene207-standard-renderable-Q6qXJ1fg.js", + "scene207-standard-renderable-DEhH2f6U.js", "scene207-std-shadow-fragment-pwyXRo4i.js", - "scene207-wgsl-helpers-CwHFFXvt.js", "scene207.js" ] } diff --git a/lab/public/bundle/manifest/scene209.json b/lab/public/bundle/manifest/scene209.json index 60d08013c4..baaf8aadf3 100644 --- a/lab/public/bundle/manifest/scene209.json +++ b/lab/public/bundle/manifest/scene209.json @@ -1,14 +1,13 @@ { - "rawKB": 54.4, - "gzipKB": 22.2, + "rawKB": 53.3, + "gzipKB": 21.8, "ignoredRawKB": 0, "runtimeChunks": [ "scene209-_mat4-storage-f64-3NavC9Rv.js", "scene209-floating-origin-DMyB87f5.js", "scene209-havok-floating-origin-CkalwAjY.js", "scene209-pack-mat4-with-offset-BS-Lz8k7.js", - "scene209-standard-renderable-BhttRL8q.js", - "scene209-wgsl-helpers-CwHFFXvt.js", + "scene209-standard-renderable-CB-AoszP.js", "scene209.js" ] } diff --git a/lab/public/bundle/manifest/scene214.json b/lab/public/bundle/manifest/scene214.json index 655be7ab70..1af8f03b5e 100644 --- a/lab/public/bundle/manifest/scene214.json +++ b/lab/public/bundle/manifest/scene214.json @@ -1,14 +1,13 @@ { - "rawKB": 68.3, - "gzipKB": 27.1, + "rawKB": 67.2, + "gzipKB": 26.7, "ignoredRawKB": 0, "runtimeChunks": [ "scene214-material-view-Dua1bl7W.js", "scene214-no-color-view-5_yMJTcH.js", "scene214-shadow-task-kZBQCrfU.js", - "scene214-standard-renderable-2VrikE7W.js", + "scene214-standard-renderable-CpRmBMBT.js", "scene214-std-shadow-fragment-i_uxbIpF.js", - "scene214-wgsl-helpers-CwHFFXvt.js", "scene214.js" ] } diff --git a/lab/public/bundle/manifest/scene217.json b/lab/public/bundle/manifest/scene217.json index eaec1c3a71..8c326de9f6 100644 --- a/lab/public/bundle/manifest/scene217.json +++ b/lab/public/bundle/manifest/scene217.json @@ -1,13 +1,12 @@ { - "rawKB": 78.2, - "gzipKB": 31.5, + "rawKB": 77.1, + "gzipKB": 31.1, "ignoredRawKB": 0, "runtimeChunks": [ "scene217-multilight-wgsl-D_ZZ-Nk7.js", "scene217-pbr-renderable-CxhvLVWg.js", "scene217-shader-composer-BFQxgkqp.js", - "scene217-standard-renderable-DGQZW6Se.js", - "scene217-wgsl-helpers-CwHFFXvt.js", + "scene217-standard-renderable-CtbT01a9.js", "scene217.js" ] } diff --git a/lab/public/bundle/manifest/scene22.json b/lab/public/bundle/manifest/scene22.json index a8a95f5f54..064a772a0f 100644 --- a/lab/public/bundle/manifest/scene22.json +++ b/lab/public/bundle/manifest/scene22.json @@ -1,6 +1,6 @@ { - "rawKB": 97.7, - "gzipKB": 39.4, + "rawKB": 96.6, + "gzipKB": 38.9, "ignoredRawKB": 0, "runtimeChunks": [ "scene22-esm-shadow-view-BpdnPOo5.js", @@ -13,8 +13,7 @@ "scene22-shader-composer-Bga-tI-0.js", "scene22-shadow-fragment-core-Dbe1xNkt.js", "scene22-shadow-task-Yvrdp5XB.js", - "scene22-standard-renderable-DFYGplzb.js", - "scene22-wgsl-helpers-CwHFFXvt.js", + "scene22-standard-renderable-CjgqKCKX.js", "scene22.js" ] } diff --git a/lab/public/bundle/manifest/scene221.json b/lab/public/bundle/manifest/scene221.json index 2acb63b9d4..94b1e754b0 100644 --- a/lab/public/bundle/manifest/scene221.json +++ b/lab/public/bundle/manifest/scene221.json @@ -1,13 +1,12 @@ { - "rawKB": 100.4, - "gzipKB": 37.9, + "rawKB": 99.3, + "gzipKB": 37.5, "ignoredRawKB": 0, "runtimeChunks": [ "scene221-shader-renderable-tHF1mFau.js", - "scene221-standard-renderable-qDSfNdr4.js", + "scene221-standard-renderable-DiV6aifY.js", "scene221-swapchain-overlay-ilhN4El_.js", "scene221-ubo-layout-CnrP4RZD.js", - "scene221-wgsl-helpers-CwHFFXvt.js", "scene221.js" ] } diff --git a/lab/public/bundle/manifest/scene222.json b/lab/public/bundle/manifest/scene222.json index 1e2079b23b..dd82726e10 100644 --- a/lab/public/bundle/manifest/scene222.json +++ b/lab/public/bundle/manifest/scene222.json @@ -1,14 +1,13 @@ { - "rawKB": 111.5, - "gzipKB": 41, + "rawKB": 110.4, + "gzipKB": 40.6, "ignoredRawKB": 0, "runtimeChunks": [ "scene222-gpu-pool-CHlSfwGp.js", "scene222-shader-renderable-D9pd8HjW.js", - "scene222-standard-renderable-BdLy8HER.js", + "scene222-standard-renderable-BGCfFabL.js", "scene222-swapchain-overlay-ilhN4El_.js", "scene222-ubo-layout-Cs5YvLYZ.js", - "scene222-wgsl-helpers-CwHFFXvt.js", "scene222.js" ] } diff --git a/lab/public/bundle/manifest/scene223.json b/lab/public/bundle/manifest/scene223.json index e25ad0fbc8..595950e82f 100644 --- a/lab/public/bundle/manifest/scene223.json +++ b/lab/public/bundle/manifest/scene223.json @@ -1,11 +1,10 @@ { - "rawKB": 63.9, - "gzipKB": 24.3, + "rawKB": 62.9, + "gzipKB": 23.9, "ignoredRawKB": 0, "runtimeChunks": [ - "scene223-standard-renderable-DnE_HU3_.js", + "scene223-standard-renderable-Ckz_QFap.js", "scene223-swapchain-overlay-ilhN4El_.js", - "scene223-wgsl-helpers-CwHFFXvt.js", "scene223.js" ] } diff --git a/lab/public/bundle/manifest/scene224.json b/lab/public/bundle/manifest/scene224.json index d8f9cd07f2..05fbdef09b 100644 --- a/lab/public/bundle/manifest/scene224.json +++ b/lab/public/bundle/manifest/scene224.json @@ -1,11 +1,10 @@ { - "rawKB": 81.8, - "gzipKB": 30.4, + "rawKB": 80.7, + "gzipKB": 30, "ignoredRawKB": 0, "runtimeChunks": [ - "scene224-standard-renderable-DWNKdo2N.js", + "scene224-standard-renderable-C_bZOxUq.js", "scene224-swapchain-overlay-ilhN4El_.js", - "scene224-wgsl-helpers-CwHFFXvt.js", "scene224.js" ] } diff --git a/lab/public/bundle/manifest/scene225.json b/lab/public/bundle/manifest/scene225.json index 11153c4a14..7171310e2d 100644 --- a/lab/public/bundle/manifest/scene225.json +++ b/lab/public/bundle/manifest/scene225.json @@ -1,10 +1,9 @@ { - "rawKB": 58.2, - "gzipKB": 23.4, + "rawKB": 57.2, + "gzipKB": 23, "ignoredRawKB": 0, "runtimeChunks": [ - "scene225-standard-renderable-DKiRZ8hQ.js", - "scene225-wgsl-helpers-CwHFFXvt.js", + "scene225-standard-renderable-BDW6UtVR.js", "scene225.js" ] } diff --git a/lab/public/bundle/manifest/scene227.json b/lab/public/bundle/manifest/scene227.json index 907677dad6..5b94296228 100644 --- a/lab/public/bundle/manifest/scene227.json +++ b/lab/public/bundle/manifest/scene227.json @@ -1,10 +1,9 @@ { - "rawKB": 48.4, - "gzipKB": 19.2, + "rawKB": 47.4, + "gzipKB": 18.7, "ignoredRawKB": 0, "runtimeChunks": [ - "scene227-standard-renderable-DSZGd6oH.js", - "scene227-wgsl-helpers-CwHFFXvt.js", + "scene227-standard-renderable-CI24_mt_.js", "scene227.js" ] } diff --git a/lab/public/bundle/manifest/scene228.json b/lab/public/bundle/manifest/scene228.json index 7e9978a74e..2271150464 100644 --- a/lab/public/bundle/manifest/scene228.json +++ b/lab/public/bundle/manifest/scene228.json @@ -1,10 +1,9 @@ { - "rawKB": 50.2, - "gzipKB": 20, + "rawKB": 49.2, + "gzipKB": 19.5, "ignoredRawKB": 0, "runtimeChunks": [ - "scene228-standard-renderable-DlLkRdiv.js", - "scene228-wgsl-helpers-CwHFFXvt.js", + "scene228-standard-renderable-BL6_DDU8.js", "scene228.js" ] } diff --git a/lab/public/bundle/manifest/scene231.json b/lab/public/bundle/manifest/scene231.json new file mode 100644 index 0000000000..71e4f02c6e --- /dev/null +++ b/lab/public/bundle/manifest/scene231.json @@ -0,0 +1,12 @@ +{ + "rawKB": 52.9, + "gzipKB": 21, + "ignoredRawKB": 0, + "runtimeChunks": [ + "scene231-standard-renderable-D0Q4Homm.js", + "scene231-std-feature-hooks-C2W70yZH.js", + "scene231-std-skeleton-fragment-XbOa0aFW.js", + "scene231-std-vertex-color-fragment-BesIHRMf.js", + "scene231.js" + ] +} diff --git a/lab/public/bundle/manifest/scene24.json b/lab/public/bundle/manifest/scene24.json index b8b6d93f74..4344ce94b4 100644 --- a/lab/public/bundle/manifest/scene24.json +++ b/lab/public/bundle/manifest/scene24.json @@ -1,6 +1,6 @@ { - "rawKB": 59, - "gzipKB": 24.6, + "rawKB": 58, + "gzipKB": 24.1, "ignoredRawKB": 0, "runtimeChunks": [ "scene24-bake-local-matrix-67U-IT8C.js", @@ -8,12 +8,11 @@ "scene24-generate-mipmaps-BaRC2la_.js", "scene24-parse-camera-D4iQaH48.js", "scene24-point-light-Dzvg6X6L.js", - "scene24-standard-renderable-a3hpbuT2.js", + "scene24-standard-renderable-CqEDqzcG.js", "scene24-std-ambient-fragment-qLXGuA_5.js", "scene24-std-cube-reflection-fragment-B-EokvPj.js", "scene24-std-opacity-fragment-BMTURaOK.js", "scene24-std-specular-fragment-DhCYMq1P.js", - "scene24-wgsl-helpers-CwHFFXvt.js", "scene24.js" ] } diff --git a/lab/public/bundle/manifest/scene25.json b/lab/public/bundle/manifest/scene25.json index 3e027f7193..181cb6aa88 100644 --- a/lab/public/bundle/manifest/scene25.json +++ b/lab/public/bundle/manifest/scene25.json @@ -1,10 +1,9 @@ { - "rawKB": 52.1, - "gzipKB": 20.7, + "rawKB": 51, + "gzipKB": 20.2, "ignoredRawKB": 0, "runtimeChunks": [ - "scene25-standard-renderable-0EV0Ofua.js", - "scene25-wgsl-helpers-CwHFFXvt.js", + "scene25-standard-renderable-D-7KZT2R.js", "scene25.js" ] } diff --git a/lab/public/bundle/manifest/scene252.json b/lab/public/bundle/manifest/scene252.json index 445b05d8d9..aa6bdcff57 100644 --- a/lab/public/bundle/manifest/scene252.json +++ b/lab/public/bundle/manifest/scene252.json @@ -1,11 +1,10 @@ { - "rawKB": 49, - "gzipKB": 19.8, + "rawKB": 48, + "gzipKB": 19.4, "ignoredRawKB": 0, "runtimeChunks": [ "scene252-morph-fragment-core-BW8kE7zi.js", - "scene252-standard-renderable-BrPvNfxw.js", - "scene252-wgsl-helpers-CwHFFXvt.js", + "scene252-standard-renderable-Dhm3MYGk.js", "scene252.js" ] } diff --git a/lab/public/bundle/manifest/scene261.json b/lab/public/bundle/manifest/scene261.json index cc20e5b688..9d2666e6a7 100644 --- a/lab/public/bundle/manifest/scene261.json +++ b/lab/public/bundle/manifest/scene261.json @@ -1,10 +1,9 @@ { - "rawKB": 54.5, - "gzipKB": 21.3, + "rawKB": 53.4, + "gzipKB": 20.8, "ignoredRawKB": 0, "runtimeChunks": [ - "scene261-standard-renderable-BVWOm7Y2.js", - "scene261-wgsl-helpers-CwHFFXvt.js", + "scene261-standard-renderable-COzhP9_C.js", "scene261.js" ] } diff --git a/lab/public/bundle/manifest/scene3.json b/lab/public/bundle/manifest/scene3.json index 6b528a415d..a1f2632be8 100644 --- a/lab/public/bundle/manifest/scene3.json +++ b/lab/public/bundle/manifest/scene3.json @@ -1,11 +1,12 @@ { - "rawKB": 54, - "gzipKB": 21.6, + "rawKB": 54.3, + "gzipKB": 21.9, "ignoredRawKB": 0, "runtimeChunks": [ "scene3-scene-uniforms-FTYH6Ct0.js", "scene3-skybox-renderable-B-1mAKv9.js", - "scene3-standard-renderable-7jpxQTFQ.js", + "scene3-standard-renderable-VUEouOUq.js", + "scene3-std-fog-wgsl-D0HYiOcd.js", "scene3-wgsl-helpers-DkIRJkUm.js", "scene3.js" ] diff --git a/lab/public/bundle/manifest/scene36.json b/lab/public/bundle/manifest/scene36.json index 3df6a3db6c..ebc600ffb4 100644 --- a/lab/public/bundle/manifest/scene36.json +++ b/lab/public/bundle/manifest/scene36.json @@ -1,11 +1,10 @@ { - "rawKB": 51.7, - "gzipKB": 20.4, + "rawKB": 50.6, + "gzipKB": 19.9, "ignoredRawKB": 0, "runtimeChunks": [ - "scene36-standard-renderable-DZtkeKp5.js", + "scene36-standard-renderable-BcvUBtCB.js", "scene36-std-emissive-fragment-DthzsVUc.js", - "scene36-wgsl-helpers-CwHFFXvt.js", "scene36.js" ] } diff --git a/lab/public/bundle/manifest/scene38.json b/lab/public/bundle/manifest/scene38.json index ee1e308513..fb3fcef046 100644 --- a/lab/public/bundle/manifest/scene38.json +++ b/lab/public/bundle/manifest/scene38.json @@ -1,10 +1,9 @@ { - "rawKB": 61.3, - "gzipKB": 24.2, + "rawKB": 60.2, + "gzipKB": 23.8, "ignoredRawKB": 0, "runtimeChunks": [ - "scene38-standard-renderable-DkWPKKU6.js", - "scene38-wgsl-helpers-CwHFFXvt.js", + "scene38-standard-renderable-BqnUkSQa.js", "scene38.js" ] } diff --git a/lab/public/bundle/manifest/scene4.json b/lab/public/bundle/manifest/scene4.json index 7cf31215f7..1b19fc9170 100644 --- a/lab/public/bundle/manifest/scene4.json +++ b/lab/public/bundle/manifest/scene4.json @@ -1,6 +1,6 @@ { - "rawKB": 72.6, - "gzipKB": 28.6, + "rawKB": 71.6, + "gzipKB": 28.2, "ignoredRawKB": 0, "runtimeChunks": [ "scene4-esm-shadow-view-7yqUFA1x.js", @@ -8,9 +8,8 @@ "scene4-material-view-Dua1bl7W.js", "scene4-no-color-view-jut7SxNQ.js", "scene4-shadow-task-DKE6tIG9.js", - "scene4-standard-renderable-C-a_tPgC.js", + "scene4-standard-renderable-BJByRoqq.js", "scene4-std-shadow-fragment-pwyXRo4i.js", - "scene4-wgsl-helpers-CwHFFXvt.js", "scene4.js" ] } diff --git a/lab/public/bundle/manifest/scene40.json b/lab/public/bundle/manifest/scene40.json index fcaaf3da39..b449e27acd 100644 --- a/lab/public/bundle/manifest/scene40.json +++ b/lab/public/bundle/manifest/scene40.json @@ -1,10 +1,9 @@ { - "rawKB": 49.7, - "gzipKB": 20, + "rawKB": 48.6, + "gzipKB": 19.5, "ignoredRawKB": 0, "runtimeChunks": [ - "scene40-standard-renderable-CYGiOwyw.js", - "scene40-wgsl-helpers-CwHFFXvt.js", + "scene40-standard-renderable-BSbBBde4.js", "scene40.js" ] } diff --git a/lab/public/bundle/manifest/scene41.json b/lab/public/bundle/manifest/scene41.json index acacb9746e..119ce50134 100644 --- a/lab/public/bundle/manifest/scene41.json +++ b/lab/public/bundle/manifest/scene41.json @@ -1,6 +1,6 @@ { - "rawKB": 92.9, - "gzipKB": 36.9, + "rawKB": 91.8, + "gzipKB": 36.5, "ignoredRawKB": 0, "runtimeChunks": [ "scene41-generate-mipmaps-BWxJCIcc.js", @@ -10,8 +10,7 @@ "scene41-gltf-sampler-desc-E_7RaQlV.js", "scene41-point-light-CnkkP9oB.js", "scene41-shader-composer-CgJmQyJj.js", - "scene41-standard-renderable-CRuhIfFk.js", - "scene41-wgsl-helpers-CwHFFXvt.js", + "scene41-standard-renderable-14ulrC65.js", "scene41.js" ] } diff --git a/lab/public/bundle/manifest/scene42.json b/lab/public/bundle/manifest/scene42.json index 457b675044..338294eb49 100644 --- a/lab/public/bundle/manifest/scene42.json +++ b/lab/public/bundle/manifest/scene42.json @@ -1,10 +1,9 @@ { - "rawKB": 51.3, - "gzipKB": 20.3, + "rawKB": 50.2, + "gzipKB": 19.9, "ignoredRawKB": 0, "runtimeChunks": [ - "scene42-standard-renderable-B-mqcMeS.js", - "scene42-wgsl-helpers-CwHFFXvt.js", + "scene42-standard-renderable-DO0JZNHm.js", "scene42.js" ] } diff --git a/lab/public/bundle/manifest/scene43.json b/lab/public/bundle/manifest/scene43.json index 8941365d23..93ea0ec283 100644 --- a/lab/public/bundle/manifest/scene43.json +++ b/lab/public/bundle/manifest/scene43.json @@ -1,12 +1,11 @@ { - "rawKB": 58.1, - "gzipKB": 23.2, + "rawKB": 57.1, + "gzipKB": 22.8, "ignoredRawKB": 0, "runtimeChunks": [ - "scene43-standard-renderable-BeC4p3CE.js", + "scene43-standard-renderable-D5wwk8xt.js", "scene43-thin-instance-fragment-CBn2miAC.js", "scene43-thin-instance-gpu-UxO3XtwE.js", - "scene43-wgsl-helpers-CwHFFXvt.js", "scene43.js" ] } diff --git a/lab/public/bundle/manifest/scene44.json b/lab/public/bundle/manifest/scene44.json index e65f5586a9..d90734a1d9 100644 --- a/lab/public/bundle/manifest/scene44.json +++ b/lab/public/bundle/manifest/scene44.json @@ -1,10 +1,9 @@ { - "rawKB": 50.2, - "gzipKB": 20.1, + "rawKB": 49.1, + "gzipKB": 19.6, "ignoredRawKB": 0, "runtimeChunks": [ - "scene44-standard-renderable-Bu9LYSr6.js", - "scene44-wgsl-helpers-CwHFFXvt.js", + "scene44-standard-renderable-D7grmEBD.js", "scene44.js" ] } diff --git a/lab/public/bundle/manifest/scene45.json b/lab/public/bundle/manifest/scene45.json index d45e53cbd3..afa0f0e24b 100644 --- a/lab/public/bundle/manifest/scene45.json +++ b/lab/public/bundle/manifest/scene45.json @@ -1,10 +1,9 @@ { - "rawKB": 51.3, - "gzipKB": 20.4, + "rawKB": 50.3, + "gzipKB": 20, "ignoredRawKB": 0, "runtimeChunks": [ - "scene45-standard-renderable-BieL1U6W.js", - "scene45-wgsl-helpers-CwHFFXvt.js", + "scene45-standard-renderable-DTOeh1Uk.js", "scene45.js" ] } diff --git a/lab/public/bundle/manifest/scene46.json b/lab/public/bundle/manifest/scene46.json index a202d34e56..d2aa068a66 100644 --- a/lab/public/bundle/manifest/scene46.json +++ b/lab/public/bundle/manifest/scene46.json @@ -1,10 +1,9 @@ { - "rawKB": 54.4, - "gzipKB": 21.4, + "rawKB": 53.4, + "gzipKB": 20.9, "ignoredRawKB": 0, "runtimeChunks": [ - "scene46-standard-renderable-hx5y8uJN.js", - "scene46-wgsl-helpers-CwHFFXvt.js", + "scene46-standard-renderable-t06DqCCs.js", "scene46.js" ] } diff --git a/lab/public/bundle/manifest/scene47.json b/lab/public/bundle/manifest/scene47.json index 0138a7dd1c..4bab5ddcff 100644 --- a/lab/public/bundle/manifest/scene47.json +++ b/lab/public/bundle/manifest/scene47.json @@ -1,6 +1,6 @@ { - "rawKB": 92.2, - "gzipKB": 36.8, + "rawKB": 91.1, + "gzipKB": 36.3, "ignoredRawKB": 0, "runtimeChunks": [ "scene47-generate-mipmaps-CmIGpFd5.js", @@ -9,8 +9,7 @@ "scene47-gltf-glb-parser-6-tsF2C2.js", "scene47-gltf-sampler-desc-BJMmnJDF.js", "scene47-shader-composer-CgJmQyJj.js", - "scene47-standard-renderable-CUonYaUG.js", - "scene47-wgsl-helpers-CwHFFXvt.js", + "scene47-standard-renderable-C8-hTfN6.js", "scene47.js" ] } diff --git a/lab/public/bundle/manifest/scene48.json b/lab/public/bundle/manifest/scene48.json index 02832779bb..bdd92db00d 100644 --- a/lab/public/bundle/manifest/scene48.json +++ b/lab/public/bundle/manifest/scene48.json @@ -1,10 +1,9 @@ { - "rawKB": 54.3, - "gzipKB": 21.6, + "rawKB": 53.3, + "gzipKB": 21.1, "ignoredRawKB": 0, "runtimeChunks": [ - "scene48-standard-renderable-C3pxu2Wg.js", - "scene48-wgsl-helpers-CwHFFXvt.js", + "scene48-standard-renderable-BLdyT1WV.js", "scene48.js" ] } diff --git a/lab/public/bundle/manifest/scene49.json b/lab/public/bundle/manifest/scene49.json index b6ae5b3185..42793cc073 100644 --- a/lab/public/bundle/manifest/scene49.json +++ b/lab/public/bundle/manifest/scene49.json @@ -1,12 +1,11 @@ { - "rawKB": 92.8, - "gzipKB": 35, + "rawKB": 91.7, + "gzipKB": 34.5, "ignoredRawKB": 0, "runtimeChunks": [ - "scene49-standard-renderable-ytL-ZaT7.js", + "scene49-standard-renderable-DypapRX-.js", "scene49-swapchain-overlay-ilhN4El_.js", "scene49-ubo-layout-CnrP4RZD.js", - "scene49-wgsl-helpers-CwHFFXvt.js", "scene49.js" ] } diff --git a/lab/public/bundle/manifest/scene52.json b/lab/public/bundle/manifest/scene52.json index c3cfaadd2f..c49737435b 100644 --- a/lab/public/bundle/manifest/scene52.json +++ b/lab/public/bundle/manifest/scene52.json @@ -1,10 +1,9 @@ { - "rawKB": 57.4, - "gzipKB": 23.1, + "rawKB": 56.4, + "gzipKB": 22.6, "ignoredRawKB": 0, "runtimeChunks": [ - "scene52-standard-renderable-DXnTjsje.js", - "scene52-wgsl-helpers-CwHFFXvt.js", + "scene52-standard-renderable-Dnrt9hqQ.js", "scene52.js" ] } diff --git a/lab/public/bundle/manifest/scene53.json b/lab/public/bundle/manifest/scene53.json index 2362aab3ae..fa538634d6 100644 --- a/lab/public/bundle/manifest/scene53.json +++ b/lab/public/bundle/manifest/scene53.json @@ -1,10 +1,9 @@ { - "rawKB": 57.6, - "gzipKB": 23, + "rawKB": 56.5, + "gzipKB": 22.5, "ignoredRawKB": 0, "runtimeChunks": [ - "scene53-standard-renderable-BwQeEm6J.js", - "scene53-wgsl-helpers-CwHFFXvt.js", + "scene53-standard-renderable-BHOghp1k.js", "scene53.js" ] } diff --git a/lab/public/bundle/manifest/scene54.json b/lab/public/bundle/manifest/scene54.json index 9c6755c2eb..5c964221dc 100644 --- a/lab/public/bundle/manifest/scene54.json +++ b/lab/public/bundle/manifest/scene54.json @@ -1,12 +1,11 @@ { - "rawKB": 60, - "gzipKB": 24.3, + "rawKB": 58.9, + "gzipKB": 23.9, "ignoredRawKB": 0, "runtimeChunks": [ "scene54-billboard-renderable-BeTxDz7N.js", "scene54-scene-uniforms-FTYH6Ct0.js", - "scene54-standard-renderable-gymiA78h.js", - "scene54-wgsl-helpers-CwHFFXvt.js", + "scene54-standard-renderable-DVTnTwex.js", "scene54.js" ] } diff --git a/lab/public/bundle/manifest/scene56.json b/lab/public/bundle/manifest/scene56.json index a8833b727c..f3dd8605ac 100644 --- a/lab/public/bundle/manifest/scene56.json +++ b/lab/public/bundle/manifest/scene56.json @@ -1,12 +1,11 @@ { - "rawKB": 60.3, - "gzipKB": 24.4, + "rawKB": 59.2, + "gzipKB": 24, "ignoredRawKB": 0, "runtimeChunks": [ "scene56-billboard-renderable-rwL30tEO.js", "scene56-scene-uniforms-FTYH6Ct0.js", - "scene56-standard-renderable-DLV9jNG_.js", - "scene56-wgsl-helpers-CwHFFXvt.js", + "scene56-standard-renderable-C919me1H.js", "scene56.js" ] } diff --git a/lab/public/bundle/manifest/scene57.json b/lab/public/bundle/manifest/scene57.json index aad25185e7..0b2c8060f3 100644 --- a/lab/public/bundle/manifest/scene57.json +++ b/lab/public/bundle/manifest/scene57.json @@ -1,12 +1,11 @@ { - "rawKB": 60.1, - "gzipKB": 24.3, + "rawKB": 59, + "gzipKB": 23.8, "ignoredRawKB": 0, "runtimeChunks": [ "scene57-billboard-renderable-CUrr_OIJ.js", "scene57-scene-uniforms-FTYH6Ct0.js", - "scene57-standard-renderable-Cv1M5x8s.js", - "scene57-wgsl-helpers-CwHFFXvt.js", + "scene57-standard-renderable-DGgYnSaX.js", "scene57.js" ] } diff --git a/lab/public/bundle/manifest/scene59.json b/lab/public/bundle/manifest/scene59.json index 87f49781c6..90eea99aff 100644 --- a/lab/public/bundle/manifest/scene59.json +++ b/lab/public/bundle/manifest/scene59.json @@ -1,12 +1,11 @@ { - "rawKB": 63.1, - "gzipKB": 25.4, + "rawKB": 62.1, + "gzipKB": 24.9, "ignoredRawKB": 0, "runtimeChunks": [ "scene59-billboard-renderable-KN9gLXsu.js", "scene59-scene-uniforms-FTYH6Ct0.js", - "scene59-standard-renderable-DnLmB7RO.js", - "scene59-wgsl-helpers-CwHFFXvt.js", + "scene59-standard-renderable-DSbJcNia.js", "scene59.js" ] } diff --git a/lab/public/bundle/manifest/scene75.json b/lab/public/bundle/manifest/scene75.json index 5552b1faeb..09d3fb2fe3 100644 --- a/lab/public/bundle/manifest/scene75.json +++ b/lab/public/bundle/manifest/scene75.json @@ -1,10 +1,9 @@ { - "rawKB": 50.4, - "gzipKB": 20.1, + "rawKB": 49.3, + "gzipKB": 19.7, "ignoredRawKB": 0, "runtimeChunks": [ - "scene75-standard-renderable-CYo4Y48I.js", - "scene75-wgsl-helpers-CwHFFXvt.js", + "scene75-standard-renderable-CzXYDff7.js", "scene75.js" ] } diff --git a/lab/public/bundle/manifest/scene84.json b/lab/public/bundle/manifest/scene84.json index b084224767..f820d15867 100644 --- a/lab/public/bundle/manifest/scene84.json +++ b/lab/public/bundle/manifest/scene84.json @@ -1,6 +1,6 @@ { - "rawKB": 84.6, - "gzipKB": 36.2, + "rawKB": 83.5, + "gzipKB": 35.7, "ignoredRawKB": 5.5, "runtimeChunks": [ "scene84-_math-factory-DFVyS8gB.js", @@ -17,12 +17,11 @@ "scene84-node-renderable-UtCGlhZJ.js", "scene84-screen-size-block-yVY2pHhh.js", "scene84-screen-space-block-Cfi3u-na.js", - "scene84-standard-renderable-B56QP5k3.js", + "scene84-standard-renderable-BAlJYZmI.js", "scene84-transform-block-PEh7VaCZ.js", "scene84-twirl-block-tQLhuAc6.js", "scene84-vector-splitter-BMf4DQi8.js", "scene84-vertex-output-C7G5u6Y0.js", - "scene84-wgsl-helpers-CwHFFXvt.js", "scene84.js" ] } diff --git a/lab/public/bundle/manifest/scene9.json b/lab/public/bundle/manifest/scene9.json index 8a66579e2e..17b4e5a13e 100644 --- a/lab/public/bundle/manifest/scene9.json +++ b/lab/public/bundle/manifest/scene9.json @@ -1,12 +1,12 @@ { "rawKB": 59.6, - "gzipKB": 24.1, + "gzipKB": 24.2, "ignoredRawKB": 0, "runtimeChunks": [ "scene9-generate-mipmaps-xw5BdfZd.js", "scene9-normal-map-fragment-BjHVJ1qk.js", "scene9-point-light-ESYN5_k0.js", - "scene9-standard-renderable-DIEblUNe.js", + "scene9-standard-renderable-B7mFN3Tk.js", "scene9-std-ambient-fragment-BT8qGSob.js", "scene9-std-opacity-fragment-Dwz7NrjB.js", "scene9-std-reflection-fragment-Cb2Nq9Do.js", diff --git a/lab/public/bundle/manifest/scene90.json b/lab/public/bundle/manifest/scene90.json index 35ea4b15a3..0355c59fdf 100644 --- a/lab/public/bundle/manifest/scene90.json +++ b/lab/public/bundle/manifest/scene90.json @@ -1,11 +1,10 @@ { - "rawKB": 59.3, - "gzipKB": 23.5, + "rawKB": 58.2, + "gzipKB": 23, "ignoredRawKB": 0, "runtimeChunks": [ "scene90-generate-mipmaps-SRXClq-S.js", - "scene90-standard-renderable-CTe6AqwL.js", - "scene90-wgsl-helpers-CwHFFXvt.js", + "scene90-standard-renderable-D9oDnwRJ.js", "scene90.js" ] } diff --git a/lab/public/bundle/manifest/scene91.json b/lab/public/bundle/manifest/scene91.json index 364bd4c468..3bf62f5d8e 100644 --- a/lab/public/bundle/manifest/scene91.json +++ b/lab/public/bundle/manifest/scene91.json @@ -1,12 +1,11 @@ { - "rawKB": 58.6, - "gzipKB": 23.4, + "rawKB": 57.5, + "gzipKB": 23, "ignoredRawKB": 1227.9, "runtimeChunks": [ "scene91-generate-mipmaps-CUt8_7AA.js", "scene91-manifold-Sh8xE2da-C8q62PkN.js", - "scene91-standard-renderable-x17W8JUu.js", - "scene91-wgsl-helpers-CwHFFXvt.js", + "scene91-standard-renderable-CYw-ygSr.js", "scene91.js" ] } diff --git a/lab/public/bundle/manifest/scene94.json b/lab/public/bundle/manifest/scene94.json index 9f236fb1d5..f4fed1dbb0 100644 --- a/lab/public/bundle/manifest/scene94.json +++ b/lab/public/bundle/manifest/scene94.json @@ -1,11 +1,10 @@ { - "rawKB": 63.9, - "gzipKB": 25.2, + "rawKB": 62.8, + "gzipKB": 24.8, "ignoredRawKB": 0, "runtimeChunks": [ "scene94-billboard-renderable-BgBdc7uu.js", - "scene94-standard-renderable-C7WeVEUG.js", - "scene94-wgsl-helpers-CwHFFXvt.js", + "scene94-standard-renderable-DbK2IvV9.js", "scene94.js" ] } diff --git a/lab/public/bundle/manifest/scene95.json b/lab/public/bundle/manifest/scene95.json index 73867ec8b4..0637d8d95f 100644 --- a/lab/public/bundle/manifest/scene95.json +++ b/lab/public/bundle/manifest/scene95.json @@ -1,11 +1,10 @@ { - "rawKB": 65, - "gzipKB": 25.6, + "rawKB": 63.9, + "gzipKB": 25.1, "ignoredRawKB": 0, "runtimeChunks": [ "scene95-billboard-renderable-D1Ojksz4.js", - "scene95-standard-renderable-Dlc9juiN.js", - "scene95-wgsl-helpers-CwHFFXvt.js", + "scene95-standard-renderable-BDf4WrSx.js", "scene95.js" ] } diff --git a/lab/public/bundle/manifest/scene98.json b/lab/public/bundle/manifest/scene98.json index cfc55ac6ff..8507a069db 100644 --- a/lab/public/bundle/manifest/scene98.json +++ b/lab/public/bundle/manifest/scene98.json @@ -1,12 +1,11 @@ { - "rawKB": 60.2, - "gzipKB": 24.4, + "rawKB": 59.2, + "gzipKB": 23.9, "ignoredRawKB": 0, "runtimeChunks": [ "scene98-billboard-renderable-jlPUXki_.js", "scene98-scene-uniforms-FTYH6Ct0.js", - "scene98-standard-renderable-uFFg5Orm.js", - "scene98-wgsl-helpers-CwHFFXvt.js", + "scene98-standard-renderable-BA0XJKwc.js", "scene98.js" ] } diff --git a/packages/babylon-lite/src/material/standard/standard-group-builder.ts b/packages/babylon-lite/src/material/standard/standard-group-builder.ts index a37ea81bdd..f0d261d173 100644 --- a/packages/babylon-lite/src/material/standard/standard-group-builder.ts +++ b/packages/babylon-lite/src/material/standard/standard-group-builder.ts @@ -55,6 +55,10 @@ export function getStandardGroupBuilder(): MeshGroupBuilder { let shadowFragment: any; let morphFragment: any; let cull: typeof import("../../mesh/thin-instance-cull-binding.js") | undefined; + // Fog WGSL is dynamic-imported only when the scene has fog, so non-fog Standard scenes + // bundle zero fog bytes (a static import would defeat tree-shaking — see std-fog-wgsl.ts). + let fogHelper = ""; + let fogBlock = ""; const imports: Promise[] = []; if (hasTI) { @@ -90,6 +94,14 @@ export function getStandardGroupBuilder(): MeshGroupBuilder { }) ); } + if (scene.fog) { + imports.push( + import("./std-fog-wgsl.js").then((m) => { + fogHelper = m.STD_FOG_HELPER; + fogBlock = m.STD_FOG_BLOCK; + }) + ); + } // Deform/vertex mesh-feature StdExts (skeleton, vertex color) are dispatched from the // module-local `_stdMeshExtDispatch` registry, populated only by the `enableStandard*()` // opt-ins loaders/scenes call. When no feature was enabled the registry is `null` and this @@ -117,7 +129,7 @@ export function getStandardGroupBuilder(): MeshGroupBuilder { } const renderableMod = await import("./standard-renderable.js"); - const result = renderableMod.buildStandardMeshRenderables(scene, meshes, { tiSync, tiFragment, shadowFragment, morphFragment, cull }); + const result = renderableMod.buildStandardMeshRenderables(scene, meshes, { tiSync, tiFragment, shadowFragment, morphFragment, cull, fogHelper, fogBlock }); // Wire the per-mesh rebuild closure used by material swap + per-pass override. builder._rebuildSingle = result.rebuildSingle; return result; diff --git a/packages/babylon-lite/src/material/standard/standard-pipeline.ts b/packages/babylon-lite/src/material/standard/standard-pipeline.ts index e1ff38710e..35d55ac5b6 100644 --- a/packages/babylon-lite/src/material/standard/standard-pipeline.ts +++ b/packages/babylon-lite/src/material/standard/standard-pipeline.ts @@ -68,7 +68,14 @@ export function _isStandardUvOffsetEnabled(): boolean { /** Compose Standard shader via the generic ShaderComposer. * @param fragments - Optional extra fragments (e.g. thin-instance). */ -export function composeStandardShader(features: number, _meshFeatures = 0, fragments: ShaderFragment[] = [], esmShadowDepthCode = ""): ComposedShader { +export function composeStandardShader( + features: number, + _meshFeatures = 0, + fragments: ShaderFragment[] = [], + esmShadowDepthCode = "", + fogHelper = "", + fogBlock = "" +): ComposedShader { const has = (bit: number) => (features & bit) !== 0; const pc = fragments[0]?._pc; const template = createStandardTemplate( @@ -81,6 +88,8 @@ export function composeStandardShader(features: number, _meshFeatures = 0, fragm _noColorOutput: has(NO_COLOR_OUTPUT), _esmShadowOutput: has(ESM_SHADOW_OUTPUT), _hasMorph: !!pc, + _fogHelper: fogHelper, + _fogBlock: fogBlock, }, esmShadowDepthCode ); @@ -154,6 +163,8 @@ export function getOrCreateStandardBindings( fragments: ShaderFragment[] = [], shaderKey = "", esmShadowDepthCode = "", + fogHelper = "", + fogBlock = "", stencil: StencilState | null = null ): StandardShaderBindings { ensureDevice(engine); @@ -170,7 +181,7 @@ export function getOrCreateStandardBindings( const cc = getComposedCache(); let composed = cc.get(key); if (!composed) { - composed = composeStandardShader(features, meshFeatures, fragments, esmShadowDepthCode); + composed = composeStandardShader(features, meshFeatures, fragments, esmShadowDepthCode, fogHelper, fogBlock); cc.set(key, composed); } diff --git a/packages/babylon-lite/src/material/standard/standard-renderable.ts b/packages/babylon-lite/src/material/standard/standard-renderable.ts index 31b3232a1a..4117b6b4f2 100644 --- a/packages/babylon-lite/src/material/standard/standard-renderable.ts +++ b/packages/babylon-lite/src/material/standard/standard-renderable.ts @@ -67,6 +67,11 @@ export interface StdFragmentFactories { morphFragment?: () => ShaderFragment; /** Present only when the scene has at least one culling-enabled thin-instance mesh. */ cull?: typeof import("../../mesh/thin-instance-cull-binding.js"); + /** `calcFogFactor` helper WGSL — present (non-empty) only when the scene has fog; threaded + * from the dynamic `std-fog-wgsl` import so non-fog scenes bundle zero fog bytes. */ + fogHelper?: string; + /** Fog blend block WGSL — present alongside `fogHelper`. */ + fogBlock?: string; } /** Build Renderable(s) + a SceneUniformUpdater for a set of standard meshes. @@ -75,7 +80,7 @@ export interface StdFragmentFactories { export function buildStandardMeshRenderables(scene: SceneContext, meshes: Mesh[], factories: StdFragmentFactories): MeshGroupBuildResult { const engine = scene.surface.engine; const device = engine._device; - const { tiSync, tiFragment, shadowFragment, cull, morphFragment } = factories; + const { tiSync, tiFragment, shadowFragment, cull, morphFragment, fogHelper = "", fogBlock = "" } = factories; // Collect per-light shadow info. const shadowLights: { lightIndex: number; shadowType: "esm" | "pcf" | "csm"; gen: ShadowGenerator }[] = []; @@ -158,7 +163,17 @@ export function buildStandardMeshRenderables(scene: SceneContext, meshes: Mesh[] } } const esmShadowDepthCode = (features & ESM_SHADOW_OUTPUT) !== 0 ? (mat as StandardMaterialProps & { readonly _esmShadowDepthCode: string })._esmShadowDepthCode : ""; - const bindings = getOrCreateStandardBindings(engine, features, meshFeatures, frags, shaderKey, esmShadowDepthCode, (mat as StandardMaterialProps).stencil ?? null); + const bindings = getOrCreateStandardBindings( + engine, + features, + meshFeatures, + frags, + shaderKey, + esmShadowDepthCode, + fogHelper, + fogBlock, + (mat as StandardMaterialProps).stencil ?? null + ); const meshShadowGens = receiveShadows ? shadowLights.map((sl) => sl.gen) : []; diff --git a/packages/babylon-lite/src/material/standard/standard-template.ts b/packages/babylon-lite/src/material/standard/standard-template.ts index c4082360ae..bd197f980c 100644 --- a/packages/babylon-lite/src/material/standard/standard-template.ts +++ b/packages/babylon-lite/src/material/standard/standard-template.ts @@ -11,7 +11,6 @@ */ import type { ShaderTemplate, UboField, VertexAttribute, Varying, BindingDecl } from "../../shader/fragment-types.js"; -import { WGSL_FOG } from "../../shader/wgsl-helpers.js"; import { MAX_LIGHTS } from "../../light/types.js"; import { appendMeshLightUboFields, meshLightIndexWGSL } from "../../render/lights-ubo.js"; @@ -69,6 +68,11 @@ export interface StandardTemplateConfig { readonly _esmShadowOutput?: boolean; /** @internal Has morph targets — switches the vertex shader to morphedPos/morphedNorm (defined by the morph fragment's VR slot). */ readonly _hasMorph?: boolean; + /** @internal `calcFogFactor` helper WGSL, supplied (non-empty) only when the scene has fog; + * threaded in from `std-fog-wgsl` so non-fog scenes bundle zero fog bytes. "" otherwise. */ + readonly _fogHelper?: string; + /** @internal Fog blend block WGSL, supplied alongside `_fogHelper`. "" for non-fog scenes. */ + readonly _fogBlock?: string; } /** @@ -76,7 +80,7 @@ export interface StandardTemplateConfig { * The template contains slot markers that the composer fills. */ export function createStandardTemplate(config: StandardTemplateConfig, esmShadowDepthCode = ""): ShaderTemplate { - const { _diffuse, _needsUV, _needsUV2, _diffuseUsesUV2, _disableLighting, _noColorOutput, _esmShadowOutput, _hasMorph } = config; + const { _diffuse, _needsUV, _needsUV2, _diffuseUsesUV2, _disableLighting, _noColorOutput, _esmShadowOutput, _hasMorph, _fogHelper = "", _fogBlock = "" } = config; // ── Base vertex attributes ────────────────────────────────── const _baseVertexAttributes: VertexAttribute[] = [ @@ -201,7 +205,7 @@ _1: f32, }; `; - const helpers = _disableLighting ? WGSL_FOG : WGSL_FOG + LIGHTING_FN; + const helpers = _disableLighting ? _fogHelper : _fogHelper + LIGHTING_FN; // reflection, shadow, bump helpers are provided by their respective fragments // Main fragment body — mirrors old composeFragmentShader exactly @@ -281,10 +285,7 @@ ${_noColorOutput ? "return;" : _esmShadowOutput ? esmShadowDepthCode : ""} ${lightingBlock} /*BC*/ color = vec4(max(color.rgb, vec3(0.0)), color.a); -if (scene.vFogInfos.x > 0.0) { -let fog = calcFogFactor(input.vf); -color = vec4(mix(scene.vFogColor.rgb, color.rgb, fog), color.a); -} +${_fogBlock} /*BA*/ ${_noColorOutput ? "" : "return color;"} }`; diff --git a/packages/babylon-lite/src/material/standard/std-fog-wgsl.ts b/packages/babylon-lite/src/material/standard/std-fog-wgsl.ts new file mode 100644 index 0000000000..1f258cc0ec --- /dev/null +++ b/packages/babylon-lite/src/material/standard/std-fog-wgsl.ts @@ -0,0 +1,23 @@ +/** + * Standard fog receiver WGSL — the `calcFogFactor` helper plus the fog blend block. + * + * Dynamically imported by `standard-group-builder` ONLY when `scene.fog` is set, then threaded into + * the Standard template as plain strings (mirrors the PBR fog path in `pbr-fog-wgsl.ts`). This keeps + * every byte of fog WGSL out of the bundles of Standard scenes that don't use fog — a static `import` + * of the helper into `standard-template` would defeat tree-shaking and inflate every Standard scene + * (see GUIDANCE §4c′). This is the ONLY module that statically holds the fog WGSL for Standard. + * + * Parity notes (matches Babylon.js `default.fragment` exactly): + * - Standard mixes fog into the final LDR colour at the end of the fragment (after the lit colour is + * clamped to non-negative), with the raw (non-linearised) `vFogColor` — no gamma round-trip, unlike PBR. + * - The fog FACTOR is the linear/exp/exp2 distance falloff from `calcFogFactor` (no `pow(.., 2.2)`). + * - The runtime `vFogInfos.x > 0.0` guard lets `fogMode` toggle none/linear/exp/exp2 at runtime. + */ + +import { WGSL_FOG } from "../../shader/wgsl-helpers.js"; + +/** `calcFogFactor` + `E_FOG` helper WGSL (reads `scene.vFogInfos`). */ +export const STD_FOG_HELPER = WGSL_FOG; + +/** Fog blend block, emitted at the end of the Standard fragment (operates on the final LDR `color`). */ +export const STD_FOG_BLOCK = "if(scene.vFogInfos.x>0.0){let fog=calcFogFactor(input.vf);color=vec4(mix(scene.vFogColor.rgb,color.rgb,fog),color.a);}"; diff --git a/scene-config.json b/scene-config.json index 275d94f287..88be8b622f 100644 --- a/scene-config.json +++ b/scene-config.json @@ -27,7 +27,7 @@ "slug": "scene3-fog", "name": "Scene 3 — Fog + Skybox", "maxMad": 0.01, - "maxRawKB": 54, + "maxRawKB": 54.5, "description": "Exponential² fog, multiple colored boxes, skybox, ground plane.", "tags": ["fog", "procedural", "std"], "skipPerf": true