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

Conversation

mockersf
Copy link
Member

@mockersf mockersf commented Mar 8, 2022

Objective

  • Fix Parent scale.z affects child sprite z-index #4149
  • Apply the sprite own scale on the z axis
    • the scale was already applied to other axis
    • the scale on z axis of parents was already applied
    • => only the z axis scale of a sprite own transform was not used

Solution

  • scale the sprite z axis by its scale.
    • as the multiplication was done several times, I factored it in its own parameter to do it only once
    • after extracting it, keeping the transform in 3d isn't as useful, so I changed it to a 2d transform
    • changing the new mul_vec2 to a single line has an impact, so I also changed mul_vec3 on transforms
fps before after
many_sprites 68~69 77~79
bevymark 1300 100 49~50 52
bevymark 10000 100 7 8~10

@github-actions github-actions bot added the S-Needs-Triage This issue needs to be labelled label Mar 8, 2022
pub struct Transform2d {
pub translation: Vec2,
pub scale: Vec2,
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"

@mockersf mockersf changed the title extracted sprites use a 2d transform separated from its z level Scale sprite z level by their scale Mar 8, 2022
@alice-i-cecile alice-i-cecile added A-Rendering Drawing game state to the screen A-Transform Translations, rotations and scales C-Bug An unexpected or incorrect behavior and removed S-Needs-Triage This issue needs to be labelled labels Mar 8, 2022
@alice-i-cecile
Copy link
Member

Are the numbers in the table linked above FPS?

@mockersf
Copy link
Member Author

mockersf commented Mar 8, 2022

yes but I 🤦 in the name of the columns fixed

value += self.translation;
value
pub fn mul_vec3(&self, value: Vec3) -> Vec3 {
self.rotation * self.scale * value + self.translation
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
self.rotation * self.scale * value + self.translation
self.scale * self.rotation * value + self.translation

Let's keep the ordering consistent here.

Copy link
Member Author

@mockersf mockersf Mar 8, 2022

Choose a reason for hiding this comment

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

I'm not sure those are commutatives. I added parentheses to make sure it happens in the right order

Copy link
Member

Choose a reason for hiding this comment

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

Is this change necessary (turning the 3 lines into 1)? I would think the compiler optimises it to the same result, and the existing notation is a lot clearer about the order of operations imo.

Though mockersf is right, it definitely should be scale applied to value first, then multiplied by rotation, then lastly translation added. perhaps translation + rotation * (scale * value) is nicer?

Copy link
Member

Choose a reason for hiding this comment

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

I like to be clear that we're following SRT here: it's much cleaner at a glance if we're adding Translation last.

Copy link
Member

Choose a reason for hiding this comment

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

It's a matter of perspective I guess; If you were to consider Scale, Rotation, Translation as independent transformations that you compose like

translate(rotate(scale(value)))

Then it's a lot more visually similar imo, since the order of operations is

translation + (rotation * (scale * value))

It only looks inside out compared to the "SRT" acronym because the inner-most (farthest right) function is applied to the value first

pub rotation: Quat,
}

impl Transform2d {
Copy link
Member

Choose a reason for hiding this comment

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

There are a large number of convenience methods and conversions I would like for this, but IMO we should keep the scope of this PR small.

@@ -186,6 +187,20 @@ pub struct ExtractedSprite {
pub flip_y: bool,
}

#[derive(Clone, Copy)]
pub struct Transform2d {
Copy link
Member

Choose a reason for hiding this comment

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

I feel quite strongly that this should be used in the public APIs for both UI and sprites, along with a public z-layer component. I'm not sure if this PR is the place for it though.

Copy link

@heavyrain266 heavyrain266 Mar 8, 2022

Choose a reason for hiding this comment

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

This should be done in it's own PR to not go out of scope for this one.

Copy link
Member Author

Choose a reason for hiding this comment

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

I renamed the struct to make it clear it is not to be used as a general Transform2d

@alice-i-cecile
Copy link
Member

So, as much as I desperately want "dedicated 2D coordinates in user-facing APIs", I don't think this PR is the place to make that change.

It will require quite a bit of churn (and lots of convenience methods). I'd rather not block a serious performance win + bug fix on that; we can use the types defined here in SpriteBundle and so on later.

Copy link
Member

@DJMcNab DJMcNab left a comment

Choose a reason for hiding this comment

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

The perf changes seem good.

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.

pub struct Transform2d {
pub translation: Vec2,
pub scale: Vec2,
pub rotation: Quat,
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.

@mockersf
Copy link
Member Author

we should move to a more complete 2d Transform rather than a in between solution like this

@mockersf mockersf closed this Mar 13, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Rendering Drawing game state to the screen A-Transform Translations, rotations and scales C-Bug An unexpected or incorrect behavior
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Parent scale.z affects child sprite z-index
5 participants