# RotationFromAxis / RotationQuaternionFromAxis to arbitrarily align a face to a plane

Hi there 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()

// PARENT NODE POSITION (0,0,0)

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

// FLOOR

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 = (mesh.data.points?.[0]).clone()
const pointB = (mesh.data.points?.[1]).clone()
const pointC = (mesh.data.points?.[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

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

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

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

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.

``````
// BAKE TRANSFORM

function bakeWorldMatrix( mesh ) {

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

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

// 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)

polygonMeshes.map( polyMesh => bakeWorldMatrix(polyMesh) )
// OR polygonMeshes.map( polyMesh => polyMesh.setParent(null) )

// NODE LOOKS AT MESH ABSOLUTE POSITION

mainTransformNode.lookAt( mesh.getAbsolutePosition() )

// CLONE NODE TO GET A NEW ROTATION (AND DELETE)

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
clone.dispose()

// ADD CHILDREN BACK TO NODE + SET NODE ROTATION TO CLONES

polygonMeshes.map( polyMesh => polyMesh.setParent( mainTransformNode ) )
if (rotationQuaternion) mainTransformNode.rotationQuaternion = rotationQuaternion
if (rotation) mainTransformNode.rotation = rotation

}

``````

Hope this is useful for others!

3 Likes