-
Notifications
You must be signed in to change notification settings - Fork 167
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
RFC: Point types #133
Comments
It is something I've been wondering about, also in conjunction with adding an affine transform type. I don't think I've used a library that had a separate point type before. My feeling is it would probably introduce a bunch of places where you'd need to convert from point to vector or vice versa, i.e. it would get in the way, but at the same time it would get around some ambiguity and needing special methods for transforming points and vectors, etc. In saying that there is still ambiguity when transforming a point3 with a mat4 or rather it's cheaper if you know you're only dealing with an affine transform. Having a separate affine transform would help there. I have been influenced a bit by Lengel's Foundations of Game Engine Development as well which has a point type and an affine transform type. I would be interested to hear what other users think. I seem to recall @repi liking not having separate point and vector types, but maybe I'm mis-remembering. Other prior art in Rust includes cgmath and euclid. |
In my pathtracer I wrap all of Glam's types in my own math library, and have separate So I definitely understand the desire for differentiating these by type. I do it myself. And letting the type system help you is typically a win. Nevertheless, my gut feeling is that Glam sits a little lower-level than that. My perspective is that Glam isn't so much a math library as it is a SIMD library targeted at performant low-dimensional linear algebra. In other words, it's not trying to encode the rules of linear algebra, it's just trying to provide efficient implementations of the operations needed to do linear algebra. For example, I don't think my I think the main argument for quaternions having their own type is less about mathematical distinction, and more about making the API easier to follow. If you take a look at the Lastly, I feel like giving vectors and points separate types might make it a little less clear which type is "agnostic" (for lack of a better word) for use-cases that don't care about or don't want that distinction. Anyway, that's my take on it. But I'm certainly not the source of truth for this crate! And everything I've written above is just what I personally would ideally like Glam to be. Reasonable people can absolutely disagree. And I don't think it will practically affect me either way as a user of the crate, so I won't really be put off regardless of what the decision ends up being here. |
Traditionally and coming from gamed C++ land I've been a bit against higher-level point & normal vector types and such, and I do also think But it is indeed an interesting spectrum and as with higher level types like affine transforms, and Rust's general preference towards explicit and constrained specific types. So I think can be of interest to sketch on optional higher level point type here also, and it wouldn't be intrusive I think. But it can be a bit hard to know where to draw the line in general, do we have a
Same opinion here, with a slight preference towards |
I wanted to add a few more thoughts on this. I'd certainly be interested in trying out a point type to see how it feels and see how much churn it causes when applying it to an existing math heavy code base and to get a better feel for using it. A point type in conjunction with an affine type would mean Adding an additional type, whatever it ends up being named also raised the question should there be a I decided against adding a point type when I initially wrote glam because I hadn't seen one in any of the C++ game math libraries I had used and they seemed reasonably uncommon in other math libraries I looked at. I made glam to be familiar to C++ game devs, with myself being the target audience initially. While I don't think "this is the way things have always been done" is a good justification to not try something, the down side could be that porting code or ideas from C++ or C# engines, books and articles, GLSL or HLSL may become more difficult if a point type was added. The programmer now has to divert time to thinking about which variables should be vectors and which should be points. Now days there are a few projects I know about using glam and probably a lot that I don't. It's hard to communicate with most users to ask them about big decisions like that and I would definitely want to cast a wide net for feedback before committing to such a change. As I said I'm definitely interested in experimenting with a point type if I find the time, but, it could be a tough sell at this, um, point. |
Please don't remove methods like |
Perhaps there's room for a crate that sits on top of glam and exposes higher-level linear algebra concepts like normals, points and planes. Glam is then more of a low-level SIMD library like @cessen says. The danger would be that this crate becomes a "mathematician's math library" like nalgebra, alienating game programmers who just want to get things done. |
The recent refactor moved the majority of the functionality into a core library which could be reused by a different high level interface. It's currently all internal, because I didn't want to supporting it as a separate crate at this stage, but it could be used for this purpose. |
Point types
This issue is meant to spark a discussion about advantages and disadvantages of adding a separate type for points.
This suggestion goes somewhat against the simplicity of
glam
, but it is possible it can be designed in an opt-in manner.I'll stick to 3D examples, but the same idea goes for 2D.
Summary
The size of
Vec4
andQuat
are the same, but since they are used very differently it is wise to give them different types (like glam does).The same goes, I would argue, for the concepts vectors and points, which are used very differently, but currently share the same type:
Vec3
.I suggest adding a new
Pos3
("Position 3D") type to represent points, and keep usingVec3
only to represent vectors.Background
In homogeneous (a.k.a projective) coordinates we express 3-dimensional XYZ points as 4-dimensional vectors with an added projective W coordinate:
{x, y, z, w}
is a general point, which corresponds to the coordinate[x/w, y/w, z/w]
{x, y, z, w=1}
is a normalized point, which corresponds to the coordinate[x, y, z]
{x, y, z, w=0}
is a vector (something with a length and a direction, but no position)The normalized point is very useful, and since the
w
is always1
we only need three values to encode. It is therefor tempting to use the same type for both vectors and normalized points (as glam does withVec3
).However, conflating points and vectors has many downsides. For instance, when transforming a vector you must use
m.transform_vector3(v)
, and for points you must usem.transform_point3(p)
. If points and vectors where different types, we could simply writem * v
andm * p
.This would work because we would have both
impl Mul<Vec3> for Mat4
andimpl Mul<Pos3> for Mat4
.Proposal
I suggest adding a new
struct Pos3 { x: f32, y: f32, z: f32 }
for points, with an implicitw=1
.The
Pos3
would have very few members, such asdistance
(to anotherPos3
). It would NOT havelength()
because there is no sensible "length" of a point, as there is for vectors.The operations possible on
Pos3
would be limited to:Pos3 + Vec3 -> Pos3
(translation)Pos3 - Vec3 -> Pos3
(translation)Pos3 - Pos3 -> Vec3
(measurement)Mat4 * Pos3 -> Pos3
(transform)Note that
Pos3 + Pos3
is NOT allowed, as it makes no sense, nor isPos3 * f32
.Quat * Pos3
is also not allowed, as again it makes no sense to rotate points (only vectors).Basically
Pos3
would be a very simple type when compared toVec3
.Benefits
Ergonomy
It is nice to be able to write
matrix * point
andmatrix * vector
instead ofm.transform_point3(p)
andm.transform_vector3(v)
.Type safety
I have many times seen the bug
matrix.transform_vector3(point)
ormatrix.transform_point3(vector)
. With separate types, such bugs would dissappear.Similarly things like
fn draw_arrow(from: Pos3, vec: Vec3)
can't accidentally be called asdraw_arrow(base, tip)
.Self-documenting code
Currently, something like
struct Arrow(Vec3, Vec3)
is ambigious (are those the base and tip of the arrow, or base and a vector?), butstruct Arrow(Pos3, Pos3)
(orstruct Arrow(Pos3, Vec3)
) is not.Name
Point3
is popular in a lot of libraries.Pos3
has the benefit of being shorter and matching the length ofVec3
. I don't feel strongly either way.Other
I beleive
Pos3
will fit in nicely with higher-level transform types (such as the isometricTransformRT
).Prior art
Point
in nalgebra andPos2
in my ownemath
.Downsides
There are a few cases where some overloads may need to be added. For instance,
Mat4::from_translation
would probably need an overloadMat4::from_point
to make it more ergonomic to create a transform that e.g. rotates around a point.There is also a concern of a "slippery slope" towards ever-more advanced types (e.g. a separate type for unit-length vectors). As far as I can tell there is nothing in this proposal that would require more advanced types elsewhere, but I think it is a good instinct to resist complexity.
Transitioning
There are also a lot of code in
glam
that treatsVec3
as points, such asVec3::distance
. I would suggest that we keep all those around for those who want to ignore the existence ofPos3
. We could make the transition a bit more ergonomic by addingimpl From<Vec3> for Pos3
andimpl From<Pos3> for Vec3
.Final thought
This may be too late to add to glam, but I thought it was worth to at least write up and have a discussion about, and see what thoughts other people have!
The text was updated successfully, but these errors were encountered: