Freedom-of-Form-Foundation / anatomy3d

A CAD tool for humanoid anatomy alterations. See the anatomy3d-blender repository for more recent work.
https://freedomofform.org/1856/3d-anatomy-project-scope-phase-1-focus-on-a-limb-joint/
GNU General Public License v2.0
7 stars 5 forks source link

Consider vectorspace-aware vector type #45

Open AdamNorberg opened 3 years ago

AdamNorberg commented 3 years ago

C# SIMD vectors (Vector3, Vector2, MatrixNxM) are limited to the float type because they are designed for processing on GPUs. We're hitting numeric stability issues with float already, so it's not clear that this is sustainable.

If we have to move to a different vector type, where we have to reimplement the various vector math functions ourselves, it might be worth complicating it by associating each vector (and matrix) with a vector space. Trying to operate on vectors of different vector spaces when using operators or functions that require the same vector space is a runtime or compiler error.

I'm thinking about this in the context of "body space", "bone space", "absolute rendering space" - all of them vector spaces, all of them with a different basis relative to each other. Body space moves with the character; bone space is local to one bone - so converting between different spaces is relative to the state of these mobile things! Screen space could be a 2D vector space if that's useful to us, although it seems like we'd want to just use absolute rendering space and leave the 2Dification to the engine. Converting a vector (or a geometric object represented by multiple vectors) to a different space would be some combination of shift and skew operations, generally.

I think it would be really easy to write bugs where we're trying to do some operation on objects that do not have the same idea of where 0,0,0 is or which way their axes point. Upgrading bugs to crashes is great, it shows immediately where the flaw is. So making vectors tote around their idea of a vector space seems useful.

I'm thinking of some kind of IVectorSpace interface, so the full name of the vector type would be something like Vector<BodySpace> or Vector<BoneSpace>, so the compiler could outright reject "clearly wrong" combinations like trying to operate between bodyspace and bonespace vectors without a conversion. Different bones would be type-compatible and errors pertaining to them would not be caught until runtime.

IVectorSpace would provide stuff like:

And probably more that I haven't thought of yet.

This trades off performance and patience (it adds irritating boilerplate) for error detection. I don't know if this tradeoff is appropriate here. It's not clear to me that it requires much code we don't have to write anyway, since we do have to convert between vector spaces, avoid interpreting vectors in different spaces as numerically interacting without such conversions, and I suspect we're going to get forced off float sooner rather than later. I'm already musing if Matrix<IVectorSpace, IVectorSpace> gets us something useful; I think it does, but I clearly need to brush up on my linear algebra here.

Ultimately, this is a question about whether we want "context-aware math" in our design. The costs are obvious: we have to define and maintain the context. But the benefits are also obvious: the compiler and runtime will be able to spot a huge variety of errors we are genuinely likely to write.

If the context checking overhead turns out to be substantial, we could use conditional compilation to remove the checks outside of debug builds. I think we'd need to keep the reference to the object representing the vector space alive, though, since conversion functions are very likely to care about it.

This is related to "write a vector type that uses Real instead of float". This might be that type. Or it might not, if the overhead is inappropriate.