Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 54 additions & 69 deletions package-lock.json

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions packages/dev/core/src/Engines/WebGPU/webgpuDrawContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,14 @@ export class WebGPUDrawContext implements IDrawContext {
this._bufferManager.setRawData(this.indirectDrawBuffer, 0, this._indirectDrawData, 0, 20);
}

/**
* 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 setVertexPulling(
useVertexPulling: boolean,
webgpuPipelineContext: WebGPUPipelineContext,
Expand Down
36 changes: 36 additions & 0 deletions packages/dev/core/src/Materials/materialHelper.functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -598,6 +599,41 @@ 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();
const sizeInBytes = GetTypeByteLength(vertexBuffer.type);
// Calculate stride in float32 elements
const stride = vertexBuffer.effectiveByteStride / sizeInBytes;
defines[`${upperName}_STRIDE`] = stride || vertexBuffer.getSize();

// Calculate offset in float32 elements
const offset = vertexBuffer.effectiveByteOffset / sizeInBytes;
defines[`${upperName}_OFFSET`] = offset;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"_COMPONENT_BYTES" is not set.

}

/**
* Helper used to prepare the list of defines associated with misc. values for shader compilation
* @param mesh defines the current mesh
Expand Down
24 changes: 23 additions & 1 deletion packages/dev/core/src/Materials/shaderMaterial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -885,12 +886,33 @@ 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");
}
}

// Add vertex buffer metadata defines for proper stride/offset handling
const geometry = renderingMesh.geometry;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you want to use the new PrepareDefinesForVertexPullingMetadata function instead?

Also, I think we should pass stride and offset as a byte count instead of a float count, to more easily handle all type conversions we will have to support (for example, type of position could be a (u)byte, (u)short, (u)int, float, and for the integer types, they could be normalized or not - these are type conversions we will have to perform in the shader).

Another thing is that we should probably use uniforms and not defines to pass data, else we will basically generate a new shader for each mesh, as (at least) offset will be different for each mesh.

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}`);
}
}
}
}
}

const drawWrapper = storeEffectOnSubMeshes ? subMesh._getDrawWrapper(undefined, true) : this._drawWrapper;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -738,6 +741,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);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#if NUM_BONE_INFLUENCERS > 0
attribute matricesIndices : vec4<f32>;
attribute matricesWeights : vec4<f32>;
attribute matricesIndices : vec4f;
attribute matricesWeights : vec4f;
#if NUM_BONE_INFLUENCERS > 4
attribute matricesIndicesExtra : vec4<f32>;
attribute matricesWeightsExtra : vec4<f32>;
attribute matricesIndicesExtra : vec4f;
attribute matricesWeightsExtra : vec4f;
#endif

#ifndef BAKED_VERTEX_ANIMATION_TEXTURE
Expand Down
119 changes: 112 additions & 7 deletions packages/dev/core/src/ShadersWGSL/iblVoxelGrid.vertex.fx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include <bakedVertexAnimationDeclaration>
#include <bonesDeclaration>
#include <bonesDeclaration>(attribute matricesIndices : vec4f;,,attribute matricesWeights : vec4f;,,attribute matricesIndicesExtra : vec4f;,,attribute matricesWeightsExtra : vec4f;,)
#include <helperFunctions>
#include <instancesDeclaration>

Expand All @@ -8,27 +8,123 @@

// 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<storage, read> indices : array<u32>;
#endif
var<storage, read> position : array<f32>;
#if NUM_BONE_INFLUENCERS > 0
var<storage, read> matricesIndices : array<u32>;
var<storage, read> matricesWeights : array<f32>;
#if NUM_BONE_INFLUENCERS > 4
var<storage, read> matricesIndicesExtra : array<u32>;
var<storage, read> matricesWeightsExtra : array<f32>;
#endif
#endif

uniform world : mat4x4f;
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

#ifndef POSITION_OFFSET
#define POSITION_OFFSET 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 + 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;
Expand Down Expand Up @@ -67,12 +163,21 @@ fn main(input : VertexInputs) -> FragmentInputs {

#include <morphTargetsVertexGlobal>
let inputPosition: vec3f = positionUpdated;
#include <morphTargetsVertex>(vertexInputs.position\\),inputPosition))[0..maxSimultaneousMorphTargets]
#include <morphTargetsVertex>(vertexInputs.position\\),inputPosition),vertexInputs.vertexIndex,vertIdx)[0..maxSimultaneousMorphTargets]

#include <instancesVertex>

#include <bakedVertexAnimation>
#include <bonesVertex>

#if NUM_BONE_INFLUENCERS > 0
let matrixIndex = readMatrixIndices(vertIdx);
let matrixWeight = readMatrixWeights(vertIdx);
#if NUM_BONE_INFLUENCERS > 4
let matrixIndexExtra = readMatrixIndicesExtra(vertIdx);
let matrixWeightExtra = readMatrixWeightsExtra(vertIdx);
#endif
#endif
#include <bonesVertex>(vertexInputs.matricesIndices,matrixIndex,vertexInputs.matricesWeights,matrixWeight)

let worldPos = finalWorld * vec4f(positionUpdated, 1.0);

Expand Down