From df7868e1fccb960307eec24098c26e83f4cec280 Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Fri, 31 Oct 2025 11:16:58 -0700 Subject: [PATCH 1/8] Fix for vertex pulling of interleaved buffers --- .../src/Engines/WebGPU/webgpuDrawContext.ts | 32 +++++++++++++++- .../src/Materials/materialHelper.functions.ts | 38 +++++++++++++++++++ .../dev/core/src/Materials/shaderMaterial.ts | 21 ++++++++++ .../src/ShadersWGSL/iblVoxelGrid.vertex.fx | 22 +++++++++-- 4 files changed, 108 insertions(+), 5 deletions(-) diff --git a/packages/dev/core/src/Engines/WebGPU/webgpuDrawContext.ts b/packages/dev/core/src/Engines/WebGPU/webgpuDrawContext.ts index 5f9eee24df9..cec25763943 100644 --- a/packages/dev/core/src/Engines/WebGPU/webgpuDrawContext.ts +++ b/packages/dev/core/src/Engines/WebGPU/webgpuDrawContext.ts @@ -1,4 +1,4 @@ -import type { VertexBuffer } from "../../Buffers/buffer"; +import { VertexBuffer } from "../../Buffers/buffer"; import type { DataBuffer } from "../../Buffers/dataBuffer"; import type { WebGPUDataBuffer } from "../../Meshes/WebGPU/webgpuDataBuffer"; import type { Nullable } from "../../types"; @@ -170,6 +170,11 @@ export class WebGPUDrawContext implements IDrawContext { this._bufferManager.setRawData(this.indirectDrawBuffer, 0, this._indirectDrawData, 0, 20); } + /** + * Metadata storage for vertex buffer configurations (stride, offset, etc.) + */ + public vertexBufferMetadata: { [name: string]: { strideInFloats: number; offsetInFloats: number; componentCount: number } } = {}; + public setVertexPulling( useVertexPulling: boolean, webgpuPipelineContext: WebGPUPipelineContext, @@ -186,6 +191,9 @@ export class WebGPUDrawContext implements IDrawContext { const bufferNames = webgpuPipelineContext.shaderProcessingContext.bufferNames; + // Clear previous metadata + this.vertexBufferMetadata = {}; + if (overrideVertexBuffers) { for (const attributeName in overrideVertexBuffers) { const vertexBuffer = overrideVertexBuffers[attributeName]; @@ -196,6 +204,17 @@ export class WebGPUDrawContext implements IDrawContext { const buffer = vertexBuffer.effectiveBuffer as Nullable; this.setBuffer(attributeName, useVertexPulling ? buffer : null); + + // Store metadata for vertex pulling + if (useVertexPulling) { + const bytesPerElement = + vertexBuffer.type === VertexBuffer.FLOAT ? 4 : vertexBuffer.type === VertexBuffer.UNSIGNED_INT || vertexBuffer.type === VertexBuffer.INT ? 4 : 2; + this.vertexBufferMetadata[attributeName] = { + strideInFloats: vertexBuffer.effectiveByteStride / bytesPerElement, // Convert bytes to float32 elements + offsetInFloats: vertexBuffer.effectiveByteOffset / bytesPerElement, // Convert bytes to float32 elements + componentCount: vertexBuffer.getSize(), + }; + } } } @@ -212,6 +231,17 @@ export class WebGPUDrawContext implements IDrawContext { const buffer = vertexBuffer.effectiveBuffer as Nullable; this.setBuffer(attributeName, useVertexPulling ? buffer : null); + + // Store metadata for vertex pulling + if (useVertexPulling) { + const bytesPerElement = + vertexBuffer.type === VertexBuffer.FLOAT ? 4 : vertexBuffer.type === VertexBuffer.UNSIGNED_INT || vertexBuffer.type === VertexBuffer.INT ? 4 : 2; + this.vertexBufferMetadata[attributeName] = { + strideInFloats: vertexBuffer.effectiveByteStride / bytesPerElement, // Convert bytes to float32 elements + offsetInFloats: vertexBuffer.effectiveByteOffset / bytesPerElement, // Convert bytes to float32 elements + componentCount: vertexBuffer.getSize(), + }; + } } if (bufferNames.indexOf("indices") !== -1) { diff --git a/packages/dev/core/src/Materials/materialHelper.functions.ts b/packages/dev/core/src/Materials/materialHelper.functions.ts index 07b785ac8ee..e4e2296e62c 100644 --- a/packages/dev/core/src/Materials/materialHelper.functions.ts +++ b/packages/dev/core/src/Materials/materialHelper.functions.ts @@ -598,6 +598,44 @@ export function GetFogState(mesh: AbstractMesh, scene: Scene) { return scene.fogEnabled && mesh.applyFog && scene.fogMode !== Constants.FOGMODE_NONE; } +/** + * Helper used to prepare vertex pulling metadata defines (stride, offset, component count) + * This should be called when USE_VERTEX_PULLING is enabled to properly configure buffer access + * @param mesh The mesh being rendered + * @param defines The defines object to update + * @param attributeNames Array of attribute names to configure (e.g., ["position", "normal"]) + */ +export function PrepareDefinesForVertexPullingMetadata(mesh: AbstractMesh, defines: any, attributeNames: string[] = ["position"]): void { + if (!defines["USE_VERTEX_PULLING"]) { + return; + } + + const geometry = mesh.geometry; + if (!geometry) { + return; + } + + for (const attributeName of attributeNames) { + const vertexBuffer = geometry.getVertexBuffer(attributeName); + if (!vertexBuffer) { + continue; + } + + const upperName = attributeName.toUpperCase(); + + // Calculate stride in float32 elements + const strideInFloats = vertexBuffer.effectiveByteStride / 4; + defines[`${upperName}_STRIDE_IN_FLOATS`] = strideInFloats || vertexBuffer.getSize(); + + // Calculate offset in float32 elements + const offsetInFloats = vertexBuffer.effectiveByteOffset / 4; + defines[`${upperName}_OFFSET_IN_FLOATS`] = offsetInFloats; + + // Component count + defines[`${upperName}_COMPONENT_COUNT`] = vertexBuffer.getSize(); + } +} + /** * Helper used to prepare the list of defines associated with misc. values for shader compilation * @param mesh defines the current mesh diff --git a/packages/dev/core/src/Materials/shaderMaterial.ts b/packages/dev/core/src/Materials/shaderMaterial.ts index d3aa0051188..a5c61882dc9 100644 --- a/packages/dev/core/src/Materials/shaderMaterial.ts +++ b/packages/dev/core/src/Materials/shaderMaterial.ts @@ -915,6 +915,27 @@ export class ShaderMaterial extends PushMaterial { defines.push("#define VERTEX_PULLING_INDEX_BUFFER_32BITS"); } } + + // Add vertex buffer metadata defines for proper stride/offset handling + const geometry = renderingMesh.geometry; + if (geometry) { + const vertexBuffers = geometry.getVertexBuffers(); + if (vertexBuffers) { + for (const attributeName in vertexBuffers) { + const vertexBuffer = vertexBuffers[attributeName]; + if (vertexBuffer) { + const upperName = attributeName.toUpperCase(); + const strideInFloats = vertexBuffer.effectiveByteStride / 4; + const offsetInFloats = vertexBuffer.effectiveByteOffset / 4; + const componentCount = vertexBuffer.getSize(); + + defines.push(`#define ${upperName}_STRIDE_IN_FLOATS ${strideInFloats || componentCount}`); + defines.push(`#define ${upperName}_OFFSET_IN_FLOATS ${offsetInFloats}`); + defines.push(`#define ${upperName}_COMPONENT_COUNT ${componentCount}`); + } + } + } + } } const drawWrapper = storeEffectOnSubMeshes ? subMesh._getDrawWrapper(undefined, true) : this._drawWrapper; diff --git a/packages/dev/core/src/ShadersWGSL/iblVoxelGrid.vertex.fx b/packages/dev/core/src/ShadersWGSL/iblVoxelGrid.vertex.fx index 069d2f6cac5..ca6f31ceb09 100644 --- a/packages/dev/core/src/ShadersWGSL/iblVoxelGrid.vertex.fx +++ b/packages/dev/core/src/ShadersWGSL/iblVoxelGrid.vertex.fx @@ -8,7 +8,7 @@ // This shader uses vertex pulling to determine the // provoked vertex and calculate the normal. Then, based on -// the direction of teh normal, it swizzles the position to +// the direction of the normal, it swizzles the position to // maximize the rasterized area. #ifdef VERTEX_PULLING_USE_INDEX_BUFFER var indices : array; @@ -21,11 +21,25 @@ uniform invWorldScale: mat4x4f; varying vNormalizedPosition : vec3f; flat varying f_swizzle: i32; +// Vertex buffer metadata (set via defines or defaults) +#ifndef POSITION_STRIDE_IN_FLOATS +#define POSITION_STRIDE_IN_FLOATS 3 +#endif + +#ifndef POSITION_OFFSET_IN_FLOATS +#define POSITION_OFFSET_IN_FLOATS 0 +#endif + +#ifndef POSITION_COMPONENT_COUNT +#define POSITION_COMPONENT_COUNT 3 +#endif + fn readVertexPosition(index : u32)->vec3f { var pos : vec3f; - pos.x = position[index * 3]; - pos.y = position[index * 3 + 1]; - pos.z = position[index * 3 + 2]; + let baseOffset = POSITION_OFFSET_IN_FLOATS + index * POSITION_STRIDE_IN_FLOATS; + pos.x = position[baseOffset]; + pos.y = position[baseOffset + 1u]; + pos.z = position[baseOffset + 2u]; return pos; } From 719cc5b71303ebe1ca76acd9aead56d6a7ee3de0 Mon Sep 17 00:00:00 2001 From: Popov72 Date: Sun, 26 Oct 2025 16:34:25 +0100 Subject: [PATCH 2/8] Fix bones when using vertex pulling --- .../IBLShadows/iblShadowsVoxelRenderer.ts | 1 + .../ShadersInclude/bonesDeclaration.fx | 8 +++---- .../src/ShadersWGSL/iblVoxelGrid.vertex.fx | 23 ++++++++++++++++--- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/packages/dev/core/src/Rendering/IBLShadows/iblShadowsVoxelRenderer.ts b/packages/dev/core/src/Rendering/IBLShadows/iblShadowsVoxelRenderer.ts index b1af8433a09..47821fea0d9 100644 --- a/packages/dev/core/src/Rendering/IBLShadows/iblShadowsVoxelRenderer.ts +++ b/packages/dev/core/src/Rendering/IBLShadows/iblShadowsVoxelRenderer.ts @@ -738,6 +738,7 @@ export class _IblShadowsVoxelRenderer { if (axis === 1) { upDirection = new Vector3(1, 0, 0); } + mrt.onBeforeRenderObservable.clear(); mrt.onBeforeRenderObservable.add(() => { voxelMaterial.setMatrix("viewMatrix", Matrix.LookAtLH(cameraPosition, targetPosition, upDirection)); voxelMaterial.setMatrix("invWorldScale", this._invWorldScaleMatrix); diff --git a/packages/dev/core/src/ShadersWGSL/ShadersInclude/bonesDeclaration.fx b/packages/dev/core/src/ShadersWGSL/ShadersInclude/bonesDeclaration.fx index 3ab2d1f410b..18770a5c482 100644 --- a/packages/dev/core/src/ShadersWGSL/ShadersInclude/bonesDeclaration.fx +++ b/packages/dev/core/src/ShadersWGSL/ShadersInclude/bonesDeclaration.fx @@ -1,9 +1,9 @@ #if NUM_BONE_INFLUENCERS > 0 - attribute matricesIndices : vec4; - attribute matricesWeights : vec4; + attribute matricesIndices : vec4f; + attribute matricesWeights : vec4f; #if NUM_BONE_INFLUENCERS > 4 - attribute matricesIndicesExtra : vec4; - attribute matricesWeightsExtra : vec4; + attribute matricesIndicesExtra : vec4f; + attribute matricesWeightsExtra : vec4f; #endif #ifndef BAKED_VERTEX_ANIMATION_TEXTURE diff --git a/packages/dev/core/src/ShadersWGSL/iblVoxelGrid.vertex.fx b/packages/dev/core/src/ShadersWGSL/iblVoxelGrid.vertex.fx index ca6f31ceb09..5b8facdb426 100644 --- a/packages/dev/core/src/ShadersWGSL/iblVoxelGrid.vertex.fx +++ b/packages/dev/core/src/ShadersWGSL/iblVoxelGrid.vertex.fx @@ -1,5 +1,5 @@ #include -#include +#include (attribute matricesIndices : vec4f;,,attribute matricesWeights : vec4f;,,attribute matricesIndicesExtra : vec4f;,,attribute matricesWeightsExtra : vec4f;,) #include #include @@ -13,7 +13,15 @@ #ifdef VERTEX_PULLING_USE_INDEX_BUFFER var indices : array; #endif -var position : array; +var position : array; +#if NUM_BONE_INFLUENCERS > 0 + var matricesIndices : array; + var matricesWeights : array; + #if NUM_BONE_INFLUENCERS > 4 + var matricesIndicesExtra : array; + var matricesWeightsExtra : array; + #endif +#endif uniform world : mat4x4f; uniform invWorldScale: mat4x4f; @@ -86,7 +94,16 @@ let inputPosition: vec3f = positionUpdated; #include #include -#include + +#if NUM_BONE_INFLUENCERS > 0 + let matrixIndex = matricesIndices[vertIdx]; + let matrixWeight = matricesWeights[vertIdx]; + #if NUM_BONE_INFLUENCERS > 4 + let matrixIndexExtra = matricesIndicesExtra[vertIdx]; + let matrixWeightExtra = matricesWeightsExtra[vertIdx]; + #endif +#endif +#include (vertexInputs.matricesIndices,matrixIndex,vertexInputs.matricesWeights,matrixWeight) let worldPos = finalWorld * vec4f(positionUpdated, 1.0); From 8d175604b3b5e2656a4eb4c683999a202317fd60 Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Fri, 31 Oct 2025 11:29:12 -0700 Subject: [PATCH 3/8] Fix vertex type in voxel shadows --- packages/dev/core/src/ShadersWGSL/iblVoxelGrid.vertex.fx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/dev/core/src/ShadersWGSL/iblVoxelGrid.vertex.fx b/packages/dev/core/src/ShadersWGSL/iblVoxelGrid.vertex.fx index 5b8facdb426..8093ca0dc6d 100644 --- a/packages/dev/core/src/ShadersWGSL/iblVoxelGrid.vertex.fx +++ b/packages/dev/core/src/ShadersWGSL/iblVoxelGrid.vertex.fx @@ -13,7 +13,7 @@ #ifdef VERTEX_PULLING_USE_INDEX_BUFFER var indices : array; #endif -var position : array; +var position : array; #if NUM_BONE_INFLUENCERS > 0 var matricesIndices : array; var matricesWeights : array; From cd0ae8d9cc71edf379df010661b7fa17b4c9d77b Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Fri, 31 Oct 2025 14:28:27 -0700 Subject: [PATCH 4/8] Trying to get skinned meshes working with voxelization --- .../src/Engines/WebGPU/webgpuDrawContext.ts | 36 ++----- .../src/Materials/materialHelper.functions.ts | 14 ++- .../dev/core/src/Materials/shaderMaterial.ts | 13 +-- .../src/ShadersWGSL/iblVoxelGrid.vertex.fx | 100 +++++++++++++++--- 4 files changed, 107 insertions(+), 56 deletions(-) diff --git a/packages/dev/core/src/Engines/WebGPU/webgpuDrawContext.ts b/packages/dev/core/src/Engines/WebGPU/webgpuDrawContext.ts index cec25763943..da548e5ac61 100644 --- a/packages/dev/core/src/Engines/WebGPU/webgpuDrawContext.ts +++ b/packages/dev/core/src/Engines/WebGPU/webgpuDrawContext.ts @@ -1,4 +1,4 @@ -import { VertexBuffer } from "../../Buffers/buffer"; +import type { VertexBuffer } from "../../Buffers/buffer"; import type { DataBuffer } from "../../Buffers/dataBuffer"; import type { WebGPUDataBuffer } from "../../Meshes/WebGPU/webgpuDataBuffer"; import type { Nullable } from "../../types"; @@ -171,10 +171,13 @@ export class WebGPUDrawContext implements IDrawContext { } /** - * Metadata storage for vertex buffer configurations (stride, offset, etc.) + * Setup or disable vertex pulling as needed. + * @param useVertexPulling Use vertex pulling or not + * @param webgpuPipelineContext The WebGPU pipeline context + * @param vertexBuffers The current vertex buffers + * @param indexBuffer The current index buffer + * @param overrideVertexBuffers The vertex buffers to override */ - public vertexBufferMetadata: { [name: string]: { strideInFloats: number; offsetInFloats: number; componentCount: number } } = {}; - public setVertexPulling( useVertexPulling: boolean, webgpuPipelineContext: WebGPUPipelineContext, @@ -191,9 +194,6 @@ export class WebGPUDrawContext implements IDrawContext { const bufferNames = webgpuPipelineContext.shaderProcessingContext.bufferNames; - // Clear previous metadata - this.vertexBufferMetadata = {}; - if (overrideVertexBuffers) { for (const attributeName in overrideVertexBuffers) { const vertexBuffer = overrideVertexBuffers[attributeName]; @@ -204,17 +204,6 @@ export class WebGPUDrawContext implements IDrawContext { const buffer = vertexBuffer.effectiveBuffer as Nullable; this.setBuffer(attributeName, useVertexPulling ? buffer : null); - - // Store metadata for vertex pulling - if (useVertexPulling) { - const bytesPerElement = - vertexBuffer.type === VertexBuffer.FLOAT ? 4 : vertexBuffer.type === VertexBuffer.UNSIGNED_INT || vertexBuffer.type === VertexBuffer.INT ? 4 : 2; - this.vertexBufferMetadata[attributeName] = { - strideInFloats: vertexBuffer.effectiveByteStride / bytesPerElement, // Convert bytes to float32 elements - offsetInFloats: vertexBuffer.effectiveByteOffset / bytesPerElement, // Convert bytes to float32 elements - componentCount: vertexBuffer.getSize(), - }; - } } } @@ -231,17 +220,6 @@ export class WebGPUDrawContext implements IDrawContext { const buffer = vertexBuffer.effectiveBuffer as Nullable; this.setBuffer(attributeName, useVertexPulling ? buffer : null); - - // Store metadata for vertex pulling - if (useVertexPulling) { - const bytesPerElement = - vertexBuffer.type === VertexBuffer.FLOAT ? 4 : vertexBuffer.type === VertexBuffer.UNSIGNED_INT || vertexBuffer.type === VertexBuffer.INT ? 4 : 2; - this.vertexBufferMetadata[attributeName] = { - strideInFloats: vertexBuffer.effectiveByteStride / bytesPerElement, // Convert bytes to float32 elements - offsetInFloats: vertexBuffer.effectiveByteOffset / bytesPerElement, // Convert bytes to float32 elements - componentCount: vertexBuffer.getSize(), - }; - } } if (bufferNames.indexOf("indices") !== -1) { diff --git a/packages/dev/core/src/Materials/materialHelper.functions.ts b/packages/dev/core/src/Materials/materialHelper.functions.ts index e4e2296e62c..b726f0f7b66 100644 --- a/packages/dev/core/src/Materials/materialHelper.functions.ts +++ b/packages/dev/core/src/Materials/materialHelper.functions.ts @@ -22,6 +22,7 @@ import { MaterialFlags } from "./materialFlags"; import { Texture } from "./Textures/texture"; import type { CubeTexture } from "./Textures/cubeTexture"; import type { Color3 } from "core/Maths/math.color"; +import { GetTypeByteLength } from "../Buffers/bufferUtils"; // For backwards compatibility, we export everything from the pure version of this file. export * from "./materialHelper.functions.pure"; @@ -622,17 +623,14 @@ export function PrepareDefinesForVertexPullingMetadata(mesh: AbstractMesh, defin } const upperName = attributeName.toUpperCase(); - + const sizeInBytes = GetTypeByteLength(vertexBuffer.type); // Calculate stride in float32 elements - const strideInFloats = vertexBuffer.effectiveByteStride / 4; - defines[`${upperName}_STRIDE_IN_FLOATS`] = strideInFloats || vertexBuffer.getSize(); + const stride = vertexBuffer.effectiveByteStride / sizeInBytes; + defines[`${upperName}_STRIDE`] = stride || vertexBuffer.getSize(); // Calculate offset in float32 elements - const offsetInFloats = vertexBuffer.effectiveByteOffset / 4; - defines[`${upperName}_OFFSET_IN_FLOATS`] = offsetInFloats; - - // Component count - defines[`${upperName}_COMPONENT_COUNT`] = vertexBuffer.getSize(); + const offset = vertexBuffer.effectiveByteOffset / sizeInBytes; + defines[`${upperName}_OFFSET`] = offset; } } diff --git a/packages/dev/core/src/Materials/shaderMaterial.ts b/packages/dev/core/src/Materials/shaderMaterial.ts index a5c61882dc9..318d02f06b8 100644 --- a/packages/dev/core/src/Materials/shaderMaterial.ts +++ b/packages/dev/core/src/Materials/shaderMaterial.ts @@ -21,6 +21,7 @@ import { EngineStore } from "../Engines/engineStore"; import { Constants } from "../Engines/constants"; import { AddClipPlaneUniforms, BindClipPlane, PrepareStringDefinesForClipPlanes } from "./clipPlaneMaterialHelper"; import type { WebGPUEngine } from "core/Engines/webgpuEngine"; +import { GetTypeByteLength } from "../Buffers/bufferUtils"; import type { ExternalTexture } from "./Textures/externalTexture"; import { @@ -924,14 +925,14 @@ export class ShaderMaterial extends PushMaterial { for (const attributeName in vertexBuffers) { const vertexBuffer = vertexBuffers[attributeName]; if (vertexBuffer) { + const componentBytes = GetTypeByteLength(vertexBuffer.type); const upperName = attributeName.toUpperCase(); - const strideInFloats = vertexBuffer.effectiveByteStride / 4; - const offsetInFloats = vertexBuffer.effectiveByteOffset / 4; - const componentCount = vertexBuffer.getSize(); + const stride = vertexBuffer.effectiveByteStride / 4; + const offset = vertexBuffer.effectiveByteOffset / 4; - defines.push(`#define ${upperName}_STRIDE_IN_FLOATS ${strideInFloats || componentCount}`); - defines.push(`#define ${upperName}_OFFSET_IN_FLOATS ${offsetInFloats}`); - defines.push(`#define ${upperName}_COMPONENT_COUNT ${componentCount}`); + defines.push(`#define ${upperName}_STRIDE ${stride}`); + defines.push(`#define ${upperName}_OFFSET ${offset}`); + defines.push(`#define ${upperName}_COMPONENT_BYTES ${componentBytes}`); } } } diff --git a/packages/dev/core/src/ShadersWGSL/iblVoxelGrid.vertex.fx b/packages/dev/core/src/ShadersWGSL/iblVoxelGrid.vertex.fx index 8093ca0dc6d..18d444f8f26 100644 --- a/packages/dev/core/src/ShadersWGSL/iblVoxelGrid.vertex.fx +++ b/packages/dev/core/src/ShadersWGSL/iblVoxelGrid.vertex.fx @@ -15,11 +15,11 @@ var indices : array; #endif var position : array; #if NUM_BONE_INFLUENCERS > 0 - var matricesIndices : array; - var matricesWeights : array; + var matricesIndices : array; + var matricesWeights : array; #if NUM_BONE_INFLUENCERS > 4 - var matricesIndicesExtra : array; - var matricesWeightsExtra : array; + var matricesIndicesExtra : array; + var matricesWeightsExtra : array; #endif #endif @@ -30,12 +30,12 @@ varying vNormalizedPosition : vec3f; flat varying f_swizzle: i32; // Vertex buffer metadata (set via defines or defaults) -#ifndef POSITION_STRIDE_IN_FLOATS -#define POSITION_STRIDE_IN_FLOATS 3 +#ifndef POSITION_STRIDE +#define POSITION_STRIDE 3 #endif -#ifndef POSITION_OFFSET_IN_FLOATS -#define POSITION_OFFSET_IN_FLOATS 0 +#ifndef POSITION_OFFSET +#define POSITION_OFFSET 0 #endif #ifndef POSITION_COMPONENT_COUNT @@ -44,13 +44,87 @@ flat varying f_swizzle: i32; fn readVertexPosition(index : u32)->vec3f { var pos : vec3f; - let baseOffset = POSITION_OFFSET_IN_FLOATS + index * POSITION_STRIDE_IN_FLOATS; + let baseOffset = POSITION_OFFSET + index * POSITION_STRIDE; pos.x = position[baseOffset]; pos.y = position[baseOffset + 1u]; pos.z = position[baseOffset + 2u]; return pos; } +#if NUM_BONE_INFLUENCERS > 0 +// Matrix indices are stored as UNSIGNED_BYTE (4 bytes packed into u32) +#ifndef MATRICESINDICES_STRIDE +#define MATRICESINDICES_STRIDE 1 +#endif +#ifndef MATRICESINDICES_OFFSET +#define MATRICESINDICES_OFFSET 0 +#endif + +fn readMatrixIndices(index : u32) -> vec4f { + let baseOffset = MATRICESINDICES_OFFSET + index * MATRICESINDICES_STRIDE; + #if MATRICESINDICES_COMPONENT_BYTES == 1 + let packed = matricesIndices[baseOffset]; + // Extract 4 bytes from u32 and convert to floats + return vec4f( + f32(packed & 0xFFu), + f32((packed >> 8u) & 0xFFu), + f32((packed >> 16u) & 0xFFu), + f32((packed >> 24u) & 0xFFu) + ); + #elif MATRICESINDICES_COMPONENT_BYTES == 2 + let packed1 = matricesIndices[baseOffset]; + let packed2 = matricesIndices[baseOffset + 1u]; + // Extract 4 bytes from two u32 and convert to floats + return vec4f( + f32(packed1 & 0xFFFFu), + f32((packed1 >> 16u) & 0xFFFFu), + f32(packed2 & 0xFFFFu), + f32((packed2 >> 16u) & 0xFFFFu) + ); + #endif +} + +#ifndef MATRICESWEIGHTS_STRIDE +#define MATRICESWEIGHTS_STRIDE 4 +#endif +#ifndef MATRICESWEIGHTS_OFFSET +#define MATRICESWEIGHTS_OFFSET 0 +#endif + +fn readMatrixWeights(index : u32) -> vec4f { + let baseOffset = MATRICESWEIGHTS_OFFSET + index * MATRICESWEIGHTS_STRIDE; + return vec4f( + matricesWeights[baseOffset], + matricesWeights[baseOffset + 1u], + matricesWeights[baseOffset + 2u], + matricesWeights[baseOffset + 3u] + ); +} + +#if NUM_BONE_INFLUENCERS > 4 +fn readMatrixIndicesExtra(index : u32) -> vec4f { + let baseOffset = MATRICESINDICESEXTRA_OFFSET + index * MATRICESINDICESEXTRA_STRIDE; + let packed = matricesIndicesExtra[baseOffset]; + return vec4f( + f32(packed & 0xFFu), + f32((packed >> 8u) & 0xFFu), + f32((packed >> 16u) & 0xFFu), + f32((packed >> 24u) & 0xFFu) + ); +} + +fn readMatrixWeightsExtra(index : u32) -> vec4f { + let baseOffset = MATRICESWEIGHTSEXTRA_OFFSET + index * MATRICESWEIGHTSEXTRA_STRIDE; + return vec4f( + matricesWeightsExtra[baseOffset], + matricesWeightsExtra[baseOffset + 1u], + matricesWeightsExtra[baseOffset + 2u], + matricesWeightsExtra[baseOffset + 3u] + ); +} +#endif +#endif + fn readVertexIndex(index : u32)->u32 { #ifndef VERTEX_PULLING_USE_INDEX_BUFFER return index; @@ -96,11 +170,11 @@ let inputPosition: vec3f = positionUpdated; #include #if NUM_BONE_INFLUENCERS > 0 - let matrixIndex = matricesIndices[vertIdx]; - let matrixWeight = matricesWeights[vertIdx]; + let matrixIndex = readMatrixIndices(vertIdx); + let matrixWeight = readMatrixWeights(vertIdx); #if NUM_BONE_INFLUENCERS > 4 - let matrixIndexExtra = matricesIndicesExtra[vertIdx]; - let matrixWeightExtra = matricesWeightsExtra[vertIdx]; + let matrixIndexExtra = readMatrixIndicesExtra(vertIdx); + let matrixWeightExtra = readMatrixWeightsExtra(vertIdx); #endif #endif #include (vertexInputs.matricesIndices,matrixIndex,vertexInputs.matricesWeights,matrixWeight) From 61f7e37f2d0dcd455730041b55d26cd2dc402c9f Mon Sep 17 00:00:00 2001 From: Popov72 Date: Mon, 3 Nov 2025 16:31:00 +0100 Subject: [PATCH 5/8] Fix wrong shadows with morphs --- packages/dev/core/src/Materials/shaderMaterial.ts | 2 +- packages/dev/core/src/ShadersWGSL/iblVoxelGrid.vertex.fx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/dev/core/src/Materials/shaderMaterial.ts b/packages/dev/core/src/Materials/shaderMaterial.ts index 318d02f06b8..c2ef04f2287 100644 --- a/packages/dev/core/src/Materials/shaderMaterial.ts +++ b/packages/dev/core/src/Materials/shaderMaterial.ts @@ -910,7 +910,7 @@ export class ShaderMaterial extends PushMaterial { defines.push("#define USE_VERTEX_PULLING"); const indexBuffer = renderingMesh.geometry?.getIndexBuffer(); - if (indexBuffer) { + if (indexBuffer && !(renderingMesh as Mesh).isUnIndexed) { defines.push("#define VERTEX_PULLING_USE_INDEX_BUFFER"); if (indexBuffer.is32Bits) { defines.push("#define VERTEX_PULLING_INDEX_BUFFER_32BITS"); diff --git a/packages/dev/core/src/ShadersWGSL/iblVoxelGrid.vertex.fx b/packages/dev/core/src/ShadersWGSL/iblVoxelGrid.vertex.fx index 18d444f8f26..037bd3983dc 100644 --- a/packages/dev/core/src/ShadersWGSL/iblVoxelGrid.vertex.fx +++ b/packages/dev/core/src/ShadersWGSL/iblVoxelGrid.vertex.fx @@ -163,7 +163,7 @@ fn main(input : VertexInputs) -> FragmentInputs { #include let inputPosition: vec3f = positionUpdated; -#include (vertexInputs.position\\),inputPosition))[0..maxSimultaneousMorphTargets] +#include (vertexInputs.position\\),inputPosition),vertexInputs.vertexIndex,vertIdx)[0..maxSimultaneousMorphTargets] #include From 3d8897e660dc3754d86c9c369b2c8705da01b485 Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Fri, 7 Nov 2025 11:31:01 -0800 Subject: [PATCH 6/8] Fix for multiple voxelization calls at once --- package-lock.json | 84 ++++++++++++------- .../IBLShadows/iblShadowsVoxelRenderer.ts | 3 + 2 files changed, 55 insertions(+), 32 deletions(-) diff --git a/package-lock.json b/package-lock.json index fee5b6297a6..7e1e0b914b9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -109,6 +109,7 @@ "version": "7.27.3", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.3.tgz", "integrity": "sha512-hyrN8ivxfvJ4i0fIJuV4EOlV0WDMz5Ui4StRTgVaAvWeiRCilXgwVvxJKtFQ3TKtHgJscB2YiXKGNJuVwhQMtA==", + "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", @@ -2091,7 +2092,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz", "integrity": "sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==", - "peer": true, "dependencies": { "tslib": "^2.0.0" }, @@ -2729,6 +2729,7 @@ "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", "license": "MIT", + "peer": true, "dependencies": { "@floating-ui/core": "^1.7.3", "@floating-ui/utils": "^0.2.10" @@ -2745,6 +2746,7 @@ "resolved": "https://registry.npmjs.org/@fluentui-contrib/react-virtualizer/-/react-virtualizer-0.5.3.tgz", "integrity": "sha512-wjkC6/PcMbELb0rQAD2h4il5dSuzoi1tvv86NyT3JLqJsNm/qCV4i0YAYL9TejKuwl/6E8zg5pXk1fl5vJz7LA==", "license": "MIT", + "peer": true, "dependencies": { "@fluentui/react-jsx-runtime": "^9.0.29", "@fluentui/react-utilities": "^9.16.0", @@ -3209,6 +3211,7 @@ "resolved": "https://registry.npmjs.org/@fluentui/react-components/-/react-components-9.70.0.tgz", "integrity": "sha512-sMFTTGp5bR15PvDyNTeNbJT1RzVlesuOIg/YaDIeD1XjHB3um0rFsFIDBidpltcpHEBGP6rGmI4eWyjAYOeEIA==", "license": "MIT", + "peer": true, "dependencies": { "@fluentui/react-accordion": "^9.8.6", "@fluentui/react-alert": "9.0.0-beta.124", @@ -3434,6 +3437,7 @@ "resolved": "https://registry.npmjs.org/@fluentui/react-icons/-/react-icons-2.0.310.tgz", "integrity": "sha512-w6HlXYg2DXTMP94TC3dc2ij9XFUiz7WiZeSNVX2ZvDBrIrLJXKSC3iza+ig0DGqHIgV6zbfwr8cuVgRqp6c+zg==", "license": "MIT", + "peer": true, "dependencies": { "@griffel/react": "^1.0.0", "tslib": "^2.1.0" @@ -4106,6 +4110,7 @@ "resolved": "https://registry.npmjs.org/@fluentui/react-shared-contexts/-/react-shared-contexts-9.25.1.tgz", "integrity": "sha512-C15uX9dnIVe0cm2wa9WMd9KhG5pdbs9jxnzgpFvraCGpLqFHniK2xJghYBRzj66zEK6xJnuRZR89/Y8wsiO11w==", "license": "MIT", + "peer": true, "dependencies": { "@fluentui/react-theme": "^9.2.0", "@swc/helpers": "^0.5.1" @@ -4805,6 +4810,7 @@ "version": "6.7.2", "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.7.2.tgz", "integrity": "sha512-yxtOBWDrdi5DD5o1pmVdq3WMCvnobT0LU6R8RyyVXPvFRd2o79/0NCuQoCjNTeZz9EzA9xS3JxNWfv54RIHFEA==", + "peer": true, "dependencies": { "@fortawesome/fontawesome-common-types": "6.7.2" }, @@ -4827,6 +4833,7 @@ "version": "6.7.2", "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.7.2.tgz", "integrity": "sha512-GsBrnOzU8uj0LECDfD5zomZJIjrPhIlWU82AHwa2s40FKH+kcxQaBvBo3Z4TxyZHIyX8XTDxsyA33/Vx9eFuQA==", + "peer": true, "dependencies": { "@fortawesome/fontawesome-common-types": "6.7.2" }, @@ -4838,6 +4845,7 @@ "version": "0.2.2", "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.2.tgz", "integrity": "sha512-EnkrprPNqI6SXJl//m29hpaNzOp1bruISWaOiRtkMi/xSvHJlzc2j2JAYS7egxt/EbjSNV/k6Xy0AQI6vB2+1g==", + "peer": true, "dependencies": { "prop-types": "^15.8.1" }, @@ -8649,7 +8657,6 @@ "dev": true, "hasInstallScript": true, "optional": true, - "peer": true, "dependencies": { "detect-libc": "^1.0.3", "is-glob": "^4.0.3", @@ -8691,7 +8698,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">= 10.0.0" }, @@ -8712,7 +8718,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">= 10.0.0" }, @@ -8733,7 +8738,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">= 10.0.0" }, @@ -8754,7 +8758,6 @@ "os": [ "freebsd" ], - "peer": true, "engines": { "node": ">= 10.0.0" }, @@ -8775,7 +8778,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 10.0.0" }, @@ -8796,7 +8798,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 10.0.0" }, @@ -8817,7 +8818,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 10.0.0" }, @@ -8838,7 +8838,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 10.0.0" }, @@ -8859,7 +8858,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 10.0.0" }, @@ -8880,7 +8878,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 10.0.0" }, @@ -8901,7 +8898,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">= 10.0.0" }, @@ -8922,7 +8918,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">= 10.0.0" }, @@ -8943,7 +8938,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">= 10.0.0" }, @@ -8958,7 +8952,6 @@ "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", "dev": true, "optional": true, - "peer": true, "bin": { "detect-libc": "bin/detect-libc.js" }, @@ -9093,20 +9086,17 @@ "node_modules/@react-dnd/asap": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-4.0.1.tgz", - "integrity": "sha512-kLy0PJDDwvwwTXxqTFNAAllPHD73AycE9ypWeln/IguoGBEbvFcPDbCV03G52bEcC5E+YgupBE0VzHGdC8SIXg==", - "peer": true + "integrity": "sha512-kLy0PJDDwvwwTXxqTFNAAllPHD73AycE9ypWeln/IguoGBEbvFcPDbCV03G52bEcC5E+YgupBE0VzHGdC8SIXg==" }, "node_modules/@react-dnd/invariant": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-2.0.0.tgz", - "integrity": "sha512-xL4RCQBCBDJ+GRwKTFhGUW8GXa4yoDfJrPbLblc3U09ciS+9ZJXJ3Qrcs/x2IODOdIE5kQxvMmE2UKyqUictUw==", - "peer": true + "integrity": "sha512-xL4RCQBCBDJ+GRwKTFhGUW8GXa4yoDfJrPbLblc3U09ciS+9ZJXJ3Qrcs/x2IODOdIE5kQxvMmE2UKyqUictUw==" }, "node_modules/@react-dnd/shallowequal": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-2.0.0.tgz", - "integrity": "sha512-Pc/AFTdwZwEKJxFJvlxrSmGe/di+aAOBn60sremrpLo6VI/6cmiUYNNwlI5KNYttg7uypzA3ILPMPgxB2GYZEg==", - "peer": true + "integrity": "sha512-Pc/AFTdwZwEKJxFJvlxrSmGe/di+aAOBn60sremrpLo6VI/6cmiUYNNwlI5KNYttg7uypzA3ILPMPgxB2GYZEg==" }, "node_modules/@recast-navigation/core": { "version": "0.43.0", @@ -10309,7 +10299,8 @@ "node_modules/@types/dagre": { "version": "0.7.52", "resolved": "https://registry.npmjs.org/@types/dagre/-/dagre-0.7.52.tgz", - "integrity": "sha512-XKJdy+OClLk3hketHi9Qg6gTfe1F3y+UFnHxKA2rn9Dw+oXa4Gb378Ztz9HlMgZKSxpPmn4BNVh9wgkpvrK1uw==" + "integrity": "sha512-XKJdy+OClLk3hketHi9Qg6gTfe1F3y+UFnHxKA2rn9Dw+oXa4Gb378Ztz9HlMgZKSxpPmn4BNVh9wgkpvrK1uw==", + "peer": true }, "node_modules/@types/draco3d": { "version": "1.4.10", @@ -10337,6 +10328,7 @@ "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", "dev": true, + "peer": true, "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -10612,6 +10604,7 @@ "version": "22.15.21", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.21.tgz", "integrity": "sha512-EV/37Td6c+MgKAbkcLG6vqZ2zEYHD7bvSrzqqs2RIhbA6w3x+Dqz8MZM3sP6kGTeLrdoOgKZe+Xja7tUB2DNkQ==", + "peer": true, "dependencies": { "undici-types": "~6.21.0" } @@ -10671,6 +10664,7 @@ "version": "18.3.23", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.23.tgz", "integrity": "sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w==", + "peer": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -10680,6 +10674,7 @@ "version": "18.3.7", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "peer": true, "peerDependencies": { "@types/react": "^18.0.0" } @@ -10843,6 +10838,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.32.1.tgz", "integrity": "sha512-LKMrmwCPoLhM45Z00O1ulb6jwyVr2kr3XJp+G+tSEZcbauNnScewcQwtJqXDhXeYPDEjZ8C1SjXm015CirEmGg==", "dev": true, + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.32.1", "@typescript-eslint/types": "8.32.1", @@ -11309,6 +11305,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "devOptional": true, + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -11384,6 +11381,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dev": true, + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -12380,6 +12378,7 @@ "url": "https://github.com/sponsors/ai" } ], + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001716", "electron-to-chromium": "^1.5.149", @@ -13834,6 +13833,7 @@ "version": "0.8.5", "resolved": "https://registry.npmjs.org/dagre/-/dagre-0.8.5.tgz", "integrity": "sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==", + "peer": true, "dependencies": { "graphlib": "^2.1.8", "lodash": "^4.17.15" @@ -14254,7 +14254,8 @@ "node_modules/devtools-protocol": { "version": "0.0.1312386", "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1312386.tgz", - "integrity": "sha512-DPnhUXvmvKT2dFA/j7B+riVLUt9Q6RKJlcppojL5CoRywJJKLDYnRlw0gTFKfgDPHP5E04UoB71SxoJlVZy8FA==" + "integrity": "sha512-DPnhUXvmvKT2dFA/j7B+riVLUt9Q6RKJlcppojL5CoRywJJKLDYnRlw0gTFKfgDPHP5E04UoB71SxoJlVZy8FA==", + "peer": true }, "node_modules/diff": { "version": "4.0.2", @@ -14290,7 +14291,6 @@ "version": "15.0.1", "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-15.0.1.tgz", "integrity": "sha512-pqVsLKNYdIYwOesmeAC9wcfDmyAHsiZwLoIYs+bDXaUjnuGZc3h/QWFenPSPFgp2ichG50P9sIFy4yuBZd49JQ==", - "peer": true, "dependencies": { "@react-dnd/asap": "^4.0.0", "@react-dnd/invariant": "^2.0.0", @@ -14511,7 +14511,8 @@ "version": "8.6.0", "resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.6.0.tgz", "integrity": "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/embla-carousel-autoplay": { "version": "8.6.0", @@ -14938,6 +14939,7 @@ "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -16004,6 +16006,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -17370,7 +17373,6 @@ "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", - "peer": true, "dependencies": { "react-is": "^16.7.0" } @@ -17378,8 +17380,7 @@ "node_modules/hoist-non-react-statics/node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "peer": true + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/homedir-polyfill": { "version": "1.0.3", @@ -18818,6 +18819,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "peer": true, "dependencies": { "@jest/core": "^29.7.0", "@jest/types": "^29.6.3", @@ -22799,8 +22801,7 @@ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", "dev": true, - "optional": true, - "peer": true + "optional": true }, "node_modules/node-fetch": { "version": "2.7.0", @@ -23456,6 +23457,7 @@ "integrity": "sha512-wWcvwoTgiT5okdrG0RIWm1tepC17bDmSpw+MrOxnjfBjARQNTURkiq4U6cxjCVsCxNHxCrlAaBSQLZeBgJZTzQ==", "dev": true, "hasInstallScript": true, + "peer": true, "dependencies": { "@nrwl/tao": "18.3.5", "@yarnpkg/lockfile": "^1.1.0", @@ -25123,6 +25125,7 @@ "url": "https://github.com/sponsors/ai" } ], + "peer": true, "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", @@ -25225,6 +25228,7 @@ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", "dev": true, + "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -25392,6 +25396,7 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "peer": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -25553,6 +25558,7 @@ "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-22.15.0.tgz", "integrity": "sha512-XjCY1SiSEi1T7iSYuxS82ft85kwDJUS7wj1Z0eGVXKdtr5g4xnVcbjwxhq5xBnpK/E7x1VZZoJDxpjAOasHT4Q==", "hasInstallScript": true, + "peer": true, "dependencies": { "@puppeteer/browsers": "2.3.0", "cosmiconfig": "^9.0.0", @@ -25694,6 +25700,7 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -25760,6 +25767,7 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -25779,6 +25787,7 @@ "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -26096,7 +26105,6 @@ "version": "4.2.1", "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", - "peer": true, "dependencies": { "@babel/runtime": "^7.9.2" } @@ -26472,6 +26480,7 @@ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.41.1.tgz", "integrity": "sha512-cPmwD3FnFv8rKMBc1MxWCwVQFxwf1JEmSX3iQXrRVVG15zerAIXRjMFVWnd5Q5QvgKF7Aj+5ykXFhUl+QGnyOw==", "dev": true, + "peer": true, "dependencies": { "@types/estree": "1.0.7" }, @@ -26784,6 +26793,7 @@ "resolved": "https://registry.npmjs.org/sass/-/sass-1.89.0.tgz", "integrity": "sha512-ld+kQU8YTdGNjOLfRWBzewJpU5cwEv/h5yyqlSeJcj6Yh8U4TDA9UA5FPicqDz/xgRPWRSYIQNiFks21TbA9KQ==", "dev": true, + "peer": true, "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", @@ -28910,6 +28920,7 @@ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "devOptional": true, + "peer": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -29009,6 +29020,7 @@ "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.3.tgz", "integrity": "sha512-qjbnuR9Tr+FJOMBqJCW5ehvIo/buZq7vH7qD7JziU98h6l3qGy0a/yPFjwO+y0/T7GFpNgNAvEcPPVfyT8rrPQ==", "dev": true, + "peer": true, "dependencies": { "esbuild": "~0.25.0", "get-tsconfig": "^4.7.5" @@ -29063,6 +29075,7 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, + "peer": true, "engines": { "node": ">=10" }, @@ -29196,6 +29209,7 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", "devOptional": true, + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -29424,6 +29438,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -29497,6 +29512,7 @@ "resolved": "https://registry.npmjs.org/usehooks-ts/-/usehooks-ts-3.1.1.tgz", "integrity": "sha512-I4diPp9Cq6ieSUH2wu+fDAVQO43xwtulo+fKEidHUwZPnYImbtkTjzIJYcDcJqxgmX31GVqNFURodvcgHcW0pA==", "license": "MIT", + "peer": true, "dependencies": { "lodash.debounce": "^4.0.8" }, @@ -29792,6 +29808,7 @@ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.9.tgz", "integrity": "sha512-brOPwM3JnmOa+7kd3NsmOUOwbDAj8FT9xDsG3IW0MgbN9yZV7Oi/s/+MNQ/EcSMqw7qfoRyXPoeEWT8zLVdVGg==", "dev": true, + "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.6", @@ -29895,6 +29912,7 @@ "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", "dev": true, + "peer": true, "dependencies": { "@discoveryjs/json-ext": "^0.5.0", "@webpack-cli/configtest": "^2.1.1", @@ -30746,6 +30764,7 @@ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", "dev": true, + "peer": true, "bin": { "yaml": "bin.mjs" }, @@ -31382,6 +31401,7 @@ "packages/public/@babylonjs/shared-ui-components": { "version": "8.38.0", "license": "Apache-2.0", + "peer": true, "devDependencies": { "@dev/build-tools": "^1.0.0", "@lts/core": "1.0.0", diff --git a/packages/dev/core/src/Rendering/IBLShadows/iblShadowsVoxelRenderer.ts b/packages/dev/core/src/Rendering/IBLShadows/iblShadowsVoxelRenderer.ts index 47821fea0d9..30450dc3909 100644 --- a/packages/dev/core/src/Rendering/IBLShadows/iblShadowsVoxelRenderer.ts +++ b/packages/dev/core/src/Rendering/IBLShadows/iblShadowsVoxelRenderer.ts @@ -643,6 +643,9 @@ export class _IblShadowsVoxelRenderer { * @param includedMeshes */ public updateVoxelGrid(includedMeshes: Mesh[]) { + if (this._voxelizationInProgress) { + return; + } this._stopVoxelization(); this._includedMeshes = includedMeshes; this._voxelizationInProgress = true; From 33b07ed19b58adb59b19b261b94b2912d7a979ae Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Fri, 21 Nov 2025 12:49:06 -0800 Subject: [PATCH 7/8] Handle vertex pulling of different data type --- .../src/Materials/materialHelper.functions.ts | 112 ++++++++- .../dev/core/src/Materials/shaderMaterial.ts | 28 +-- .../src/ShadersWGSL/iblVoxelGrid.vertex.fx | 237 ++++++++++++------ 3 files changed, 267 insertions(+), 110 deletions(-) diff --git a/packages/dev/core/src/Materials/materialHelper.functions.ts b/packages/dev/core/src/Materials/materialHelper.functions.ts index b726f0f7b66..d669bd4e4f6 100644 --- a/packages/dev/core/src/Materials/materialHelper.functions.ts +++ b/packages/dev/core/src/Materials/materialHelper.functions.ts @@ -23,6 +23,8 @@ import { Texture } from "./Textures/texture"; import type { CubeTexture } from "./Textures/cubeTexture"; import type { Color3 } from "core/Maths/math.color"; import { GetTypeByteLength } from "../Buffers/bufferUtils"; +import type { Geometry } from "../Meshes/geometry"; +import { Vector3 } from "core/Maths/math.vector"; // For backwards compatibility, we export everything from the pure version of this file. export * from "./materialHelper.functions.pure"; @@ -600,24 +602,105 @@ export function GetFogState(mesh: AbstractMesh, scene: Scene) { } /** - * Helper used to prepare vertex pulling metadata defines (stride, offset, component count) - * This should be called when USE_VERTEX_PULLING is enabled to properly configure buffer access - * @param mesh The mesh being rendered - * @param defines The defines object to update - * @param attributeNames Array of attribute names to configure (e.g., ["position", "normal"]) + * Interface representing metadata for vertex pulling */ -export function PrepareDefinesForVertexPullingMetadata(mesh: AbstractMesh, defines: any, attributeNames: string[] = ["position"]): void { - if (!defines["USE_VERTEX_PULLING"]) { +export interface IVertexPullingMetadata { + /** + * Offset in vertex buffer where data starts + */ + offset: number; + + /** + * Stride between elements in the vertex buffer + */ + stride: number; + + /** + * Type of the vertex buffer (e.g., float, int) + */ + type: number; // VertexBuffer type constant +} + +// Store vertex pulling metadata per geometry +const _VertexPullingMetadataCache = new WeakMap>(); + +/** + * Prepares vertex pulling uniforms for the given attributes and mesh + * @param geometry The geometry containing the vertex buffers + * @returns A map of attribute names to their metadata, or null if unavailable + */ +export function PrepareVertexPullingUniforms(geometry: Geometry): Nullable> { + if (!geometry) { + return null; + } + const vertexBuffers = geometry.getVertexBuffers(); + if (!vertexBuffers) { + return null; + } + + // Check cache first + let metadata = _VertexPullingMetadataCache.get(geometry); + if (!metadata) { + metadata = new Map(); + _VertexPullingMetadataCache.set(geometry, metadata); + } else { + // Return cached metadata if it exists and hasn't changed + let needsUpdate = false; + for (const vb in vertexBuffers) { + if (!metadata.has(vb)) { + needsUpdate = true; + break; + } + } + if (!needsUpdate) { + return metadata; + } + } + + // Build or update metadata + for (const vb in vertexBuffers) { + const vertexBuffer = vertexBuffers[vb]; + if (vertexBuffer) { + const offset = vertexBuffer.byteOffset; + const stride = vertexBuffer.byteStride; + const type = vertexBuffer.type; + + metadata.set(vb, { + offset: offset, + stride: stride, + type: type, + }); + } + } + + return metadata; +} + +export function BindVertexPullingUniforms(effect: Effect, metadata: Map): void { + if (!metadata || !effect) { return; } - const geometry = mesh.geometry; + for (const [attribute, data] of metadata) { + const uniformName = `vp_${attribute}_info`; + // Pack into vec4: (offset, stride, type) + effect.setVector3(uniformName, new Vector3(data.offset, data.stride, data.type)); + } +} + +/** + * Helper used to prepare vertex pulling metadata defines (stride, offset, component count) + * This should be called when USE_VERTEX_PULLING is enabled to properly configure buffer access + * @param geometry The geometry being rendered + * @param defines The defines object to update + */ +export function PrepareDefinesForVertexPullingMetadata(geometry: Geometry, defines: any): void { if (!geometry) { return; } - - for (const attributeName of attributeNames) { - const vertexBuffer = geometry.getVertexBuffer(attributeName); + const vertexBuffers = geometry.getVertexBuffers(); + for (const attributeName in vertexBuffers) { + const vertexBuffer = vertexBuffers[attributeName]; if (!vertexBuffer) { continue; } @@ -626,11 +709,14 @@ export function PrepareDefinesForVertexPullingMetadata(mesh: AbstractMesh, defin const sizeInBytes = GetTypeByteLength(vertexBuffer.type); // Calculate stride in float32 elements const stride = vertexBuffer.effectiveByteStride / sizeInBytes; - defines[`${upperName}_STRIDE`] = stride || vertexBuffer.getSize(); + defines.push(`#define ${upperName}_STRIDE ${stride}`); // Calculate offset in float32 elements const offset = vertexBuffer.effectiveByteOffset / sizeInBytes; - defines[`${upperName}_OFFSET`] = offset; + defines.push(`#define ${upperName}_OFFSET ${offset}`); + // Calculate component count + const componentBytes = GetTypeByteLength(vertexBuffer.type); + defines.push(`#define ${upperName}_COMPONENT_BYTES ${componentBytes}`); } } diff --git a/packages/dev/core/src/Materials/shaderMaterial.ts b/packages/dev/core/src/Materials/shaderMaterial.ts index c2ef04f2287..d71967217f2 100644 --- a/packages/dev/core/src/Materials/shaderMaterial.ts +++ b/packages/dev/core/src/Materials/shaderMaterial.ts @@ -21,7 +21,6 @@ import { EngineStore } from "../Engines/engineStore"; import { Constants } from "../Engines/constants"; import { AddClipPlaneUniforms, BindClipPlane, PrepareStringDefinesForClipPlanes } from "./clipPlaneMaterialHelper"; import type { WebGPUEngine } from "core/Engines/webgpuEngine"; -import { GetTypeByteLength } from "../Buffers/bufferUtils"; import type { ExternalTexture } from "./Textures/externalTexture"; import { @@ -31,8 +30,12 @@ import { BindMorphTargetParameters, BindSceneUniformBuffer, PrepareDefinesAndAttributesForMorphTargets, + PrepareDefinesForVertexPullingMetadata, + PrepareVertexPullingUniforms, + BindVertexPullingUniforms, PushAttributesForInstances, } from "./materialHelper.functions"; +import type { IVertexPullingMetadata } from "./materialHelper.functions"; import type { IColor3Like, IColor4Like, IVector2Like, IVector3Like, IVector4Like } from "core/Maths/math.like"; import type { InternalTexture } from "./Textures/internalTexture"; @@ -148,6 +151,7 @@ export class ShaderMaterial extends PushMaterial { private _cachedWorldViewMatrix = new Matrix(); private _cachedWorldViewProjectionMatrix = new Matrix(); private _multiview = false; + private _vertexPullingMetadata: Map | null = null; /** * @internal @@ -920,22 +924,8 @@ export class ShaderMaterial extends PushMaterial { // Add vertex buffer metadata defines for proper stride/offset handling const geometry = renderingMesh.geometry; if (geometry) { - const vertexBuffers = geometry.getVertexBuffers(); - if (vertexBuffers) { - for (const attributeName in vertexBuffers) { - const vertexBuffer = vertexBuffers[attributeName]; - if (vertexBuffer) { - const componentBytes = GetTypeByteLength(vertexBuffer.type); - const upperName = attributeName.toUpperCase(); - const stride = vertexBuffer.effectiveByteStride / 4; - const offset = vertexBuffer.effectiveByteOffset / 4; - - defines.push(`#define ${upperName}_STRIDE ${stride}`); - defines.push(`#define ${upperName}_OFFSET ${offset}`); - defines.push(`#define ${upperName}_COMPONENT_BYTES ${componentBytes}`); - } - } - } + PrepareDefinesForVertexPullingMetadata(geometry, defines); + this._vertexPullingMetadata = PrepareVertexPullingUniforms(geometry); } } @@ -1107,6 +1097,10 @@ export class ShaderMaterial extends PushMaterial { // Clip plane BindClipPlane(effect, this, scene); + if (this._vertexPullingMetadata) { + BindVertexPullingUniforms(effect, this._vertexPullingMetadata); + } + // Misc if (this._useLogarithmicDepth) { BindLogDepth(storeEffectOnSubMeshes ? subMesh.materialDefines : effect.defines, effect, scene); diff --git a/packages/dev/core/src/ShadersWGSL/iblVoxelGrid.vertex.fx b/packages/dev/core/src/ShadersWGSL/iblVoxelGrid.vertex.fx index 037bd3983dc..26a4a5e22b1 100644 --- a/packages/dev/core/src/ShadersWGSL/iblVoxelGrid.vertex.fx +++ b/packages/dev/core/src/ShadersWGSL/iblVoxelGrid.vertex.fx @@ -17,9 +17,13 @@ var position : array; #if NUM_BONE_INFLUENCERS > 0 var matricesIndices : array; var matricesWeights : array; + uniform vp_matricesIndices_info: vec4f; + uniform vp_matricesWeights_info: vec4f; #if NUM_BONE_INFLUENCERS > 4 var matricesIndicesExtra : array; var matricesWeightsExtra : array; + uniform vp_matricesIndicesExtra_info: vec4f; + uniform vp_matricesWeightsExtra_info: vec4f; #endif #endif @@ -29,97 +33,170 @@ uniform invWorldScale: mat4x4f; varying vNormalizedPosition : vec3f; flat varying f_swizzle: i32; -// Vertex buffer metadata (set via defines or defaults) -#ifndef POSITION_STRIDE -#define POSITION_STRIDE 3 -#endif +uniform vp_position_info: vec4f; // (bufferIndex, offset, stride, type) -#ifndef POSITION_OFFSET -#define POSITION_OFFSET 0 -#endif +fn convertToFloat(word: u32, byteInWord: u32, dataType: u32) -> f32 { + switch (dataType) { + case 5120u: { // BYTE + let shift = byteInWord * 8u; + let value = (word >> shift) & 0xFFu; + return f32(i32(value << 24u) >> 24u) / 127.0; // Sign extend and normalize + } + case 5121u: { // UNSIGNED_BYTE + let shift = byteInWord * 8u; + let value = (word >> shift) & 0xFFu; + return f32(value) / 255.0; + } + case 5122u: { // SHORT + let shift = (byteInWord / 2u) * 16u; + let value = (word >> shift) & 0xFFFFu; + return f32(i32(value << 16u) >> 16u) / 32767.0; + } + case 5123u: { // UNSIGNED_SHORT + let shift = (byteInWord / 2u) * 16u; + let value = (word >> shift) & 0xFFFFu; + return f32(value) / 65535.0; + } + case 5126u: { // FLOAT + return bitcast(word); + } + default: { + return 0.0; + } + } +} -#ifndef POSITION_COMPONENT_COUNT -#define POSITION_COMPONENT_COUNT 3 -#endif +fn readPositionValue(byteOffset: u32, dataType: u32) -> f32 { + let wordOffset = byteOffset / 4u; + let byteInWord = byteOffset % 4u; + let word: u32 = bitcast(position[wordOffset]); + + return convertToFloat(word, byteInWord, dataType); +} -fn readVertexPosition(index : u32)->vec3f { - var pos : vec3f; - let baseOffset = POSITION_OFFSET + index * POSITION_STRIDE; - pos.x = position[baseOffset]; - pos.y = position[baseOffset + 1u]; - pos.z = position[baseOffset + 2u]; - return pos; +// Helper function to read a vec3 attribute +fn readVertexPosition(info: vec4f, vertexIndex: u32) -> vec3f { + let baseOffset = u32(info.y); + let stride = u32(info.z); + let dataType = u32(info.w); + + let offset = baseOffset + vertexIndex * stride; + + // Determine component size based on type + let componentSize = select(select(2u, 1u, dataType == 5120u || dataType == 5121u), 4u, dataType == 5126u); + + return vec3f( + readPositionValue(offset, dataType), + readPositionValue(offset + componentSize, dataType), + readPositionValue(offset + componentSize * 2u, dataType) + ); } #if NUM_BONE_INFLUENCERS > 0 -// Matrix indices are stored as UNSIGNED_BYTE (4 bytes packed into u32) -#ifndef MATRICESINDICES_STRIDE -#define MATRICESINDICES_STRIDE 1 -#endif -#ifndef MATRICESINDICES_OFFSET -#define MATRICESINDICES_OFFSET 0 -#endif -fn readMatrixIndices(index : u32) -> vec4f { - let baseOffset = MATRICESINDICES_OFFSET + index * MATRICESINDICES_STRIDE; - #if MATRICESINDICES_COMPONENT_BYTES == 1 - let packed = matricesIndices[baseOffset]; - // Extract 4 bytes from u32 and convert to floats - return vec4f( - f32(packed & 0xFFu), - f32((packed >> 8u) & 0xFFu), - f32((packed >> 16u) & 0xFFu), - f32((packed >> 24u) & 0xFFu) - ); - #elif MATRICESINDICES_COMPONENT_BYTES == 2 - let packed1 = matricesIndices[baseOffset]; - let packed2 = matricesIndices[baseOffset + 1u]; - // Extract 4 bytes from two u32 and convert to floats - return vec4f( - f32(packed1 & 0xFFFFu), - f32((packed1 >> 16u) & 0xFFFFu), - f32(packed2 & 0xFFFFu), - f32((packed2 >> 16u) & 0xFFFFu) - ); - #endif +fn readMatrixIndexValue(byteOffset: u32, dataType: u32) -> f32 { + let wordOffset = byteOffset / 4u; + let byteInWord = byteOffset % 4u; + let word: u32 = bitcast(matricesIndices[wordOffset]); + + return convertToFloat(word, byteInWord, dataType); } -#ifndef MATRICESWEIGHTS_STRIDE -#define MATRICESWEIGHTS_STRIDE 4 -#endif -#ifndef MATRICESWEIGHTS_OFFSET -#define MATRICESWEIGHTS_OFFSET 0 -#endif +fn readMatrixIndices(info: vec4f, vertexIndex : u32) -> vec4f { + let baseOffset = u32(info.y); + let stride = u32(info.z); + let dataType = u32(info.w); + + let offset = baseOffset + vertexIndex * stride; + + // Determine component size based on type + let componentSize = select(select(2u, 1u, dataType == 5120u || dataType == 5121u), 4u, dataType == 5126u); -fn readMatrixWeights(index : u32) -> vec4f { - let baseOffset = MATRICESWEIGHTS_OFFSET + index * MATRICESWEIGHTS_STRIDE; return vec4f( - matricesWeights[baseOffset], - matricesWeights[baseOffset + 1u], - matricesWeights[baseOffset + 2u], - matricesWeights[baseOffset + 3u] + readMatrixIndexValue(offset, dataType), + readMatrixIndexValue(offset + componentSize, dataType), + readMatrixIndexValue(offset + componentSize * 2u, dataType), + readMatrixIndexValue(offset + componentSize * 3u, dataType) + ); +} + +fn readMatrixWeightValue(byteOffset: u32, dataType: u32) -> f32 { + let wordOffset = byteOffset / 4u; + let byteInWord = byteOffset % 4u; + let word: u32 = bitcast(matricesWeights[wordOffset]); + + return convertToFloat(word, byteInWord, dataType); +} + +fn readMatrixWeights(info: vec4f, vertexIndex : u32) -> vec4f { + let baseOffset = u32(info.y); + let stride = u32(info.z); + let dataType = u32(info.w); + + let offset = baseOffset + vertexIndex * stride; + + // Determine component size based on type + let componentSize = select(select(2u, 1u, dataType == 5120u || dataType == 5121u), 4u, dataType == 5126u); + + return vec4f( + readMatrixWeightValue(offset, dataType), + readMatrixWeightValue(offset + componentSize, dataType), + readMatrixWeightValue(offset + componentSize * 2u, dataType), + readMatrixWeightValue(offset + componentSize * 3u, dataType) ); } #if NUM_BONE_INFLUENCERS > 4 -fn readMatrixIndicesExtra(index : u32) -> vec4f { - let baseOffset = MATRICESINDICESEXTRA_OFFSET + index * MATRICESINDICESEXTRA_STRIDE; - let packed = matricesIndicesExtra[baseOffset]; + +fn readMatrixIndexExtraValue(byteOffset: u32, dataType: u32) -> f32 { + let wordOffset = byteOffset / 4u; + let byteInWord = byteOffset % 4u; + let word: u32 = bitcast(matricesIndicesExtra[wordOffset]); + + return convertToFloat(word, byteInWord, dataType); +} + +fn readMatrixIndicesExtra(info: vec4f, vertexIndex : u32) -> vec4f { + let baseOffset = u32(info.y); + let stride = u32(info.z); + let dataType = u32(info.w); + + let offset = baseOffset + vertexIndex * stride; + + // Determine component size based on type + let componentSize = select(select(2u, 1u, dataType == 5120u || dataType == 5121u), 4u, dataType == 5126u); + return vec4f( - f32(packed & 0xFFu), - f32((packed >> 8u) & 0xFFu), - f32((packed >> 16u) & 0xFFu), - f32((packed >> 24u) & 0xFFu) + readMatrixIndexExtraValue(offset, dataType), + readMatrixIndexExtraValue(offset + componentSize, dataType), + readMatrixIndexExtraValue(offset + componentSize * 2u, dataType), + readMatrixIndexExtraValue(offset + componentSize * 3u, dataType) ); } -fn readMatrixWeightsExtra(index : u32) -> vec4f { - let baseOffset = MATRICESWEIGHTSEXTRA_OFFSET + index * MATRICESWEIGHTSEXTRA_STRIDE; +fn readMatrixWeightExtraValue(byteOffset: u32, dataType: u32) -> f32 { + let wordOffset = byteOffset / 4u; + let byteInWord = byteOffset % 4u; + let word: u32 = bitcast(matricesWeightsExtra[wordOffset]); + + return convertToFloat(word, byteInWord, dataType); +} + +fn readMatrixIndicesExtra(info: vec4f, vertexIndex : u32) -> vec4f { + let baseOffset = u32(info.y); + let stride = u32(info.z); + let dataType = u32(info.w); + + let offset = baseOffset + vertexIndex * stride; + + // Determine component size based on type + let componentSize = select(select(2u, 1u, dataType == 5120u || dataType == 5121u), 4u, dataType == 5126u); + return vec4f( - matricesWeightsExtra[baseOffset], - matricesWeightsExtra[baseOffset + 1u], - matricesWeightsExtra[baseOffset + 2u], - matricesWeightsExtra[baseOffset + 3u] + readMatrixWeightExtraValue(offset, dataType), + readMatrixWeightExtraValue(offset + componentSize, dataType), + readMatrixWeightExtraValue(offset + componentSize * 2u, dataType), + readMatrixWeightExtraValue(offset + componentSize * 3u, dataType) ); } #endif @@ -159,7 +236,7 @@ fn calculateTriangleNormal(v0 @vertex fn main(input : VertexInputs) -> FragmentInputs { var vertIdx = readVertexIndex(input.vertexIndex); - var positionUpdated = readVertexPosition(vertIdx); + var positionUpdated = readVertexPosition(uniforms.vp_position_info, vertIdx); #include let inputPosition: vec3f = positionUpdated; @@ -170,14 +247,14 @@ let inputPosition: vec3f = positionUpdated; #include #if NUM_BONE_INFLUENCERS > 0 - let matrixIndex = readMatrixIndices(vertIdx); - let matrixWeight = readMatrixWeights(vertIdx); + let matrixIndex = readMatrixIndices(uniforms.vp_matricesIndices_info, vertIdx); + let matrixWeight = readMatrixWeights(uniforms.vp_matricesWeights_info, vertIdx); #if NUM_BONE_INFLUENCERS > 4 - let matrixIndexExtra = readMatrixIndicesExtra(vertIdx); - let matrixWeightExtra = readMatrixWeightsExtra(vertIdx); + let matrixIndexExtra = readMatrixIndicesExtra(uniforms.vp_matricesIndicesExtra_info, vertIdx); + let matrixWeightExtra = readMatrixWeightsExtra(uniforms.vp_matricesWeightsExtra_info, vertIdx); #endif #endif -#include (vertexInputs.matricesIndices,matrixIndex,vertexInputs.matricesWeights,matrixWeight) +#include(vertexInputs.matricesIndices,matrixIndex,vertexInputs.matricesWeights,matrixWeight) let worldPos = finalWorld * vec4f(positionUpdated, 1.0); @@ -185,9 +262,9 @@ let inputPosition: vec3f = positionUpdated; vertexOutputs.position = uniforms.invWorldScale * worldPos; var provokingVertNum : u32 = input.vertexIndex / 3 * 3; - var pos0 = readVertexPosition(readVertexIndex(provokingVertNum)); - var pos1 = readVertexPosition(readVertexIndex(provokingVertNum + 1)); - var pos2 = readVertexPosition(readVertexIndex(provokingVertNum + 2)); + var pos0 = readVertexPosition(uniforms.vp_position_info, readVertexIndex(provokingVertNum)); + var pos1 = readVertexPosition(uniforms.vp_position_info, readVertexIndex(provokingVertNum + 1)); + var pos2 = readVertexPosition(uniforms.vp_position_info, readVertexIndex(provokingVertNum + 2)); var N : vec3 = calculateTriangleNormal(pos0, pos1, pos2); // Check the direction that maximizes the rasterized area and swizzle as From 437c627b56245aadafc52dfc28399c4dc37202cb Mon Sep 17 00:00:00 2001 From: Mike Bond Date: Fri, 21 Nov 2025 13:35:42 -0800 Subject: [PATCH 8/8] Cleanup and fixes --- .../src/Materials/materialHelper.functions.ts | 42 +++------------- .../dev/core/src/Materials/shaderMaterial.ts | 2 - .../src/ShadersWGSL/iblVoxelGrid.vertex.fx | 50 +++++++++---------- 3 files changed, 32 insertions(+), 62 deletions(-) diff --git a/packages/dev/core/src/Materials/materialHelper.functions.ts b/packages/dev/core/src/Materials/materialHelper.functions.ts index d669bd4e4f6..dc63f45e0e8 100644 --- a/packages/dev/core/src/Materials/materialHelper.functions.ts +++ b/packages/dev/core/src/Materials/materialHelper.functions.ts @@ -22,7 +22,6 @@ import { MaterialFlags } from "./materialFlags"; import { Texture } from "./Textures/texture"; import type { CubeTexture } from "./Textures/cubeTexture"; import type { Color3 } from "core/Maths/math.color"; -import { GetTypeByteLength } from "../Buffers/bufferUtils"; import type { Geometry } from "../Meshes/geometry"; import { Vector3 } from "core/Maths/math.vector"; @@ -676,50 +675,23 @@ export function PrepareVertexPullingUniforms(geometry: Geometry): Nullable): void { if (!metadata || !effect) { return; } - for (const [attribute, data] of metadata) { + for (const [attribute, data] of metadata.entries()) { const uniformName = `vp_${attribute}_info`; - // Pack into vec4: (offset, stride, type) + // Pack into vec3: (offset, stride, type) effect.setVector3(uniformName, new Vector3(data.offset, data.stride, data.type)); } } -/** - * Helper used to prepare vertex pulling metadata defines (stride, offset, component count) - * This should be called when USE_VERTEX_PULLING is enabled to properly configure buffer access - * @param geometry The geometry being rendered - * @param defines The defines object to update - */ -export function PrepareDefinesForVertexPullingMetadata(geometry: Geometry, defines: any): void { - if (!geometry) { - return; - } - const vertexBuffers = geometry.getVertexBuffers(); - for (const attributeName in vertexBuffers) { - const vertexBuffer = vertexBuffers[attributeName]; - if (!vertexBuffer) { - continue; - } - - const upperName = attributeName.toUpperCase(); - const sizeInBytes = GetTypeByteLength(vertexBuffer.type); - // Calculate stride in float32 elements - const stride = vertexBuffer.effectiveByteStride / sizeInBytes; - defines.push(`#define ${upperName}_STRIDE ${stride}`); - - // Calculate offset in float32 elements - const offset = vertexBuffer.effectiveByteOffset / sizeInBytes; - defines.push(`#define ${upperName}_OFFSET ${offset}`); - // Calculate component count - const componentBytes = GetTypeByteLength(vertexBuffer.type); - defines.push(`#define ${upperName}_COMPONENT_BYTES ${componentBytes}`); - } -} - /** * Helper used to prepare the list of defines associated with misc. values for shader compilation * @param mesh defines the current mesh diff --git a/packages/dev/core/src/Materials/shaderMaterial.ts b/packages/dev/core/src/Materials/shaderMaterial.ts index d71967217f2..e25b858dc9b 100644 --- a/packages/dev/core/src/Materials/shaderMaterial.ts +++ b/packages/dev/core/src/Materials/shaderMaterial.ts @@ -30,7 +30,6 @@ import { BindMorphTargetParameters, BindSceneUniformBuffer, PrepareDefinesAndAttributesForMorphTargets, - PrepareDefinesForVertexPullingMetadata, PrepareVertexPullingUniforms, BindVertexPullingUniforms, PushAttributesForInstances, @@ -924,7 +923,6 @@ export class ShaderMaterial extends PushMaterial { // Add vertex buffer metadata defines for proper stride/offset handling const geometry = renderingMesh.geometry; if (geometry) { - PrepareDefinesForVertexPullingMetadata(geometry, defines); this._vertexPullingMetadata = PrepareVertexPullingUniforms(geometry); } } diff --git a/packages/dev/core/src/ShadersWGSL/iblVoxelGrid.vertex.fx b/packages/dev/core/src/ShadersWGSL/iblVoxelGrid.vertex.fx index 26a4a5e22b1..95afc75d502 100644 --- a/packages/dev/core/src/ShadersWGSL/iblVoxelGrid.vertex.fx +++ b/packages/dev/core/src/ShadersWGSL/iblVoxelGrid.vertex.fx @@ -17,13 +17,13 @@ var position : array; #if NUM_BONE_INFLUENCERS > 0 var matricesIndices : array; var matricesWeights : array; - uniform vp_matricesIndices_info: vec4f; - uniform vp_matricesWeights_info: vec4f; + uniform vp_matricesIndices_info: vec3f; + uniform vp_matricesWeights_info: vec3f; #if NUM_BONE_INFLUENCERS > 4 var matricesIndicesExtra : array; var matricesWeightsExtra : array; - uniform vp_matricesIndicesExtra_info: vec4f; - uniform vp_matricesWeightsExtra_info: vec4f; + uniform vp_matricesIndicesExtra_info: vec3f; + uniform vp_matricesWeightsExtra_info: vec3f; #endif #endif @@ -33,7 +33,7 @@ uniform invWorldScale: mat4x4f; varying vNormalizedPosition : vec3f; flat varying f_swizzle: i32; -uniform vp_position_info: vec4f; // (bufferIndex, offset, stride, type) +uniform vp_position_info: vec3f; // (bufferIndex, offset, stride, type) fn convertToFloat(word: u32, byteInWord: u32, dataType: u32) -> f32 { switch (dataType) { @@ -75,10 +75,10 @@ fn readPositionValue(byteOffset: u32, dataType: u32) -> f32 { } // Helper function to read a vec3 attribute -fn readVertexPosition(info: vec4f, vertexIndex: u32) -> vec3f { - let baseOffset = u32(info.y); - let stride = u32(info.z); - let dataType = u32(info.w); +fn readVertexPosition(info: vec3f, vertexIndex: u32) -> vec3f { + let baseOffset = u32(info.x); + let stride = u32(info.y); + let dataType = u32(info.z); let offset = baseOffset + vertexIndex * stride; @@ -102,10 +102,10 @@ fn readMatrixIndexValue(byteOffset: u32, dataType: u32) -> f32 { return convertToFloat(word, byteInWord, dataType); } -fn readMatrixIndices(info: vec4f, vertexIndex : u32) -> vec4f { - let baseOffset = u32(info.y); - let stride = u32(info.z); - let dataType = u32(info.w); +fn readMatrixIndices(info: vec3f, vertexIndex : u32) -> vec4f { + let baseOffset = u32(info.x); + let stride = u32(info.y); + let dataType = u32(info.z); let offset = baseOffset + vertexIndex * stride; @@ -128,10 +128,10 @@ fn readMatrixWeightValue(byteOffset: u32, dataType: u32) -> f32 { return convertToFloat(word, byteInWord, dataType); } -fn readMatrixWeights(info: vec4f, vertexIndex : u32) -> vec4f { - let baseOffset = u32(info.y); - let stride = u32(info.z); - let dataType = u32(info.w); +fn readMatrixWeights(info: vec3f, vertexIndex : u32) -> vec4f { + let baseOffset = u32(info.x); + let stride = u32(info.y); + let dataType = u32(info.z); let offset = baseOffset + vertexIndex * stride; @@ -156,10 +156,10 @@ fn readMatrixIndexExtraValue(byteOffset: u32, dataType: u32) -> f32 { return convertToFloat(word, byteInWord, dataType); } -fn readMatrixIndicesExtra(info: vec4f, vertexIndex : u32) -> vec4f { - let baseOffset = u32(info.y); - let stride = u32(info.z); - let dataType = u32(info.w); +fn readMatrixIndicesExtra(info: vec3f, vertexIndex : u32) -> vec4f { + let baseOffset = u32(info.x); + let stride = u32(info.y); + let dataType = u32(info.z); let offset = baseOffset + vertexIndex * stride; @@ -182,10 +182,10 @@ fn readMatrixWeightExtraValue(byteOffset: u32, dataType: u32) -> f32 { return convertToFloat(word, byteInWord, dataType); } -fn readMatrixIndicesExtra(info: vec4f, vertexIndex : u32) -> vec4f { - let baseOffset = u32(info.y); - let stride = u32(info.z); - let dataType = u32(info.w); +fn readMatrixIndicesExtra(info: vec3f, vertexIndex : u32) -> vec4f { + let baseOffset = u32(info.x); + let stride = u32(info.y); + let dataType = u32(info.z); let offset = baseOffset + vertexIndex * stride;