-
-
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
Material: Add TwoPassDoubleSide
.
#25165
Conversation
See: mrdoob/three.js#25165 also add doc comment of Side
This sounds good, but is it a regression by default now? I think |
I don't think I'd consider it a regression, one way or the other. But we can do whichever we think is likely to be the best choice for most users, and I'm fine with either option. |
Two-pass rendering feels like something that should be opt-in (as after this PR) rather than opt-out. |
According to the user feedback in the last months I think that, too. |
My impression from the user feedback (though I can't find the older threads now) was that the main reason to avoid two-pass rendering was for performance in some non-PBR use cases. For PBR, we get pretty ugly artifacts without the two-pass, hence why it was added. Since GLTF is for PBR, this is why I'd recommend changing this default in the Loader. Especially because this will be a pretty tricky change for a user to make after the fact, and also a difficult artifact to debug in the first place in order to find this solution. |
I don't think I agree that two-pass rendering is more necessary for PBR materials than any other materials, or that the performance cost is any less relevant with PBR. Or that "GLTF is for PBR" for that matter. We can't advise people to use FBX just because they want unlit materials, glTF is also a great choice for that. Both the visual issue we originally solved here, and the performance regression introduced by our fix, are difficult for users to debug themselves. It is probably most important that we be consistent in whatever we decide is the right default. |
I, too, think two-pass rendering for transparent double-sided materials should be the default. @mrdoob also thought so, which is why he added the feature. IMO, this has nothing to do with glTF or PBR. I also think users who are rendering single-plane, transparent, double-sided objects and are having a performance issue should have the ability to opt-out. This means reverting this PR in favor of a different API. // Also, IMO, this PR does not "fix" #25149 as claimed in the original post above. The issue with |
I don't think I followed the link between the earlier sentences and this conclusion, why do you feel that |
Maybe something like |
@donmccurdy I thought we would have to revert to an different API, but maybe the suggestion by @elalish is OK... |
Thanks @elalish and @WestLangley! If we think that two-pass rendering is the right default for most users then giving single-pass rendering another name makes sense to me. I don't know whether @mrdoob still prefers two passes, as the performance drawbacks were less obvious at the time of the original change. Aside — There's some advantage to leading with a common prefix when we can. Like |
Well, ...but this is such an edge case, I compare it to |
* docs: update constructor doc comment of geometries See: mrdoob/three.js#25086 * docs: update doc comment of the constructor of BufferAttribute See: mrdoob/three.js#25046 the `normalized` was already optional in the typedef * feat: add TwoPassDoubleSide See: mrdoob/three.js#25165 also add doc comment of Side * feat: add `Mesh.getVertexPosition()` - add `Mesh.getVertexPosition()` - add doc comment of `SceneUtils.reduceVertices` See: mrdoob/three.js#25049 * feat: add `Object3D.getObjectsByProperty()` - add `Object3D.getObjectsByProperty()` - add doc comment of `Object3D.getObjectByProperty()` See: mrdoob/three.js#25006 * docs: add a doc comment of `PointLight.castShadow` See: mrdoob/three.js#25136 * feat (GLTFLoader): add loadNode hook See: mrdoob/three.js#25077 * feat (Nodes): New features and revisions - add three new nodes: `CacheNode`, `StackNode`, and `SpecularMIPLevelNode` - add `NodeCache` - add `getDefaultUV()` to `CubeTextureNode` and `TextureNode` - add `isGlobal()` to `Node` - add `cache` and `globalCache` to `NodeBuilder` - add missing `flowsData` to `NodeBuilder` - add `hasDependencies` to `TempNode` - add `maxMipLevel` and `cache` to `ShaderNodeBaseElements` - replace `maxMipLevel` -> `specularMIPLevel` of `ShaderNodeElements` - change constructor type and texture type of `MaxMipLevelNode` - add `SpecularMIPLevelNode` * feat (Nodes): add FogExp2 node Co-authored-by: Josh <[email protected]>
But all 8 possible combinations do not make sense. That means there is something wrong with the API. |
THB, I see no reason for changing anything since I question your premise that every possible combination of properties has to make sense. Let's just take |
Is this necessarily true? I can imagine using TwoPassDoubleSide for additive blending with |
With all due respect, to me, that means the API is a poor one. I would vote to revert to the previous implementation where two-pass was the default, and add a per-object opt-out akin to I anticipate |
Something like this? if ( material.transparent === true && material.side === DoubleSide && object.renderDoubleSideSinglePass === false ) {
material.side = BackSide;
material.needsUpdate = true;
_this.renderBufferDirect( camera, scene, geometry, material, object, group );
material.side = FrontSide;
material.needsUpdate = true;
_this.renderBufferDirect( camera, scene, geometry, material, object, group );
material.side = DoubleSide;
} else {
_this.renderBufferDirect( camera, scene, geometry, material, object, group );
} |
Fwiw if a material is opaque and set to "TwoPassDoubleSide" I'd expect it to render the opaque object double sided. Rendering the object single sided is clearly misleading. |
@gkjohnson Oh! Didn't think of that. Right... |
This change should be called out in https://github.com/mrdoob/three.js/wiki/Migration-Guide for r148, since the default behavior for certain objects has changed. |
Added:
|
For a few versions now I can't get the back of a solid object to render... |
@d3x0r Do you mind creating jsfiddle? |
This is a VERY old version that was barely even working; but is enough to show that it shows the inside-back side of half spheres... This uses three.js 111 this is the current version (150dev) This is the repo... phong init (old) I am doing lots of 'work' to build the sphere mesh geometries... but the winding order is correct for the front, so I'd think the back would also be right. I do apologize for not minimizing it to just a plane or something... |
@d3x0r Can you please create a minimal jsfiddle that shows the issue? We can't help you otherwise. |
This should have a 4 pixel image included... without the .map it doesn't not show the backs... But not it's not showing the texture either. https://jsfiddle.net/ptrceavx/ (105) if ( set , transparent : true ) (like line 173 ) then nothing shows.... https://jsfiddle.net/26dybawe/ (149) I don't know why the texture isn't showing though- it's all black in the simplified version. |
Is that as simple as you're able to make the example? |
Here's a simple jsfiddle you can build on top of: https://jsfiddle.net/em4j9hvu/ |
https://jsfiddle.net/86fmkban/2/ added texture - added to window (small red dot upper left, so you can see it IS a valid PNG image) ... it's 2 pixels opaque red and 2 pixels mostly opaque red (slightly transparent) I know I didn't have to - but I did also add a conservative onload so the Image() is definitely loaded... I know images stream in and three.js takes care of that pretty well but... I don't see any reason it should be black. https://jsfiddle.net/86fmkban/4/ |
Here's your jsfiddle fixed: https://jsfiddle.net/6espjogh/ Please, continue working on the jsfiddle until it shows the issue you're trying to describe. |
https://jsfiddle.net/7ac2wfh8/3/ seems to work fine still. Includes BufferGeometry, OrthoCamera, phong material, complex geometry -- I see no difference between This and mine other than count of objects; but I still have no backsides. Matched the canvas to be transparent too. swapped the image to the high res one I'm using(worked fine so went back to the small one). |
Sorry, I can't read blobs of text like that. I've asked ChatGPT to summarise it:
Feel free to ask for help on discord. |
Credits to thespite on twitter for the ChatGPT idea: |
Nice. That IS what I said. https://jsfiddle.net/ox1bqyse/
Anything > 1 for scale causes the back to not show. |
You need to add |
Maybe you can use ChatGPT to summarise your text before posting here next time. |
I'm having an issue related to this and getting gl_FrontFacing to work right. I setup a simple jsfiddle example : WIth transparent:true, both faces get colored red. If I turn transparent:false then uncomment the discard condition in the fragment shader, then both faces get different colors. Not sure if its a depth issue since I'm using a sphere and trying to hide half of it. For context, I'm trying to recreate minionsart's fake liquid shader from unity. |
@sketchpunk For a workaround, see #25149 (comment). It will work for You can also set If you need more help, please post at the forum. |
If you move the ball to y=-0.5 instead of y=0.5 it works (?) |
It has been resolved already: |
Fixed #24711.
Fixed #25149.
Description
Alternative implementation to #25156 as suggested in #24711 (comment). Instead of introducing a new
Object3D
property, a newMaterial.side
constant controls the rendering of double-sided transparent objects instead.