RotationFromAxis / RotationQuaternionFromAxis to arbitrarily align a face to a plane

Hi there :wave: Having some troubles trying to work out how to align faces of a polyhedra to a plane.

Code is intermingled with lots of other things but this is basically it:


A Face of a Tetrahedron can be double clicked and each face is its own mesh with a single TransformNode as their parent:

* TransformNode / node
	* Polygon Face / mesh
	* Polygon Face / mesh
	* Polygon Face / mesh
	* Polygon Face / mesh
	* etc


function onDoublepick(e) {

	const camera = context.getCamera()
	const mesh = e.detail.mesh
	const center = new BB.Vector3(0,0,0)

	// MESH POSITION (center of the face)

	const meshPosition = mesh.position.clone()
	const meshPositionAbs = mesh.getAbsolutePosition()


	const nodePosition = node.position.clone()
	const nodePositionAbs = node.getAbsolutePosition()


	const floor = new BB.Vector3( 0, -9999, 0 )

	// hard reset node rotations

	node.rotationQuaternion = center.clone()
	node.rotation = center.clone()

	// individual points in the polygon face

	const pointA = ([0]).clone()
	const pointB = ([1]).clone()
	const pointC = ([2]).clone()

	// attempt rotation to the floor (based on documentation example)

	const axis1 = pointA.clone().subtract(pointB.clone())
	const axis3 = BB.Vector3.Cross(floor, axis1)
	const axis2 = BB.Vector3.Cross(axis3, axis1)

	node.rotationQuaternion = BB.Quaternion.RotationQuaternionFromAxis(axis1, axis2, axis3)

	// OR (same thing): node.rotation = BB.Vector3.RotationFromAxis(axis1, axis2, axis3)


Just trying to align the face to the floor for now - and this is without manipulating the camera or using lookAt methods. Thing I’m confused over is how to best create axis1 / axis2 / axis3. I’ve read as much as I can on the forum and in the documentation but no dice :frowning:

Could you replicate your code in a playground, this would be easier for us to help,

also, Quaternion.FromLookDirectionLH might be helpful.

 const forward = planeCenter.subtract(faceCenter).normalize();
 const up = Vector3.Zero();

 const rotation = Quaternion.FromLookDirectionLH(forward, up);

Not a problem - I created a sketch here:

It randomises polygons around a center origin, and when a polygon face is clicked, it tries to align the face to the ground (and creates an absolute position copy of the original sphere positions for reference).

In essence, just trying to align a point to a point around an origin!

NB, perhaps another way of approaching it is to change the meshes forward direction to point at an arbitrary point, and then use mesh.lookAt (for example mesh.lookAt(floor), mesh.lookAt(camera) etc).

OK, fixed!

My solution is convoluted but it allows me to freely rotate an object until a Vector3 is aligned to another Vector3:

  • bake world matrix into absolute position and rotation of each child node (this is different to bakeTransformIntoVertices, and is a custom function I saw here), edit: or just remove parent of child node
  • remove parent reference temporarily from each child node (they are now freely floating in space in the same position)
  • clone the transform node and make it look at one of the absolute positions of the former child nodes
  • re-add the child nodes to the original parent node
  • copy the rotation from the cloned transform node to the original transform node

In the sketch this basically just means click on a mesh → mesh centers in the viewport

And it could also be done with “lookAt” instead of creating a clone - but this way there is future possibility to interpolate or modify the rotation start and end point.


    function bakeWorldMatrix( mesh ) {

        if (mesh.parent) mesh.parent.computeWorldMatrix(true)
        let rotation = BABYLON.Quaternion.Identity()
        let position = BABYLON.Vector3.Zero()

        mesh.getWorldMatrix().decompose(BABYLON.Vector3.Zero(), rotation, position)
        if (mesh.rotationQuaternion) {
        } else {

        // REMOVE PARENT

        if (mesh.parent) mesh.parent = undefined

        mesh.position.x = position.x
        mesh.position.y = position.y
        mesh.position.z = position.z

        return mesh 

    // ============ ATTEMPT ============

    function alignPolygonMeshToFloor( mesh ) {

        const centerPoint = new BABYLON.Vector3(0,0,0)
        const groundPoint = ground.getAbsolutePosition().clone()
        const cameraPoint = camera.position.clone()

        // BAKE TRANSFORMS INTO CHILDREN (AND REMOVE PARENT) polyMesh => bakeWorldMatrix(polyMesh) )
        // OR polyMesh => polyMesh.setParent(null) )


        mainTransformNode.lookAt( mesh.getAbsolutePosition() )


        let clone = mainTransformNode.clone("clonedTransformNode")
        clone.lookAt( cameraPoint )
        bakeWorldMatrix( clone )
        const rotationQuaternion = clone.rotationQuaternion ? clone.rotationQuaternion.clone() : null
        const rotation = clone.rotation ? clone.rotation.clone() : null

        // ADD CHILDREN BACK TO NODE + SET NODE ROTATION TO CLONES polyMesh => polyMesh.setParent( mainTransformNode ) )
        if (rotationQuaternion) mainTransformNode.rotationQuaternion = rotationQuaternion
        if (rotation) mainTransformNode.rotation = rotation


Hope this is useful for others!