#How to access GPULights in vertex stage?

11 messages · Page 1 of 1 (latest)

crystal karma
#

I would like to calculate lighting per vertex instead of per fragment, but I can't access bevy_pbr::mesh_view_bindings::lights or bevy_pbr::ambient::ambient_light in the vertex stage of my shader.

I think I need to modify the entries of MeshPipelineViewLayout by adding VERTEX⁩ visibility to the GpuLights⁩ uniform buffer⁨. layout_entries is used to configure everything and it's only used in FromWorld for MeshViewPipelineLayouts (generate_view_layouts is never used?).

I tried inserting MeshPipelineViewLayouts in my plugin's finish to replace the one inserted by the MeshRenderPlugin, but that didn't work.

I forked bevy, tried doing exactly that, and got my shader working, but that's not ideal.

Do I need to make my own pipeline or is there an easy way to do this?

crystal karma
#

visual example of what I'm trying to achieve with forked bevy.
Left is StandardMaterial, right is GouraudMaterial

crystal karma
#

This is the error you get when you try to use any lights in vertex:

Caused by:
  In Device::create_render_pipeline, label = 'opaque_mesh_pipeline'
    Error matching ShaderStages(VERTEX) shader requirements against the pipeline
      Shader global ResourceBinding { group: 0, binding: 1 } is not available in the pipeline layout
        Visibility flags don't include the shader stage

And this is what happens when you try to fix that through specialize:

fn specialize(
    _pipeline: &MaterialPipeline,
    descriptor: &mut RenderPipelineDescriptor,
    _layout: &MeshVertexBufferLayoutRef,
    _key: MaterialPipelineKey<Self>
) -> Result<(), SpecializedMeshPipelineError> {
    for layout in descriptor.layout.iter_mut() {
        for item in layout.entries.iter_mut() {
            if item.binding == 1 {
                item.visibility |= ShaderStages::VERTEX;
            }
        }
    }

    Ok(())
}
Caused by:
  In a CommandEncoder
    In a draw command, kind: MultiDrawIndirectCount
      The BindGroupLayout with 'mesh_view_layout' label of current set BindGroup with 'mesh_view_bind_group' label at index 0 is not compatible with the corresponding BindGroupLayout with 'mesh_view_layout' label of RenderPipeline with 'opaque_mesh_pipeline' label
        Entries with binding 1 differ in visibility: expected ShaderStages(VERTEX | FRAGMENT), got ShaderStages(FRAGMENT)
#

any insight would be greatly appreciated.

frozen sky
crystal karma
# frozen sky i doubt youll be able to do it without a fork (without a custom pipeline), since...

You can, at least partially, get it working by replacing the pipeline's MeshPipelineViewLayouts' inner arc before it gets cloned around.

// some plugin
fn finish(&self, app: &mut App) {
    // Add VERTEX visibility to some of the mesh pipeline's view layout entries.
    let render_app = app.get_sub_app_mut(RenderApp).expect("RenderApp should exist");
    let render_world = render_app.world_mut();

    let mut pipeline = render_world.resource_mut::<MeshPipeline>();

    let layouts: &[MeshPipelineViewLayout; _] = pipeline.view_layouts.0.as_ref();
    let mut new_layouts = layouts.clone();

    const APPEND_VERTEX_TO: [usize; 3] = [1, 8, 9];

    for layout in &mut new_layouts {
        for (i, item) in layout.main_layout.entries
            .iter_mut()
            .enumerate()
            .chain(layout.binding_array_layout.entries.iter_mut().enumerate()) {
            if APPEND_VERTEX_TO.contains(&i) {
                item.visibility |= ShaderStages::VERTEX;
            }
        }
    }

    pipeline.view_layouts = MeshPipelineViewLayouts(std::sync::Arc::new(new_layouts));
}

but I'm not sure if this has secret consequences.~~ I think there may be an issue with minimizing the window after doing this~~. And obviously cloning the layout like this feels pretty bad.

frozen sky
frozen sky
crystal karma
# frozen sky gotcha, well thats super helpful to me, i was just getting ready to do my own pi...

Nice. I ended up using an extended material too and then basically yoinking bevy's vertex shader as a template before doing simple lighting calc and passing it to fragment. It's nice because then you can build the PbrInput and apply main_pass_post_lighting_processing

You might wanna do the same thing, or if you have a better idea lmk

GitHub

A refreshingly simple data-driven game engine built in Rust - bevyengine/bevy

frozen sky