I am using an engine that uses a texture mapper where instead of providing per-vertex UV coordinates a 3D point(P) and 2 vectors(M, N) is provided, the texture coordinates can be directly computed from the basis vectors.

Note: from this point onwards I'll refer to PMN as 3 vectors instead of a point and 2 basis vectors

P is the origin of the texture, M the horizontal end of the texture, and N the vertical end

Then 3 new 'magic' vectors are computed:

A = P.cross(N)
B = M.cross(P)
C = N.cross(M)

Then for each pixel(x, y):

S = Vector3f(x, y, 1)
float a = dot(S, A)
float b = dot(S, B)
float c = dot(S, C)

float u = texture.width * a / c
float v = texture.height * b / c
color = texture.pixels[u + v * texture.width]

The algorithm & derivation is explained more in depth here: https://nothings.org/gamedev/ray_plane.html

Now i have found an algorithm that converts PMN vectors to per-vertex UV coordinates:

                        Point3D a = ... // first vertex of the triangle
                        Point3D b = ... // second vertex of the triangle
                        Point3D c = ... // third vertex of the triangle

                        Point3D p = ... // origin of the texture
                        Point3D m = ... // horizontal end of the texture
                        Point3D n = ... // vertical end of the texture

                        Point3D pM = m.subtract(p);
                        Point3D pN = n.subtract(p);
                        Point3D pA = a.subtract(p);
                        Point3D pB = b.subtract(p);
                        Point3D pC = c.subtract(p);

                        Point3D pMxPn = pM.crossProduct(pN);

                        Point3D uCoordinate = pN.crossProduct(pMxPn);
                        double mU = 1.0F / uCoordinate.dotProduct(pM);

                        double uA = uCoordinate.dotProduct(pA) * mU; // u coordinate of the first vertex
                        double uB = uCoordinate.dotProduct(pB) * mU; // u coordinate of the second vertex
                        double uC = uCoordinate.dotProduct(pC) * mU; // u coordinate of the third vertex

                        Point3D vCoordinate = pM.crossProduct(pMxPn);
                        double mV = 1.0 / vCoordinate.dotProduct(pN);
                        double vA = vCoordinate.dotProduct(pA) * mV; // v coordinate of the first vertex
                        double vB = vCoordinate.dotProduct(pB) * mV; // v coordinate of the second vertex
                        double vC = vCoordinate.dotProduct(pC) * mV; // v coordinate of the third vertex

I am looking for an explanation on how this PMN -> UV conversion method works.

I am also interested in how the algorithm using PMN works as i still don't intuitively understand how these texture coordinates are computed from the basis vectors, so an explanation of that would also help me a lot but is not necessary as i mostly want to understand how the PMN -> UV conversion method works

A very specific question that i have about the PMN texture mapping algorithm, is what do the a, b, c values define for each pixel? Every article i've found that describes this algorithm has simply referred to them as "magic coordinates" similarly A, B, C is simply referred to as "magic vectors" which isn't very helpful for anyone actually wanting to understand each part of the algorithm instead of just implementing it.


1 Answer 1


Points PMN define a plane, and a parallelogram in that plane. You can imagine taking your texture and rotating/stretching/skewing it to fit that parallelogram. For a tiling texture, you can then repeat that parallelogram of texture to completely cover the plane.

For any other point A, B, or C, or any arbitrary point X in between them, we can project it onto that PMN plane. Imagine a light shining along the direction normal to plane PMN, from whatever side our point X is on, falling perpendicularly onto plane PMN. Wherever the shadow of X lands on the plane, which we tiled with our distorted texture, that's the spot it takes its texture coordinate (and corresponding texel colour) from.

  • \$\begingroup\$ ah, now all the dot/cross products in the PMN texture mapping algorithm make slightly more sense than before, what about the PMN -> UV method? actually i think i got that one figured out to an extent but i don't get what the vector pMxPn does/defines \$\endgroup\$
    – Suic
    Commented Jan 18, 2022 at 17:31
  • \$\begingroup\$ That's the normal to the plane PMN, the direction we shine the light along. \$\endgroup\$
    – DMGregory
    Commented Jan 18, 2022 at 17:33
  • \$\begingroup\$ I see, one more thing im curious about is what do the a, b, c values define that are computed for each pixel? i don't understand how a / c and b / c computes the u, v coordinate either(but perhaps i will after i understand what the a, b, c values define) \$\endgroup\$
    – Suic
    Commented Jan 18, 2022 at 17:44

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .