How are your quads represented?

I’ve previously written a ray tracer and I found it’s easiest to have primitives be as simple as possible and allow for a transformation matrix to do the hard work. When ray tracing I transformed the ray into local space and resolved the collision check against the simple version of the primitive. For example, for a quad the primitive would be a square defined by two vectors of unit length along the x and y axes. If you transform rays into that local space, the collision coordinates will already be the UV coordinates.

If you represent your quads in another way, you need to do a change of basis from world space to the unit square space mentioned above. To do that, first create matrix with as first two columns the vectors along the sides of your quad (horizontal and vertical respectively), as third column the cross product of the first two vectors and as fourth column the bottom left (in local space, so the origin of the vectors) of the quad. These are all 3d vectors, so the last row isn’t filled yet. That should be 0 0 0 1 (for anyone unfamiliar with the underlying maths, this is needed for the translation; check out Wikipedia on transformation matrices and homogeneous coordinates if you’re interested). That’s the transformation matrix from local space to world space. If you invert it and transform your point with the result, the x and y coordinates of the transformed vector will be the UVs.

There’s probably some simplifications you can make to this calculation because you don’t need the z coordinate of the result and if you track the inverse transform when building the quad you never need to explicitly compute the inverse transform. If you write out the whole computation it’s easy to figure out the simplified version. Though it’s surely somewhere on the internet already

Tracking inverse transform for basic transformations is pretty easy. For rotation rotate the same amount but the other direction, for translation translate with negated sign and for scaling scale by the inverse. You can use the `Matrix.CreateX`

methods for those.

Sorry if this was a bit incoherent, I’m on mobile

Hope that helps!