-
-
Notifications
You must be signed in to change notification settings - Fork 35.6k
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
[WIP] GLTFLoader: Add .setUseNodes() option. #14572
Conversation
// * ao | ||
// * aoMap | ||
|
||
var ao = builder.findNode( props.ao, inputs.ao ), |
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.
Oops this should be aoMapIntensity and included in shortcuts
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.
Yeah. To shortcuts in MeshNodeMaterial
you can add here:
https://github.com/donmccurdy/three.js/blob/6a498fd2793befd33aa315716ae2af2022c71bb9/examples/js/nodes/materials/nodes/MeshStandardNode.js#L18
And
https://github.com/donmccurdy/three.js/blob/6a498fd2793befd33aa315716ae2af2022c71bb9/examples/js/nodes/materials/nodes/MeshStandardNode.js#L25
*Edit
https://github.com/donmccurdy/three.js/blob/6a498fd2793befd33aa315716ae2af2022c71bb9/examples/js/nodes/materials/MeshStandardNodeMaterial.js#L29
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.
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.
@sunag I'd be glad to open separate PRs for any of this, but if you have other PRs in progress I'll avoid the merge conflict and leave it to you.
Thank you! About conflict do not worry, I will not go post other PR big so early, I can use your code if you post first. Would be great you post PR with these fixes and improvements :-)
// * ao | ||
// * aoMap | ||
|
||
var ao = builder.findNode( props.ao, inputs.ao ), |
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.
Yeah. To shortcuts in MeshNodeMaterial
you can add here:
https://github.com/donmccurdy/three.js/blob/6a498fd2793befd33aa315716ae2af2022c71bb9/examples/js/nodes/materials/nodes/MeshStandardNode.js#L18
And
https://github.com/donmccurdy/three.js/blob/6a498fd2793befd33aa315716ae2af2022c71bb9/examples/js/nodes/materials/nodes/MeshStandardNode.js#L25
*Edit
https://github.com/donmccurdy/three.js/blob/6a498fd2793befd33aa315716ae2af2022c71bb9/examples/js/nodes/materials/MeshStandardNodeMaterial.js#L29
@@ -203,7 +209,7 @@ ColorSpaceNode.LOG_LUV_TO_LINEAR = 'LogLuvToLinear'; | |||
|
|||
ColorSpaceNode.prototype = Object.create( TempNode.prototype ); | |||
ColorSpaceNode.prototype.constructor = ColorSpaceNode; | |||
ColorSpaceNode.prototype.nodeType = "ColorAdjustment"; | |||
ColorSpaceNode.prototype.nodeType = "ColorSpaceNode"; |
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.
Node in final is not necessary, only nodeType = "ColorSpace"
// * ao | ||
// * aoMap | ||
|
||
var ao = builder.findNode( props.ao, inputs.ao ), |
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.
@@ -14,6 +14,10 @@ function MeshStandardNodeMaterial() { | |||
|
|||
this.type = "MeshStandardNodeMaterial"; | |||
|
|||
var options = arguments[ 0 ]; | |||
|
|||
if ( typeof options === 'object' ) Object.assign( this, options ); |
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 think we could follow this standard?
https://github.com/donmccurdy/three.js/blob/1ffd8db807e096af16960887c2c086bf3856bc3a/src/materials/MeshStandardMaterial.js#L56
|
||
if ( this.method === undefined ) { | ||
|
||
this.method = this.getEncodingMethod( this.input.value.encoding ); |
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 think that this already included in TextureNode and CubeTextureNode.
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, the lines I added above are incorrect and don't solve the issue I was trying to fix. But with or without these lines, colorspace conversion is coming out backwards... when map.encoding === THREE.sRGBEncoding
, I get the following generated GLSL:
vec3 diffuseColor = ( vec4( nVu0, 1.0 ) * LinearTosRGB( tex2D( nVu1, vUv ) ) ).xyz;
which should be sRGBToLinear.
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.colorSpace = this.colorSpace || new ColorSpaceNode( this ); |
this.colorSpace = this.colorSpace || new ColorSpaceNode( this ); |
I think that it being sould be:
builder.addContext( { input: code, include: builder.isShader( 'vertex' ) } );
this.colorSpace = this.colorSpace || new ColorSpaceNode( this );
this.colorSpace.fromDecoding( builder.getTextureEncodingFromMap( this.value ) );
code = this.colorSpace.build( builder, this.type );
builder.removeContext();
ColorSpaceNode.prototype.fromDecoding= function ( decoding ) {
this.method = this.getDecodingMethod ( decoding )[ 0 ];
return this;
};
@@ -6,21 +6,29 @@ import { MeshStandardNode } from './nodes/MeshStandardNode.js'; | |||
import { NodeMaterial } from './NodeMaterial.js'; | |||
import { NodeUtils } from '../core/NodeUtils.js'; | |||
|
|||
function MeshStandardNodeMaterial() { | |||
function MeshStandardNodeMaterial( parameters ) { |
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'm not sure about this. I never liked passing parameters as an object, it's error-prone and limited.
We have a chance to move away from it here.
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 thought the goal of MeshStandardNodeMaterial
was to be a backward-compatible alternative to MeshStandardMaterial
, whereas StandardNodeMaterial
would provide a new, fully node-based syntax? If we don't want this class to support old syntax then maybe I've misunderstood the difference.
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.
@sunag is that correct, or what would be the goal with the two material classes here? Put another way, is this what we want?
- MeshStandardMaterial (current)
- MeshStandardNodeMaterial (node-based, fully backward-compatible)
- StandardNodeMaterial (node-based, new API, new features)
I’m assuming here that MeshStandardMaterial would eventually be replaced by MeshStandardNodeMaterial. If that’s not the goal, or if we want the existing system to exist alongside node-based materials indefinitely, then perhaps we don’t need a backward-compatible MeshStandardNodeMaterial?
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 think the plan was to make MeshStandardMaterial
node-based to keep backwards-compatibility.
Maybe MeshStandardMaterial
could extend MeshStandardNodeMaterial
.
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 never liked passing parameters as an object
Personally, I much prefer parameters
as an object to
Texture( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding )
where the order matters. Very annoying.
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 agree that passing parameters like Texture
currently does is also annoying.
I prefer this kind of API:
new THREE.Texture( image ).setMapping( mapping ).setFormat( format );
Or:
var texture = new THREE.Texture( image );
texture.mapping = mapping;
texture.format = format;
But the problem of the last one is that the user could make a typo like texture.fromat
and javascript won't complain. Unless we start using Object.freeze()
.
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.
We could just delete MeshStandardMaterial, rename MeshStandardNodeMaterial as MeshStandardMaterial, and if everything is backward-compatible there is no user-facing change. Users should only know about MeshStandardMaterial and the new NodeStandardMaterial.
I think that's a big change. Too many tutorials/articles that will get obsolete.
I think it's easier to think about *NodeMaterial
as having a different API. If we bring parameters to the new API we're carrying over the problem and it'll be harder to maintain.
We can always add parameter support to MeshStandardNodeMaterial
later. For the time being I prefer to not over complicate the new API.
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.
Hm... I don't think that we should introduce two new standard materials (MeshStandardNodeMaterial
, StandardNodeMaterial
) that both have different, breaking APIs for the same features. For the new API, StandardNodeMaterial
seems like the place to start — we can leave parameter support out there. If MeshStandardNodeMaterial
will not have the same API as MeshStandardMaterial
, I think we should just delete it (MeshStandardNodeMaterial
) to prevent confusion, unless it has some other purpose I've missed.
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 never liked passing parameters as an object, it's error-prone and limited.
Can you explain why this:
const mat = new MeshStandardMaterial( { color: oxff0000, roughness: 0.25, transparency: true, map, alphaMap, normalMap } ) ;
is more error prone or limited than
const mat = new MeshStandardMaterial().setColor( 0xff0000).setRoughness( 0.25 ).setTransparent( true ).setMap( map ).setAlphaMap( alphaMap ).setNormalMap( normalMap );
The second approach seems much more verbose to me, with no advantage in clarity - especially since this would be a breaking change.
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.
But the problem of the last one is that the user could make a typo like texture.fromat and javascript won't complain. Unless we start using Object.freeze().
If that is the problem I think this could be fixed with hasOwnProperty
declaring all properties
before of setValues
even undefined
variables:
Example (1)
var obj = { format : undefined };
// inside while
var prop = "fromat", val = "any value";
if ( obj.hasOwnProperty( prop ) ) obj[prop] = val;
else console.warn(prop, "property does not exist or has become obsolete.");
Example( 2)
NodeMaterial.prototype.setValues = function( values ) {
if ( values === undefined ) return;
for ( var key in values ) {
if ( this.hasOwnProperty( key ) ) {
this[ key ] = values[ key ];
} else {
console.warn(key, "property does not exist or has become obsolete.");
}
}
};
Personally, I much prefer parameters as an object to [ordered parameters]
+1 I think this could come from the an evolution of compiler too like interface
of typescript
. For me, besides being practical to define parameters it techniques is good to avoid changes if a property is to be depreciate in relation to ordered parameters, in relation at setParamA(a).setParamB(b)
could help to reduce the code.
Another third thing could be to create a classe just for this.
new THREE.SetValues( this, params );
// or
THREE.SetValues( this, params )
I'd meant to help write documentation for NodeMaterial but it is blocked on this question... I don't know which of these classes we actually want people to start using, and which are internal or transitional. 🤔 |
What's the |
I believe (@sunag please correct me if I'm wrong) that ^Or that's my guess at what the code currently does. Whether the names should be kept or changed is another question. |
@donmccurdy Exactly. Complementing only that |
I'd like to rebase this PR and change its API so that nodes are looked up from a dictionary, rather than direct dependence on the import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
import * as Nodes from 'three/examples/jsm/nodes/Nodes.js';
var loader = new GLTFLoader();
loader.setNodeMaterialDictionary( Nodes ); // Optional. If set, NodeMaterial is used.
loader.load( 'model.glb', ... ); With that done, I think it would be alright to merge this, providing users an easy way to get started with NodeMaterial from an existing glTF model. Does this sound OK? |
I think that sounds good to me. |
Closing for now, this will need a rewrite... |
Follow-up from #14149.
This isn't meant to be merged, or at least not at the moment, does make it easier for me to test glTF models with NodeMaterial, and hopefully helps @sunag a bit. Supporting NodeMaterial as an "opt-in" experimental thing in GLTFLoader is looking much easier with the MeshStandardNodeMaterial. :)
A few issues found:
MeshStandardNodeMaterial and others don't apply constructor arguments. (would help for backward compatibility).copy()
methods should returnthis
or cloning will fail.sRGB textures are treated as linear. I tried to fix this below but didn't find the problem yet.aoMap
missing?@sunag I'd be glad to open separate PRs for any of this, but if you have other PRs in progress I'll avoid the merge conflict and leave it to you. 😇