-
-
Notifications
You must be signed in to change notification settings - Fork 35.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Examples: GPGPU Water Port #29147
Examples: GPGPU Water Port #29147
Conversation
📦 Bundle sizeFull ESM build, minified and gzipped.
🌳 Bundle size after tree-shakingMinimal build including a renderer, camera, empty scene, and dependencies.
|
Kind of stumped by the WebGL Backend behavior here: WebGL.Compute.Water.mp4 |
d687a0b
to
a4dc324
Compare
Think I understand the issue with the WebGL backend, it seems like the conversion to GLSL does not yet account for accessing the same buffer multiple times. For instance, this TSL code const { viscosity, mousePos, mouseSize } = effectController;
const height = heightStorage.element( instanceIndex );
const prevHeight = prevHeightStorage.element( instanceIndex );
const { north, south, east, west } = getNeighborValuesTSL( instanceIndex, heightStorage );
const neighborHeight = north.add( south ).add( east ).add( west );
neighborHeight.mulAssign( 0.5 );
neighborHeight.subAssign( prevHeight );
const newHeight = neighborHeight.mul( viscosity ); Generates this GLSL output: float nodeVar0;
float nodeVar1;
// transforms
nodeVarying0 = nodeAttribute0;
nodeVarying1 = nodeAttribute1;
// flow code
nodeVar0 = ( ( ( nodeVarying0 + nodeVarying0 ) + nodeVarying0 ) + nodeVarying0 );
nodeVar0 = ( nodeVar0 * 0.5 );
nodeVar0 = ( nodeVar0 - nodeVarying1 );
nodeVar1 = ( nodeVar0 * c_viscosity );
The first line of code corresponds with the getNeighborValuesTSL call but only the same height value it already read in. Presumably there's a workaround with storageObjects.... Equivalent WGSL output for comparison // system
instanceIndex = id.x + id.y * numWorkgroups.x * u32(64) + id.z * numWorkgroups.x * numWorkgroups.y * u32(64);
// vars
var nodeVar0 : u32;
var nodeVar1 : u32;
var nodeVar2 : f32;
var nodeVar3 : f32;
// flow code
nodeVar0 = ( instanceIndex / 128u );
nodeVar1 = ( instanceIndex % 128u );
nodeVar2 = ( ( ( NodeBuffer_476.Height[ ( ( min( ( nodeVar0 + u32( 1.0 ) ), ( 128u - u32( 1.0 ) ) ) * 128u ) + nodeVar1 ) ] +
NodeBuffer_476.Height[ ( ( max( u32( 0.0 ), ( nodeVar0 - u32( 1.0 ) ) ) * 128u ) + nodeVar1 ) ] ) + NodeBuffer_476.Height[ ( (
nodeVar0 * 128u ) + min( ( nodeVar1 + u32( 1.0 ) ), ( 128u - u32( 1.0 ) ) ) ) ] ) + NodeBuffer_476.Height[ ( ( nodeVar0 * 128u )
+ max( u32( 0.0 ), ( nodeVar1 - u32( 1.0 ) ) ) ) ] );
nodeVar2 = ( nodeVar2 * 0.5 );
nodeVar2 = ( nodeVar2 - NodeBuffer_477.PrevHeight[ instanceIndex ] );
nodeVar3 = ( nodeVar2 * object.viscosity ); |
layout( std140 ) uniform compute_object {
float c_viscosity;
vec2 c_mousePos;
float c_mouseSize;
};
uniform highp sampler2D Height;
uniform highp sampler2D PrevHeight;
// varyings
out float nodeVarying0;
out float nodeVarying1;
// attributes
layout( location = 0 ) in float nodeAttribute2;
layout( location = 1 ) in float nodeAttribute6;
void main() {
// variable declarations omitted
// transforms
nodeVarying0 = nodeAttribute2;
nodeVarying1 = nodeAttribute6;
// flow
nodeVar1Size = uint( textureSize( Height, 0 ).x );
nodeVar1 = vec4(texelFetch( Height, ivec2(uint( gl_InstanceID ) % nodeVar1Size, uint( gl_InstanceID ) / nodeVar1Size), 0 )).x;
nodeVar0 = nodeVar1;
nodeVar4Size = uint( textureSize( PrevHeight, 0 ).x );
nodeVar4 = vec4(texelFetch( PrevHeight, ivec2(uint( gl_InstanceID ) % nodeVar4Size, uint( gl_InstanceID ) / nodeVar4Size), 0 )).x;
nodeVar3 = nodeVar4;
// Worrisome neighborHeight code
nodeVar6 = ( ( ( nodeVarying0 + nodeVarying0 ) + nodeVarying0 ) + nodeVarying0 );
nodeVar6 = ( nodeVar6 * 0.5 ); |
} | ||
|
||
const heightBufferAttribute = new THREE.StorageBufferAttribute( heightArray, 1 ); | ||
const prevHeightBufferAttribute = new THREE.StorageBufferAttribute( prevHeightArray, 1 ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
StorageInstancedBufferAttribute
examples/webgpu_compute_water.html
Outdated
// To correct the lighting as our mesh undulates, we have to reassign the normals in the position shader. | ||
const { normalX, normalY } = getNormalsFromHeightTSL( vertexIndex, heightRead ); | ||
|
||
varyingProperty( 'vec3', 'v_normalView' ).assign( modelNormalMatrix.mul( vec3( normalX, negate( normalY ), 1.0 ) ) ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TSL now have a function for this: transformNormalToView( vec3( normalX, negate( normalY ), 1.0 ) )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to break the lighting when I test it, but I'll check back in on it tomorrow ( I am in PST ). Aren't modelNormalMatrix and modelNormalViewMatrix distinct? And if they aren't, should the name of the node be updated to reflect that?
…e differential between webgl compute and webgpu compute
2fceb6d
to
6d087cd
Compare
Related issue: #XXXX
Description
Port of the WebGL GPGPU Water Sample.
EDIT 1: Sphere dynamics have been modified to leverage to used the positionNode shader over the CPU.
EDIT 2: Original WebGL sample slightly adjusted to demonstrate WebGL vs. WebGPU performance differential.
Compute.Water.mp4