Skip to content
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

[Merged by Bors] - add globals to mesh view bind group #5409

Closed
wants to merge 2 commits into from

Conversation

IceSentry
Copy link
Contributor

@IceSentry IceSentry commented Jul 21, 2022

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
shader_material_SH7SH4AvgA.mp4

Changelog

  • Added a GlobalsUniform at 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

@IceSentry IceSentry added the A-Rendering Drawing game state to the screen label Jul 21, 2022
crates/bevy_pbr/src/render/mesh_view_types.wgsl Outdated Show resolved Hide resolved
crates/bevy_render/src/globals.rs Outdated Show resolved Hide resolved
assets/shaders/custom_material.wgsl Outdated Show resolved Hide resolved
crates/bevy_render/src/globals.rs Show resolved Hide resolved
HackerFoo added a commit to HackerFoo/bevy that referenced this pull request Aug 7, 2022
@HackerFoo
Copy link
Contributor

I used this PR for my animated shader: https://youtu.be/BanMIX3_GiU

HackerFoo added a commit to HackerFoo/bevy that referenced this pull request Aug 10, 2022
HackerFoo added a commit to HackerFoo/bevy that referenced this pull request Aug 13, 2022
HackerFoo added a commit to HackerFoo/bevy that referenced this pull request Aug 14, 2022
@wilk10
Copy link
Contributor

wilk10 commented Aug 31, 2022

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.

@IceSentry
Copy link
Contributor Author

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 #5843

assets/shaders/custom_material.wgsl Outdated Show resolved Hide resolved
HackerFoo added a commit to HackerFoo/bevy that referenced this pull request Sep 6, 2022
HackerFoo added a commit to HackerFoo/bevy that referenced this pull request Sep 8, 2022
@IceSentry
Copy link
Contributor Author

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 Local that I increment with wrapping_add(1) in the prepare system

Copy link
Contributor

@superdump superdump left a 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 what I think of the name Globals. I wanted to say GlobalUniforms but then we'd need GlobalUniformsUniform. :)

crates/bevy_pbr/src/render/mesh_view_types.wgsl Outdated Show resolved Hide resolved
crates/bevy_render/src/globals.rs Outdated Show resolved Hide resolved
crates/bevy_render/src/globals.rs Outdated Show resolved Hide resolved
crates/bevy_render/src/globals.rs Outdated Show resolved Hide resolved
crates/bevy_render/src/globals.rs Outdated Show resolved Hide resolved
examples/shader/animate_shader.rs Show resolved Hide resolved
examples/shader/animate_shader.rs Show resolved Hide resolved
examples/shader/animate_shader.rs Show resolved Hide resolved
@IceSentry
Copy link
Contributor Author

I'm not sure what I think of the name Globals. I wanted to say GlobalUniforms but then we'd need GlobalUniformsUniform. :)

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.

@mockersf
Copy link
Member

something around frame metadata rather than globals?

@IceSentry
Copy link
Contributor Author

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.

@mockersf
Copy link
Member

The time since startup value isn't really related to the frame though

Oh you mean the frame start time 😄

@alice-i-cecile alice-i-cecile added C-Usability A simple quality-of-life change that makes Bevy easier to use A-Time Involves time keeping and reporting labels Sep 14, 2022
bors bot pushed a commit that referenced this pull request Sep 23, 2022
# Objective

- Sometimes, like when using shaders, you can only use a time value in `f32`. Unfortunately this suffers from floating precision issues pretty quickly. The standard approach to this problem is to wrap the time after a given period
- This is necessary for #5409

## Solution

- Add a `seconds_since_last_wrapping_period` method on `Time` that returns a `f32` that is the `seconds_since_startup` modulo the `max_wrapping_period`

---

## Changelog

Added `seconds_since_last_wrapping_period` to `Time`

## Additional info

I'm very opened to hearing better names. I don't really like the current naming, I just went with something descriptive.

Co-authored-by: Charles <IceSentry@users.noreply.github.com>
@IceSentry
Copy link
Contributor Author

I rebased and used the now merged wrapping time api. This should be ready for a final review pass I think.

Copy link
Contributor

@wilk10 wilk10 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for this! This is going to be a huge time saver for users, imo. It's also great to see the animate_shader example be way more accessible.

I have a comment about 2d, that I don't necessarily think has to be addressed in this PR, but maybe it's worth tracking with an issue afterwards..? Not sure what you people think.

Comment on lines +2 to 3
// The time since startup data is in the globals binding which is part of the mesh_view_bindings import
#import bevy_pbr::mesh_view_bindings
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about 2d users? They may not depend on bevy_pbr, but it's possible they still want to access the globals binding.

Possible solutions (imo):

  • make the globals binding available also in bevy_sprite::mesh2d_view_bindings
  • have an example with sprites that shows importing mesh_view_bindings from bevy_pbr

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I'll address this in a follow up PR. I honestly didn't think of that. I'll probably add the bindings to mesh2d_view_bindings. Although, I wonder if we could have some sort of "core" bindings that are shared between both.

Copy link
Contributor

@superdump superdump left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Just one small nit. :)

crates/bevy_render/src/globals.rs Outdated Show resolved Hide resolved
Co-authored-by: Robert Swain <robert.swain@gmail.com>
Copy link
Contributor

@superdump superdump left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bors r+

bors bot pushed a commit that referenced this pull request Sep 28, 2022
# 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 `GlobalsUniform` at 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)` where `t` is the value in seconds
    - Also has delta time, sin time and cos time
- ShaderToy: <https://www.shadertoy.com/howto>
    - iTime is the time since startup in seconds.
    - iFrameRate
    - iTimeDelta
    - iFrame frame counter

Co-authored-by: Charles <IceSentry@users.noreply.github.com>
@bors bors bot changed the title add globals to mesh view bind group [Merged by Bors] - add globals to mesh view bind group Sep 28, 2022
@bors bors bot closed this Sep 28, 2022
@IceSentry IceSentry deleted the global-binding branch September 28, 2022 05:54
james7132 pushed a commit to james7132/bevy that referenced this pull request Oct 19, 2022
# Objective

- Sometimes, like when using shaders, you can only use a time value in `f32`. Unfortunately this suffers from floating precision issues pretty quickly. The standard approach to this problem is to wrap the time after a given period
- This is necessary for bevyengine#5409

## Solution

- Add a `seconds_since_last_wrapping_period` method on `Time` that returns a `f32` that is the `seconds_since_startup` modulo the `max_wrapping_period`

---

## Changelog

Added `seconds_since_last_wrapping_period` to `Time`

## Additional info

I'm very opened to hearing better names. I don't really like the current naming, I just went with something descriptive.

Co-authored-by: Charles <IceSentry@users.noreply.github.com>
james7132 pushed a commit to james7132/bevy that referenced this pull request Oct 19, 2022
# 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 `GlobalsUniform` at 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)` where `t` is the value in seconds
    - Also has delta time, sin time and cos time
- ShaderToy: <https://www.shadertoy.com/howto>
    - iTime is the time since startup in seconds.
    - iFrameRate
    - iTimeDelta
    - iFrame frame counter

Co-authored-by: Charles <IceSentry@users.noreply.github.com>
james7132 pushed a commit to james7132/bevy that referenced this pull request Oct 28, 2022
# Objective

- Sometimes, like when using shaders, you can only use a time value in `f32`. Unfortunately this suffers from floating precision issues pretty quickly. The standard approach to this problem is to wrap the time after a given period
- This is necessary for bevyengine#5409

## Solution

- Add a `seconds_since_last_wrapping_period` method on `Time` that returns a `f32` that is the `seconds_since_startup` modulo the `max_wrapping_period`

---

## Changelog

Added `seconds_since_last_wrapping_period` to `Time`

## Additional info

I'm very opened to hearing better names. I don't really like the current naming, I just went with something descriptive.

Co-authored-by: Charles <IceSentry@users.noreply.github.com>
james7132 pushed a commit to james7132/bevy that referenced this pull request Oct 28, 2022
# 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 `GlobalsUniform` at 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)` where `t` is the value in seconds
    - Also has delta time, sin time and cos time
- ShaderToy: <https://www.shadertoy.com/howto>
    - iTime is the time since startup in seconds.
    - iFrameRate
    - iTimeDelta
    - iFrame frame counter

Co-authored-by: Charles <IceSentry@users.noreply.github.com>
ItsDoot pushed a commit to ItsDoot/bevy that referenced this pull request Feb 1, 2023
# Objective

- Sometimes, like when using shaders, you can only use a time value in `f32`. Unfortunately this suffers from floating precision issues pretty quickly. The standard approach to this problem is to wrap the time after a given period
- This is necessary for bevyengine#5409

## Solution

- Add a `seconds_since_last_wrapping_period` method on `Time` that returns a `f32` that is the `seconds_since_startup` modulo the `max_wrapping_period`

---

## Changelog

Added `seconds_since_last_wrapping_period` to `Time`

## Additional info

I'm very opened to hearing better names. I don't really like the current naming, I just went with something descriptive.

Co-authored-by: Charles <IceSentry@users.noreply.github.com>
ItsDoot pushed a commit to ItsDoot/bevy that referenced this pull request Feb 1, 2023
# 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 `GlobalsUniform` at 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)` where `t` is the value in seconds
    - Also has delta time, sin time and cos time
- ShaderToy: <https://www.shadertoy.com/howto>
    - iTime is the time since startup in seconds.
    - iFrameRate
    - iTimeDelta
    - iFrame frame counter

Co-authored-by: Charles <IceSentry@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Rendering Drawing game state to the screen A-Time Involves time keeping and reporting C-Usability A simple quality-of-life change that makes Bevy easier to use
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

9 participants