CameraProjection::compute_frustum (#11139)

Frustum computation is nontrivial amount of code private in
`update_frusta` system.

Make it public.

This is needed to decide which entities to spawn/despawn in `Update`
based on camera changes. But if `Update` also changed camera, frustum is
not yet recomputed.

Technically it is probably possible to run an iteration of
`update_frusta` system by a user in `Update` schedule after propagating
`GlobalTransform` to the cameras, but it is easier to just compute
frustum manually using API added in this PR.

Also replace two places where this code is used.

---------

Co-authored-by: vero <email@atlasdostal.com>
This commit is contained in:
Stepan Koltsov 2024-02-04 01:21:07 +00:00 committed by GitHub
parent 1974723a63
commit 08654ad8d8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 20 additions and 24 deletions

View File

@ -45,14 +45,7 @@ impl Default for Camera2dBundle {
..Default::default() ..Default::default()
}; };
let transform = Transform::default(); let transform = Transform::default();
let view_projection = let frustum = projection.compute_frustum(&GlobalTransform::from(transform));
projection.get_projection_matrix() * transform.compute_matrix().inverse();
let frustum = Frustum::from_view_projection_custom_far(
&view_projection,
&transform.translation,
&transform.back(),
projection.far(),
);
Self { Self {
camera_render_graph: CameraRenderGraph::new(SubGraph2d), camera_render_graph: CameraRenderGraph::new(SubGraph2d),
projection, projection,
@ -84,14 +77,7 @@ impl Camera2dBundle {
..Default::default() ..Default::default()
}; };
let transform = Transform::from_xyz(0.0, 0.0, far - 0.1); let transform = Transform::from_xyz(0.0, 0.0, far - 0.1);
let view_projection = let frustum = projection.compute_frustum(&GlobalTransform::from(transform));
projection.get_projection_matrix() * transform.compute_matrix().inverse();
let frustum = Frustum::from_view_projection_custom_far(
&view_projection,
&transform.translation,
&transform.back(),
projection.far(),
);
Self { Self {
camera_render_graph: CameraRenderGraph::new(SubGraph3d), camera_render_graph: CameraRenderGraph::new(SubGraph3d),
projection, projection,

View File

@ -1,12 +1,14 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use std::ops::{Div, DivAssign, Mul, MulAssign}; use std::ops::{Div, DivAssign, Mul, MulAssign};
use crate::primitives::Frustum;
use bevy_app::{App, Plugin, PostStartup, PostUpdate}; use bevy_app::{App, Plugin, PostStartup, PostUpdate};
use bevy_ecs::{prelude::*, reflect::ReflectComponent}; use bevy_ecs::{prelude::*, reflect::ReflectComponent};
use bevy_math::{AspectRatio, Mat4, Rect, Vec2, Vec3A}; use bevy_math::{AspectRatio, Mat4, Rect, Vec2, Vec3A};
use bevy_reflect::{ use bevy_reflect::{
std_traits::ReflectDefault, GetTypeRegistration, Reflect, ReflectDeserialize, ReflectSerialize, std_traits::ReflectDefault, GetTypeRegistration, Reflect, ReflectDeserialize, ReflectSerialize,
}; };
use bevy_transform::components::GlobalTransform;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
/// Adds [`Camera`](crate::camera::Camera) driver systems for a given projection type. /// Adds [`Camera`](crate::camera::Camera) driver systems for a given projection type.
@ -60,6 +62,21 @@ pub trait CameraProjection {
fn update(&mut self, width: f32, height: f32); fn update(&mut self, width: f32, height: f32);
fn far(&self) -> f32; fn far(&self) -> f32;
fn get_frustum_corners(&self, z_near: f32, z_far: f32) -> [Vec3A; 8]; fn get_frustum_corners(&self, z_near: f32, z_far: f32) -> [Vec3A; 8];
/// Compute camera frustum for camera with given projection and transform.
///
/// This code is called by [`update_frusta`](crate::view::visibility::update_frusta) system
/// for each camera to update its frustum.
fn compute_frustum(&self, camera_transform: &GlobalTransform) -> Frustum {
let view_projection =
self.get_projection_matrix() * camera_transform.compute_matrix().inverse();
Frustum::from_view_projection_custom_far(
&view_projection,
&camera_transform.translation(),
&camera_transform.back(),
self.far(),
)
}
} }
/// A configurable [`CameraProjection`] that can select its projection type at runtime. /// A configurable [`CameraProjection`] that can select its projection type at runtime.

View File

@ -281,14 +281,7 @@ pub fn update_frusta<T: Component + CameraProjection + Send + Sync + 'static>(
>, >,
) { ) {
for (transform, projection, mut frustum) in &mut views { for (transform, projection, mut frustum) in &mut views {
let view_projection = *frustum = projection.compute_frustum(transform);
projection.get_projection_matrix() * transform.compute_matrix().inverse();
*frustum = Frustum::from_view_projection_custom_far(
&view_projection,
&transform.translation(),
&transform.back(),
projection.far(),
);
} }
} }