bevyengine / bevy

A refreshingly simple data-driven game engine built in Rust
https://bevyengine.org
Apache License 2.0
34.88k stars 3.41k forks source link

Spherical Vec3 Representation in bevy::math #11004

Open dmyyy opened 8 months ago

dmyyy commented 8 months ago

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

It can be easier to reason about transforms in terms of spherical coordinates.

For example, say I want to position a camera facing the +x, -z quadrant (where the camera is in the -x, +z quadrant). The camera should be rotated 225 degrees on the xz-plane from the +x-axis, and 30 degrees above the xz plane relative to the origin. The camera should be 5 units away from the origin.

Doing something like this with the current api isn't very trivial.

let mut transform = Transform::from_xyz(5., 0., 0.);
transform.rotate_y(5 * PI / 4);
// find the axis perpendicular to the current transform on the xz plane
// rotate around that axis 30 degrees

Doing this via spherical coordinates is a one liner

Transform::from_spherical(5.0, PI / 3, 5 * PI / 4);

This makes writing a camera for a 3d platformer easy.

What solution would you like?

At the very least a from_spherical_coord(rho: f32, phi: f32, theta: f32) function in Transform.

Alternatively an explicit SphericalVec3 either in bevy::math or glam itself might be helpful.

struct SphericalVec3 {
    /// Distance from origin
    rho: f32,
    /// Angle from the +y-axis
    phi: f32,
    /// Angle from the +x-axis
    theta: f32,
}

What alternative(s) have you considered?

People can write this themselves or hack around it using the current bevy_math primitives. There's also https://crates.io/crates/lina which seems to have support for spherical coords.

Prior Art

Unreal 4 seems to support something related as part of their core math library: https://docs.unrealengine.com/4.27/en-US/API/Runtime/Core/Math/FVector/UnitCartesianToSpherical/

soqb commented 8 months ago

i wonder if we could implement a Spherical/Cylindrical wrapper (that works over all vectors), like Wrapping and Saturating.

rlidwka commented 8 months ago

Doing something like this with the current api isn't very trivial.

It is trivial. Should look something like that if I remember correctly:

Quat::from_euler(EulerRot::YXZ, PI / 3., 5. * PI / 4., 0.) * Transform::from_xyz(5., 0., 0.)
dmyyy commented 8 months ago

@rlidwka Thanks for this! I figured there was a way to do this using quaternions - unfortunately it's only trivial insofar as quaternions are trivial (which isn't really - at least from personal experience).

I was thinking this could be a nice middle ground for beginners (since I think spherical coordinates are easier to understand)

Octorine commented 7 months ago

i wonder if we could implement a Spherical/Cylindrical wrapper (that works over all vectors), like Wrapping and Saturating.

I implemented spherical and cylindrical coordinates for a project I was working on a while back . The coords.rs file from the linked repo could be a good starting point.

IQuick143 commented 4 months ago

I don't see a reason to be scared of quaternions in this example, all a person needs to know is that quaternions represent 3D rotations and Quat::from_euler let's me make a rotation.

I'm not against a spherical coordinate helper, although I'm not sure how generally useful it is, because spherical coordinates require a specifically chosen axis and angles, so they'll work great for as long as your application lines up with the chosen coordinates.

vveisard commented 4 months ago

I'm not against a spherical coordinate helper, although I'm not sure how generally useful it is, because spherical coordinates require a specifically chosen axis and angles, so they'll work great for as long as your application lines up with the chosen coordinates.

Spherical (and cylindrical) coordinates are very useful for describing relative positions of objects.