I am attempting to make a curved 3D arrow in three.js. To accomplish this task, I have created a Tube that follows a curved path and a Cylinder shaped as a cone (by setting radiusTop to be tiny). They currently look like so:
I am attempting to position the Arrow Head (Cylinder shaped as a cone) at the end of the Tube like so: (Photoshopped)
I am not terribly strong in math and pretty new to three.js. Could someone help me understand how to connect the two?
Here is my current code:
import T from 'three';
var findY = function(r, x)
{
return Math.sqrt((r * r) - (x * x));
}
var radius = 25;
var x = 0;
var z = 0;
var numberOfPoints = 10;
var interval = (radius/numberOfPoints);
var points = [];
for (var i = numberOfPoints; i >= 0; i--)
{
var y = findY(radius, x);
points.push(new T.Vector3(x, y, z))
x = x + interval;
}
x = x - interval;
for (var i = numberOfPoints - 1 ; i >= 0; i--)
{
y = findY(radius, x) * -1;
points.push(new T.Vector3(x, y, z));
x = x - interval;
}
var path = new T.CatmullRomCurve3(points);
var tubeGeometry = new T.TubeGeometry(
path, //path
10, //segments
radius / 10, //radius
8, //radiusSegments
false //closed
);
var coneGeometry = new T.CylinderGeometry(
radiusTop = 0.1,
radiusBottom = radius/5,
height = 10,
radialSegments = 10,
heightSegments = 10,
openEnded = 1
);
var material = new T.MeshBasicMaterial( { color: 0x00ff00 } );
var tube = new T.Mesh( tubeGeometry, material );
var cone = new T.Mesh( coneGeometry, material );
// Translate and Rotate cone?
I would greatly appreciate if someone could attempt a simple explanation of what is necessary mathematically and programmatically accomplish
- Finding the normal located at the end of the tube
- Shifting the Cone to the correct location
Any help is appreciated!
Do not use rotation for this when you can create the arrowhead directly in place. Similarly the bended tube can be done this way too. Only thing you need for it is the last line segment defined by
A,B
endpoints.Let
A
be the sharp point andB
the disc base center. To create arrowhead you need 2 additional basis vectors let call themU,V
and radiusr
of base disc. From them you can create disc points with simple circle formula like this:obtain
AB
endpointscompute
U,V
basis vectorsThe
U,V
should lie in the disc base of arrowhead and should be perpendicular to each other. direction of the arrowhead (line|BA|
) is the disc base normal so exploit cross product which returns perpendicular vector to the multiplied ones so:create/render arrowhead geometry
That is easy booth
A,B
are centers of triangle fan (need 2) and the disc base points are computed like this:So just loop
ang
through the whole circle with some step so you got enough points (usually 36 is enough) and do both triangle fans from them. Do not forget the last disc point must be the same as the first one otherwise you will got ugly seems or hole on theang = 0
or360
deg.If you still want to go for rotations instead then this is doable like this. compute
U,V,W
in the same way as above and construct transformation matrix from them. the originO
will be pointB
and axisesX,Y,Z
will beU,V,W
the order depends on your arrowhead model.W
should match the model axis.U,V
can be in any order. So just copy all the vectors to their places and use this matrix for rendering. For more info see:[Notes]
If you do not know how to compute vector operations like cross/dot products or absolute value see:
[Edit1] simple GL implementation
I do not code in your environment but as downvote and comment suggest you guys are not able to put this together on your own which is odd considering you got this far so here simple C++/GL exmaple of how to do this (you can port this to your environment):
This renders bended arrow in XY plane with center
x,y,z
and big radiusr
. Ther0
is tube radius andr1
is arrowhead base radius. As I do not have your curve definition I choose circle in XY plane. Thea0,a1,a2
are angles where arrow starts (a0
), arrowhead starts (a1
) and ends (a2
). Thepi2
is just constantpi2=6.283185307179586476925286766559
.The idea is to remember actual and previous tube segment circle points so there for the
ptab,p0,p1
otherwise you would need to compute everything twice.As I chose XY plane directly then I know that one base vector is normal to it. and second is perpendicular to it and to arrow direction luckily circle properties provides this on its own therefore no need for cross products in this case.
Hope it is clear enough if not comment me.
[Edit2]
I needed to add this to my engine so here is the 3D version (not bound just to axis aligned arrows and the cone is bended too). It is the same except the basis vector computation and I also change the angles a bit in the header
<a0,a1>
is the whole interval andaa
is the arrowhead size but latter in code it is converted to the original convention. I added also normals for lighting computations. I added also linear Arrow where the computation of basis vectors is not taking advantage of circle properties in case you got different curve. Here result:usage:
and overview of the arows (on the right side of image):
I am using my vector lib so here are some explanations:
vector_mul(a[3],b[3],c[3])
is cross producta = b x c
vector_mul(a[3],b[3],c)
is simple multiplication by scalara = b.c
a = vector_mul(b[3],c[3])
is dot producta = (b.c)
vector_one(a[3],b[3])
is unit vectora = b/|b|
vector_copy(a[3],b[3])
is just copya = b
vector_add(a[3],b[3],c[3])
is addinga = b + c
vector_sub(a[3],b[3],c[3])
is substractinga = b - c
vector_neg(a[3],b[3])
is negationa = -b
vector_ld(a[3],x,y,z)
is just loadinga = (x,y,z)
The
pos
is the center position of your circle arrow andnor
is normal of the plane in which the arrow lies.bin
is bi-normal and the angles are starting from this axis. should be perpendicular tonor
.r,r0,r1
are the radiuses of the arrow (bend,tube,cone)The linear arrow is similar the
dir
is direction of the arrow,l
is arrow size andal
is arrowhead size.