Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions src/render/attribute_pass/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use bevy_camera::{Camera, Camera3d};
use bevy_core_pipeline::core_3d::graph::Core3d;
use bevy_ecs::{change_detection::Tick, prelude::*};
use bevy_log::prelude::*;
use bevy_pbr::{MeshPipelineKey, SetMeshViewBindGroup};
use bevy_pbr::{ExtractedAtmosphere, MeshPipelineKey, SetMeshViewBindGroup};
use bevy_platform::collections::HashSet;
use bevy_render::{
batching::gpu_preprocessing::{GpuPreprocessingMode, GpuPreprocessingSupport},
Expand Down Expand Up @@ -136,20 +136,30 @@ fn queue_attribute_pass(
custom_draw_pipeline: Res<AttributePassPipeline>,
point_clouds_3d: Query<&PointCloud3d>,
mut custom_render_phases: ResMut<ViewBinnedRenderPhases<PointCloud3dAttributePhase>>,
mut views: Query<(&ExtractedView, &RenderVisibleEntities, &Msaa)>,
mut views: Query<(
&ExtractedView,
&RenderVisibleEntities,
&Msaa,
Has<ExtractedAtmosphere>,
)>,
main_entities: Query<&MainEntity>,
mut next_tick: Local<Tick>,
) {
for (view, visible_entities, msaa) in &mut views {
for (view, visible_entities, msaa, has_atmosphere) in &mut views {
let Some(custom_phase) = custom_render_phases.get_mut(&view.retained_view_entity) else {
continue;
};
let draw_custom = custom_draw_functions.read().id::<DrawAttributePass>();

// Create the key based on the view.
// In this case we only care about MSAA and HDR
let view_key = MeshPipelineKey::from_msaa_samples(msaa.samples())
let mut view_key = MeshPipelineKey::from_msaa_samples(msaa.samples())
| MeshPipelineKey::from_hdr(view.hdr);
// See queue_depth_pass — atmosphere views use
// the atmosphere mesh-view layout variant.
if has_atmosphere {
view_key |= MeshPipelineKey::ATMOSPHERE;
}

let attribute_key = AttributePipelineKey {
mesh_key: view_key,
Expand Down
3 changes: 2 additions & 1 deletion src/render/attribute_pass/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,8 @@ impl SpecializedRenderPipeline for AttributePassPipeline {
shader_defs,
entry_point: Some("fragment".into()),
targets: vec![Some(ColorTargetState {
format: TextureFormat::Rgba32Float,
// Matches the f16 texture.
format: TextureFormat::Rgba16Float,
// Additive blending to allow merging close points
blend: Some(BlendState {
color: BlendComponent {
Expand Down
6 changes: 4 additions & 2 deletions src/render/attribute_pass/texture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use bevy_render::{
},
render_resource::{
binding_types::texture_2d, BindGroup, BindGroupEntries, BindGroupLayout, Extent3d,
ShaderStages, TextureDescriptor, TextureDimension, TextureFormat::Rgba32Float,
ShaderStages, TextureDescriptor, TextureDimension, TextureFormat::Rgba16Float,
TextureSampleType, TextureUsages, TextureView,
},
renderer::RenderDevice,
Expand Down Expand Up @@ -83,7 +83,9 @@ pub fn prepare_attribute_pass_textures(
mip_level_count: 1,
sample_count: msaa.samples(),
dimension: TextureDimension::D2,
format: Rgba32Float,
// F16 — float32 is neither
// multisampliable nor blendable under WebGPU core.
format: Rgba16Float,
usage: TextureUsages::RENDER_ATTACHMENT | TextureUsages::TEXTURE_BINDING,
view_formats: &[],
};
Expand Down
14 changes: 11 additions & 3 deletions src/render/depth_pass/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use bevy_camera::{Camera, Camera3d};
use bevy_core_pipeline::core_3d::graph::{Core3d, Node3d};
use bevy_ecs::{change_detection::Tick, prelude::*};
use bevy_log::prelude::*;
use bevy_pbr::{MeshPipelineKey, SetMeshViewBindGroup};
use bevy_pbr::{ExtractedAtmosphere, MeshPipelineKey, SetMeshViewBindGroup};
use bevy_platform::collections::HashSet;
use bevy_render::{
batching::gpu_preprocessing::{GpuPreprocessingMode, GpuPreprocessingSupport},
Expand Down Expand Up @@ -145,19 +145,27 @@ fn queue_depth_pass(
&RenderVisibleEntities,
&Msaa,
Option<&PointCloudRenderMode>,
Has<ExtractedAtmosphere>,
)>,
mut next_tick: Local<Tick>,
) {
for (view, visible_entities, msaa, point_cloud_render_mode) in &mut views {
for (view, visible_entities, msaa, point_cloud_render_mode, has_atmosphere) in &mut views {
let Some(custom_phase) = custom_render_phases.get_mut(&view.retained_view_entity) else {
continue;
};
let draw_custom = custom_draw_functions.read().id::<DrawDepthPass>();

// Create the key based on the view.
// In this case we only care about MSAA and HDR
let view_key = MeshPipelineKey::from_msaa_samples(msaa.samples())
let mut view_key = MeshPipelineKey::from_msaa_samples(msaa.samples())
| MeshPipelineKey::from_hdr(view.hdr);
// Views with an atmosphere (e.g. cameras with
// bevy_pbr's `Atmosphere`) use the atmosphere variant of the mesh-view
// bind group layout (extra LUT bindings); the pipeline layout must be
// specialized to match or wgpu rejects the draw.
if has_atmosphere {
view_key |= MeshPipelineKey::ATMOSPHERE;
}

let depth_key = DepthPipelineKey {
mesh_key: view_key,
Expand Down
5 changes: 3 additions & 2 deletions src/render/depth_pass/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,10 @@ impl SpecializedRenderPipeline for DepthPipeline {
// Because we can't bind the depth buffer in WASM/WebGL
targets: vec![Some(ColorTargetState {
format: if key.use_edl {
TextureFormat::Rg32Float
// Matches the f16 texture.
TextureFormat::Rg16Float
} else {
TextureFormat::R32Float
TextureFormat::R16Float
},
blend: None,
write_mask: ColorWrites::ALL,
Expand Down
8 changes: 5 additions & 3 deletions src/render/depth_pass/texture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use bevy_render::{
render_resource::{
binding_types::texture_2d,
BindGroup, BindGroupLayout, Extent3d, ShaderStages, TextureDescriptor, TextureDimension,
TextureFormat::{R32Float, Rg32Float},
TextureFormat::{R16Float, Rg16Float},
TextureSampleType, TextureUsages, TextureView,
},
renderer::RenderDevice,
Expand Down Expand Up @@ -96,9 +96,11 @@ pub fn prepare_depth_pass_textures(
sample_count: msaa.samples(),
dimension: TextureDimension::D2,
format: if point_cloud_render_mode.use_edl() {
Rg32Float
// F16 — float32 formats are
// not multisampliable under WebGPU core.
Rg16Float
} else {
R32Float
R16Float
},
usage: TextureUsages::RENDER_ATTACHMENT | TextureUsages::TEXTURE_BINDING,
view_formats: &[],
Expand Down
8 changes: 5 additions & 3 deletions src/render/normalize_pass/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use bevy_ecs::prelude::*;
use bevy_render::{
render_graph::{RenderGraphExt, ViewNodeRunner},
render_resource::{PipelineCache, SpecializedRenderPipelines},
view::Msaa,
view::{ExtractedView, Msaa},
Render, RenderApp, RenderSystems,
};
use node::{NormalizePassLabel, NormalizePassNode};
Expand Down Expand Up @@ -79,16 +79,18 @@ fn prepare_normalize_pass_pipelines(
pipeline_cache: Res<PipelineCache>,
mut pipelines: ResMut<SpecializedRenderPipelines<NormalizePassPipeline>>,
pipeline: Res<NormalizePassPipeline>,
views: Query<(Entity, &Msaa, Option<&PointCloudRenderMode>)>,
views: Query<(Entity, &ExtractedView, &Msaa, Option<&PointCloudRenderMode>)>,
) {
for (entity, msaa, point_cloud_render_mode) in &views {
for (entity, view, msaa, point_cloud_render_mode) in &views {
let pipeline_id = pipelines.specialize(
&pipeline_cache,
&pipeline,
NormalizePassPipelineKey {
samples: msaa.samples(),
use_edl: point_cloud_render_mode.use_edl(),
edl_neighbour_count: point_cloud_render_mode.edl_neighbour_count(),
// See NormalizePassPipelineKey::hdr.
hdr: view.hdr,
},
);

Expand Down
14 changes: 13 additions & 1 deletion src/render/normalize_pass/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use bevy_render::render_resource::{
binding_types::{texture_2d, texture_2d_multisampled},
*,
};
use bevy_render::view::ViewTarget;
use bevy_shader::ShaderDefVal;

use crate::render::{
Expand All @@ -16,6 +17,12 @@ pub struct NormalizePassPipelineKey {
pub samples: u32,
pub use_edl: bool,
pub edl_neighbour_count: u32,
/// Specialize the color target on the view's
/// HDR-ness. The normalize pass writes to the camera's view target, which
/// is Rgba16Float for HDR views (e.g. cameras with `Atmosphere`); a
/// hardcoded `bevy_default()` (Rgba8UnormSrgb) fails wgpu
/// validation on such views.
pub hdr: bool,
}

#[derive(Component)]
Expand Down Expand Up @@ -106,7 +113,12 @@ impl SpecializedRenderPipeline for NormalizePassPipeline {
shader_defs,
entry_point: Some("fragment".into()),
targets: vec![Some(ColorTargetState {
format: TextureFormat::bevy_default(),
// Match the view target format.
format: if key.hdr {
ViewTarget::TEXTURE_FORMAT_HDR
} else {
TextureFormat::bevy_default()
},
blend: None,
write_mask: ColorWrites::ALL,
})],
Expand Down
12 changes: 10 additions & 2 deletions src/render/point_cloud.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,16 @@ fn vertex(vertex: Vertex) -> VertexOutput {
#else
let point_size = select(material.point_size, vertex.i_pos_size.w, material.point_size <= 0.0) * transform_scale;

// Compute radius to size the point correctly with viewport size
let radius = point_size / min(viewport[2], viewport[3]);
// Clamp to a minimum SCREEN-SPACE size, mirroring
// the IS_OCTREE branch. The unclamped view-space radius drops below one
// raster sample at distance, so far points vanish entirely (and shimmer/
// moire on the way down). min/max_point_size are in pixels.
let f_simple = view_bindings::view.clip_from_view[1][1];
let slope_simple = 1.0 / f_simple;
let proj_factor_simple = -0.5 * viewport[3] / (slope_simple * view_position.z);
var radius_screen_simple = (point_size / min(viewport[2], viewport[3])) * proj_factor_simple;
radius_screen_simple = clamp(radius_screen_simple, material.min_point_size, material.max_point_size);
let radius = radius_screen_simple / proj_factor_simple;
#endif

// Compute the offset to apply for creating a quad
Expand Down