diff --git a/packages/dev/core/src/Engines/webgpuEngine.ts b/packages/dev/core/src/Engines/webgpuEngine.ts index 14bf08a80d1..32d14825b87 100644 --- a/packages/dev/core/src/Engines/webgpuEngine.ts +++ b/packages/dev/core/src/Engines/webgpuEngine.ts @@ -1613,7 +1613,11 @@ export class WebGPUEngine extends ThinWebGPUEngine { view = data; } - const dataBuffer = this._bufferManager.createBuffer(view, WebGPUConstants.BufferUsage.Vertex | WebGPUConstants.BufferUsage.CopyDst, label); + const dataBuffer = this._bufferManager.createBuffer( + view, + WebGPUConstants.BufferUsage.Vertex | WebGPUConstants.BufferUsage.CopyDst | WebGPUConstants.BufferUsage.Storage, + label + ); return dataBuffer; } @@ -3693,6 +3697,35 @@ export class WebGPUEngine extends ThinWebGPUEngine { this._currentMaterialContext.textureState = textureState; const pipeline = this._cacheRenderPipeline.getRenderPipeline(fillMode, this._currentEffect!, this.currentSampleCount, textureState); + + // Compare the vertex buffers that we have to the ones that are bound to the pipeline. + // If there are vertex buffers that are not bound to the pipeline, AND they're used + // by the shader, we will bind them to the current draw context. + const availableVertexBuffers: { [key: string]: VertexBuffer } = (this._cacheRenderPipeline as any)._vertexBuffers; + const appliedVertexBuffers = this._cacheRenderPipeline.vertexBuffers; + const vertexBufferNames = Object.keys(availableVertexBuffers); + if (Object.keys(availableVertexBuffers).length !== appliedVertexBuffers.length) { + const unboundVertexBuffers: { [key: string]: VertexBuffer } = {}; + for (let i = 0; i < vertexBufferNames.length; i++) { + const name = vertexBufferNames[i]; + if (appliedVertexBuffers.findIndex((v) => v === availableVertexBuffers[name]) === -1) { + unboundVertexBuffers[name] = availableVertexBuffers[name]; + } + } + if (Object.keys(unboundVertexBuffers).length > 0) { + for (const unboundVertexBufferName of Object.keys(unboundVertexBuffers)) { + if (webgpuPipelineContext.shaderProcessingContext.bufferNames.findIndex((name) => name === unboundVertexBufferName) !== -1) { + this._currentDrawContext.buffers[unboundVertexBufferName] = unboundVertexBuffers[unboundVertexBufferName].effectiveBuffer as WebGPUDataBuffer; + } + } + } + // TODO - handle binding index buffer. + // if (webgpuPipelineContext.shaderProcessingContext.bufferNames.findIndex((name) => name === "indices") !== -1) { + // const indexBuffer = this._currentIndexBuffer ? this._currentIndexBuffer : (this._cacheRenderPipeline as any)._indexBuffer; + // this._currentDrawContext.buffers["indices"] = indexBuffer as WebGPUDataBuffer; + // } + } + const bindGroups = this._cacheBindGroups.getBindGroups(webgpuPipelineContext, this._currentDrawContext, this._currentMaterialContext); if (!this._snapshotRendering.record) { diff --git a/packages/dev/core/src/Materials/material.ts b/packages/dev/core/src/Materials/material.ts index e45c8ae8e49..3b21e560bc8 100644 --- a/packages/dev/core/src/Materials/material.ts +++ b/packages/dev/core/src/Materials/material.ts @@ -239,6 +239,12 @@ export class Material implements IAnimatable, IClipPlanesHolder { protected _forceGLSL = false; + /** + * Tells the engine to draw geometry using vertex pulling instead of index drawing. This will automatically + * set the vertex buffers as storage buffers and make them accessible to the vertex shader. + */ + public useVertexPulling = false; + /** @internal */ public get _supportGlowLayer() { return false; diff --git a/packages/dev/core/src/Meshes/mesh.ts b/packages/dev/core/src/Meshes/mesh.ts index 5024fabf7fa..949512d3b70 100644 --- a/packages/dev/core/src/Meshes/mesh.ts +++ b/packages/dev/core/src/Meshes/mesh.ts @@ -2054,6 +2054,7 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData { const scene = this.getScene(); const engine = scene.getEngine(); + const material = subMesh.getMaterial(); if ((this._unIndexed && fillMode !== Material.WireFrameFillMode) || fillMode == Material.PointFillMode) { // or triangles as points @@ -2061,6 +2062,9 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData { } else if (fillMode == Material.WireFrameFillMode) { // Triangles as wireframe engine.drawElementsType(fillMode, 0, subMesh._linesIndexCount, this.forcedInstanceCount || instancesCount); + } else if (material && material.useVertexPulling) { + // We're rendering the number of indices in the index buffer but the vertex shader is handling the data itself. + engine.drawArraysType(fillMode, subMesh.indexStart, subMesh.indexCount, this.forcedInstanceCount || instancesCount); } else { engine.drawElementsType(fillMode, subMesh.indexStart, subMesh.indexCount, this.forcedInstanceCount || instancesCount); }