How do I align a cylinder along an axis?

I am trying to position and orient a set of cylinders. As input I have a list of xyz locations. Each cylinder is positioned and oriented from successive pairs of xyz values. One after another. Here is the code:

const geometries = []
        let previousVertex = undefined

        const vertices = EnsembleManager.getSingleCentroidVerticesWithTrace(trace)

        for (let vertex of vertices) {

            if (previousVertex) {

                // create cylinder with length equal to the distance between successive vertices
                const distance = previousVertex.distanceTo( vertex )
                const cylinder = new THREE.CylinderGeometry(stickRadius, stickRadius, distance, stickTesselation.radial, stickTesselation.length)

                // move cylinder to location central between vertices
                const { x:cx, y:cy, z:cz } = previousVertex.lerp(vertex, 0.5)
                cylinder.translate(cx, cy, cz)
              
               // use quaterion to orient cylinder to align along the vector formed between
               // the pair of vertices
                const { x:px, y:py, z:pz } = previousVertex
                const { x, y, z } = vertex

                const alignmentVector = new THREE.Vector3(x-px, y-py, z-pz)

                const cylinderDefaultAxis = new THREE.Vector3(0, 1, 0)

                const quaternion = new THREE.Quaternion()
                quaternion.setFromUnitVectors(cylinderDefaultAxis, alignmentVector.normalize())
                cylinder.applyQuaternion(quaternion)

                geometries.push(cylinder)
            }

            previousVertex = vertex
        }

        const material = sceneManager.stickMaterial.clone();
        const mesh = new THREE.Mesh(mergeBufferGeometries( geometries ), material);

When I run this code none of the cylinders appear. If I remove the quaterion code, the cylinders appear in the correct location but lack - obviously - the required orientation.

What am I missing here?

1 Like

Hi!
I would log variables and check if there are ones that have NaN or undefined values.

Solved. Here is the code for anyone with a similar need:

createSticks(trace, stickRadius) {

    const geometries = []
    const vertices = EnsembleManager.getSingleCentroidVerticesWithTrace(trace)

    const endPoints = []
    for (let i = 0; i < vertices.length - 1; i++) {
        endPoints.push({ a: vertices[ i ], b: vertices[ i + 1 ] })
    }

    for (let { a, b } of endPoints) {

        // stick has length equal to distance between endpoints
        const distance = a.distanceTo( b )
        const cylinder = new THREE.CylinderGeometry(stickRadius, stickRadius, distance, stickTesselation.radial, stickTesselation.length)

        // stick endpoints define the axis of stick alignment
        const { x:ax, y:ay, z:az } = a
        const { x:bx, y:by, z:bz } = b
        const stickAxis = new THREE.Vector3(bx-ax, by-ay, bz-az).normalize()

        // Use quaternion to rotate cylinder from default to target orientation
        const quaternion = new THREE.Quaternion()
        const cylinderUpAxis = new THREE.Vector3( 0, 1, 0 )
        quaternion.setFromUnitVectors(cylinderUpAxis, stickAxis)
        cylinder.applyQuaternion(quaternion)

        // Translate oriented stick to location between endpoints
        cylinder.translate((bx+ax)/2, (by+ay)/2, (bz+az)/2)

        // add to geometry list
        geometries.push(cylinder)

    }

    // Aggregate geometry list into single BufferGeometry
    const material = sceneManager.stickMaterial.clone();
    const mesh = new THREE.Mesh(mergeBufferGeometries( geometries ), material);
    mesh.name = 'stick';
    return mesh;

}
2 Likes