mirror of
https://github.com/bevyengine/bevy
synced 2024-11-14 00:47:32 +00:00
Cam scale cluster fix (#7078)
# Objective fix clustering calculations for cameras with non-unit scale ## Solution get view scale and apply to light range at various points
This commit is contained in:
parent
5a152d7d75
commit
5581cfe0d1
1 changed files with 15 additions and 5 deletions
|
@ -912,12 +912,13 @@ const VEC2_HALF_NEGATIVE_Y: Vec2 = Vec2::new(0.5, -0.5);
|
||||||
/// `Z` in view space, with range `[-inf, -f32::MIN_POSITIVE]`
|
/// `Z` in view space, with range `[-inf, -f32::MIN_POSITIVE]`
|
||||||
fn cluster_space_light_aabb(
|
fn cluster_space_light_aabb(
|
||||||
inverse_view_transform: Mat4,
|
inverse_view_transform: Mat4,
|
||||||
|
view_inv_scale: Vec3,
|
||||||
projection_matrix: Mat4,
|
projection_matrix: Mat4,
|
||||||
light_sphere: &Sphere,
|
light_sphere: &Sphere,
|
||||||
) -> (Vec3, Vec3) {
|
) -> (Vec3, Vec3) {
|
||||||
let light_aabb_view = Aabb {
|
let light_aabb_view = Aabb {
|
||||||
center: Vec3A::from(inverse_view_transform * light_sphere.center.extend(1.0)),
|
center: Vec3A::from(inverse_view_transform * light_sphere.center.extend(1.0)),
|
||||||
half_extents: Vec3A::splat(light_sphere.radius),
|
half_extents: Vec3A::from(light_sphere.radius * view_inv_scale.abs()),
|
||||||
};
|
};
|
||||||
let (mut light_aabb_view_min, mut light_aabb_view_max) =
|
let (mut light_aabb_view_min, mut light_aabb_view_max) =
|
||||||
(light_aabb_view.min(), light_aabb_view.max());
|
(light_aabb_view.min(), light_aabb_view.max());
|
||||||
|
@ -1287,6 +1288,8 @@ pub(crate) fn assign_lights_to_clusters(
|
||||||
let mut requested_cluster_dimensions = config.dimensions_for_screen_size(screen_size);
|
let mut requested_cluster_dimensions = config.dimensions_for_screen_size(screen_size);
|
||||||
|
|
||||||
let view_transform = camera_transform.compute_matrix();
|
let view_transform = camera_transform.compute_matrix();
|
||||||
|
let view_inv_scale = camera_transform.compute_transform().scale.recip();
|
||||||
|
let view_inv_scale_max = view_inv_scale.abs().max_element();
|
||||||
let inverse_view_transform = view_transform.inverse();
|
let inverse_view_transform = view_transform.inverse();
|
||||||
let is_orthographic = camera.projection_matrix().w_axis.w == 1.0;
|
let is_orthographic = camera.projection_matrix().w_axis.w == 1.0;
|
||||||
|
|
||||||
|
@ -1297,7 +1300,7 @@ pub(crate) fn assign_lights_to_clusters(
|
||||||
.iter()
|
.iter()
|
||||||
.map(|light| {
|
.map(|light| {
|
||||||
-inverse_view_row_2.dot(light.transform.translation().extend(1.0))
|
-inverse_view_row_2.dot(light.transform.translation().extend(1.0))
|
||||||
+ light.range
|
+ light.range * view_inv_scale.z
|
||||||
})
|
})
|
||||||
.reduce(f32::max)
|
.reduce(f32::max)
|
||||||
.unwrap_or(0.0)
|
.unwrap_or(0.0)
|
||||||
|
@ -1319,6 +1322,8 @@ pub(crate) fn assign_lights_to_clusters(
|
||||||
(false, 1) => config.first_slice_depth().max(far_z),
|
(false, 1) => config.first_slice_depth().max(far_z),
|
||||||
_ => config.first_slice_depth(),
|
_ => config.first_slice_depth(),
|
||||||
};
|
};
|
||||||
|
let first_slice_depth = first_slice_depth * view_inv_scale.z;
|
||||||
|
|
||||||
// NOTE: Ensure the far_z is at least as far as the first_depth_slice to avoid clustering problems.
|
// NOTE: Ensure the far_z is at least as far as the first_depth_slice to avoid clustering problems.
|
||||||
let far_z = far_z.max(first_slice_depth);
|
let far_z = far_z.max(first_slice_depth);
|
||||||
let cluster_factors = calculate_cluster_factors(
|
let cluster_factors = calculate_cluster_factors(
|
||||||
|
@ -1343,6 +1348,7 @@ pub(crate) fn assign_lights_to_clusters(
|
||||||
// it can overestimate more significantly when light ranges are only partially in view
|
// it can overestimate more significantly when light ranges are only partially in view
|
||||||
let (light_aabb_min, light_aabb_max) = cluster_space_light_aabb(
|
let (light_aabb_min, light_aabb_max) = cluster_space_light_aabb(
|
||||||
inverse_view_transform,
|
inverse_view_transform,
|
||||||
|
view_inv_scale,
|
||||||
camera.projection_matrix(),
|
camera.projection_matrix(),
|
||||||
&light_sphere,
|
&light_sphere,
|
||||||
);
|
);
|
||||||
|
@ -1500,6 +1506,7 @@ pub(crate) fn assign_lights_to_clusters(
|
||||||
let (light_aabb_xy_ndc_z_view_min, light_aabb_xy_ndc_z_view_max) =
|
let (light_aabb_xy_ndc_z_view_min, light_aabb_xy_ndc_z_view_max) =
|
||||||
cluster_space_light_aabb(
|
cluster_space_light_aabb(
|
||||||
inverse_view_transform,
|
inverse_view_transform,
|
||||||
|
view_inv_scale,
|
||||||
camera.projection_matrix(),
|
camera.projection_matrix(),
|
||||||
&light_sphere,
|
&light_sphere,
|
||||||
);
|
);
|
||||||
|
@ -1530,12 +1537,14 @@ pub(crate) fn assign_lights_to_clusters(
|
||||||
// center point on the axis of interest plus the radius, and that is not true!
|
// center point on the axis of interest plus the radius, and that is not true!
|
||||||
let view_light_sphere = Sphere {
|
let view_light_sphere = Sphere {
|
||||||
center: Vec3A::from(inverse_view_transform * light_sphere.center.extend(1.0)),
|
center: Vec3A::from(inverse_view_transform * light_sphere.center.extend(1.0)),
|
||||||
radius: light_sphere.radius,
|
radius: light_sphere.radius * view_inv_scale_max,
|
||||||
};
|
};
|
||||||
let spot_light_dir_sin_cos = light.spot_light_angle.map(|angle| {
|
let spot_light_dir_sin_cos = light.spot_light_angle.map(|angle| {
|
||||||
let (angle_sin, angle_cos) = angle.sin_cos();
|
let (angle_sin, angle_cos) = angle.sin_cos();
|
||||||
(
|
(
|
||||||
(inverse_view_transform * light.transform.back().extend(0.0)).truncate(),
|
(inverse_view_transform * light.transform.back().extend(0.0))
|
||||||
|
.truncate()
|
||||||
|
.normalize(),
|
||||||
angle_sin,
|
angle_sin,
|
||||||
angle_cos,
|
angle_cos,
|
||||||
)
|
)
|
||||||
|
@ -1676,7 +1685,8 @@ pub(crate) fn assign_lights_to_clusters(
|
||||||
let angle_cull =
|
let angle_cull =
|
||||||
distance_closest_point > cluster_aabb_sphere.radius;
|
distance_closest_point > cluster_aabb_sphere.radius;
|
||||||
|
|
||||||
let front_cull = v1_len > cluster_aabb_sphere.radius + light.range;
|
let front_cull = v1_len
|
||||||
|
> cluster_aabb_sphere.radius + light.range * view_inv_scale_max;
|
||||||
let back_cull = v1_len < -cluster_aabb_sphere.radius;
|
let back_cull = v1_len < -cluster_aabb_sphere.radius;
|
||||||
|
|
||||||
if !angle_cull && !front_cull && !back_cull {
|
if !angle_cull && !front_cull && !back_cull {
|
||||||
|
|
Loading…
Reference in a new issue