-
-
Notifications
You must be signed in to change notification settings - Fork 21.7k
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
Add layers
and layers_cull_mode
properties to BaseMaterial3D
#99565
base: master
Are you sure you want to change the base?
Add layers
and layers_cull_mode
properties to BaseMaterial3D
#99565
Conversation
87f8f12
to
b75d6ce
Compare
This comment was marked as resolved.
This comment was marked as resolved.
b75d6ce
to
88598c7
Compare
This comment was marked as resolved.
This comment was marked as resolved.
88598c7
to
303d73e
Compare
You may find it helpful to run pre-commit locally: https://docs.godotengine.org/en/latest/contributing/development/code_style_guidelines.html#pre-commit-hook |
303d73e
to
884ed36
Compare
scene/resources/material.cpp
Outdated
if (layers_cull_mode == LAYERS_CULL_VERTEX) { | ||
code += R"( | ||
if ((CAMERA_VISIBLE_LAYERS & layers) == 0u) { // Begin vertex cull mode | ||
VERTEX = vec3(1.0 / 0.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.
My experience with this trick to discard a triangle as been mixed at best. On at least a few devices I tested on this resulted in corrupted triangles instead of discarding the triangle
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.
Do you know if there is a best way to do this? I've seen several suggestions online, but i don't have the experience to know which might work the best:
- Set all the vertices to NaN/Inf
- Set all vertices outside of the view frustum
- Set all the vertices to the same value so that the primitive collapses to a point
I did make a note in the class documentation about the vertex method potentially not working on all systems. Don't know if that would be enough to allow this through:
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've had the best luck setting the vertex outside the view frustum. To do that here you would need to use the POSITION
built in instead of VERTEX
because VERTEX
is the view space position.
Overall though I'm not certain the shader is the best place for this check. With this approach the draw call still happens even if it's filtered out.
You could pass the later into the rendering server and then filter the material when the instance buffer is being set up. That way you can skip the draw call entirely (and all the associated setup cost)
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.
Okay, that makes sense about stopping it before the draw call. I think both lyuma and tetrapod (in the proposal) mentioned the same thing. The main reason i went about it this way is i wasn't sure how to do it the other way 😅 (I know C++ and Godot shader code, but not OpenGL or Vulcan.) I might look into it, though, and see if i can figure it out. Would you have any pointers on where i could start, such as where visual instances are culled?
If i'm able to figure it out, would it make more sense for this property to go on Material
instead of BaseMaterial3D
? I suppose there's probably a significant difference between 3D and 2D layers/rendering, which might make things more complicated if working with just Material
. But maybe i could copy how next_pass
/render_priority
work and only expose the layers
property for 3D materials.
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 used VERTEX = vec3(-INF);
to hide particles on contact back when I implemented particle collision (the current implementation sets ACTIVE = false
instead, a particles-only built-in).
884ed36
to
80989ed
Compare
Set all the vertices to NaN/Inf
I believe your code for this was not correct. You were doing `vec3(1.0/0.0)` but the problem is many compilers/optimizers (these are inside the driver itself) will optimize out certain statements containing values known at compile time to be NaN.
I usually use sqrt(value not known at compile time but always negative). For example, `VERTEX = vec3(sqrt(-VIEW_MATRIX[3].w));`
If done right without triggering compiler optimizers, this approach has worked on all PC hardware I have tested as well as all android based VR devices (tested on Quest 1 and newer). I have not tested on other mobile chipsets so I will defer to clayjohn's expertise.
Set all vertices outside of the view frustum
Can also do this, but it doesn't help if everything is degenerate anyway.
Set all the vertices to the same value so that the primitive collapses to a point
This is the correct/best answer if the material setting affects the whole mesh. No need to depend on undocumented behavior if you can achieve the same effect by making all triangles degenerate.
Personally, though, I would like to question the overall approach of doing this. Why are we submitting the draw call and then culling it in the vertex shader? It seems to me that this culling property makes more sense to be applied in RenderingServer similar to how layer_cull_mask currently works on visual instances.
The proposal indicates a desire to make the debug materials on a demo project easier to test, but I think there ought to be a better way to do this that doesn't involve swapping around layers on materials. It just doesn't feel like the right place to do this even if it is possible, given that it includes a performance cost that users might not expect. (You can write this code in a shader material if needed)
|
@clayjohn @lyuma I looked into culling before the draw call, but it's well beyond me. If you all definitely want to approach it from that direction, i could make a new issue (or amend the current issue) asking for it to be implemented on all 3D materials, and then see if someone else comes along who wants to tackle it. If you think the current solution could work with minor tweaks, I'd be happy to make any necessary changes, such as changing how it is culled in the vertex function. If so, let me know what the best solution for this is... seems like maybe it is setting the vertices outside of the view frustum, per clayjohn's suggestion above. |
@lyuma Regarding this, my original goal for this PR was to provide a way for users who don't know shaders to more easily use an example project i'm working on, which you can find here. (I know this project isn't an optimal solution. I've just put it up as a possible workaround until the compositor is complete.) I also thought being able to render different materials on different layers might be helpful for other visual effects, such as thermal vision. Of course that's already possible in shaders, but I thought it could be helpful to make that more accessible. |
80989ed
to
8c85cac
Compare
8c85cac
to
8357093
Compare
8357093
to
47ab113
Compare
This PR adds two new properties to
BaseMaterial3D
which allow it to render only on selected layers:layers
- Determines which layers this material will be rendered on.layers_cull_mode
- Determines how to cull the material on the layers where it is not rendered. Has three options:LAYERS_CULL_DISABLED
- No layer-based culling will occur. (Exactly the same as currentBaseMaterial3D
.)LAYERS_CULL_VERTEX
- Layer-based culling will occur via code generated in thevertex()
function.LAYERS_CULL_FRAGMENT
- Layer-based culling will occur via code generated in thefragment()
function.Motivation
The purpose of this is to allow users to apply
StandardMaterial3D
orORMMaterial3D
to an object only on certain render layers. Godot shaders can already accomplish this, and other effects, through use ofCAMERA_VISIBLE_LAYERS
(see #67387). This PR exposes some of that same functionality to users ofStandardMaterial3D
andORMMaterial3D
. Combined with the ability to add more materials vianext_pass
, this will allow users a greater level of control over how their objects render on different layers.Implementation
If either
LAYERS_CULL_VERTEX
orLAYERS_CULL_FRAGMENT
are selected, a uniform will be added to the generated Godot shader code. It will be controlled by the newlayers
property.If the mode
LAYERS_CULL_VERTEX
is selected, the following will be added inside thevertex()
function in the generated Godot shader code:If the mode
LAYERS_CULL_FRAGMENT
is selected, the following will be added at the beginning of thefragment()
function in the generated Godot shader code:Bugsquad edit: Implements and closes godotengine/godot-proposals#11210