I had the idea to create a "Thick Arrow" mesh, essentially an arrow similar to the standard Arrow Helper but with the shaft constructed using a cylinder
instead of a line
.
tldr; do not just copy the Arrow Helper design; refer to the Epilogue section at the end of the question.
So, I decided to replicate and modify the code to suit my requirements (omitting the constructor and methods) and after making the necessary adjustments, it now functions correctly:-
// Modified from https://github.com/mrdoob/three.js/blob/master/src/helpers/ArrowHelper.js
function F_Arrow_Fat_noDoesLookAt_Make ( dir, origin, length, shaftBaseWidth, shaftTopWidth, color, headLength, headBaseWidth, headTopWidth )
{
var thisArrow = new THREE.Object3D();
// Parameters set if not defined
if ( dir === undefined ) dir = new THREE.Vector3( 0, 0, 1 );
if ( origin === undefined ) origin = new THREE.Vector3( 0, 0, 0 );
if ( length === undefined ) length = 1;
if ( shaftBaseWidth === undefined ) shaftBaseWidth = 0.02 * length;
if ( shaftTopWidth === undefined ) shaftTopWidth = 0.02 * length;
if ( color === undefined ) color = 0xffff00;
if ( headLength === undefined ) headLength = 0.2 * length;
if ( headBaseWidth === undefined ) headBaseWidth = 0.4 * headLength;
if ( headTopWidth === undefined ) headTopWidth = 0.2 * headLength;
/* CylinderBufferGeometry parameters:
* radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength
*/
var shaftGeometry = new THREE.CylinderBufferGeometry( 0.1, 0.1, 1, 8, 1 ); // cylindrical shaft
var headGeometry = new THREE.CylinderBufferGeometry( 0, 0.5, 1, 5, 1 );
// Set positions
shaftGeometry.translate( 0, +0.5, 0 );
headGeometry.translate( 0, -0.5, 0 );
// Create components
thisArrow.shaft = new THREE.Mesh( shaftGeometry, new THREE.MeshLambertMaterial({ color: color }) );
thisArrow.head = new THREE.Mesh( headGeometry, new THREE.MeshLambertMaterial({ color: color }) );
thisArrow.position.copy(origin);
thisArrow.add(thisArrow.shaft);
thisArrow.add(thisArrow.head);
// Additional functionality
scene.add(thisArrow);
}
// Other supporting functions for direction, length, and color settings
This approach works well for a fixed-direction arrow where the direction is specified during construction.
However, what I now need is the ability to change the orientation of the arrow over time (to track a moving target). The current method using Object3D.lookAt() does not support this functionality as it aligns the y-axis of the object with the target position, whereas the Thick Arrow requires alignment along the z-axis.
Experimenting with rotations yielded partial success, but the shapes are distorted and the head mesh appears offset from the shaft. While trial and error may yield results in specific cases, I seek a more robust solution that is adaptable to different scenarios and future updates in THREE.js.
I welcome any suggestions or recommendations on achieving the desired lookAt() capability for the "Thick Arrow".
Epilogue
The key lesson learned here is not to simply follow the design of the Helper Arrow.
As highlighted in responses from TheJim01 and somethinghere, a simpler approach involves nesting cylinder meshes (for shaft and head), rotating them appropriately within parent objects, and then utilizing lookAt() on a grandparent object to achieve the desired orientation.
Using Object3D.add() for nesting, along with proper rotations, provides a more flexible and scalable solution compared to replicating the Arrow Helper design. Additionally, dynamic usage of Arrow Helper can be achieved by setting the internal direction before calling lookAt().