Skip to content

WebGPUPathTracer: Add support for SkinnedMeshes#729

Open
gkjohnson wants to merge 9 commits intowebgpu-pathtracerfrom
webgpu/skinning
Open

WebGPUPathTracer: Add support for SkinnedMeshes#729
gkjohnson wants to merge 9 commits intowebgpu-pathtracerfrom
webgpu/skinning

Conversation

@gkjohnson
Copy link
Owner

@gkjohnson gkjohnson commented Feb 28, 2026

  • Adds support for skinned meshes using "SkinnedMeshBVH"
  • Adds a custom version of "applyBoneMatrix" that takes a vec4 to support normals + positions (I'll probably try to get this added back to three)
image

cc @TheBlek

@gkjohnson gkjohnson added this to the v0.0.25 milestone Feb 28, 2026
@gkjohnson
Copy link
Owner Author

gkjohnson commented Feb 28, 2026

@TheBlek - one thing I noticed while working on this was what looks like a floating point difference between the megakernel and wavefront kernel approach. You can see that there are some black artifacts in the megakernel one that aren't in the wavefront image. Is there a different offset being applied after hit somehow? Any thoughts?

Megakernel

image

Wavefront

image

You can repro it by loading this glb model and adding it to the scene like so:

new GLTFLoader().loadAsync( MODEL_URL ).then( gltf => {
	gltf.scene.traverse( c => {
		if ( c.isSkinnedMesh ) {
			scene.add( new Mesh( c.geometry ) );
		}
	} );
	pathTracer.setScene( scene, camera );
} );

}

// Get skinned vertex positions
mesh.getVertexPosition( ai, _v0 );
Copy link

Choose a reason for hiding this comment

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

Using getVertexPosition each time bounds for a triangle is requested does feel inefficient. Each vertex will be requested at least once, and probably more than that. So they can be calculated once and cached. Worth noting somewhere, that further improvements could probably be made to build speed at cost of memory. Perhaps its worth adding a benchmark case for skinned mesh build speed?

const indirectBuffer = this._indirectBuffer;
const index = geometry.index ? geometry.index.array : null;

const tri = indirectBuffer ? indirectBuffer[ i ] : i;
Copy link

Choose a reason for hiding this comment

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

Is this equivalent to resolvePrimitiveIndex? If so, perhaps its best to use that for consistency?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants