adjust cluster index for viewport origin (#5947)
# Objective fixes #5946 ## Solution adjust cluster index calculation for viewport origin. from reading point 2 of the rasterization algorithm description in https://gpuweb.github.io/gpuweb/#rasterization, it looks like framebuffer space (and so @bulitin(position)) is not meant to be adjusted for viewport origin, so we need to subtract that to get the right cluster index. - add viewport origin to rust `ExtractedView` and wgsl `View` structs - subtract from frag coord for cluster index calculation
This commit is contained in:
parent
deeab3fc90
commit
503c2a9677
@ -1,4 +1,5 @@
|
|||||||
#import bevy_pbr::mesh_view_bindings
|
#import bevy_pbr::mesh_view_bindings
|
||||||
|
#import bevy_pbr::utils
|
||||||
|
|
||||||
@group(1) @binding(0)
|
@group(1) @binding(0)
|
||||||
var texture: texture_2d<f32>;
|
var texture: texture_2d<f32>;
|
||||||
@ -12,7 +13,7 @@ fn fragment(
|
|||||||
#import bevy_sprite::mesh2d_vertex_output
|
#import bevy_sprite::mesh2d_vertex_output
|
||||||
) -> @location(0) vec4<f32> {
|
) -> @location(0) vec4<f32> {
|
||||||
// Get screen position with coordinates from 0 to 1
|
// Get screen position with coordinates from 0 to 1
|
||||||
let uv = position.xy / vec2<f32>(view.width, view.height);
|
let uv = coords_to_viewport_uv(position.xy, view.viewport);
|
||||||
let offset_strength = 0.02;
|
let offset_strength = 0.02;
|
||||||
|
|
||||||
// Sample each color channel with an arbitrary shift
|
// Sample each color channel with an arbitrary shift
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#import bevy_pbr::mesh_view_bindings
|
#import bevy_pbr::mesh_view_bindings
|
||||||
|
#import bevy_pbr::utils
|
||||||
|
|
||||||
@group(1) @binding(0)
|
@group(1) @binding(0)
|
||||||
var texture: texture_2d<f32>;
|
var texture: texture_2d<f32>;
|
||||||
@ -10,7 +11,7 @@ fn fragment(
|
|||||||
@builtin(position) position: vec4<f32>,
|
@builtin(position) position: vec4<f32>,
|
||||||
#import bevy_pbr::mesh_vertex_output
|
#import bevy_pbr::mesh_vertex_output
|
||||||
) -> @location(0) vec4<f32> {
|
) -> @location(0) vec4<f32> {
|
||||||
let uv = position.xy / vec2<f32>(view.width, view.height);
|
let uv = coords_to_viewport_uv(position.xy, view.viewport);
|
||||||
let color = textureSample(texture, texture_sampler, uv);
|
let color = textureSample(texture, texture_sampler, uv);
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ fn view_z_to_z_slice(view_z: f32, is_orthographic: bool) -> u32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn fragment_cluster_index(frag_coord: vec2<f32>, view_z: f32, is_orthographic: bool) -> u32 {
|
fn fragment_cluster_index(frag_coord: vec2<f32>, view_z: f32, is_orthographic: bool) -> u32 {
|
||||||
let xy = vec2<u32>(floor(frag_coord * lights.cluster_factors.xy));
|
let xy = vec2<u32>(floor((frag_coord - view.viewport.xy) * lights.cluster_factors.xy));
|
||||||
let z_slice = view_z_to_z_slice(view_z, is_orthographic);
|
let z_slice = view_z_to_z_slice(view_z, is_orthographic);
|
||||||
// NOTE: Restricting cluster index to avoid undefined behavior when accessing uniform buffer
|
// NOTE: Restricting cluster index to avoid undefined behavior when accessing uniform buffer
|
||||||
// arrays based on the cluster index.
|
// arrays based on the cluster index.
|
||||||
|
@ -967,8 +967,8 @@ pub fn prepare_lights(
|
|||||||
ambient_color: Vec4::from_slice(&ambient_light.color.as_linear_rgba_f32())
|
ambient_color: Vec4::from_slice(&ambient_light.color.as_linear_rgba_f32())
|
||||||
* ambient_light.brightness,
|
* ambient_light.brightness,
|
||||||
cluster_factors: Vec4::new(
|
cluster_factors: Vec4::new(
|
||||||
clusters.dimensions.x as f32 / extracted_view.width as f32,
|
clusters.dimensions.x as f32 / extracted_view.viewport.z as f32,
|
||||||
clusters.dimensions.y as f32 / extracted_view.height as f32,
|
clusters.dimensions.y as f32 / extracted_view.viewport.w as f32,
|
||||||
cluster_factors_zw.x,
|
cluster_factors_zw.x,
|
||||||
cluster_factors_zw.y,
|
cluster_factors_zw.y,
|
||||||
),
|
),
|
||||||
@ -1024,8 +1024,12 @@ pub fn prepare_lights(
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
ExtractedView {
|
ExtractedView {
|
||||||
width: point_light_shadow_map.size as u32,
|
viewport: UVec4::new(
|
||||||
height: point_light_shadow_map.size as u32,
|
0,
|
||||||
|
0,
|
||||||
|
point_light_shadow_map.size as u32,
|
||||||
|
point_light_shadow_map.size as u32,
|
||||||
|
),
|
||||||
transform: view_translation * *view_rotation,
|
transform: view_translation * *view_rotation,
|
||||||
projection: cube_face_projection,
|
projection: cube_face_projection,
|
||||||
},
|
},
|
||||||
@ -1076,8 +1080,12 @@ pub fn prepare_lights(
|
|||||||
pass_name: format!("shadow pass spot light {}", light_index,),
|
pass_name: format!("shadow pass spot light {}", light_index,),
|
||||||
},
|
},
|
||||||
ExtractedView {
|
ExtractedView {
|
||||||
width: directional_light_shadow_map.size as u32,
|
viewport: UVec4::new(
|
||||||
height: directional_light_shadow_map.size as u32,
|
0,
|
||||||
|
0,
|
||||||
|
directional_light_shadow_map.size as u32,
|
||||||
|
directional_light_shadow_map.size as u32,
|
||||||
|
),
|
||||||
transform: spot_view_transform,
|
transform: spot_view_transform,
|
||||||
projection: spot_projection,
|
projection: spot_projection,
|
||||||
},
|
},
|
||||||
@ -1156,8 +1164,12 @@ pub fn prepare_lights(
|
|||||||
pass_name: format!("shadow pass directional light {}", i),
|
pass_name: format!("shadow pass directional light {}", i),
|
||||||
},
|
},
|
||||||
ExtractedView {
|
ExtractedView {
|
||||||
width: directional_light_shadow_map.size as u32,
|
viewport: UVec4::new(
|
||||||
height: directional_light_shadow_map.size as u32,
|
0,
|
||||||
|
0,
|
||||||
|
directional_light_shadow_map.size as u32,
|
||||||
|
directional_light_shadow_map.size as u32,
|
||||||
|
),
|
||||||
transform: GlobalTransform::from(view.inverse()),
|
transform: GlobalTransform::from(view.inverse()),
|
||||||
projection,
|
projection,
|
||||||
},
|
},
|
||||||
|
@ -8,8 +8,8 @@ struct View {
|
|||||||
projection: mat4x4<f32>,
|
projection: mat4x4<f32>,
|
||||||
inverse_projection: mat4x4<f32>,
|
inverse_projection: mat4x4<f32>,
|
||||||
world_position: vec3<f32>,
|
world_position: vec3<f32>,
|
||||||
width: f32,
|
// viewport(x_origin, y_origin, width, height)
|
||||||
height: f32,
|
viewport: vec4<f32>,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PointLight {
|
struct PointLight {
|
||||||
|
@ -21,3 +21,11 @@ fn hsv2rgb(hue: f32, saturation: f32, value: f32) -> vec3<f32> {
|
|||||||
fn random1D(s: f32) -> f32 {
|
fn random1D(s: f32) -> f32 {
|
||||||
return fract(sin(s * 12.9898) * 43758.5453123);
|
return fract(sin(s * 12.9898) * 43758.5453123);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns the (0-1, 0-1) position within the given viewport for the current buffer coords .
|
||||||
|
// buffer coords can be obtained from `@builtin(position).xy`.
|
||||||
|
// the view uniform struct contains the current camera viewport in `view.viewport`.
|
||||||
|
// topleft = 0,0
|
||||||
|
fn coords_to_viewport_uv(position: vec2<f32>, viewport: vec4<f32>) -> vec2<f32> {
|
||||||
|
return (position - viewport.xy) / viewport.zw;
|
||||||
|
}
|
||||||
|
@ -17,7 +17,7 @@ use bevy_ecs::{
|
|||||||
reflect::ReflectComponent,
|
reflect::ReflectComponent,
|
||||||
system::{Commands, ParamSet, Query, Res},
|
system::{Commands, ParamSet, Query, Res},
|
||||||
};
|
};
|
||||||
use bevy_math::{Mat4, UVec2, Vec2, Vec3};
|
use bevy_math::{Mat4, UVec2, UVec4, Vec2, Vec3};
|
||||||
use bevy_reflect::prelude::*;
|
use bevy_reflect::prelude::*;
|
||||||
use bevy_reflect::FromReflect;
|
use bevy_reflect::FromReflect;
|
||||||
use bevy_transform::components::GlobalTransform;
|
use bevy_transform::components::GlobalTransform;
|
||||||
@ -418,7 +418,8 @@ pub fn extract_cameras(
|
|||||||
if !camera.is_active {
|
if !camera.is_active {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if let (Some(viewport_size), Some(target_size)) = (
|
if let (Some((viewport_origin, _)), Some(viewport_size), Some(target_size)) = (
|
||||||
|
camera.physical_viewport_rect(),
|
||||||
camera.physical_viewport_size(),
|
camera.physical_viewport_size(),
|
||||||
camera.physical_target_size(),
|
camera.physical_target_size(),
|
||||||
) {
|
) {
|
||||||
@ -437,8 +438,12 @@ pub fn extract_cameras(
|
|||||||
ExtractedView {
|
ExtractedView {
|
||||||
projection: camera.projection_matrix(),
|
projection: camera.projection_matrix(),
|
||||||
transform: *transform,
|
transform: *transform,
|
||||||
width: viewport_size.x,
|
viewport: UVec4::new(
|
||||||
height: viewport_size.y,
|
viewport_origin.x,
|
||||||
|
viewport_origin.y,
|
||||||
|
viewport_size.x,
|
||||||
|
viewport_size.y,
|
||||||
|
),
|
||||||
},
|
},
|
||||||
visible_entities.clone(),
|
visible_entities.clone(),
|
||||||
));
|
));
|
||||||
|
@ -21,7 +21,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use bevy_app::{App, Plugin};
|
use bevy_app::{App, Plugin};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_math::{Mat4, Vec3};
|
use bevy_math::{Mat4, UVec4, Vec3, Vec4};
|
||||||
use bevy_reflect::Reflect;
|
use bevy_reflect::Reflect;
|
||||||
use bevy_transform::components::GlobalTransform;
|
use bevy_transform::components::GlobalTransform;
|
||||||
use bevy_utils::HashMap;
|
use bevy_utils::HashMap;
|
||||||
@ -81,8 +81,8 @@ impl Default for Msaa {
|
|||||||
pub struct ExtractedView {
|
pub struct ExtractedView {
|
||||||
pub projection: Mat4,
|
pub projection: Mat4,
|
||||||
pub transform: GlobalTransform,
|
pub transform: GlobalTransform,
|
||||||
pub width: u32,
|
// uvec4(origin.x, origin.y, width, height)
|
||||||
pub height: u32,
|
pub viewport: UVec4,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExtractedView {
|
impl ExtractedView {
|
||||||
@ -101,8 +101,8 @@ pub struct ViewUniform {
|
|||||||
projection: Mat4,
|
projection: Mat4,
|
||||||
inverse_projection: Mat4,
|
inverse_projection: Mat4,
|
||||||
world_position: Vec3,
|
world_position: Vec3,
|
||||||
width: f32,
|
// viewport(x_origin, y_origin, width, height)
|
||||||
height: f32,
|
viewport: Vec4,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Resource, Default)]
|
#[derive(Resource, Default)]
|
||||||
@ -163,8 +163,7 @@ fn prepare_view_uniforms(
|
|||||||
projection,
|
projection,
|
||||||
inverse_projection,
|
inverse_projection,
|
||||||
world_position: camera.transform.translation(),
|
world_position: camera.transform.translation(),
|
||||||
width: camera.width as f32,
|
viewport: camera.viewport.as_vec4(),
|
||||||
height: camera.height as f32,
|
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -8,6 +8,6 @@ struct View {
|
|||||||
projection: mat4x4<f32>,
|
projection: mat4x4<f32>,
|
||||||
inverse_projection: mat4x4<f32>,
|
inverse_projection: mat4x4<f32>,
|
||||||
world_position: vec3<f32>,
|
world_position: vec3<f32>,
|
||||||
width: f32,
|
// viewport(x_origin, y_origin, width, height)
|
||||||
height: f32,
|
viewport: vec4<f32>,
|
||||||
};
|
};
|
||||||
|
@ -6,8 +6,8 @@ struct View {
|
|||||||
projection: mat4x4<f32>,
|
projection: mat4x4<f32>,
|
||||||
inverse_projection: mat4x4<f32>,
|
inverse_projection: mat4x4<f32>,
|
||||||
world_position: vec3<f32>,
|
world_position: vec3<f32>,
|
||||||
width: f32,
|
// viewport(x_origin, y_origin, width, height)
|
||||||
height: f32,
|
viewport: vec4<f32>,
|
||||||
};
|
};
|
||||||
@group(0) @binding(0)
|
@group(0) @binding(0)
|
||||||
var<uniform> view: View;
|
var<uniform> view: View;
|
||||||
|
@ -9,7 +9,7 @@ use crate::{prelude::UiCameraConfig, CalculatedClip, Node, UiColor, UiImage};
|
|||||||
use bevy_app::prelude::*;
|
use bevy_app::prelude::*;
|
||||||
use bevy_asset::{load_internal_asset, AssetEvent, Assets, Handle, HandleUntyped};
|
use bevy_asset::{load_internal_asset, AssetEvent, Assets, Handle, HandleUntyped};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_math::{Mat4, Rect, Vec2, Vec3, Vec4Swizzles};
|
use bevy_math::{Mat4, Rect, UVec4, Vec2, Vec3, Vec4Swizzles};
|
||||||
use bevy_reflect::TypeUuid;
|
use bevy_reflect::TypeUuid;
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
camera::{Camera, CameraProjection, OrthographicProjection, WindowOrigin},
|
camera::{Camera, CameraProjection, OrthographicProjection, WindowOrigin},
|
||||||
@ -238,8 +238,9 @@ pub fn extract_default_ui_camera_view<T: Component>(
|
|||||||
if matches!(camera_ui, Some(&UiCameraConfig { show_ui: false, .. })) {
|
if matches!(camera_ui, Some(&UiCameraConfig { show_ui: false, .. })) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if let (Some(logical_size), Some(physical_size)) = (
|
if let (Some(logical_size), Some((physical_origin, _)), Some(physical_size)) = (
|
||||||
camera.logical_viewport_size(),
|
camera.logical_viewport_size(),
|
||||||
|
camera.physical_viewport_rect(),
|
||||||
camera.physical_viewport_size(),
|
camera.physical_viewport_size(),
|
||||||
) {
|
) {
|
||||||
let mut projection = OrthographicProjection {
|
let mut projection = OrthographicProjection {
|
||||||
@ -257,8 +258,12 @@ pub fn extract_default_ui_camera_view<T: Component>(
|
|||||||
0.0,
|
0.0,
|
||||||
UI_CAMERA_FAR + UI_CAMERA_TRANSFORM_OFFSET,
|
UI_CAMERA_FAR + UI_CAMERA_TRANSFORM_OFFSET,
|
||||||
),
|
),
|
||||||
width: physical_size.x,
|
viewport: UVec4::new(
|
||||||
height: physical_size.y,
|
physical_origin.x,
|
||||||
|
physical_origin.y,
|
||||||
|
physical_size.x,
|
||||||
|
physical_size.y,
|
||||||
|
),
|
||||||
})
|
})
|
||||||
.id();
|
.id();
|
||||||
commands.get_or_spawn(entity).insert_bundle((
|
commands.get_or_spawn(entity).insert_bundle((
|
||||||
|
@ -6,8 +6,8 @@ struct View {
|
|||||||
projection: mat4x4<f32>,
|
projection: mat4x4<f32>,
|
||||||
inverse_projection: mat4x4<f32>,
|
inverse_projection: mat4x4<f32>,
|
||||||
world_position: vec3<f32>,
|
world_position: vec3<f32>,
|
||||||
width: f32,
|
// viewport(x_origin, y_origin, width, height)
|
||||||
height: f32,
|
viewport: vec4<f32>,
|
||||||
};
|
};
|
||||||
@group(0) @binding(0)
|
@group(0) @binding(0)
|
||||||
var<uniform> view: View;
|
var<uniform> view: View;
|
||||||
|
Loading…
Reference in New Issue
Block a user