Only use the AABB center for mesh visibility range testing if specified. (#16468)
PR #15164 made Bevy consider the center of the mesh to be the center of the axis-aligned bounding box (AABB). Unfortunately, this breaks crossfading in many cases. LODs may have different AABBs and so the center of the AABB may differ for different LODs of the same mesh. The crossfading, however, relies on all LODs having *precisely* the same position. To address this problem, this PR adds a new field, `use_aabb`, to `VisibilityRange`, which makes the AABB center point behavior opt-in. @BenjaminBrienen first noticed this issue when reviewing PR #16286. That PR contains a video showing the effects of this regression on the `visibility_range` example. This commit fixes that example. ## Migration Guide * The `VisibilityRange` component now has an extra field, `use_aabb`. Generally, you can safely set it to false.
This commit is contained in:
parent
b319c56e3c
commit
5a369abdda
@ -112,7 +112,7 @@ impl Plugin for VisibilityRangePlugin {
|
||||
/// that the `end_margin` of a higher LOD is always identical to the
|
||||
/// `start_margin` of the next lower LOD; this is important for the crossfade
|
||||
/// effect to function properly.
|
||||
#[derive(Component, Clone, PartialEq, Reflect)]
|
||||
#[derive(Component, Clone, PartialEq, Default, Reflect)]
|
||||
#[reflect(Component, PartialEq, Hash)]
|
||||
pub struct VisibilityRange {
|
||||
/// The range of distances, in world units, between which this entity will
|
||||
@ -132,6 +132,20 @@ pub struct VisibilityRange {
|
||||
///
|
||||
/// `end_margin.start` must be greater than or equal to `start_margin.end`.
|
||||
pub end_margin: Range<f32>,
|
||||
|
||||
/// If set to true, Bevy will use the center of the axis-aligned bounding
|
||||
/// box ([`Aabb`]) as the position of the mesh for the purposes of
|
||||
/// visibility range computation.
|
||||
///
|
||||
/// Otherwise, if this field is set to false, Bevy will use the origin of
|
||||
/// the mesh as the mesh's position.
|
||||
///
|
||||
/// Usually you will want to leave this set to false, because different LODs
|
||||
/// may have different AABBs, and smooth crossfades between LOD levels
|
||||
/// require that all LODs of a mesh be at *precisely* the same position. If
|
||||
/// you aren't using crossfading, however, and your meshes aren't centered
|
||||
/// around their origins, then this flag may be useful.
|
||||
pub use_aabb: bool,
|
||||
}
|
||||
|
||||
impl Eq for VisibilityRange {}
|
||||
@ -161,6 +175,7 @@ impl VisibilityRange {
|
||||
Self {
|
||||
start_margin: start..start,
|
||||
end_margin: end..end,
|
||||
use_aabb: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -391,14 +406,17 @@ pub fn check_visibility_ranges(
|
||||
for (entity, entity_transform, maybe_model_aabb, visibility_range) in entity_query.iter_mut() {
|
||||
let mut visibility = 0;
|
||||
for (view_index, &(_, view_position)) in views.iter().enumerate() {
|
||||
let model_pos = if let Some(model_aabb) = maybe_model_aabb {
|
||||
let world_from_local = entity_transform.affine();
|
||||
world_from_local.transform_point3a(model_aabb.center)
|
||||
} else {
|
||||
entity_transform.translation_vec3a()
|
||||
// If instructed to use the AABB and the model has one, use its
|
||||
// center as the model position. Otherwise, use the model's
|
||||
// translation.
|
||||
let model_position = match (visibility_range.use_aabb, maybe_model_aabb) {
|
||||
(true, Some(model_aabb)) => entity_transform
|
||||
.affine()
|
||||
.transform_point3a(model_aabb.center),
|
||||
_ => entity_transform.translation_vec3a(),
|
||||
};
|
||||
|
||||
if visibility_range.is_visible_at_all((view_position - model_pos).length()) {
|
||||
if visibility_range.is_visible_at_all((view_position - model_position).length()) {
|
||||
visibility |= 1 << view_index;
|
||||
}
|
||||
}
|
||||
|
@ -26,10 +26,12 @@ const MIN_ZOOM_DISTANCE: f32 = 0.5;
|
||||
static NORMAL_VISIBILITY_RANGE_HIGH_POLY: VisibilityRange = VisibilityRange {
|
||||
start_margin: 0.0..0.0,
|
||||
end_margin: 3.0..4.0,
|
||||
use_aabb: false,
|
||||
};
|
||||
static NORMAL_VISIBILITY_RANGE_LOW_POLY: VisibilityRange = VisibilityRange {
|
||||
start_margin: 3.0..4.0,
|
||||
end_margin: 8.0..9.0,
|
||||
use_aabb: false,
|
||||
};
|
||||
|
||||
// A visibility model that we use to always show a model (until the camera is so
|
||||
@ -37,12 +39,14 @@ static NORMAL_VISIBILITY_RANGE_LOW_POLY: VisibilityRange = VisibilityRange {
|
||||
static SINGLE_MODEL_VISIBILITY_RANGE: VisibilityRange = VisibilityRange {
|
||||
start_margin: 0.0..0.0,
|
||||
end_margin: 8.0..9.0,
|
||||
use_aabb: false,
|
||||
};
|
||||
|
||||
// A visibility range that we use to completely hide a model.
|
||||
static INVISIBLE_VISIBILITY_RANGE: VisibilityRange = VisibilityRange {
|
||||
start_margin: 0.0..0.0,
|
||||
end_margin: 0.0..0.0,
|
||||
use_aabb: false,
|
||||
};
|
||||
|
||||
// Allows us to identify the main model.
|
||||
|
Loading…
Reference in New Issue
Block a user