Giter VIP home page Giter VIP logo

glam-rs's Introduction

glam

Build Status Coverage Status Latest Version docs Minimum Supported Rust Version

A simple and fast 3D math library for games and graphics.

Development status

glam is in beta stage. Base functionality has been implemented and the look and feel of the API has solidified.

Features

  • f32 types
    • vectors: Vec2, Vec3, Vec3A and Vec4
    • square matrices: Mat2, Mat3, Mat3A and Mat4
    • a quaternion type: Quat
    • affine transformation types: Affine2 and Affine3A
  • f64 types
    • vectors: DVec2, DVec3 and DVec4
    • square matrices: DMat2, DMat3 and DMat4
    • a quaternion type: DQuat
    • affine transformation types: DAffine2 and DAffine3
  • i16 types
    • vectors: I16Vec2, I16Vec3 and I16Vec4
  • u16 types
    • vectors: U16Vec2, U16Vec3 and U16Vec4
  • i32 types
    • vectors: IVec2, IVec3 and IVec4
  • u32 types
    • vectors: UVec2, UVec3 and UVec4
  • i64 types
    • vectors: I64Vec2, I64Vec3 and I64Vec4
  • u64 types
    • vectors: U64Vec2, U64Vec3 and U64Vec4
  • bool types
    • vectors: BVec2, BVec3 and BVec4

SIMD

The Vec3A, Vec4, Quat, Mat2, Mat3A, Mat4, Affine2 and Affine3A types use 128-bit wide SIMD vector types for storage on x86, x86_64 and wasm32 architectures. As a result, these types are all 16 byte aligned and depending on the size of the type or the type's members, they may contain internal padding. This results in some wasted space in the cases of Vec3A, Mat3A, Affine2 and Affine3A. However, the use of SIMD generally results in better performance than scalar math.

glam outperforms similar Rust libraries for common operations as tested by the mathbench project.

Enabling SIMD

SIMD is supported on x86, x86_64 and wasm32 targets.

  • SSE2 is enabled by default on x86_64 targets.
  • To enable SSE2 on x86 targets add -C target-feature=+sse2 to RUSTCFLAGS.
  • NEON is enabled by default on aarch64 targets.
  • To enable NEON on aarch64 targets add -C target-feature=+neon to RUSTFLAGS.
  • To enable simd128 on wasm32 targets add -C target-feature=+simd128 to RUSTFLAGS.
  • Experimental portable simd support can be enabled with the core-simd feature. This requires the nightly compiler as it is still unstable in Rust.

Note that SIMD on wasm32 passes tests but has not been benchmarked, performance may or may not be better than scalar math.

no_std support

no_std support can be enabled by compiling with --no-default-features to disable std support and --features libm for math functions that are only defined in std. For example:

[dependencies]
glam = { version = "0.28", default-features = false, features = ["libm"] }

To support both std and no_std builds in project, you can use the following in your Cargo.toml:

[features]
default = ["std"]

std = ["glam/std"]
libm = ["glam/libm"]

[dependencies]
glam = { version = "0.28", default-features = false }

Optional features

  • approx - traits and macros for approximate float comparisons
  • bytemuck - for casting into slices of bytes
  • libm - uses libm math functions instead of std, required to compile with no_std
  • mint - for interoperating with other 3D math libraries
  • rand - implementations of Distribution trait for all glam types.
  • serde - implementations of Serialize and Deserialize for all glam types. Note that serialization should work between builds of glam with and without SIMD enabled
  • rkyv - implementations of Archive, Serialize and Deserialize for all glam types. Note that serialization is not interoperable with and without the scalar-math feature. It should work between all other builds of glam. Endian conversion is currently not supported
  • bytecheck - to perform archive validation when using the rkyv feature

Feature gates

  • scalar-math - compiles with SIMD support disabled
  • debug-glam-assert - adds assertions in debug builds which check the validity of parameters passed to glam to help catch runtime errors
  • glam-assert - adds validation assertions to all builds
  • cuda - forces glam types to match expected cuda alignment
  • fast-math - By default, glam attempts to provide bit-for-bit identical results on all platforms. Using this feature will enable platform specific optimizations that may not be identical to other platforms. Intermediate libraries should not use this feature and defer the decision to the final binary build.
  • core-simd - enables SIMD support via the portable simd module. This is an unstable feature which requires a nightly Rust toolchain and std support.

Minimum Supported Rust Version (MSRV)

The minimum supported version of Rust for glam is 1.68.2.

Conventions

Column vectors

glam interprets vectors as column matrices (also known as "column vectors") meaning when transforming a vector with a matrix the matrix goes on the left, e.g. v' = Mv. DirectX uses row vectors, OpenGL uses column vectors. There are pros and cons to both.

Column-major order

Matrices are stored in column major format. Each column vector is stored in contiguous memory.

Co-ordinate system

glam is co-ordinate system agnostic and intends to support both right-handed and left-handed conventions.

Design Philosophy

The design of this library is guided by a desire for simplicity and good performance.

  • No generics and minimal traits in the public API for simplicity of usage
  • All dependencies are optional (e.g. mint, rand and serde)
  • Follows the Rust API Guidelines where possible
  • Aiming for 100% test coverage
  • Common functionality is benchmarked using Criterion.rs

Architecture

See ARCHITECTURE.md for details on glam's internals.

Inspirations

There were many inspirations for the interface and internals of glam from the Rust and C++ worlds. In particular:

License

Licensed under either of

at your option.

Contribution

Contributions in any form (issues, pull requests, etc.) to this project must adhere to Rust's Code of Conduct.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

If you are interested in contributing or have a request or suggestion start a discussion on GitHub. See CONTRIBUTING.md for more information for contributors.

Most code in glam is generated, see the codegen README for details.

Thank you to all of the glam contributors!

Support

The Game Development in Rust Discord and Bevy Engine Discord servers are not official support channels but can be good places to ask for help with glam.

Attribution

glam contains code ported from the following C++ libraries:

  • DirectXMath - MIT License - Copyright (c) 2011-2020 Microsoft Corp
  • Realtime Math - MIT License - Copyright (c) 2018 Nicholas Frechette
  • GLM - MIT License - Copyright (c) 2005 - G-Truc Creation

See ATTRIBUTION.md for details.

glam-rs's People

Contributors

ababwa avatar aloucks avatar atlv24 avatar basro avatar benfrankel avatar bitshifter avatar cessen avatar chompaa avatar cleancut avatar deprilula28 avatar emilk avatar fu5ha avatar irate-devil avatar iwikal avatar kawogi avatar khyperia avatar marijns95 avatar mattbork avatar matthias-fauconneau avatar michal-z avatar mrgunflame avatar msvbg avatar neo-zhixing avatar oisyn avatar rafalh avatar repi avatar specificprotagonist avatar virxec avatar waywardmonkeys avatar xampprocky avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

glam-rs's Issues

no_std support

You mention in the readme that you'd like to have no_std support, what are the current blockers?

Implement common traits for `Vec*Mask` types

The VecNMask types were initially "intermediary" types which were output by VecN::cmp* functions. They have a bit more functionality now so it would be good to make sure they support common traits from the Rust API guidelines https://rust-lang-nursery.github.io/api-guidelines/interoperability.html#types-eagerly-implement-common-traits-c-common-traits

That list is:

  • Copy
  • Clone
  • Eq
  • PartialEq
  • Ord
  • PartialOrd
  • Hash
  • Debug
  • Display
  • Default
  • AsRef

Probably the most useful ones would be Debug, PartialEq and Eq to start with.

Usually with glam types I make the scalar-math version derive the trait and then make the SIMD version match the scalar behaviour. Although in the case of this type it might make sense for debug to show hex values of the u32 elements and possibly make Display show as bool.

Remove custom Debug implementations and add Display for all types

Debug is currently implemented so that it prints the same whether using _m128 or scalar implementation.

The fmt docs state:

fmt::Debug implementations should be implemented for all public types. Output will typically represent the internal state as faithfully as possible. The purpose of the Debug trait is to facilitate debugging Rust code. In most cases, using #[derive(Debug)] is sufficient and recommended.

So glam should probably do that.

Conversely Display should be implemented for all types, it's currently missing for Mat2, Mat3 and Mat4. See https://rust-lang-nursery.github.io/api-guidelines/interoperability.html

Unnecessary handedness in rotation explanation

In the landing page of the documentation at https://docs.rs/glam you can read the following:

Rotations follow left-hand rule. The direction of the axis gives the direction of rotation: with the left thumb pointing in the positive direction of the axis the left fingers curl around the axis in the direction of the rotation.

Then follows his code:

// rotate +x 90 degrees clockwise around y giving -z
let m = Mat3::from_rotation_y(90.0_f32.to_radians());
let v = m * Vec3::unit_x();
assert!(v.abs_diff_eq(-Vec3::unit_z(), core::f32::EPSILON));

The thing is: quarternion rotations are not tied to any frame or handedness. For left-handed coordinate systems it follows left-hand rule, and for right-handed coordinate systems it follows right-hand rule. Consider a right handed X-Y-Z system. 90 deg rotation around Y would bring +X to the -Z direction, just like the example above.

So the above paragraph muddies the waters and may unnecessarily scare away people who use right-handed systems.

SUMMARY: glam is (mostly) handedness agnostic. I think it would help the project to say so up-front, instead of implying the opposite!

to euler angles

I have seen some people wanting to extract euler angles from Quaternion and Matrix rotations. Then I've seen others disparaging them for using euler angles. Euler angles are commonly used in editors and while we can create glam rotations from euler angles there's currently no support for going the other way. I don't want to encourage using euler angles where they aren't appropriate but there might be legitimate use cases where providing this functionality would be appropriate.

Missing serialization support for Mat2/Mat3/Mat4

Was experimenting with glam as a potential replacement for us for nalgebra-glm and one of the first issues I ran into was that the Mat2, Mat3 and Mat4 types was missing serde serialization support.

Currently it is only implemented for Vec2, Vec3, Vec4 and Quat in glam_serde.rs but likely shouldn't be too hard to add support for matrix types as well?.

travis job is not linked to PR actions

The travis job is running but the result isn't showing up in the list of checks so nobody is being notified of failed builds.

I suspect this started happening when github actions were enabled.

I was notified about this in PR #52.

I found this action which looks like it can be set up to run travis on push and pull requests https://github.com/travis-ci/actions

Migrate from Travis to GitHub Actions

Having a github action for cargo deny seems to have broken travis builds for PRs, which is unfortunate. I think most likely the simplest thing to do is to migrate entirely to github actions. Also needs to work with code coverage.

Edit: the travis builds still happen for PRs but they don't appear in GitHub, at least they don't on success.

Remove approx and rand from default features

approx and rand define traits which must be implemented inside glam for them to be used in test and bench executables. Unfortunately this means they must be enabled by default so that a simple cargo test or cargo bench will work without needing to specify additional features. I'd rather not enable them by default.

For the purposes of glam's tests and benches it is probably easier to implement a simple non-crypto rand and some approx eq functions.

glam could use it's own approx_eq functions anyway as we don't re-export the approx crate, I'd prefer not to need users to have to import traits for this and the approx traits aren't documented much.

The rand crate is quite complex and we're not concerned with crypto strength random numbers for the purposes of our unit tests.

The current implementations of approx and rand can be kept unless it becomes a burden to maintain them.

  • approx
  • rand

Merge SIMD and f32 implementations into the same file

At the moment different implementations are split into different modules, e.g. for Vec4:

  • vec4_f32.rs - scalar f32 struct Vec4 declaration and implementation
  • vec4_sse2.rs - SSE2 SIMD struct Vec4 declaration and implementation
  • vec4.rs - common methods use by both implementations

The advantages of doing things this way are:

  • Keeps different implementations separate, so there's no need for #[cfg(...)] blocks everywhere, just where the modules are imported
  • The code is simple - if you are debugging SSE2 it's straight Rust code and just the SSE2 implementation

However, there are a number of downsides to this approach:

  • The interface needs to be duplicated for each implementation - this is mitigated somewhat by ensuring the interface has 100% test coverage.
  • Documentation also needs to be duplicated for each implementation - this is a bit more annoying
  • Adding additional architectures will start to make the library difficult to maintain due to the above issues

I'm looking at alternatives to the current approach including using cfg-if and some other ideas I'm trying out.

Consider providing SIMD `From` conversions for mask types

Hi, and thanks for writing this amazing library! I have been using it in some projects and have occasionally needed to write some SIMD intrinsics that operate directly on the SIMD types in this library. You can do it now in a messy way with unsafe raw pointer casts, but it feels a little unnecessary. It would be super useful to make the struct members that are currently marked as pub(crate) just pub, so that the underlying SIMD types could be easily accessed directly.

I guess the downside to this is that depending on which configuration you are using to build the library, you would end up with different struct members. In practice, this would mean the caller would also have to gate their code on the build configuration, but this seems reasonable to me. But if this is a step too far, then perhaps an alternative approach would be to add an extra "direct access" trait for the SIMD types only?

Is this something that could be considered? If so, I'd be happy to prepare a contribution, if you could provide some guidance on what approach fits best.

impl Add<Quat> and Sub<Quat> for Quat

In short: Through a somewhat complicated chain of traits and supertraits in multiple different libraries, I've found myself needing glam::Quat to implement addition and subtraction. I've started working on a PR.

In long: I'm trying to implement skeletal animation for the bevy engine. They use glam, and rotations are represented by your quaternions. We're looking to use the splines crate to handle interpolation between keyframes, which is a very generic crate. It does however require the supplied type to implement addition and subtraction, and through a shim I've managed to get it working, but at the cost of user convenience. The splines crate provides implementations of its traits for a number of external math crates, but I am unable to add support for glam because of the requirement of these ops.

I understand that adding support for addition and subtraction ops might mislead users who are trying to combine rotations, but perhaps with good documentation we can mitigate this risk and steer them towards correct usage.

Add an affine transform matrix type.

I've been poking at Psychopath a bit again, and I realized that in the context of a ray tracer you pretty much never need full projective transforms, you only need affine transforms. And this presents a lot of opportunities for optimization:

  • An affine transform matrix only needs to store 4x3 floats, not 4x4, because the fourth row is implicitly known.
  • Transforming points/vectors can be further optimized due to the statically-known implicit fourth row.
  • Matrix inversion can also be further optimized.
  • There are tricks for directly performing inverse transforms on points/vectors that are more efficient than fully inverting the matrix + transforming.

I'm mainly filing this issue to find out if this is something you'd be interested in including in Glam. If so, then when I get some time (which might be a while) I'll take a crack at implementing this. If not, I'll just create my own custom type in Psychopath.

Remove Angle?

Have there been any thoughts about keeping or removing the Angle type?

I'm a bit conflicted but it feels a bit out of place to have a higher level type wrapper like Angle to make radians vs degrees explicit and safe, but at the same time not have a type such as Point3.

I'm not proposing to add a Point3 though and think it is good to just have the core primitive types here.

I do like the explicitness of Angle::from_radians but I could just as well see glam declaring that all angles are radians (which is how they are stored anyway) and that is how we've have defined inside our engine as well.

So I do have a slight preference to simply not having an Angle type, and wanted to start a discussion to see what @bitshifter and everyone else thinks.

Coordinate system agnostic

glam is mostly agnostic to coordinate systems and handedness - and I think that's great. When a choice must be made, glam often leaves it to the user to pick, like with orthographic_lh + orthographic_rh.

There is, however, one exception to this rule: from_rotation_ypr (found in Quat, Mat3 and Mat4).

On Mat3::from_rotation_ypr the documentation simply says Creates a 3x3 rotation matrix from the given Euler angles (in radians). which is deceptive, as it implies only one way to construct such a matrix from yaw/pitch/roll.

Quat::from_rotation_ypr is better, and states: "Create a quaternion from the given yaw (around y), pitch (around x) and roll (around z) in radians.". It still neglects to mention the order. Is this Quat::from_axis_angle(Y, yaw) * Quat::from_axis_angle(X, pitch) * Quat::from_axis_angle(Z, roll) or Quat::from_axis_angle(Z, roll) * Quat::from_axis_angle(X, pitch) * Quat::from_axis_angle(Y, yaw) ?

But the deeper issue is that this implies that we all agree that +Y is up. A lot of people use +Z as up and may reach for from_rotation_ypr and not realize it won't do what they think it will.

Solutions

A few potential solutions spring to mind:

  • Remove: Just delete the function and let people explicitly chain several from_axis_angle calls like above (though less efficiently).
  • Rename: Call attention to the implied coordinate system: from_yxz_angles (or is it from_zxy_angles ?)
  • Replace: Replace with a more generic function, like from_cardinal_angles(glam::Axes::YXZ, yaw, pitch, roll)
  • Move: Hide it behind a trait, like use glam::coordinate_systems::xyz_right_up_back::Rotation;

glam won't build because of sse2, but im on x86_64?

I'm trying to build glam alongside glium in a project, the code compiles and runs completely fine on my other computer but on my laptop it's giving me this error:

error[E0599]: no method named `map_or` found for type `std::result::Result<std::string::String, std:
:env::VarError>` in the current scope
 --> C:\Users\anumr\.cargo\registry\src\github.com-1ecc6299db9ec823\glam-0.8.7\build.rs:8:10
  |
8 |         .map_or(false, |cfg| cfg.split(',').find(|&f| f == "sse2").is_some());
  |          ^^^^^^ help: there is a method with a similar name: `map_err`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0599`.
error: Could not compile `glam`.
warning: build failed, waiting for other jobs to finish...
error: build failed

Swizzle support

It would be good to support generic swizzles.

Ideally this would support swizzling to return the same size vector but a long term goal would be to provide swizzling into a vector of a different size, smaller or larger.

The problem with SSE2 shuffles is the mask needs to be constant. The intrinsic itself is not a const function so I can't provide a method that will take a mask or at least I don't think that's possible. There are a couple of alternatives:

  • Generate shuffle methods for all possible permutations. This is what pathfinder does but that's 255 methods for swizzling a Vec4 to another Vec4, potentially more if swizzling to a different size is supported. My main concern with this approach is making sure it doesn't make a mess of the docs.
  • Use macros - the underlying __m128 is accessible so I think a macro solution would be possible. I would probably provide vec4_swizzle, vec3_swizzle, and vec2_swizzle so that the type is known and the number of lanes specified in the macro could be used to specify the output size.

2d array conversion rows vs columns mismatch?

One issue I ran into when starting using glam for our stuff was this 2d array conversion function:

impl From<[[f32; 4]; 4]> for Mat4 {
    #[inline]
    fn from(m: [[f32; 4]; 4]) -> Self {
        Mat4 {
            x_axis: m[0].into(),
            y_axis: m[1].into(),
            z_axis: m[2].into(),
            w_axis: m[3].into(),
        }
    }
}

I wasn't expecting it to load the rows of the fixed 2d array into the columns and vice versa here. Think when converting from a 2d array that has a definition of rows and columns the most expected result would be to convert from that representation to the internal representation (which in glam is colum-major) for storage.

So how about changing this function to internally transpose the stores here?

Also have the impl From<[f32; 16]> for Mat4 and for that it makes sense store the data linearly directly as colum-major because there is no additional information about how the source is organized wrt to rows and vectors.

Distance between two points

It would be nice to implement two functions distance and distance_squared which returns the Euclidean distance between two points. In other words, distance would return sqrt((x1-x2)^2 + (y1-y2)^2 + (z1-z2)^2) while distance_squared would return (x1-x2)^2 + (y1-y2)^2 + (z1-z2)^2.

Confusing Debug format of Vec3

The Debug formater for Vec3 includes the dummy fourth component, which I find somewhat confusing:

Actual: Vec3(__m128(0.8072419, -7.489461, 14.073505, 13.841213))

Expected: Vec3(0.8072419, -7.489461, 14.073505)

Support for const types

Currently, constant types don't seem to be supported:

error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
  --> src/main.rs:
   |
17 | const INIT_POS: Vec3 = vec3(1.0, 1.0, 1.0);
   |                        ^^^^^^^^^^^^^^^^^^^

I can't construct the tuple manually either, since there is only crate-level visibility. Would it be possible to implement this?

write docs

Need to add crate and module level docs plus docs describing methods and requirements of parameters.

  • Mat2
  • Mat3
  • Mat4
  • Quat
  • Vec2
  • Vec2Mask
  • Vec3
  • Vec3Mask
  • Vec4
  • Vec4Mask

Internal rewrite

I'm opening this for visibility, particularly for #85 since internal changes will require rework for any one with active glam forks.

The primary design goals of glam have always been having a simple user facing API and trying to get the best performance for scalar math by using SIMD under the hood where possible. Part of keeping things simple was limiting glam to only supporting f32, since the majority of the time I've only needed f32. Inside glam I have also opted to keep things simple and accepted to a bit of code duplication to avoid complicating the implementation with generics, traits and macros.

It has been a pleasant surprise that other people have liked and adopted the crate. Other people, it turns out, sometimes want different things from me. For example f64 or i32 support. Or support for different architectures like WASM or Neon. Long term I think supporting these things is going to tip the scales away from code duplication in favour of a more complex implementation to reduce the development and maintenance burden on myself and contributors. I do not wish to burden users with additional complexity so the public API should remain the same.

This refactor should help with:

  • #70
  • #95
  • Adding support for other SIMD architectures (although this could also be achieved by using the packed_simd or wide crates.
  • Possible Vec2 optimisations - that is internally loading into SIMD, performing the operation and storing back to the Vec2 (see pathfinder_geometry)
  • Possibly exposing a low level API similar to DirectX math that can be used to write high level APIs that are different to glam

At a high level the idea is to add storage types and implement operations on those storage types. Similar to how DirectXMath has its XMVECTOR type and functions that perform Vector3, Vector4, Quaternion operations on the one type. It's not a friendly API for users but it makes sense internally. My idea is the make traits for these methods and implement them for the different storage types that I want to support, e.g. struct XYZ<T> { x: T, y: T, z: T} or __m128 could both implement a Vector3 trait. Using traits does make it slightly easier to support f32, f64, i32 and so on without having to add duplicate implementations. The high level types like Vec3, or DVec3 can be defined using a single macro that specifies the scalar type.

I have a work in progress branch here https://github.com/bitshifter/glam-rs/tree/refactor.

Things to do:

  • f64 types - DVec2, DVec3, DVec4, DQuat, DMat2, DMat3, DMat4
  • i32 types - IVec2, IVec3, IVec4
  • u32 types - UVec2, UVec3, UVec4
  • bool types - BVec2, BVec3, BVec4 - mask type can just be used when SIMD is available
  • Check performance
  • Check documentation makes sense
    • Document internal architecture
    • Improve module level module docs (maybe split types by module)
    • Document Deref usage
    • Document as cast methods
  • Check debugging experience (VS Code)
    • Using map functions obsfucates implementation a bit
    • Need to check matrix debugging.
  • Tests for const macros
  • Swizzles for all types
  • Casts between different types
  • Support optional features (serde, mint, rand) for the new types
  • Remove build.rs
  • Check with rust-gpu
  • Check with bevy
  • Check with macroquad (can't - it's using an older version of glam)
  • Check build times
    • Make num-traits optional to reduce build times

Glam check macro

Instead of using debug_assert! to check input parameters add a glam_assert! that can be enabled as a feature.

Add GLSL doc aliases to functions.

Some of the functions that perform the same operations from GLSL have different names in glam. It would be nice if the names for these operations were added as doc aliases so for example if I search mix, I would get results for lerp functions.

Example

#[doc(alias = "mix")]
fn lerp() {}

Unexpected token issues with v0.11.1, broke MSRV

Hey reporting that we can not compile Glam v0.11.1 release with the CI at Bevy on Rust version 1.43.

This breaks the MSRV 1.36.0 gurantee as stated in the README.md.

error: unexpected token: `0.0`
   --> /home/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/glam-0.11.1/src/f32/vec3a_mask.rs:171:28
    |
170 |             Vec3A {
    |             ----- while parsing this struct
171 |                 x: if self.0.0 != 0 { if_true.x } else { if_false.x },
    |                       -----^^^
    |                       |    |
    |                       |    unexpected token
    |                       help: try parenthesizing the first index: `(self.0).0`

error: unexpected token: `0.1`
   --> /home/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/glam-0.11.1/src/f32/vec3a_mask.rs:172:28
    |
170 |             Vec3A {
    |             ----- while parsing this struct
171 |                 x: if self.0.0 != 0 { if_true.x } else { if_false.x },
172 |                 y: if self.0.1 != 0 { if_true.y } else { if_false.y },
    |                       -----^^^
    |                       |    |
    |                       |    unexpected token
    |                       help: try parenthesizing the first index: `(self.0).1`

error: unexpected token: `0.2`
   --> /home/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/glam-0.11.1/src/f32/vec3a_mask.rs:173:28
    |
170 |             Vec3A {
    |             ----- while parsing this struct
...
173 |                 z: if self.0.2 != 0 { if_true.z } else { if_false.z },
    |                       -----^^^
    |                       |    |
    |                       |    unexpected token
    |                       help: try parenthesizing the first index: `(self.0).2`

This PR is the culprit: 0b71355

Add Quat::inverse

It looks like Quat only has a conjugate operation but no inverse. I'm currently using this separately, but it would be nice to include it.

fn quat_inverse(q: glam::Quat) -> glam::Quat {
    let norm_squared = q.length_squared();

    if norm_squared < 0.000001 {
        glam::quat(0.0, 0.0, 0.0, 0.0)
    } else {
        let conjugate = q.conjugate();
        let as_vec4: glam::Vec4 = conjugate.into();
        glam::Quat::from(as_vec4 * (1.0 / norm_squared))
    }
}

Modifying individual elements of a Mat2 is very awkward

Presumably the same goes for the other matrix sizes.

The natural thing would seem to be:

my_matrix.x_axis().set_y(xy_value);

However, this does not work, as x_axis() does not return a mutable reference. You have to, as far as I can tell:

let mut x_axis = my_matrix.x_axis();
x_axis.set_y(xy_value);
my_matrix.set_x_axis(x_axis);

This is of course quite awkward. I'm not sure how you'd like the interface to look, so I haven't made a PR.

There's some commented-out accessors col and col_mut which seem like they would do the trick.

Alternate Vec3 that's actually 12 bytes

I've found that when dealing with mesh data files and meshes in memory and similar, you sometimes really want a Vec3 type that's guaranteed to actually be 12 bytes (3*mem::size_of()) in size.

I could of course implement my own Vec3 and have it by the side, but I think this need might be common enough that it might be worth including (since glam's SIMD Vec3 is stuck at 16 bytes, for pretty good reasons).

One idea might want to be to export a RawVec3 type or something that's essentially equivalent to the current non-SIMD fallback, even if SIMD is enabled. What do you think?

Behaviour for normalization of zero-vectors

Hey all! In #71 I proposed to add normalized_safe() as a quick way to deal with vectors that might be zero (see the example). However @bitshifter said that this should be subject of discussion (on which I agree).

So the questions are:

  • Do we need to simplify normalization of zero vectors?
  • If so, how should that function look like?

Would clamp methods be welcome?

A common thing I do in my game projects is clamp vector length to a certain max, min, or both. Would functionality like that be welcome in glam? I am willing to open a PR if this would be useful for glam itself (though I'd likely need assistance with the SIMD part). I'm thinking something along the lines of (for Vec2, for example):

    /// Returns a `Vec2` with a length no less than `min` and no more than `max`
    pub fn clamp(&self, min: f32, max: f32) -> Self {
        if self.length() < min {
            self.normalize() * min
        } else if self.length() > max {
            self.normalize() * max
        } else {
            *self
        }
    }

    /// Returns a `Vec2` with a length no more than `max`
    pub fn clamp_max(&self, max: f32) -> Self {
        if self.length() > max {
            self.normalize() * max
        } else {
            *self
        }
    }

    /// Returns a `Vec2` with a length no less than `min`
    pub fn clamp_min(&self, min: f32) -> Self {
        if self.length() < min {
            self.normalize() * min
        } else {
            *self
        }
    }

Additional References

packed_simd implementation

Long term I think it would make sense to replace the SSE2 implementation with packed_simd. The main reason being that packed_simd will support multiple platforms meaning glam won't need to implement support for other platforms itself.

I always want glam to build on stable so until packed_simd is stabilised, any work on it should live in a branch.

I would probably keep the scalar-math implementation in glam so it can be built without SIMD or custom alignment of types.

There are a few other questions around packed_simd:

  • It's in the nursery but development doesn't look very active, is there a plan to get it to stable?
  • I what gets generated on platforms that packed_simd doesn't support?
  • Is it possible to turn off SIMD

https://github.com/rust-lang-nursery/packed_simd

Expose named fields for non-simd vector types

The motivation is that it's kind of a pain to pay the cost of only accessing fields through function calls when you're not actually using simd. This is coming up for Embark both in WASM and (now) GPU code. Opening this issue to see what your thoughts/concerns are about this.

There's a couple options for implementation... the simplest would be to just make things that can be a plain struct with public named fields, i.e.

pub struct Vec3 {
    pub x: f32,
    pub y: f32,
    pub z: f32,
}

Another option is to use the strategy that nalgebra uses which is to create specific "component bag" structs and then impl Deref for them for things which make sense. For example:

struct XYZ {
    x: f32,
    y: f32,
    z: f32,
}

struct RGB {
    r: f32,
    g: f32,
    b: f32,
}
impl Deref<XYZ> for Vec3 {
   //...
}
impl Deref<RGB> for Vec3 {
   //...
}

Now you can write both vec.x or vec.r and you get the same thing as vec.x() currently.

Add basic logic operations to `Vec*Mask` types.

I would like to implement or, and, and not operators for the various Vec*Mask types.

My use-case:

In my path tracer I accumulate the results of many ray/box intersection tests via an or operation, as part of a ray streaming architecture. Rays are tested against four bounding boxes at once via SIMD, and the results from many rays are accumulated via the SSE _mm_or_ps() intrinsic.

In my specific case, I only need the or operation on Vec4Mask. However, or, and, and not seem like they would be generally useful for the mask types, given that they essentially represent boolean values.

Alternative

The same logical result can be achieved with glam already by first converting to a bitmask and using integer operations. But that adds an additional conversion operation in a tight loop, instead of doing the conversion once at the end of the accumulation. Having these operators available directly on the mask types allows writing more efficient code.

Couple Missing Trait Impls on Vec3A

I'm migrating to 0.9 from 0.8, and personally I love the split between the Vec3 and Vec3A. I came across a couple issues however with Vec3A not having impls for some operations. For example, Mat3 * Vec3A doesn't compile, functions that take a Vec3 don't have versions for Vec3A (though I can .into() it, it seems silly to be constantly converting).

I'm not sure what exactly the right solution to this, but it's a pretty big ergonomics issue, when I kinda expect to be able to do /s/Vec3/Vec3A/ in my source code to transition from 0.8 to 0.9.

Support f64 and i32

Once the glam API is stable (e.g. 1.0) I think it would make sense to add support for f64 and i32. I still would avoid using generics, since I couldn't easily provide SIMD implementation without specialisation, and even if specialisation was available it would complicate the API using generics. So perhaps some macros behind the scenes or just copy and paste. A lot of functionality is pretty simple so I don't think duplication is the end of the world, once the API is stable.

Should Vec4 truncate return Vec3 instead of Vec3A

I've seen this trip up new users. It is done this way because it's effectively a no-op, but perhaps the default behaviour should be to return Vec3 and provide another method for coverting to Vec3A.

Add/Subtract Traits for vecs

It appears that add/subtract operator traits are only implemented for when lhs & rhs are the same type, but multiply/divide is implemented for more types.

For example, this works: Vec3::one() * 3.0
But this does not: Vec3::one() + 3.0

Is there something blocking this functionality, or some reason this shouldn't be implemented? I'm glad to help write implementations/tests if appropriate.

Thanks for all your work on this project!

Consider adding transform types

When dealing with transforms that only contain position, orientation and possibly scale many operations can be performed more efficiently than using a general purpose matrix.

A while ago I experimented with transform types which contained position and orientation (as a quaternion) much like Unreal's FTransform, but I found these to not be particularly more efficient or to save much space in practice, so they are not enabled by default. They can be enabled using the transform-types feature.

Another option might be to have these kind of transforms backed by a matrix with simplified methods/operators similar to Transform4D described in Foundations of Game Engine Development Volume 1.

Semantics of `Vec4Mask::bitmask()` are different in SIMD and scalar code

While adding tests for my work on issue #9 , I discovered that the SIMD and scalar versions of the bitmask() function produce different results. Specifically, the order of the produced bits is reversed. The SIMD code maps element x to the highest of the four bits in the mask, whereas the scalar code maps it to the lowest of the four bits.

In retrospect, the SIMD version seems a bit more intuitive to me, because it preserves reading order between x, y, z, w and listing the bits in binary (e.g. 0b0011). It also seems wise to use the SIMD order anyway, since that keeps the SIMD code fast, whereas the ordering doesn't affect the speed of the scalar code at all.

I can knock out a quick fix for this. However, keeping my tests requires making the Vec4Mask::new() function public in the scalar code, and adding a corresponding function for the SIMD code.

Would you like me to go ahead with this and make a PR?

Add a way to opt-out of asserts

In quite some cases it's unwanted to have the application terminate when a (slight) math error occurs, even if it's only in debug. Often it's more desirable to have slightly incorrect results instead and keep processing / running. It would be nice to have a feature toggle to completely disable asserts.

Add `Mat4::ortho`

Because orthographic projections are cool. If you want this, I'll happily PR it.

Rename or remove `Mat4::perspective_glu`?

Also probably should rename the perspective_glu function here also, or maybe (depending on how opinionated we want to be) simply remove it? It is only useful in OpenGL due to the -1,1 depth range and it should have a _rh suffix to indicate it is right-handed.

Suggested in #23.

Precision test failure in test_angle

Was building and running the tests on Mac and got a failure on the test_angle test with the exact floating point percision assert failing:

     Running target/debug/deps/angle-d27d130bd1388bec

running 2 tests
test test_angle ... FAILED
test test_angle_rnd ... ok

failures:

---- test_angle stdout ----
thread 'test_angle' panicked at 'assertion failed: `(left == right)`
  left: `Angle(3.1415925)`,
 right: `Angle(3.1415927)`', tests/angle.rs:21:5
note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.

From:

assert_eq!(rad((-1.0f32).acos()), Angle::acos(-1.0));

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.