bevy
bevy copied to clipboard
add globals to mesh view bind group
Objective
- It's often really useful to have access to the time when writing shaders.
Solution
- Add a UnifformBuffer in the mesh view bind group
- This buffer contains the time, delta time and a wrapping frame count
https://user-images.githubusercontent.com/8348954/180130314-97948c2a-2d11-423d-a9c4-fb5c9d1892c7.mp4
Changelog
- Added a
GlobalsUniformat position 9 of the mesh view bind group
Notes
The implementation is currently split between bevy_render and bevy_pbr because I was basing my implementation on the ViewPlugin. I'm not sure if that's the right way to structure it.
I named this globals instead of just time because we could potentially add more things to it.
References in other engines
- Godot: https://docs.godotengine.org/en/stable/tutorials/shaders/shader_reference/canvas_item_shader.html#global-built-ins
- Global time since startup, in seconds, by default resets to 0 after 3600 seconds
- Doesn't seem to have anything else
- Unreal: https://docs.unrealengine.com/4.26/en-US/RenderingAndGraphics/Materials/ExpressionReference/Constant/
- Generic time value that updates every frame. Can be paused or scaled.
- Frame count node, doesn't seem to be an equivalent for shaders: https://docs.unrealengine.com/4.26/en-US/BlueprintAPI/Utilities/GetFrameCount/
- Unity: https://docs.unity3d.com/Manual/SL-UnityShaderVariables.html
- time since startup in seconds. No mention of time wrapping. Stored as a
vec4(t/20, t, t*2, t*3)wheretis the value in seconds - Also has delta time, sin time and cos time
- time since startup in seconds. No mention of time wrapping. Stored as a
- ShaderToy: https://www.shadertoy.com/howto
- iTime is the time since startup in seconds.
- iFrameRate
- iTimeDelta
- iFrame frame counter
I used this PR for my animated shader: https://youtu.be/BanMIX3_GiU
I'm very much in favour of this, i know at least Unity offers this out of the box, I would imagine other engines do too, but I haven't checked.
I think the percentage of users that would need this in a shader is higher than the percentage of users that can easily understand how to implement it themselves, since it requires getting to work at a lower level than deriving AsBindGroup for a custom material (and the very few other requirements since 0.8).
On thing I would consider:
How does this interact with the animate_shader example? On one hand it kind of makes it redundant, because extracting time is the aspect of that example that is the most needed by the average user, on the other hand the example shows how to manually set the bind group in a custom draw command, which is the most interesting bit, but for more advanced users.
Maybe the solution is to have a different example that shows setting the bing group for a different functionality, and adapt animate_shader to use the solution from this PR? (I guess only the latter is needed for this PR). Otherwise I think it might be confusing, but I'm not sure what you people think.
I'll update the animate_shader example soon to reflect the changes and after some quick discussion with @superdump we agreed that we indeed need lower level examples instead of relying on examples showcasing multiple things. These will be added in a separate PR. See https://github.com/bevyengine/bevy/issues/5843
I added the frame count as a wrapping u32. Unfotunately, I can't rely on the FrameTimeDiagnosticsPlugin to be present, since it's not part of DefaultPlugins, so I just used a Localwrapping_add(1) in the prepare system
I'm not sure what I think of the name
Globals. I wanted to sayGlobalUniformsbut then we'd needGlobalUniformsUniform. :)
Yeah, I was hoping somebody would have proposed a better name. I guess since this is only for time stuff this could just be a TimeUniform. Most engine do seem to treat time as something separate.
something around frame metadata rather than globals?
The time since startup value isn't really related to the frame though, since it's just the time since startup (or at least, the time since the last wrap period). Godot, unreal and unity all seem to put this under Time.
The time since startup value isn't really related to the frame though
Oh you mean the frame start time 😄
I rebased and used the now merged wrapping time api. This should be ready for a final review pass I think.
Pull request successfully merged into main.
Build succeeded: