Use Affine3A for GlobalTransform to allow any affine transformation (#4379)
# Objective - Add capability to use `Affine3A`s for some `GlobalTransform`s. This allows affine transformations that are not possible using a single `Transform` such as shear and non-uniform scaling along an arbitrary axis. - Related to #1755 and #2026 ## Solution - `GlobalTransform` becomes an enum wrapping either a `Transform` or an `Affine3A`. - The API of `GlobalTransform` is minimized to avoid inefficiency, and to make it clear that operations should be performed using the underlying data types. - using `GlobalTransform::Affine3A` disables transform propagation, because the main use is for cases that `Transform`s cannot support. --- ## Changelog - `GlobalTransform`s can optionally support any affine transformation using an `Affine3A`. Co-authored-by: Carter Anderson <mcanders1@gmail.com>
This commit is contained in:
parent
8810a73e87
commit
9f8bdeeeb9
@ -1,7 +1,7 @@
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_math::{Mat4, Quat, UVec2, UVec3, Vec2, Vec3, Vec3A, Vec3Swizzles, Vec4, Vec4Swizzles};
|
use bevy_math::{Mat4, UVec2, UVec3, Vec2, Vec3, Vec3A, Vec3Swizzles, Vec4, Vec4Swizzles};
|
||||||
use bevy_reflect::prelude::*;
|
use bevy_reflect::prelude::*;
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
camera::{Camera, CameraProjection, OrthographicProjection},
|
camera::{Camera, CameraProjection, OrthographicProjection},
|
||||||
@ -12,7 +12,7 @@ use bevy_render::{
|
|||||||
renderer::RenderDevice,
|
renderer::RenderDevice,
|
||||||
view::{ComputedVisibility, RenderLayers, VisibleEntities},
|
view::{ComputedVisibility, RenderLayers, VisibleEntities},
|
||||||
};
|
};
|
||||||
use bevy_transform::components::GlobalTransform;
|
use bevy_transform::{components::GlobalTransform, prelude::Transform};
|
||||||
use bevy_utils::tracing::warn;
|
use bevy_utils::tracing::warn;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -755,13 +755,21 @@ pub(crate) fn point_light_order(
|
|||||||
// data required for assigning lights to clusters
|
// data required for assigning lights to clusters
|
||||||
pub(crate) struct PointLightAssignmentData {
|
pub(crate) struct PointLightAssignmentData {
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
translation: Vec3,
|
transform: GlobalTransform,
|
||||||
rotation: Quat,
|
|
||||||
range: f32,
|
range: f32,
|
||||||
shadows_enabled: bool,
|
shadows_enabled: bool,
|
||||||
spot_light_angle: Option<f32>,
|
spot_light_angle: Option<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PointLightAssignmentData {
|
||||||
|
pub fn sphere(&self) -> Sphere {
|
||||||
|
Sphere {
|
||||||
|
center: self.transform.translation_vec3a(),
|
||||||
|
radius: self.range,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct GlobalVisiblePointLights {
|
pub struct GlobalVisiblePointLights {
|
||||||
entities: HashSet<Entity>,
|
entities: HashSet<Entity>,
|
||||||
@ -815,8 +823,7 @@ pub(crate) fn assign_lights_to_clusters(
|
|||||||
.map(
|
.map(
|
||||||
|(entity, transform, point_light, _visibility)| PointLightAssignmentData {
|
|(entity, transform, point_light, _visibility)| PointLightAssignmentData {
|
||||||
entity,
|
entity,
|
||||||
translation: transform.translation,
|
transform: GlobalTransform::from_translation(transform.translation()),
|
||||||
rotation: Quat::default(),
|
|
||||||
shadows_enabled: point_light.shadows_enabled,
|
shadows_enabled: point_light.shadows_enabled,
|
||||||
range: point_light.range,
|
range: point_light.range,
|
||||||
spot_light_angle: None,
|
spot_light_angle: None,
|
||||||
@ -830,8 +837,7 @@ pub(crate) fn assign_lights_to_clusters(
|
|||||||
.map(
|
.map(
|
||||||
|(entity, transform, spot_light, _visibility)| PointLightAssignmentData {
|
|(entity, transform, spot_light, _visibility)| PointLightAssignmentData {
|
||||||
entity,
|
entity,
|
||||||
translation: transform.translation,
|
transform: *transform,
|
||||||
rotation: transform.rotation,
|
|
||||||
shadows_enabled: spot_light.shadows_enabled,
|
shadows_enabled: spot_light.shadows_enabled,
|
||||||
range: spot_light.range,
|
range: spot_light.range,
|
||||||
spot_light_angle: Some(spot_light.outer_angle),
|
spot_light_angle: Some(spot_light.outer_angle),
|
||||||
@ -872,11 +878,7 @@ pub(crate) fn assign_lights_to_clusters(
|
|||||||
if lights_in_view_count == MAX_UNIFORM_BUFFER_POINT_LIGHTS + 1 {
|
if lights_in_view_count == MAX_UNIFORM_BUFFER_POINT_LIGHTS + 1 {
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
let light_sphere = Sphere {
|
let light_sphere = light.sphere();
|
||||||
center: Vec3A::from(light.translation),
|
|
||||||
radius: light.range,
|
|
||||||
};
|
|
||||||
|
|
||||||
let light_in_view = frusta
|
let light_in_view = frusta
|
||||||
.iter()
|
.iter()
|
||||||
.any(|frustum| frustum.intersects_sphere(&light_sphere, true));
|
.any(|frustum| frustum.intersects_sphere(&light_sphere, true));
|
||||||
@ -932,7 +934,8 @@ pub(crate) fn assign_lights_to_clusters(
|
|||||||
lights
|
lights
|
||||||
.iter()
|
.iter()
|
||||||
.map(|light| {
|
.map(|light| {
|
||||||
-inverse_view_row_2.dot(light.translation.extend(1.0)) + light.range
|
-inverse_view_row_2.dot(light.transform.translation().extend(1.0))
|
||||||
|
+ light.range
|
||||||
})
|
})
|
||||||
.reduce(f32::max)
|
.reduce(f32::max)
|
||||||
.unwrap_or(0.0)
|
.unwrap_or(0.0)
|
||||||
@ -966,10 +969,7 @@ pub(crate) fn assign_lights_to_clusters(
|
|||||||
if config.dynamic_resizing() {
|
if config.dynamic_resizing() {
|
||||||
let mut cluster_index_estimate = 0.0;
|
let mut cluster_index_estimate = 0.0;
|
||||||
for light in lights.iter() {
|
for light in lights.iter() {
|
||||||
let light_sphere = Sphere {
|
let light_sphere = light.sphere();
|
||||||
center: Vec3A::from(light.translation),
|
|
||||||
radius: light.range,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Check if the light is within the view frustum
|
// Check if the light is within the view frustum
|
||||||
if !frustum.intersects_sphere(&light_sphere, true) {
|
if !frustum.intersects_sphere(&light_sphere, true) {
|
||||||
@ -1124,10 +1124,7 @@ pub(crate) fn assign_lights_to_clusters(
|
|||||||
|
|
||||||
let mut update_from_light_intersections = |visible_lights: &mut Vec<Entity>| {
|
let mut update_from_light_intersections = |visible_lights: &mut Vec<Entity>| {
|
||||||
for light in lights.iter() {
|
for light in lights.iter() {
|
||||||
let light_sphere = Sphere {
|
let light_sphere = light.sphere();
|
||||||
center: Vec3A::from(light.translation),
|
|
||||||
radius: light.range,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Check if the light is within the view frustum
|
// Check if the light is within the view frustum
|
||||||
if !frustum.intersects_sphere(&light_sphere, true) {
|
if !frustum.intersects_sphere(&light_sphere, true) {
|
||||||
@ -1177,8 +1174,7 @@ pub(crate) fn assign_lights_to_clusters(
|
|||||||
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.rotation * Vec3::Z).extend(0.0))
|
(inverse_view_transform * light.transform.back().extend(0.0)).truncate(),
|
||||||
.truncate(),
|
|
||||||
angle_sin,
|
angle_sin,
|
||||||
angle_cos,
|
angle_cos,
|
||||||
)
|
)
|
||||||
@ -1432,7 +1428,7 @@ pub fn update_directional_light_frusta(
|
|||||||
* transform.compute_matrix().inverse();
|
* transform.compute_matrix().inverse();
|
||||||
*frustum = Frustum::from_view_projection(
|
*frustum = Frustum::from_view_projection(
|
||||||
&view_projection,
|
&view_projection,
|
||||||
&transform.translation,
|
&transform.translation(),
|
||||||
&transform.back(),
|
&transform.back(),
|
||||||
directional_light.shadow_projection.far(),
|
directional_light.shadow_projection.far(),
|
||||||
);
|
);
|
||||||
@ -1451,7 +1447,7 @@ pub fn update_point_light_frusta(
|
|||||||
Mat4::perspective_infinite_reverse_rh(std::f32::consts::FRAC_PI_2, 1.0, POINT_LIGHT_NEAR_Z);
|
Mat4::perspective_infinite_reverse_rh(std::f32::consts::FRAC_PI_2, 1.0, POINT_LIGHT_NEAR_Z);
|
||||||
let view_rotations = CUBE_MAP_FACES
|
let view_rotations = CUBE_MAP_FACES
|
||||||
.iter()
|
.iter()
|
||||||
.map(|CubeMapFace { target, up }| GlobalTransform::identity().looking_at(*target, *up))
|
.map(|CubeMapFace { target, up }| Transform::identity().looking_at(*target, *up))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
for (entity, transform, point_light, mut cubemap_frusta) in &mut views {
|
for (entity, transform, point_light, mut cubemap_frusta) in &mut views {
|
||||||
@ -1467,7 +1463,7 @@ pub fn update_point_light_frusta(
|
|||||||
// ignore scale because we don't want to effectively scale light radius and range
|
// ignore scale because we don't want to effectively scale light radius and range
|
||||||
// by applying those as a view transform to shadow map rendering of objects
|
// by applying those as a view transform to shadow map rendering of objects
|
||||||
// and ignore rotation because we want the shadow map projections to align with the axes
|
// and ignore rotation because we want the shadow map projections to align with the axes
|
||||||
let view_translation = GlobalTransform::from_translation(transform.translation);
|
let view_translation = Transform::from_translation(transform.translation());
|
||||||
let view_backward = transform.back();
|
let view_backward = transform.back();
|
||||||
|
|
||||||
for (view_rotation, frustum) in view_rotations.iter().zip(cubemap_frusta.iter_mut()) {
|
for (view_rotation, frustum) in view_rotations.iter().zip(cubemap_frusta.iter_mut()) {
|
||||||
@ -1476,7 +1472,7 @@ pub fn update_point_light_frusta(
|
|||||||
|
|
||||||
*frustum = Frustum::from_view_projection(
|
*frustum = Frustum::from_view_projection(
|
||||||
&view_projection,
|
&view_projection,
|
||||||
&transform.translation,
|
&transform.translation(),
|
||||||
&view_backward,
|
&view_backward,
|
||||||
point_light.range,
|
point_light.range,
|
||||||
);
|
);
|
||||||
@ -1503,7 +1499,6 @@ pub fn update_spot_light_frusta(
|
|||||||
|
|
||||||
// ignore scale because we don't want to effectively scale light radius and range
|
// ignore scale because we don't want to effectively scale light radius and range
|
||||||
// by applying those as a view transform to shadow map rendering of objects
|
// by applying those as a view transform to shadow map rendering of objects
|
||||||
let view_translation = GlobalTransform::from_translation(transform.translation);
|
|
||||||
let view_backward = transform.back();
|
let view_backward = transform.back();
|
||||||
|
|
||||||
let spot_view = spot_light_view_matrix(transform);
|
let spot_view = spot_light_view_matrix(transform);
|
||||||
@ -1512,7 +1507,7 @@ pub fn update_spot_light_frusta(
|
|||||||
|
|
||||||
*frustum = Frustum::from_view_projection(
|
*frustum = Frustum::from_view_projection(
|
||||||
&view_projection,
|
&view_projection,
|
||||||
&view_translation.translation,
|
&transform.translation(),
|
||||||
&view_backward,
|
&view_backward,
|
||||||
spot_light.range,
|
spot_light.range,
|
||||||
);
|
);
|
||||||
@ -1623,7 +1618,7 @@ pub fn check_light_mesh_visibility(
|
|||||||
|
|
||||||
let view_mask = maybe_view_mask.copied().unwrap_or_default();
|
let view_mask = maybe_view_mask.copied().unwrap_or_default();
|
||||||
let light_sphere = Sphere {
|
let light_sphere = Sphere {
|
||||||
center: Vec3A::from(transform.translation),
|
center: Vec3A::from(transform.translation()),
|
||||||
radius: point_light.range,
|
radius: point_light.range,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1686,7 +1681,7 @@ pub fn check_light_mesh_visibility(
|
|||||||
|
|
||||||
let view_mask = maybe_view_mask.copied().unwrap_or_default();
|
let view_mask = maybe_view_mask.copied().unwrap_or_default();
|
||||||
let light_sphere = Sphere {
|
let light_sphere = Sphere {
|
||||||
center: Vec3A::from(transform.translation),
|
center: Vec3A::from(transform.translation()),
|
||||||
radius: point_light.range,
|
radius: point_light.range,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ use bevy_render::{
|
|||||||
},
|
},
|
||||||
Extract,
|
Extract,
|
||||||
};
|
};
|
||||||
use bevy_transform::components::GlobalTransform;
|
use bevy_transform::{components::GlobalTransform, prelude::Transform};
|
||||||
use bevy_utils::FloatOrd;
|
use bevy_utils::FloatOrd;
|
||||||
use bevy_utils::{
|
use bevy_utils::{
|
||||||
tracing::{error, warn},
|
tracing::{error, warn},
|
||||||
@ -728,7 +728,7 @@ pub fn calculate_cluster_factors(
|
|||||||
// could move this onto transform but it's pretty niche
|
// could move this onto transform but it's pretty niche
|
||||||
pub(crate) fn spot_light_view_matrix(transform: &GlobalTransform) -> Mat4 {
|
pub(crate) fn spot_light_view_matrix(transform: &GlobalTransform) -> Mat4 {
|
||||||
// the matrix z_local (opposite of transform.forward())
|
// the matrix z_local (opposite of transform.forward())
|
||||||
let fwd_dir = transform.local_z().extend(0.0);
|
let fwd_dir = transform.back().extend(0.0);
|
||||||
|
|
||||||
let sign = 1f32.copysign(fwd_dir.z);
|
let sign = 1f32.copysign(fwd_dir.z);
|
||||||
let a = -1.0 / (fwd_dir.z + sign);
|
let a = -1.0 / (fwd_dir.z + sign);
|
||||||
@ -745,7 +745,7 @@ pub(crate) fn spot_light_view_matrix(transform: &GlobalTransform) -> Mat4 {
|
|||||||
right_dir,
|
right_dir,
|
||||||
up_dir,
|
up_dir,
|
||||||
fwd_dir,
|
fwd_dir,
|
||||||
transform.translation.extend(1.0),
|
transform.translation().extend(1.0),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -779,7 +779,7 @@ pub fn prepare_lights(
|
|||||||
Mat4::perspective_infinite_reverse_rh(std::f32::consts::FRAC_PI_2, 1.0, POINT_LIGHT_NEAR_Z);
|
Mat4::perspective_infinite_reverse_rh(std::f32::consts::FRAC_PI_2, 1.0, POINT_LIGHT_NEAR_Z);
|
||||||
let cube_face_rotations = CUBE_MAP_FACES
|
let cube_face_rotations = CUBE_MAP_FACES
|
||||||
.iter()
|
.iter()
|
||||||
.map(|CubeMapFace { target, up }| GlobalTransform::identity().looking_at(*target, *up))
|
.map(|CubeMapFace { target, up }| Transform::identity().looking_at(*target, *up))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
global_light_meta.entity_to_index.clear();
|
global_light_meta.entity_to_index.clear();
|
||||||
@ -893,7 +893,7 @@ pub fn prepare_lights(
|
|||||||
* light.intensity)
|
* light.intensity)
|
||||||
.xyz()
|
.xyz()
|
||||||
.extend(1.0 / (light.range * light.range)),
|
.extend(1.0 / (light.range * light.range)),
|
||||||
position_radius: light.transform.translation.extend(light.radius),
|
position_radius: light.transform.translation().extend(light.radius),
|
||||||
flags: flags.bits,
|
flags: flags.bits,
|
||||||
shadow_depth_bias: light.shadow_depth_bias,
|
shadow_depth_bias: light.shadow_depth_bias,
|
||||||
shadow_normal_bias: light.shadow_normal_bias,
|
shadow_normal_bias: light.shadow_normal_bias,
|
||||||
@ -989,7 +989,7 @@ pub fn prepare_lights(
|
|||||||
// ignore scale because we don't want to effectively scale light radius and range
|
// ignore scale because we don't want to effectively scale light radius and range
|
||||||
// by applying those as a view transform to shadow map rendering of objects
|
// by applying those as a view transform to shadow map rendering of objects
|
||||||
// and ignore rotation because we want the shadow map projections to align with the axes
|
// and ignore rotation because we want the shadow map projections to align with the axes
|
||||||
let view_translation = GlobalTransform::from_translation(light.transform.translation);
|
let view_translation = GlobalTransform::from_translation(light.transform.translation());
|
||||||
|
|
||||||
for (face_index, view_rotation) in cube_face_rotations.iter().enumerate() {
|
for (face_index, view_rotation) in cube_face_rotations.iter().enumerate() {
|
||||||
let depth_texture_view =
|
let depth_texture_view =
|
||||||
@ -1042,7 +1042,7 @@ pub fn prepare_lights(
|
|||||||
.enumerate()
|
.enumerate()
|
||||||
{
|
{
|
||||||
let spot_view_matrix = spot_light_view_matrix(&light.transform);
|
let spot_view_matrix = spot_light_view_matrix(&light.transform);
|
||||||
let spot_view_transform = GlobalTransform::from_matrix(spot_view_matrix);
|
let spot_view_transform = spot_view_matrix.into();
|
||||||
|
|
||||||
let angle = light.spot_light_angles.expect("lights should be sorted so that \
|
let angle = light.spot_light_angles.expect("lights should be sorted so that \
|
||||||
[point_light_shadow_maps_count..point_light_shadow_maps_count + spot_light_shadow_maps_count] are spot lights").1;
|
[point_light_shadow_maps_count..point_light_shadow_maps_count + spot_light_shadow_maps_count] are spot lights").1;
|
||||||
@ -1152,7 +1152,7 @@ pub fn prepare_lights(
|
|||||||
ExtractedView {
|
ExtractedView {
|
||||||
width: directional_light_shadow_map.size as u32,
|
width: directional_light_shadow_map.size as u32,
|
||||||
height: directional_light_shadow_map.size as u32,
|
height: directional_light_shadow_map.size as u32,
|
||||||
transform: GlobalTransform::from_matrix(view.inverse()),
|
transform: GlobalTransform::from(view.inverse()),
|
||||||
projection,
|
projection,
|
||||||
},
|
},
|
||||||
RenderPhase::<Shadow>::default(),
|
RenderPhase::<Shadow>::default(),
|
||||||
|
@ -189,7 +189,7 @@ impl SkinnedMeshJoints {
|
|||||||
let start = buffer.len();
|
let start = buffer.len();
|
||||||
for (inverse_bindpose, joint) in bindposes.zip(skin_joints).take(MAX_JOINTS) {
|
for (inverse_bindpose, joint) in bindposes.zip(skin_joints).take(MAX_JOINTS) {
|
||||||
if let Ok(joint) = joints.get(*joint) {
|
if let Ok(joint) = joints.get(*joint) {
|
||||||
buffer.push(joint.compute_affine() * *inverse_bindpose);
|
buffer.push(joint.affine() * *inverse_bindpose);
|
||||||
} else {
|
} else {
|
||||||
buffer.truncate(start);
|
buffer.truncate(start);
|
||||||
return None;
|
return None;
|
||||||
|
@ -162,7 +162,7 @@ fn prepare_view_uniforms(
|
|||||||
inverse_view,
|
inverse_view,
|
||||||
projection,
|
projection,
|
||||||
inverse_projection,
|
inverse_projection,
|
||||||
world_position: camera.transform.translation,
|
world_position: camera.transform.translation(),
|
||||||
width: camera.width as f32,
|
width: camera.width as f32,
|
||||||
height: camera.height as f32,
|
height: camera.height as f32,
|
||||||
}),
|
}),
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
mod render_layers;
|
mod render_layers;
|
||||||
|
|
||||||
use bevy_math::Vec3A;
|
|
||||||
pub use render_layers::*;
|
pub use render_layers::*;
|
||||||
|
|
||||||
use bevy_app::{CoreStage, Plugin};
|
use bevy_app::{CoreStage, Plugin};
|
||||||
@ -205,7 +204,7 @@ pub fn update_frusta<T: Component + CameraProjection + Send + Sync + 'static>(
|
|||||||
projection.get_projection_matrix() * transform.compute_matrix().inverse();
|
projection.get_projection_matrix() * transform.compute_matrix().inverse();
|
||||||
*frustum = Frustum::from_view_projection(
|
*frustum = Frustum::from_view_projection(
|
||||||
&view_projection,
|
&view_projection,
|
||||||
&transform.translation,
|
&transform.translation(),
|
||||||
&transform.back(),
|
&transform.back(),
|
||||||
projection.far(),
|
projection.far(),
|
||||||
);
|
);
|
||||||
@ -324,7 +323,7 @@ pub fn check_visibility(
|
|||||||
let model = transform.compute_matrix();
|
let model = transform.compute_matrix();
|
||||||
let model_sphere = Sphere {
|
let model_sphere = Sphere {
|
||||||
center: model.transform_point3a(model_aabb.center),
|
center: model.transform_point3a(model_aabb.center),
|
||||||
radius: (Vec3A::from(transform.scale) * model_aabb.half_extents).length(),
|
radius: transform.radius_vec3a(model_aabb.half_extents),
|
||||||
};
|
};
|
||||||
// Do quick sphere-based frustum culling
|
// Do quick sphere-based frustum culling
|
||||||
if !frustum.intersects_sphere(&model_sphere, false) {
|
if !frustum.intersects_sphere(&model_sphere, false) {
|
||||||
|
@ -410,9 +410,9 @@ pub fn queue_sprites(
|
|||||||
extracted_sprites.sort_unstable_by(|a, b| {
|
extracted_sprites.sort_unstable_by(|a, b| {
|
||||||
match a
|
match a
|
||||||
.transform
|
.transform
|
||||||
.translation
|
.translation()
|
||||||
.z
|
.z
|
||||||
.partial_cmp(&b.transform.translation.z)
|
.partial_cmp(&b.transform.translation().z)
|
||||||
{
|
{
|
||||||
Some(Ordering::Equal) | None => a.image_handle_id.cmp(&b.image_handle_id),
|
Some(Ordering::Equal) | None => a.image_handle_id.cmp(&b.image_handle_id),
|
||||||
Some(other) => other,
|
Some(other) => other,
|
||||||
@ -517,7 +517,7 @@ pub fn queue_sprites(
|
|||||||
});
|
});
|
||||||
|
|
||||||
// These items will be sorted by depth with other phase items
|
// These items will be sorted by depth with other phase items
|
||||||
let sort_key = FloatOrd(extracted_sprite.transform.translation.z);
|
let sort_key = FloatOrd(extracted_sprite.transform.translation().z);
|
||||||
|
|
||||||
// Store the vertex data and add the item to the render phase
|
// Store the vertex data and add the item to the render phase
|
||||||
if current_batch.colored {
|
if current_batch.colored {
|
||||||
|
@ -82,7 +82,8 @@ pub fn extract_text2d_sprite(
|
|||||||
) {
|
) {
|
||||||
let scale_factor = windows.scale_factor(WindowId::primary()) as f32;
|
let scale_factor = windows.scale_factor(WindowId::primary()) as f32;
|
||||||
|
|
||||||
for (entity, computed_visibility, text, transform, calculated_size) in text2d_query.iter() {
|
for (entity, computed_visibility, text, text_transform, calculated_size) in text2d_query.iter()
|
||||||
|
{
|
||||||
if !computed_visibility.is_visible() {
|
if !computed_visibility.is_visible() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -100,9 +101,6 @@ pub fn extract_text2d_sprite(
|
|||||||
HorizontalAlign::Right => Vec3::new(-width, 0.0, 0.0),
|
HorizontalAlign::Right => Vec3::new(-width, 0.0, 0.0),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut text_transform = *transform;
|
|
||||||
text_transform.scale /= scale_factor;
|
|
||||||
|
|
||||||
for text_glyph in text_glyphs {
|
for text_glyph in text_glyphs {
|
||||||
let color = text.sections[text_glyph.section_index]
|
let color = text.sections[text_glyph.section_index]
|
||||||
.style
|
.style
|
||||||
@ -118,8 +116,10 @@ pub fn extract_text2d_sprite(
|
|||||||
let glyph_transform = Transform::from_translation(
|
let glyph_transform = Transform::from_translation(
|
||||||
alignment_offset * scale_factor + text_glyph.position.extend(0.),
|
alignment_offset * scale_factor + text_glyph.position.extend(0.),
|
||||||
);
|
);
|
||||||
|
// NOTE: Should match `bevy_ui::render::extract_text_uinodes`
|
||||||
let transform = text_transform.mul_transform(glyph_transform);
|
let transform = *text_transform
|
||||||
|
* GlobalTransform::from_scale(Vec3::splat(scale_factor.recip()))
|
||||||
|
* glyph_transform;
|
||||||
|
|
||||||
extracted_sprites.sprites.push(ExtractedSprite {
|
extracted_sprites.sprites.push(ExtractedSprite {
|
||||||
entity,
|
entity,
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
|
use std::ops::Mul;
|
||||||
|
|
||||||
use super::Transform;
|
use super::Transform;
|
||||||
use bevy_ecs::{component::Component, reflect::ReflectComponent};
|
use bevy_ecs::{component::Component, reflect::ReflectComponent};
|
||||||
use bevy_math::{Affine3A, Mat3, Mat4, Quat, Vec3};
|
use bevy_math::{Affine3A, Mat4, Quat, Vec3, Vec3A};
|
||||||
use bevy_reflect::prelude::*;
|
use bevy_reflect::Reflect;
|
||||||
use std::ops::Mul;
|
|
||||||
|
|
||||||
/// Describe the position of an entity relative to the reference frame.
|
/// Describe the position of an entity relative to the reference frame.
|
||||||
///
|
///
|
||||||
@ -25,223 +26,129 @@ use std::ops::Mul;
|
|||||||
/// update the[`Transform`] of an entity in this stage or after, you will notice a 1 frame lag
|
/// update the[`Transform`] of an entity in this stage or after, you will notice a 1 frame lag
|
||||||
/// before the [`GlobalTransform`] is updated.
|
/// before the [`GlobalTransform`] is updated.
|
||||||
#[derive(Component, Debug, PartialEq, Clone, Copy, Reflect)]
|
#[derive(Component, Debug, PartialEq, Clone, Copy, Reflect)]
|
||||||
#[reflect(Component, Default, PartialEq)]
|
#[reflect(Component, PartialEq)]
|
||||||
pub struct GlobalTransform {
|
pub struct GlobalTransform(Affine3A);
|
||||||
/// The position of the global transform
|
|
||||||
pub translation: Vec3,
|
macro_rules! impl_local_axis {
|
||||||
/// The rotation of the global transform
|
($pos_name: ident, $neg_name: ident, $axis: ident) => {
|
||||||
pub rotation: Quat,
|
#[doc=std::concat!("Return the local ", std::stringify!($pos_name), " vector (", std::stringify!($axis) ,").")]
|
||||||
/// The scale of the global transform
|
#[inline]
|
||||||
pub scale: Vec3,
|
pub fn $pos_name(&self) -> Vec3 {
|
||||||
|
(self.0.matrix3 * Vec3::$axis).normalize()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc=std::concat!("Return the local ", std::stringify!($neg_name), " vector (-", std::stringify!($axis) ,").")]
|
||||||
|
#[inline]
|
||||||
|
pub fn $neg_name(&self) -> Vec3 {
|
||||||
|
-self.$pos_name()
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GlobalTransform {
|
impl GlobalTransform {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn from_xyz(x: f32, y: f32, z: f32) -> Self {
|
pub fn from_xyz(x: f32, y: f32, z: f32) -> Self {
|
||||||
Self::from_translation(Vec3::new(x, y, z))
|
Self::from_translation(Vec3::new(x, y, z))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new identity [`GlobalTransform`], with no translation, rotation, and a scale of 1
|
#[doc(hidden)]
|
||||||
/// on all axes.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn identity() -> Self {
|
pub fn from_translation(translation: Vec3) -> Self {
|
||||||
GlobalTransform {
|
GlobalTransform(Affine3A::from_translation(translation))
|
||||||
translation: Vec3::ZERO,
|
|
||||||
rotation: Quat::IDENTITY,
|
|
||||||
scale: Vec3::ONE,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_matrix(matrix: Mat4) -> Self {
|
pub fn from_rotation(rotation: Quat) -> Self {
|
||||||
let (scale, rotation, translation) = matrix.to_scale_rotation_translation();
|
GlobalTransform(Affine3A::from_rotation_translation(rotation, Vec3::ZERO))
|
||||||
|
|
||||||
GlobalTransform {
|
|
||||||
translation,
|
|
||||||
rotation,
|
|
||||||
scale,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn from_translation(translation: Vec3) -> Self {
|
pub fn from_scale(scale: Vec3) -> Self {
|
||||||
GlobalTransform {
|
GlobalTransform(Affine3A::from_scale(scale))
|
||||||
translation,
|
|
||||||
..Self::identity()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
/// Returns the 3d affine transformation matrix as a [`Mat4`].
|
||||||
#[inline]
|
|
||||||
pub const fn from_rotation(rotation: Quat) -> Self {
|
|
||||||
GlobalTransform {
|
|
||||||
rotation,
|
|
||||||
..Self::identity()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[inline]
|
|
||||||
pub const fn from_scale(scale: Vec3) -> Self {
|
|
||||||
GlobalTransform {
|
|
||||||
scale,
|
|
||||||
..Self::identity()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub fn looking_at(mut self, target: Vec3, up: Vec3) -> Self {
|
|
||||||
self.look_at(target, up);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn with_translation(mut self, translation: Vec3) -> Self {
|
|
||||||
self.translation = translation;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn with_rotation(mut self, rotation: Quat) -> Self {
|
|
||||||
self.rotation = rotation;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn with_scale(mut self, scale: Vec3) -> Self {
|
|
||||||
self.scale = scale;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the 3d affine transformation matrix from this transforms translation,
|
|
||||||
/// rotation, and scale.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn compute_matrix(&self) -> Mat4 {
|
pub fn compute_matrix(&self) -> Mat4 {
|
||||||
Mat4::from_scale_rotation_translation(self.scale, self.rotation, self.translation)
|
Mat4::from(self.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the 3d affine transformation from this transforms translation,
|
/// Returns the 3d affine transformation matrix as an [`Affine3A`].
|
||||||
/// rotation, and scale.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn compute_affine(&self) -> Affine3A {
|
pub fn affine(&self) -> Affine3A {
|
||||||
Affine3A::from_scale_rotation_translation(self.scale, self.rotation, self.translation)
|
self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the unit vector in the local `X` direction
|
/// Returns the transformation as a [`Transform`].
|
||||||
|
///
|
||||||
|
/// The transform is expected to be non-degenerate and without shearing, or the output
|
||||||
|
/// will be invalid.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn local_x(&self) -> Vec3 {
|
pub fn compute_transform(&self) -> Transform {
|
||||||
self.rotation * Vec3::X
|
let (scale, rotation, translation) = self.0.to_scale_rotation_translation();
|
||||||
}
|
Transform {
|
||||||
|
|
||||||
/// Equivalent to [`-local_x()`][GlobalTransform::local_x]
|
|
||||||
#[inline]
|
|
||||||
pub fn left(&self) -> Vec3 {
|
|
||||||
-self.local_x()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Equivalent to [`local_x()`][GlobalTransform::local_x]
|
|
||||||
#[inline]
|
|
||||||
pub fn right(&self) -> Vec3 {
|
|
||||||
self.local_x()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the unit vector in the local `Y` direction
|
|
||||||
#[inline]
|
|
||||||
pub fn local_y(&self) -> Vec3 {
|
|
||||||
self.rotation * Vec3::Y
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Equivalent to [`local_y()`][GlobalTransform::local_y]
|
|
||||||
#[inline]
|
|
||||||
pub fn up(&self) -> Vec3 {
|
|
||||||
self.local_y()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Equivalent to [`-local_y()`][GlobalTransform::local_y]
|
|
||||||
#[inline]
|
|
||||||
pub fn down(&self) -> Vec3 {
|
|
||||||
-self.local_y()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the unit vector in the local `Z` direction
|
|
||||||
#[inline]
|
|
||||||
pub fn local_z(&self) -> Vec3 {
|
|
||||||
self.rotation * Vec3::Z
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Equivalent to [`-local_z()`][GlobalTransform::local_z]
|
|
||||||
#[inline]
|
|
||||||
pub fn forward(&self) -> Vec3 {
|
|
||||||
-self.local_z()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Equivalent to [`local_z()`][GlobalTransform::local_z]
|
|
||||||
#[inline]
|
|
||||||
pub fn back(&self) -> Vec3 {
|
|
||||||
self.local_z()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[inline]
|
|
||||||
pub fn rotate(&mut self, rotation: Quat) {
|
|
||||||
self.rotation = rotation * self.rotation;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[inline]
|
|
||||||
pub fn rotate_around(&mut self, point: Vec3, rotation: Quat) {
|
|
||||||
self.translation = point + rotation * (self.translation - point);
|
|
||||||
self.rotate(rotation);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Multiplies `self` with `transform` component by component, returning the
|
|
||||||
/// resulting [`GlobalTransform`]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub fn mul_transform(&self, transform: Transform) -> Self {
|
|
||||||
let translation = self.mul_vec3(transform.translation);
|
|
||||||
let rotation = self.rotation * transform.rotation;
|
|
||||||
let scale = self.scale * transform.scale;
|
|
||||||
Self {
|
|
||||||
translation,
|
translation,
|
||||||
rotation,
|
rotation,
|
||||||
scale,
|
scale,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extracts `scale`, `rotation` and `translation` from `self`.
|
||||||
|
///
|
||||||
|
/// The transform is expected to be non-degenerate and without shearing, or the output
|
||||||
|
/// will be invalid.
|
||||||
|
#[inline]
|
||||||
|
pub fn to_scale_rotation_translation(&self) -> (Vec3, Quat, Vec3) {
|
||||||
|
self.0.to_scale_rotation_translation()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new identity [`GlobalTransform`], that maps all points in space to themselves.
|
||||||
|
#[inline]
|
||||||
|
pub const fn identity() -> Self {
|
||||||
|
Self(Affine3A::IDENTITY)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_local_axis!(right, left, X);
|
||||||
|
impl_local_axis!(up, down, Y);
|
||||||
|
impl_local_axis!(back, forward, Z);
|
||||||
|
|
||||||
|
/// Get the translation as a [`Vec3`].
|
||||||
|
#[inline]
|
||||||
|
pub fn translation(&self) -> Vec3 {
|
||||||
|
self.0.translation.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mutably access the internal translation.
|
||||||
|
#[inline]
|
||||||
|
pub fn translation_mut(&mut self) -> &mut Vec3A {
|
||||||
|
&mut self.0.translation
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the translation as a [`Vec3A`].
|
||||||
|
#[inline]
|
||||||
|
pub fn translation_vec3a(&self) -> Vec3A {
|
||||||
|
self.0.translation
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get an upper bound of the radius from the given `extents`.
|
||||||
|
#[inline]
|
||||||
|
pub fn radius_vec3a(&self, extents: Vec3A) -> f32 {
|
||||||
|
(self.0.matrix3 * extents).length()
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a [`Vec3`] of this [`Transform`] applied to `value`.
|
/// Returns a [`Vec3`] of this [`Transform`] applied to `value`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn mul_vec3(&self, mut value: Vec3) -> Vec3 {
|
pub fn mul_vec3(&self, v: Vec3) -> Vec3 {
|
||||||
value = self.scale * value;
|
self.0.transform_point3(v)
|
||||||
value = self.rotation * value;
|
|
||||||
value += self.translation;
|
|
||||||
value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
/// Multiplies `self` with `transform` component by component, returning the
|
||||||
#[inline]
|
/// resulting [`GlobalTransform`]
|
||||||
pub fn apply_non_uniform_scale(&mut self, scale: Vec3) {
|
pub fn mul_transform(&self, transform: Transform) -> Self {
|
||||||
self.scale *= scale;
|
Self(self.0 * transform.compute_affine())
|
||||||
}
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[inline]
|
|
||||||
pub fn look_at(&mut self, target: Vec3, up: Vec3) {
|
|
||||||
let forward = Vec3::normalize(self.translation - target);
|
|
||||||
let right = up.cross(forward).normalize();
|
|
||||||
let up = forward.cross(right);
|
|
||||||
self.rotation = Quat::from_mat3(&Mat3::from_cols(right, up, forward));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,11 +160,19 @@ impl Default for GlobalTransform {
|
|||||||
|
|
||||||
impl From<Transform> for GlobalTransform {
|
impl From<Transform> for GlobalTransform {
|
||||||
fn from(transform: Transform) -> Self {
|
fn from(transform: Transform) -> Self {
|
||||||
Self {
|
Self(transform.compute_affine())
|
||||||
translation: transform.translation,
|
}
|
||||||
rotation: transform.rotation,
|
}
|
||||||
scale: transform.scale,
|
|
||||||
}
|
impl From<Affine3A> for GlobalTransform {
|
||||||
|
fn from(affine: Affine3A) -> Self {
|
||||||
|
Self(affine)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Mat4> for GlobalTransform {
|
||||||
|
fn from(matrix: Mat4) -> Self {
|
||||||
|
Self(Affine3A::from_mat4(matrix))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,7 +181,7 @@ impl Mul<GlobalTransform> for GlobalTransform {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mul(self, global_transform: GlobalTransform) -> Self::Output {
|
fn mul(self, global_transform: GlobalTransform) -> Self::Output {
|
||||||
self.mul_transform(global_transform.into())
|
GlobalTransform(self.0 * global_transform.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use super::GlobalTransform;
|
use super::GlobalTransform;
|
||||||
use bevy_ecs::{component::Component, reflect::ReflectComponent};
|
use bevy_ecs::{component::Component, reflect::ReflectComponent};
|
||||||
use bevy_math::{Mat3, Mat4, Quat, Vec3};
|
use bevy_math::{Affine3A, Mat3, Mat4, Quat, Vec3};
|
||||||
use bevy_reflect::prelude::*;
|
use bevy_reflect::prelude::*;
|
||||||
use bevy_reflect::Reflect;
|
use bevy_reflect::Reflect;
|
||||||
use std::ops::Mul;
|
use std::ops::Mul;
|
||||||
@ -141,6 +141,13 @@ impl Transform {
|
|||||||
Mat4::from_scale_rotation_translation(self.scale, self.rotation, self.translation)
|
Mat4::from_scale_rotation_translation(self.scale, self.rotation, self.translation)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the 3d affine transformation matrix from this transforms translation,
|
||||||
|
/// rotation, and scale.
|
||||||
|
#[inline]
|
||||||
|
pub fn compute_affine(&self) -> Affine3A {
|
||||||
|
Affine3A::from_scale_rotation_translation(self.scale, self.rotation, self.translation)
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the unit vector in the local `X` direction.
|
/// Get the unit vector in the local `X` direction.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn local_x(&self) -> Vec3 {
|
pub fn local_x(&self) -> Vec3 {
|
||||||
@ -332,13 +339,11 @@ impl Default for Transform {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The transform is expected to be non-degenerate and without shearing, or the output
|
||||||
|
/// will be invalid.
|
||||||
impl From<GlobalTransform> for Transform {
|
impl From<GlobalTransform> for Transform {
|
||||||
fn from(transform: GlobalTransform) -> Self {
|
fn from(transform: GlobalTransform) -> Self {
|
||||||
Self {
|
transform.compute_transform()
|
||||||
translation: transform.translation,
|
|
||||||
rotation: transform.rotation,
|
|
||||||
scale: transform.scale,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,13 +320,7 @@ mod test {
|
|||||||
|
|
||||||
let mut state = app.world.query::<&GlobalTransform>();
|
let mut state = app.world.query::<&GlobalTransform>();
|
||||||
for global in state.iter(&app.world) {
|
for global in state.iter(&app.world) {
|
||||||
assert_eq!(
|
assert_eq!(global, &GlobalTransform::from_translation(translation));
|
||||||
global,
|
|
||||||
&GlobalTransform {
|
|
||||||
translation,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +112,7 @@ pub fn ui_focus_system(
|
|||||||
.iter_mut()
|
.iter_mut()
|
||||||
.filter_map(
|
.filter_map(
|
||||||
|(entity, node, global_transform, interaction, focus_policy, clip)| {
|
|(entity, node, global_transform, interaction, focus_policy, clip)| {
|
||||||
let position = global_transform.translation;
|
let position = global_transform.translation();
|
||||||
let ui_position = position.truncate();
|
let ui_position = position.truncate();
|
||||||
let extents = node.size / 2.0;
|
let extents = node.size / 2.0;
|
||||||
let mut min = ui_position - extents;
|
let mut min = ui_position - extents;
|
||||||
|
@ -283,7 +283,7 @@ pub fn extract_text_uinodes(
|
|||||||
>,
|
>,
|
||||||
) {
|
) {
|
||||||
let scale_factor = windows.scale_factor(WindowId::primary()) as f32;
|
let scale_factor = windows.scale_factor(WindowId::primary()) as f32;
|
||||||
for (entity, uinode, transform, text, visibility, clip) in uinode_query.iter() {
|
for (entity, uinode, global_transform, text, visibility, clip) in uinode_query.iter() {
|
||||||
if !visibility.is_visible() {
|
if !visibility.is_visible() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -305,15 +305,15 @@ pub fn extract_text_uinodes(
|
|||||||
let rect = atlas.textures[index];
|
let rect = atlas.textures[index];
|
||||||
let atlas_size = Some(atlas.size);
|
let atlas_size = Some(atlas.size);
|
||||||
|
|
||||||
let transform =
|
// NOTE: Should match `bevy_text::text2d::extract_text2d_sprite`
|
||||||
Mat4::from_rotation_translation(transform.rotation, transform.translation)
|
let extracted_transform = global_transform.compute_matrix()
|
||||||
* Mat4::from_scale(transform.scale / scale_factor)
|
* Mat4::from_scale(Vec3::splat(scale_factor.recip()))
|
||||||
* Mat4::from_translation(
|
* Mat4::from_translation(
|
||||||
alignment_offset * scale_factor + text_glyph.position.extend(0.),
|
alignment_offset * scale_factor + text_glyph.position.extend(0.),
|
||||||
);
|
);
|
||||||
|
|
||||||
extracted_uinodes.uinodes.push(ExtractedUiNode {
|
extracted_uinodes.uinodes.push(ExtractedUiNode {
|
||||||
transform,
|
transform: extracted_transform,
|
||||||
color,
|
color,
|
||||||
rect,
|
rect,
|
||||||
image: texture,
|
image: texture,
|
||||||
|
@ -108,7 +108,7 @@ fn update_clipping(
|
|||||||
let children_clip = match style.overflow {
|
let children_clip = match style.overflow {
|
||||||
Overflow::Visible => clip,
|
Overflow::Visible => clip,
|
||||||
Overflow::Hidden => {
|
Overflow::Hidden => {
|
||||||
let node_center = global_transform.translation.truncate();
|
let node_center = global_transform.translation().truncate();
|
||||||
let node_rect = Rect {
|
let node_rect = Rect {
|
||||||
min: node_center - node.size / 2.,
|
min: node_center - node.size / 2.,
|
||||||
max: node_center + node.size / 2.,
|
max: node_center + node.size / 2.,
|
||||||
|
@ -152,7 +152,7 @@ fn interact_bodies(mut query: Query<(&Mass, &GlobalTransform, &mut Acceleration)
|
|||||||
while let Some([(Mass(m1), transform1, mut acc1), (Mass(m2), transform2, mut acc2)]) =
|
while let Some([(Mass(m1), transform1, mut acc1), (Mass(m2), transform2, mut acc2)]) =
|
||||||
iter.fetch_next()
|
iter.fetch_next()
|
||||||
{
|
{
|
||||||
let delta = transform2.translation - transform1.translation;
|
let delta = transform2.translation() - transform1.translation();
|
||||||
let distance_sq: f32 = delta.length_squared();
|
let distance_sq: f32 = delta.length_squared();
|
||||||
|
|
||||||
let f = GRAVITY_CONSTANT / distance_sq;
|
let f = GRAVITY_CONSTANT / distance_sq;
|
||||||
|
@ -226,7 +226,7 @@ fn setup_scene_after_load(
|
|||||||
// a Sphere, and then back to an Aabb to find the conservative min and max points.
|
// a Sphere, and then back to an Aabb to find the conservative min and max points.
|
||||||
let sphere = Sphere {
|
let sphere = Sphere {
|
||||||
center: Vec3A::from(transform.mul_vec3(Vec3::from(aabb.center))),
|
center: Vec3A::from(transform.mul_vec3(Vec3::from(aabb.center))),
|
||||||
radius: (Vec3A::from(transform.scale) * aabb.half_extents).length(),
|
radius: transform.radius_vec3a(aabb.half_extents),
|
||||||
};
|
};
|
||||||
let aabb = Aabb::from(sphere);
|
let aabb = Aabb::from(sphere);
|
||||||
min = min.min(aabb.min());
|
min = min.min(aabb.min());
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//! Illustrates the difference between direction of a translation in respect to local object or
|
//! Illustrates the difference between direction of a translation in respect to local object or
|
||||||
//! global object Transform.
|
//! global object Transform.
|
||||||
|
|
||||||
use bevy::prelude::*;
|
use bevy::{math::Vec3A, prelude::*};
|
||||||
|
|
||||||
// Define a marker for entities that should be changed via their global transform.
|
// Define a marker for entities that should be changed via their global transform.
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
@ -129,7 +129,7 @@ fn move_cubes_according_to_global_transform(
|
|||||||
timer: Res<Time>,
|
timer: Res<Time>,
|
||||||
) {
|
) {
|
||||||
for mut global_transform in &mut cubes {
|
for mut global_transform in &mut cubes {
|
||||||
global_transform.translation += direction.0 * timer.delta_seconds();
|
*global_transform.translation_mut() += Vec3A::from(direction.0) * timer.delta_seconds();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user