-
-
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
WebGPU: NodeMaterial BSDFs, revision and updates #21322
Conversation
|
||
let RE_Direct = null; | ||
|
||
if ( material.isMeshPhongMaterial === true ) { |
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.
Any reasons why you have decided for MeshPhongMaterial
instead of MeshStandardMaterial
? When I remember correctly, it was considered once to not support phong in WebGPU anymore.
@mrdoob Do you have a preference here? I personally would start with a PBR material as a first lit material. Although phong would be easier to implement/port. And we would need to support it for WebGL anyway.
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.
Any reasons why you have decided for MeshPhongMaterial instead of MeshStandardMaterial?
It is a popular material and more easier to implement... but I can start with MeshStandardMaterial
I see no problem about it.
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.
Let's wait for @mrdoob's feedback. TBH, I'm not sure anymore if there was a conclusion about this topic and how it looked like.
One question about But it is still the plan that materials will still respond to lights added to the scene graph, right? I mean this is obviously not yet implemented since the renderer needs to be enhanced. But I'd like to clarify this roadmap a bit. |
|
||
if ( material.isMeshPhongMaterial === true ) { | ||
|
||
RE_Direct = RE_Direct_BlinnPhong; |
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.
I have not yet debugged this part in detail but I assume the define RE_Direct
in the phong shader will be set to the generated code of RE_Direct_BlinnPhong
?
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.
Yes, but RE_Direct
is a FunctionCallNode
. I am preserving the names to facilitate. NodeMaterial
not need set a define
for this. With LightContextNode
and no defines
we can adopt even two light model, like Phong
and Physical
runing simultaneously on the same material. - This is just adding a few nodes.
This should be very easy to implement, e.g: // WebGPUNodeBuilder.js
// cache light context and share with all materials of the scene
const sceneLightNodeSlot = new NodeSlot( new LightContextNode( LightsNode.fromLights( sceneLightsArray ) ), 'LIGHT', 'vec3' );
_parseMaterial() {
...
if ( material.lightNode !== undefined ) {
// selective light
const materialLightContextNode = new LightContextNode( material.lightNode );
this.addSlot( 'fragment', new NodeSlot( materialLightContextNode, 'LIGHT', 'vec3' ) );
} else {
// scene lights
this.addSlot( 'fragment', sceneLightNodeSlot );
}
} |
I would like your option about keywords, what standard should we use:
1 is the current. -- void RE_Direct_BlinnPhong( vec3 lightDirection, vec3 lightColor ) {
float dotNL = saturate( dot( NormalView, lightDirection ) );
vec3 irradiance = dotNL * lightColor;
#ifndef PHYSICALLY_CORRECT_LIGHTS
irradiance *= PI; // punctual light
#endif
ReflectedLightDirectDiffuse += irradiance * BRDF_Diffuse_Lambert( MaterialDiffuseColor.rgb );
} void RE_Direct_BlinnPhong( vec3 lightDirection, vec3 lightColor ) {
float dotNL = saturate( dot( NORMAL_VIEW, lightDirection ) );
vec3 irradiance = dotNL * lightColor;
#ifndef PHYSICALLY_CORRECT_LIGHTS
irradiance *= PI; // punctual light
#endif
REFLECTED_LIGHT_DIRECT_DIFFUSE += irradiance * BRDF_Diffuse_Lambert( MATERIAL_DIFFUSE_COLOR.rgb );
} |
I think I prefer |
Another thing... It is possible to maintain compatibility with a |
For example, in case of |
I create Example of // added by user or WebGPUNodeBuilder if material.colorNode is empty
material.colorNode = new MaterialNode( MaterialNode.COLOR );
// user can change the values of the material in legacy mode (THREE.Color)
// and MaterialNode will auto update the relative nodes
material.color = new THREE.Color( 0xFF00FF ); |
If that for interesting I would put other fields in |
Seems that
if ( skeleton ) {
geo.setAttribute( 'skinIndex', new Float32BufferAttribute( buffers.weightsIndices, 4 ) ); // work
//geo.setAttribute( 'skinIndex', new Uint16BufferAttribute( buffers.weightsIndices, 4 ) ); // not work
geo.setAttribute( 'skinWeight', new Float32BufferAttribute( buffers.vertexWeights, 4 ) );
// used later to bind the skeleton to the model
geo.FBX_Deformer = skeleton;
} |
Should be solved via Mugen87@006b2fc. |
@sunag Awesome work!
Um, do we need a BTW: By doing this |
This is going to need a review. I think that the way forward would be to generalize to an super class for position/normal manipulation, like At the moment I think about it for the next step: const boneMatrixStructNode = new BoneMatrixStructNode( index, boneTexture, boneTextureSize );
position = new SkinningPositionNode( position, boneMatrixStructNode, weight, bindMatrix, bindMatrixInverse );
normal = new SkinningNormalNode( normal, boneMatrixStructNode, weight, bindMatrix, bindMatrixInverse ); |
Where do we pass the instance of I would also suggest to pass in the entire skinned mesh/node to const skinningNode = new SkinningNode( skinnedMesh );
const positionNode = new SkinningPositionNode( position, skinningNode );
const normalNode = new SkinningNormalNode( normal, skinningNode ); |
BTW: I think this is a good opportunity to find out how to use the node system to implement renderer features like skinning less hard-wired^^. |
We just need one more intermediate vertex class for position/normal statics, I did not get to add that yet, so that gap remained. |
Okay, then let's continue with the skinning topic when this new class is ready. |
@Mugen87 Is possible you merger your skinning PR so I can make some updates? |
The PR is quite outdated and it's probably better to make a new branch based on latest For stability reasons, it's probably better to merge it after |
No problem we can wait after r132 has be published. There is a lot of thing to do here too. |
I've realized today that the skinning branch is broken and does not work with latest It's probably better if you just copy these changes to your local branch and then apply the respective updates. |
Thank you very much! Moreover, bring Skinning Mesh to WebGPU was a great initiative. |
@Mugen87 I am having several problems using layout(set = 0, binding = 0) uniform sampler nodeUniform2_sampler;
layout(set = 0, binding = 1) uniform texture2D nodeUniform2;
vec3 nodeCode0 ( texture2D A, sampler B ) {
return vec3( 0.0 );
}
void main() {
// Tint SPIRV reader failure:
// Parser: error: function parameter of pointer type cannot be in 'none' storage class
nodeCode0( nodeUniform2, nodeUniform2_sampler )
} Full code#version 450
// <node_builder>
#define NODE_MATERIAL
// defines
#define NODE_CODE nodeVary0 = uv;
#define NODE_CODE_MVP nodeVar0 = ( nodeUniforms.nodeUniform0 * nodeUniforms.nodeUniform1 ); PositionLocal = position; nodeVar1 = nodeCode0( nodeUniform2, nodeUniform2_sampler );
#define NODE_MVP ( nodeVar0 * vec4( nodeVar1, 1.0 ) )
// uniforms
layout(set = 0, binding = 0) uniform sampler nodeUniform2_sampler; layout(set = 0, binding = 1) uniform texture2D nodeUniform2; layout(set = 0, binding = 2) uniform NodeUniforms { uniform mat4 nodeUniform0; uniform mat4 nodeUniform1; } nodeUniforms;
// attributes
layout(location = 0) in vec3 position; layout(location = 1) in vec2 uv;
// varys
layout(location = 0) out vec2 nodeVary0;
// vars
mat4 nodeVar0; vec3 nodeVar1; vec3 PositionLocal;
// codes
vec3 nodeCode0 ( texture2D A, sampler B ) {
return PositionLocal;
}
// </node_builder>
void main(){
NODE_CODE
NODE_CODE_MVP
gl_Position = NODE_MVP;
} |
Another example: layout(set = 0, binding = 0) uniform sampler nodeUniform2_sampler;
layout(set = 0, binding = 1) uniform texture2D nodeUniform2;
vec3 nodeCode0 ( texture2D A, sampler B ) {
// Tint SPIRV reader failure:
// Parser: error: no matching call to textureSampleLevel(ptr<void, read_write>, ptr<void, read_write>, vec2<f32>, f32)
return texture( sampler2D( A, B ), vec2( 0.0 ) ).xyz;
}
void main() {
nodeCode0( nodeUniform2, nodeUniform2_sampler ) |
That is strange. I'll try to have a look at this tomorrow. In the meanwhile, you might want to ask for advice directly at the Dawn or WebGPU chatrooms. https://matrix.to/#/#webgpu-dawn:matrix.org For this issue, the Dawn chatroom seems more right. The second links is more about WebGPU standard related questions. |
Thanks! I published a TextureNode PR needed for test this issue using NodeMaterial: #22501 |
It worked ( |
Now I see the warning, too:
The strange thing is that the texture sampling does not look different compared to the existing samplings in other examples (e.g. in
The only difference is that the skinning code samples in the vertex shader. |
Strange that this pattern work if used without function argument in both shader stage. |
I still have many issues with // 60fps
vec3 getSkinningPosition( ) {
mat4 boneMatX = bones[ int( index.x ) ];
...
}
// 5~ fps
vec3 getSkinningPosition( in mat4[ 52 ] bones ) {
mat4 boneMatX = bones[ int( index.x ) ];
...
}
|
/cc @Kangz |
Uh, this must be because the underlying code is doing a copy of the 52 mat4s when calling the function. You'd be able to more precisly control the costs of what's happening by using WGSL directly. If you want to see what code is produced you can run chrome with the additional Note that the SPIR-V input to |
@Kangz Thanks! This makes a lot of sense and I was already suspicous that other issues I had like this ( #21322 (comment) ) one is related too with GLSL to SPIR-V compiler |
FunctionNode
,FunctionCallNode
and depedenciesObject3DNode
- base forModelNode
,CameraNode
Object3DNode.VIEW_POSITION
- need for lightsNormalNode: LOCAL, WORLD, VIEW
- revisedPositionNode: LOCAL, WORLD, VIEW, VIEW_DIRECTION
- revisedConstNode
and depedenciesrevision matrix names
MathConsts
libraryMathFunction
libraryBSDFunctions
libraryVarNode
variable creation nodeWebGPUNodeSampler
andWebGPUNodeSampledTexture
for instanceNodeTexture
ContextNode
andLightContextNode
LightNode
node for useTHREE.Light
PropertyNode
for material propertiesMaterialNode
: generate nodes from native material propertiesLightsNode
collect allLightNode
to use selective lights per materialLightsNode
implementation forBlinnPhong
webgpu_lights_webgl.html
remove test examplewebgpu_selective_lights.html
finish exampleWebGPU - Selective Lights
https://raw.githack.com/sunag/three.js/nodematerial-light/examples/webgpu_lights_selective.html
Suggested syntax for selective lights: