Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scale sprite z level by their scale #4156

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 45 additions & 16 deletions crates/bevy_sprite/src/render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use bevy_ecs::{
prelude::*,
system::{lifetimeless::*, SystemParamItem},
};
use bevy_math::{const_vec2, Vec2};
use bevy_math::{const_vec2, Quat, Vec2};
use bevy_reflect::Uuid;
use bevy_render::{
color::Color,
Expand Down Expand Up @@ -171,9 +171,14 @@ impl SpecializedPipeline for SpritePipeline {
}
}

/// Extracted informations about a [`Sprite`] used to render it.
#[derive(Component, Clone, Copy)]
pub struct ExtractedSprite {
mockersf marked this conversation as resolved.
Show resolved Hide resolved
pub transform: GlobalTransform,
/// 2d extracted transform from the sprite [`GlobalTransform`]
pub transform: Extracted2dTransform,
/// Z layer at which the sprite should be shown
pub z_layer: f32,
/// Color of the sprite
pub color: Color,
/// Select an area of the texture
pub rect: Option<Rect>,
Expand All @@ -182,10 +187,30 @@ pub struct ExtractedSprite {
/// Handle to the `Image` of this sprite
/// PERF: storing a `HandleId` instead of `Handle<Image>` enables some optimizations (`ExtractedSprite` becomes `Copy` and doesn't need to be dropped)
pub image_handle_id: HandleId,
/// Is it flipped along the X axis
pub flip_x: bool,
/// Is it flipped along the Y axis
pub flip_y: bool,
}

/// A 2d representation of a [`GlobalTransform`] for an [`ExtractedSprite`]
#[derive(Clone, Copy)]
pub struct Extracted2dTransform {
/// The 2d position
pub translation: Vec2,
/// The 2d scale
pub scale: Vec2,
/// The rotation
pub rotation: Quat,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it feels wrong to keep a Quat for rotations, but I'm not sure if keeping only two axis of rotations would be enough here. I feel it would, which would probably make it faster?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we only need a single 2D rotation axis?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

heh 3d rotations in 2d are one of the things where I give up usually...

Copy link
Member

@DJMcNab DJMcNab Mar 8, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can use Quat::mul_vec3 with Vec3::X, and truncate that. We then get the angle from that Vec2, e.g. Vec2::angle_between with Vec2::X.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can use Quat::mul_vec3 with Vec3::X

that's exactly what local_x() does, so it's simply

Vec2::X.angle_between(transform.local_x().truncate())

"Get the angle between the global x-axis and the local x unit-vector"

}

impl Extracted2dTransform {
#[inline]
fn mul_vec2(&self, value: Vec2) -> Vec2 {
(self.rotation * (self.scale * value).extend(0.0)).truncate() + self.translation
}
}

#[derive(Default)]
pub struct ExtractedSprites {
pub sprites: Vec<ExtractedSprite>,
Expand Down Expand Up @@ -240,7 +265,12 @@ pub fn extract_sprites(
// PERF: we don't check in this function that the `Image` asset is ready, since it should be in most cases and hashing the handle is expensive
extracted_sprites.sprites.alloc().init(ExtractedSprite {
color: sprite.color,
transform: *transform,
transform: Extracted2dTransform {
translation: transform.translation.truncate(),
scale: transform.scale.truncate(),
rotation: transform.rotation,
},
z_layer: transform.translation.z * transform.scale.z,
// Use the full texture
rect: None,
// Pass the custom size
Expand All @@ -258,7 +288,12 @@ pub fn extract_sprites(
let rect = Some(texture_atlas.textures[atlas_sprite.index as usize]);
extracted_sprites.sprites.alloc().init(ExtractedSprite {
color: atlas_sprite.color,
transform: *transform,
transform: Extracted2dTransform {
translation: transform.translation.truncate(),
scale: transform.scale.truncate(),
rotation: transform.rotation,
},
z_layer: transform.translation.z * transform.scale.z,
// Select the area in the texture atlas
rect,
// Pass the custom size
Expand Down Expand Up @@ -393,16 +428,9 @@ pub fn queue_sprites(
transparent_phase.items.reserve(extracted_sprites.len());

// Sort sprites by z for correct transparency and then by handle to improve batching
extracted_sprites.sort_unstable_by(|a, b| {
match a
.transform
.translation
.z
.partial_cmp(&b.transform.translation.z)
{
Some(Ordering::Equal) | None => a.image_handle_id.cmp(&b.image_handle_id),
Some(other) => other,
}
extracted_sprites.sort_unstable_by(|a, b| match a.z_layer.partial_cmp(&b.z_layer) {
Some(Ordering::Equal) | None => a.image_handle_id.cmp(&b.image_handle_id),
Some(other) => other,
});

// Impossible starting values that will be replaced on the first iteration
Expand Down Expand Up @@ -489,12 +517,13 @@ pub fn queue_sprites(
let positions = QUAD_VERTEX_POSITIONS.map(|quad_pos| {
extracted_sprite
.transform
.mul_vec3((quad_pos * quad_size).extend(0.))
.mul_vec2(quad_pos * quad_size)
.extend(extracted_sprite.z_layer)
.into()
});

// 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.z_layer);

// Store the vertex data and add the item to the render phase
if current_batch.colored {
Expand Down
9 changes: 7 additions & 2 deletions crates/bevy_text/src/text2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use bevy_ecs::{
};
use bevy_math::{Size, Vec3};
use bevy_render::{texture::Image, view::Visibility, RenderWorld};
use bevy_sprite::{ExtractedSprite, ExtractedSprites, TextureAtlas};
use bevy_sprite::{Extracted2dTransform, ExtractedSprite, ExtractedSprites, TextureAtlas};
use bevy_transform::prelude::{GlobalTransform, Transform};
use bevy_window::{WindowId, Windows};

Expand Down Expand Up @@ -92,7 +92,12 @@ pub fn extract_text2d_sprite(
let transform = text_transform.mul_transform(glyph_transform);

extracted_sprites.sprites.push(ExtractedSprite {
transform,
transform: Extracted2dTransform {
translation: transform.translation.truncate(),
scale: transform.scale.truncate(),
rotation: transform.rotation,
},
z_layer: transform.translation.z * transform.scale.z,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
z_layer: transform.translation.z * transform.scale.z,
z_layer: transform.translation.z,

The sprite has 0 width, changing the depth here based on the scale doesn't make sense.

color,
rect,
custom_size: None,
Expand Down
7 changes: 2 additions & 5 deletions crates/bevy_transform/src/components/global_transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,11 +212,8 @@ impl GlobalTransform {

/// Returns a [`Vec3`] of this [`Transform`] applied to `value`.
#[inline]
pub fn mul_vec3(&self, mut value: Vec3) -> Vec3 {
value = self.scale * value;
value = self.rotation * value;
value += self.translation;
value
pub fn mul_vec3(&self, value: Vec3) -> Vec3 {
self.rotation * (self.scale * value) + self.translation
}

#[doc(hidden)]
Expand Down
7 changes: 2 additions & 5 deletions crates/bevy_transform/src/components/transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,11 +222,8 @@ impl Transform {

/// Returns a [`Vec3`] of this [`Transform`] applied to `value`.
#[inline]
pub fn mul_vec3(&self, mut value: Vec3) -> Vec3 {
value = self.scale * value;
value = self.rotation * value;
value += self.translation;
value
pub fn mul_vec3(&self, value: Vec3) -> Vec3 {
self.rotation * (self.scale * value) + self.translation
}

/// Changes the `scale` of this [`Transform`], multiplying the current `scale` by
Expand Down