I have two meshes (A and B) and I know that a triangle in A has the same size and same angles as a triangle in B.

For simplicity, suppose A is an octahedron and B is a tetrahedron. And suppose the triangle in A is the first one and the triangle in B is the first one.

I want to find a way (a matrix) to move B such that the triangle is coincident with the triangle in A.

Octahedron and tetrahedron with one green triangle each

I'd like to move the blue mesh such as the green triangle touches the green triangle in the orange mesh.

I'd like to move the mesh such so that its triangle's normal will point opposite to that of the stationary mesh's face (so the octahedron and tetrahedron "dock" along the shared face, like pressing two dice together)

I'm using javascript with thee.js, but I'm not tied to any framework or language.

  • \$\begingroup\$ @DMGregory yes, I'm usign the shiny github.com/thi-ng/umbrella for maths, vectors, matrices, and other algorithm... if you don't know it the math signatures for webgl are more or less the same of gl-matrix (glmatrix.net) or regl or stack.gl \$\endgroup\$
    – nkint
    Commented Feb 14, 2023 at 16:55

1 Answer 1


This is a bit easier if you have a quaternion "look rotation" method handy, but I don't see one in the library you're using, so I'll describe the algorithm in high level pseudocode and you can translate it as needed. That can include implementing your own lookRotation(forward, up), which returns a quaternion that rotates (0, 0, 1) to point along forward and (0, 1, 0) to point as close as possible to up using the remaining degree of freedom.

So, we have object 1 with a triangular face ABC and object 2 with a triangular face PQR, each defined in the objects' own local coordinates. We want to move object 2 so that P meets A, Q meets C, and R meets B.

First we'll compute the normal to each face, the centroid of each face, and a vector from the centroid to the vertex we want to match up on each face:

n1 = cross(B - A, C - A)
n2 = cross(Q - P, R - P)

c1 = (A + B + C)/3
c2 = (P + Q + R)/3

v1 = A - c1
v2 = P - c2

We'll use that to compute an orientation of each face within its object's local coordinate space:

q1 = lookRotation(-n1, v1)
q2 = lookRotation(n2, v2)

We negate n1 to flip the face, so we dock object 2 to the outside of the face, not the inside.

Now ABC's orientation in world space is:

worldSpaceOrientation = object1.rotation * q1

And we can undo the effects of PQR's local orientation by inverting it, to get...

object2.rotation = worldSpaceOrientation * q2.inverse

Now we've rotated the second object so PRQ is in the right orientation to match ABC, but it's still probably in the wrong position. All we have to do now is get the vector between the two centroids, and translate object 2 by that vector:

c1World = object1.matrix * c1
c2World = object2.matrix * c2

object2.position += c2World - c1World

Make sure you do this after rotating object 2, otherwise the rotation can change the translation you need, twisting them out of alignment again.

  • \$\begingroup\$ thanks! I'll try \$\endgroup\$
    – nkint
    Commented Mar 15, 2023 at 19:43
  • \$\begingroup\$ what is the difference between object1.rotation and object1.matrix? does the rotation is encoded into the object matrix? \$\endgroup\$
    – nkint
    Commented Mar 23, 2023 at 20:15
  • \$\begingroup\$ The matrix will also include translation and scale. \$\endgroup\$
    – DMGregory
    Commented Mar 23, 2023 at 21:00
  • \$\begingroup\$ so what do you mean with object2.rotation = worldSpaceOrientation * q2.inverse ? what is the type of rotation? is it a number? a quaternion? a matrix 4x4? \$\endgroup\$
    – nkint
    Commented Mar 23, 2023 at 22:11
  • \$\begingroup\$ A quaternion or a matrix can both store a rotation. Which format you use is up to you and does not alter the strategy in any way. \$\endgroup\$
    – DMGregory
    Commented Mar 23, 2023 at 23:10

You must log in to answer this question.

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