Skip to content

Commit

Permalink
allow prepass in webgl
Browse files Browse the repository at this point in the history
  • Loading branch information
IceSentry committed Feb 7, 2023
1 parent 0cbb9f7 commit f7e86a6
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 93 deletions.
12 changes: 8 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ repository = "https://github.com/bevyengine/bevy"
rust-version = "1.67.0"

[workspace]
exclude = ["benches", "crates/bevy_ecs_compile_fail_tests", "crates/bevy_reflect_compile_fail_tests"]
exclude = [
"benches",
"crates/bevy_ecs_compile_fail_tests",
"crates/bevy_reflect_compile_fail_tests",
]
members = [
"crates/*",
"examples/mobile",
Expand Down Expand Up @@ -43,7 +47,7 @@ default = [
"vorbis",
"x11",
"filesystem_watcher",
"android_shared_stdcxx"
"android_shared_stdcxx",
]

# Force dynamic linking, which improves iterative compile times
Expand Down Expand Up @@ -1258,9 +1262,9 @@ path = "examples/shader/shader_prepass.rs"

[package.metadata.example.shader_prepass]
name = "Material Prepass"
description = "A shader that uses the depth texture generated in a prepass"
description = "A shader that uses the various textures generated by the prepass"
category = "Shaders"
wasm = false
wasm = true


[[example]]
Expand Down
33 changes: 26 additions & 7 deletions assets/shaders/show_prepass.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,44 @@
#import bevy_pbr::mesh_view_bindings
#import bevy_pbr::prepass_utils

struct ShowPrepassSettings {
show_depth: f32,
show_normals: f32,
is_webgl: f32,
padding__: f32,
}
@group(1) @binding(0)
var<uniform> show_depth: f32;
var<uniform> settings: ShowPrepassSettings;
@group(1) @binding(1)
var<uniform> show_normal: f32;
var show_prepass_sampler: sampler;

@fragment
fn fragment(
@builtin(position) frag_coord: vec4<f32>,
#ifndef WEBGL
@builtin(sample_index) sample_index: u32,
#endif// WEBGL
#import bevy_pbr::mesh_vertex_output
) -> @location(0) vec4<f32> {
if show_depth == 1.0 {
if settings.show_depth == 1.0 {
#ifdef WEBGL
// prepass_depth() uses textureLoad which doesn't work in WebGL for depth textures.
// Instead we need to use a sampler
let dims = textureDimensions(depth_prepass_texture);
let uv = frag_coord.xy / vec2<f32>(dims);
let depth = textureSample(depth_prepass_texture, show_prepass_sampler, uv);
#else
let depth = prepass_depth(frag_coord, sample_index);
#endif // WEBGL
return vec4(depth, depth, depth, 1.0);
} else if show_normal == 1.0 {
} else if settings.show_normals == 1.0 {
#ifdef WEBGL
let normal = prepass_normal(frag_coord, 0u);
#else // WEBGL
let normal = prepass_normal(frag_coord, sample_index);
#endif // WEBGL
return vec4(normal, 1.0);
} else {
// transparent
return vec4(0.0);
}

return vec4(0.0);
}
84 changes: 76 additions & 8 deletions crates/bevy_pbr/src/prepass/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,17 @@ use bevy_render::{
},
render_resource::{
BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayout, BindGroupLayoutDescriptor,
BindGroupLayoutEntry, BindingType, BlendState, BufferBindingType, ColorTargetState,
ColorWrites, CompareFunction, DepthBiasState, DepthStencilState, Extent3d, FragmentState,
FrontFace, MultisampleState, PipelineCache, PolygonMode, PrimitiveState,
RenderPipelineDescriptor, Shader, ShaderDefVal, ShaderRef, ShaderStages, ShaderType,
SpecializedMeshPipeline, SpecializedMeshPipelineError, SpecializedMeshPipelines,
StencilFaceState, StencilState, TextureDescriptor, TextureDimension, TextureFormat,
TextureUsages, VertexState,
BindGroupLayoutEntry, BindingResource, BindingType, BlendState, BufferBindingType,
ColorTargetState, ColorWrites, CompareFunction, DepthBiasState, DepthStencilState,
Extent3d, FragmentState, FrontFace, MultisampleState, PipelineCache, PolygonMode,
PrimitiveState, RenderPipelineDescriptor, Shader, ShaderDefVal, ShaderRef, ShaderStages,
ShaderType, SpecializedMeshPipeline, SpecializedMeshPipelineError,
SpecializedMeshPipelines, StencilFaceState, StencilState, TextureDescriptor,
TextureDimension, TextureFormat, TextureSampleType, TextureUsages, TextureViewDimension,
VertexState,
},
renderer::RenderDevice,
texture::TextureCache,
texture::{FallbackImagesDepth, FallbackImagesMsaa, TextureCache},
view::{ExtractedView, Msaa, ViewUniform, ViewUniformOffset, ViewUniforms, VisibleEntities},
Extract, ExtractSchedule, RenderApp, RenderSet,
};
Expand Down Expand Up @@ -328,6 +329,73 @@ where
}
}

pub fn get_bind_group_layout_entries(
bindings: [u32; 2],
multisampled: bool,
) -> [BindGroupLayoutEntry; 2] {
[
// Depth texture
BindGroupLayoutEntry {
binding: bindings[0],
visibility: ShaderStages::FRAGMENT,
ty: BindingType::Texture {
multisampled,
sample_type: TextureSampleType::Depth,
view_dimension: TextureViewDimension::D2,
},
count: None,
},
// Normal texture
BindGroupLayoutEntry {
binding: bindings[1],
visibility: ShaderStages::FRAGMENT,
ty: BindingType::Texture {
multisampled,
sample_type: TextureSampleType::Float { filterable: true },
view_dimension: TextureViewDimension::D2,
},
count: None,
},
]
}

pub fn get_bindings<'a>(
prepass_textures: Option<&'a ViewPrepassTextures>,
fallback_images: &'a mut FallbackImagesMsaa,
fallback_depths: &'a mut FallbackImagesDepth,
msaa: &'a Msaa,
bindings: [u32; 2],
) -> [BindGroupEntry<'a>; 2] {
let depth_view = match prepass_textures.and_then(|x| x.depth.as_ref()) {
Some(texture) => &texture.default_view,
None => {
&fallback_depths
.image_for_samplecount(msaa.samples())
.texture_view
}
};

let normal_view = match prepass_textures.and_then(|x| x.normal.as_ref()) {
Some(texture) => &texture.default_view,
None => {
&fallback_images
.image_for_samplecount(msaa.samples())
.texture_view
}
};

[
BindGroupEntry {
binding: bindings[0],
resource: BindingResource::TextureView(depth_view),
},
BindGroupEntry {
binding: bindings[1],
resource: BindingResource::TextureView(normal_view),
},
]
}

// Extract the render phases for the prepass
pub fn extract_camera_prepass_phase(
mut commands: Commands,
Expand Down
8 changes: 4 additions & 4 deletions crates/bevy_pbr/src/prepass/prepass_utils.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ fn prepass_normal(frag_coord: vec4<f32>, sample_index: u32) -> vec3<f32> {
#ifdef MULTISAMPLED
let normal_sample = textureLoad(normal_prepass_texture, vec2<i32>(frag_coord.xy), i32(sample_index));
#else
let normal_sample = textureLoad(normal_prepass_texture, vec2<i32>(frag_coord.xy), 0);
#endif
let normal_sample = textureLoad(normal_prepass_texture, vec2<i32>(frag_coord.xy), 0i);
#endif //MULTISAMPLED
return normal_sample.xyz * 2.0 - vec3(1.0);
}
#endif // NORMAL_PREPASS
Expand All @@ -16,8 +16,8 @@ fn prepass_depth(frag_coord: vec4<f32>, sample_index: u32) -> f32 {
#ifdef MULTISAMPLED
let depth_sample = textureLoad(depth_prepass_texture, vec2<i32>(frag_coord.xy), i32(sample_index));
#else
let depth_sample = textureLoad(depth_prepass_texture, vec2<i32>(frag_coord.xy), 0);
#endif
let depth_sample = textureLoad(depth_prepass_texture, vec2<i32>(frag_coord.xy), 0i);
#endif // MULTISAMPLED
return depth_sample;
}
#endif // DEPTH_PREPASS
69 changes: 16 additions & 53 deletions crates/bevy_pbr/src/render/mesh.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
FogMeta, GlobalLightMeta, GpuFog, GpuLights, GpuPointLights, LightMeta, NotShadowCaster,
NotShadowReceiver, ShadowPipeline, ViewClusterBindings, ViewFogUniformOffset,
prepass, FogMeta, GlobalLightMeta, GpuFog, GpuLights, GpuPointLights, LightMeta,
NotShadowCaster, NotShadowReceiver, ShadowPipeline, ViewClusterBindings, ViewFogUniformOffset,
ViewLightsUniformOffset, ViewShadowBindings, CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT,
MAX_CASCADES_PER_LIGHT, MAX_DIRECTIONAL_LIGHTS,
};
Expand Down Expand Up @@ -412,29 +412,11 @@ impl FromWorld for MeshPipeline {
count: None,
},
];
if cfg!(not(feature = "webgl")) {
// Depth texture
entries.push(BindGroupLayoutEntry {
binding: 11,
visibility: ShaderStages::FRAGMENT,
ty: BindingType::Texture {
multisampled,
sample_type: TextureSampleType::Depth,
view_dimension: TextureViewDimension::D2,
},
count: None,
});
// Normal texture
entries.push(BindGroupLayoutEntry {
binding: 12,
visibility: ShaderStages::FRAGMENT,
ty: BindingType::Texture {
multisampled,
sample_type: TextureSampleType::Float { filterable: true },
view_dimension: TextureViewDimension::D2,
},
count: None,
});
if cfg!(not(feature = "webgl")) || (cfg!(feature = "webgl") && !multisampled) {
entries.extend_from_slice(&prepass::get_bind_group_layout_entries(
[11, 12],
multisampled,
));
}
entries
}
Expand Down Expand Up @@ -982,34 +964,15 @@ pub fn queue_mesh_view_bind_groups(
},
];

// When using WebGL with MSAA, we can't create the fallback textures required by the prepass
// When using WebGL, and MSAA is disabled, we can't bind the textures either
if cfg!(not(feature = "webgl")) {
let depth_view = match prepass_textures.and_then(|x| x.depth.as_ref()) {
Some(texture) => &texture.default_view,
None => {
&fallback_depths
.image_for_samplecount(msaa.samples())
.texture_view
}
};
entries.push(BindGroupEntry {
binding: 11,
resource: BindingResource::TextureView(depth_view),
});

let normal_view = match prepass_textures.and_then(|x| x.normal.as_ref()) {
Some(texture) => &texture.default_view,
None => {
&fallback_images
.image_for_samplecount(msaa.samples())
.texture_view
}
};
entries.push(BindGroupEntry {
binding: 12,
resource: BindingResource::TextureView(normal_view),
});
// When using WebGL, we can't have a depth texture with multisampling
if cfg!(not(feature = "webgl")) || (cfg!(feature = "webgl") && msaa.samples() == 1) {
entries.extend_from_slice(&prepass::get_bindings(
prepass_textures,
&mut fallback_images,
&mut fallback_depths,
&msaa,
[11, 12],
));
}

let view_bind_group = render_device.create_bind_group(&BindGroupDescriptor {
Expand Down
Loading

0 comments on commit f7e86a6

Please sign in to comment.