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

Provide the camera's view matrix to shaders via the Camera uniform #1203

Closed
wants to merge 5 commits into from

Conversation

lwansbrough
Copy link
Contributor

I'm writing a shader which depends on the camera position. This change adds the view matrix as a second mat4 on the Camera uniform which provides the camera's transform to the shader. Existing shaders in bevy's repository have been updated, but this is a breaking change for any shaders depending on the Camera uniform.

@@ -110,7 +110,10 @@ impl<Q: WorldQuery> PassNode<Q> {
index: 0,
bind_type: BindType::Uniform {
dynamic: false,
property: UniformProperty::Struct(vec![UniformProperty::Mat4]),
property: UniformProperty::Struct(vec![
UniformProperty::Mat4,

This comment was marked as resolved.

@Moxinilian Moxinilian added C-Enhancement A new feature A-Rendering Drawing game state to the screen labels Jan 4, 2021
@cart
Copy link
Member

cart commented Jan 6, 2021

I like everything about this but the fact that every shader needs to include both ViewProj and View. Logically it makes sense to group them inside the same uniform, but I'm not sure thats worth the added cost of needing to define both everywhere. Maybe we could split these out into separate bindings?

@lwansbrough
Copy link
Contributor Author

I had a similar concern - a separate binding seems appropriate. If I get some time I'll update this PR.

@quarz
Copy link

quarz commented Jan 7, 2021

I like everything about this but the fact that every shader needs to include both ViewProj and View. Logically it makes sense to group them inside the same uniform, but I'm not sure thats worth the added cost of needing to define both everywhere. Maybe we could split these out into separate bindings?

I think the root issue here is lack of #include support. There is always gonna be shared shader code, this View matrix case is just one of many.

Shaderc does have #include support (https://docs.rs/shaderc/0.7.0/shaderc/struct.CompileOptions.html#method.set_include_callback), but we don't use it currently. Do you think it would make sense to put some effort into this direction?

@cart
Copy link
Member

cart commented Jan 7, 2021

I think its worth trying to add some sort of "importing", but I'm not sure I want to solve this type of problem with "pasting in bindings from other files". I'd rather just let people declare the bindings they want and have it all just work as expected.

@cart
Copy link
Member

cart commented Jan 7, 2021

And I think we might want to build our own "post processing shader import system" that integrates directly with Bevy Asset. And that way we aren't directly tied to shaderc or glsl-to-spirv (when its ready we want to move to Naga).

@Neo-Zhixing
Copy link
Contributor

Neo-Zhixing commented Jan 26, 2021

I like everything about this but the fact that every shader needs to include both ViewProj and View. Logically it makes sense to group them inside the same uniform, but I'm not sure thats worth the added cost of needing to define both everywhere. Maybe we could split these out into separate bindings?

@cart Why is it that the Camera uniform is always using

layout(set = 0, binding = 0) uniform Camera

?

It seems that if I use any binding locations other than set 0 binding 0 the camera would not work. Searching through the code there are multiple locations where this was hard coded, for example here, here and here. Is there a reason for doing so? I have a feeling that if we want to allow users to choose View or ViewProj based on their binding we need to address this problem first.

I'm expecting that the user would be able to do this

layout(set = 0, binding = 2) uniform Camera3dViewProj
layout(set = 0, binding = 0) uniform Camera3dView
layout(set = 0, binding = 1) uniform Camera3dTransform
layout(set = 0, binding = 4) uniform PerspectiveProjection {
    float near, far, for, aspect_ratio;
}

with arbitrary set and binding numbers.

@cart
Copy link
Member

cart commented Jan 26, 2021

Is there a reason for doing so?

Yup! RenderPassNodes can have different cameras assigned to each pass. The higher level RenderResourceBindings can currently be global, from entities, or from assets. None of those categories fits the "per pass" setup very well. And the current approach let us do the minimal amount of work required to bind the camera. We could consider giving each PassNode RenderResourceBindings instead, but off the top of my head im not sure thats the best path forward yet.

I definitely agree that with the addition of more camera properties, something needs to change.

@Neo-Zhixing
Copy link
Contributor

Neo-Zhixing commented Jan 27, 2021

We could consider giving each PassNode RenderResourceBindings instead, but off the top of my head im not sure thats the best path forward yet.

I understand that we can have different cameras assigned to each pass, but what's the problem with setting the camera bindings in the global RenderResourceBindings? If we require that the camera names must be unique, will it enable the cameras to be binded just like any other render resources?

@cart With wgpu 0.7 we will also have push constants. Maybe consider using that for cameras?

@mtsr
Copy link
Contributor

mtsr commented Mar 13, 2021

@cart With wgpu 0.7 we will also have push constants. Maybe consider using that for cameras?

From a cursory reading it seems push constants can only accommodate 128 bytes reliably on all hardware. That's just about enough for View and ViewProj, but nothing else. I don't think that will cut it.

@Neo-Zhixing
Copy link
Contributor

@cart With wgpu 0.7 we will also have push constants. Maybe consider using that for cameras?

From a cursory reading it seems push constants can only accommodate 128 bytes reliably on all hardware. That's just about enough for View and ViewProj, but nothing else. I don't think that will cut it.

Right. And on a second thought, using push constants require that we copy the camera data to the command buffer for every draw call. With a uniform buffer we'll be able to reuse this data every frame.

bors bot pushed a commit that referenced this pull request Mar 19, 2021
Alternative to #1203 and #1611

Camera bindings have historically been "hacked in". They were _required_ in all shaders and only supported a single Mat4. PBR (#1554) requires the CameraView matrix, but adding this using the "hacked" method forced users to either include all possible camera data in a single binding (#1203) or include all possible bindings (#1611).

This approach instead assigns each "active camera" its own RenderResourceBindings, which are populated by CameraNode. The PassNode then retrieves (and initializes) the relevant bind groups for all render pipelines used by visible entities. 

* Enables any number of camera bindings , including zero (with any set or binding number ... set 0 should still be used to avoid rebinds).
* Renames Camera binding to CameraViewProj
* Adds CameraView binding
@Neo-Zhixing
Copy link
Contributor

Can we close this PR now that 1689 was merged?

@cart
Copy link
Member

cart commented Mar 23, 2021

Yup!

@cart cart closed this Mar 23, 2021
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 C-Enhancement A new feature S-Duplicate This issue or PR already exists
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants