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

Enhance 2D Transform/Vec2 Quality of Life #2548

Open
notverymoe opened this issue Jul 26, 2021 · 3 comments
Open

Enhance 2D Transform/Vec2 Quality of Life #2548

notverymoe opened this issue Jul 26, 2021 · 3 comments
Labels
A-Transform Translations, rotations and scales C-Feature A new feature, making something new possible C-Usability A targeted quality-of-life change that makes Bevy easier to use D-Complex Quite challenging from either a design or technical perspective. Ask for help! S-Needs-Design-Doc This issue or PR is particularly complex, and needs an approved design doc before it can be merged X-Controversial There is active debate or serious implications around merging this PR

Comments

@notverymoe
Copy link
Contributor

notverymoe commented Jul 26, 2021

What problem does this solve or what need does it fill?

Currently working with transforms in 2D space is a second-class experience, as the user is responsible for truncating Vec3s from Transforms, extending Vec2s to apply them to Transforms and dealing with quite a few calculations for the go-between of Z-Axis angle <-> Quaternion (ie. x_axis.y.atan2(x_axis.x) and Quat::from_axis_angle(Vec2::Z, angle).

One particularly of irritation for 2D work is that you can't work directly with the struct values without manually extending/truncating each value.

This makes a lot of 2D code look messy, ultimately pushing the user to implement their own helper methods that:

  1. Require them to have an decent understanding of the math behind 2D transformations, and how to extend them into 3D. Which is good to have, but could push newer users away by front-loading them.
  2. Create accidental incompatibilities between 2D libraries that implement their helpers using different conventions.

What solution would you like?

I would like Transform & Vec2 (and potentially Mat3 for completeness) to provide functions useful for clean, clear, optimal and concise transformations in 2D space and define the convention.

What alternative(s) have you considered?

A Transform2D component would be more ideal, but that seems to go against the resolution of #229 / #374.

Provide a feature that converts Transform to a purely 2D representation (PosX, PosY, Layer, Angle, ScaleX, Scaley). This would be smaller and ideal for a purely 2D game, which is where I imagine these methods will have the most use. I've implemented this in the past and it required very few changes in the engine itself. Issue being that it complicates code that should work for both transform types and makes it so you can't have mixed-2D/3D applications without completely falling back to 3D.

Related

Could be seen as related to #501, however that seems to be focused more general/3D QoL, such as Transforms with Transforms

@notverymoe notverymoe added C-Feature A new feature, making something new possible S-Needs-Triage This issue needs to be labelled labels Jul 26, 2021
@notverymoe
Copy link
Contributor Author

notverymoe commented Jul 26, 2021

One Possible List of Methods

I want to propose that Transform provides 2d alternatives of the following methods:

  • Transform::from_matrix - Mat3 -> Transform
  • Transform::from_translation - Translation with z=0
  • Transform::from_rotation - Rotation around Z
  • Transform::from_scale - Scale with z=1
  • Transform::looking_at - Orients +x towards target
  • Transform::compute_matrix - Transform -> Mat3
  • Transform::local_x
  • Transform::left
  • Transform::right
  • Transform::local_y
  • Transform::up
  • Transform::down
  • Transform::mul_vec3 - Apply transform as if it has a Mat3
  • Transform::apply_non_uniform_scale - Applies non-uniform scale with Z=1
  • Transform::look_at - See looking_at

Additionally to assist with relative modifications without constructing full transforms and apply-ing them, the following should be added:

  • Transform::add_translation - 2D*/3D variants, equivalent to self.translation += value;
  • Transform::sub_translation - 2D*/3D variants, equivalent to self.translation -= value;
  • Transform::set_translation - 2D*/3D variants, equivalent to self.translation = value;
  • Transform::add_scale - 2D*/3D variants, equivalent to self.scale += value;
  • Transform::sub_scale - 2D*/3D variants, equivalent to self.scale -= value;
  • Transform::set_scale - 2D*/3D variants, equivalent to self.scale = value;
  • Transform::get_angle_x/y/z** - 2D***/3D variants, returns the angle on a particular axis
  • Transform::set_angle_x/y/z** - 2D***/3D variants, equivalent to self.rotation = Quat::from_axis_angle(axis, angle);
  • Transform::add_angle_x/y/z** - 2D***/3D variants, equivalent to self.rotation *= Quat::from_axis_angle(axis, angle);
  • Transform::sub_angle_x/y/z** - 2D***/3D variants, equivalent to self.rotation *= Quat::from_axis_angle(axis, -angle);

Unsure if we require specialized 2D/3D functions for mul/div for Vecs and Scalars. In most cases scale mul/div can be applied directly, scaling z-scale doesn't affect 2D (But would for 2.5D games) and it would be fairly strange to multiply translation (though if you normalized it first, then scaled, I could see it being used to fix something to a circle?) but could cause issues with the z-axis being scaled and changing the layering.

* 2D variants will extend the input to preserve the 3D value's extra data. For example add would extend with 0.0, whilst mul would extend with 1.0.

** We could also add variants for left, right, up, down, forward, back to match with the axis functions.

*** 2D only requires angle_z, which could be called angle_2d for the variant, and can be expressed as let axis = self.local_x(); return axis.y.atan2(axis.x), though there might be some faster Quat magic I'm unaware of.

With Vec2 some helper functions to establish convention and provide common utility present in other engines, and would require the addition of:

  • Vec2::from_angle -> Vec2::new(angle.cos(), angle.sin());
  • Vec2::angle -> self.y.atan2(self.x);
  • Vec2::rotate_by_angle -> self.rotate_by_norm(Vec2::from_angle(angle));
  • Vec2::rotate_by_norm -> *self = Self::new(self.x*norm.x - self.y*norm.y, self.x*norm.y + self.y*norm.x);
  • Vec2::rotated_by_angle - Copy version of rotate_by_angle
  • Vec2::rotated_by_norm - Copy version of rotate_by_norm

These helper functions would establish ccw rotations on the xy-plane, +x being 0deg/rad, which I believe is the "industry-standard", right?

If we're being greedy/complete, we could also add some helper methods to Mat3. Mostly for constructing/destructing TRS matrices.

@alice-i-cecile alice-i-cecile added A-Core C-Usability A targeted quality-of-life change that makes Bevy easier to use S-Needs-Design-Doc This issue or PR is particularly complex, and needs an approved design doc before it can be merged and removed S-Needs-Triage This issue needs to be labelled labels Jul 26, 2021
@blaind
Copy link
Contributor

blaind commented Aug 2, 2021

I'll chime in here, although my needs are more for 3d space. Personally, I'd like to have a way to construct a Transform with a shorthand method, where:

  1. Translation + rotation: Transform::from_xyz(...).looking_at(...) = DONE
  2. Translation + scale: Transform::from_xyz(...).scale_by(vector) // scaling multiplication
  3. Translation + scale: Transform::from_xyz(...).scale_by(scalar)

and maybe

  1. Rotation + translation: Transform::from_rotation(...).translate_tox, y, z) // or better named method for setting the translation to specific point

@nathanfranke
Copy link

I think Transform should be Transform3D, with Transform2D a separate type.

@alice-i-cecile alice-i-cecile added A-Transform Translations, rotations and scales D-Complex Quite challenging from either a design or technical perspective. Ask for help! X-Controversial There is active debate or serious implications around merging this PR and removed A-Core labels Nov 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Transform Translations, rotations and scales C-Feature A new feature, making something new possible C-Usability A targeted quality-of-life change that makes Bevy easier to use D-Complex Quite challenging from either a design or technical perspective. Ask for help! S-Needs-Design-Doc This issue or PR is particularly complex, and needs an approved design doc before it can be merged X-Controversial There is active debate or serious implications around merging this PR
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants