Here's the code. Attached is the exe and source.
Use the mouse to move the end points around.
Left button+drag - move start point (red)
Right button+drag - move end point (blue)
Hold down shift to move the point in and out of the screen with up/down mouse drag.
'Example of how to align a cylinder between 2 points
'By Jim Shaw
'27/6/2007
'$include: 'GL/gl.bi'
'$include: 'GL/glu.bi'
'$include: 'windows.bi'
option explicit
TYPE vector
x AS SINGLE
y AS SINGLE
z AS SINGLE
END TYPE
declare sub drawblob(byval p as vector, byval colour as uinteger)
declare sub readinput()
dim camang as single
dim screenwidth as uinteger
dim screenheight as uinteger
dim shared init as integer
dim shared ox as integer
dim shared oy as integer
DIM shared O AS vector
DIM shared P as vector
DIM X as vector
dim Y as vector
dim Y2 as vector
dim Z as vector
dim matrix(16) as GLfloat
dim d as single
dim shared sphere as GLUQuadricObj ptr
dim radius as GLdouble
dim length as GLdouble
dim segments as GLint
dim stacks as GLint
dim cylinder as GLUQuadricObj ptr
screenwidth = 640
screenheight = 480
init = 0
SCREEN 18,32,,2
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(60,cast(single, screenwidth)/screenheight,1,1024)
glEnable(GL_DEPTH_TEST)
glDepthFunc(GL_LEQUAL)
glClearDepth(1)
'glEnable(GL_TEXTURE_2D)
glClearColor(0,1,0,1)
sphere = gluNewQuadric()
'---------------------------------------------------------------------------------------
' cylinder params
'---------------------------------------------------------------------------------------
cylinder = gluNewQuadric()
gluQuadricNormals(cylinder, GLU_SMOOTH)
gluQuadricTexture(cylinder, GL_TRUE)
radius = 10
segments = 9
stacks = 2
O.x = -100
O.y = -50
O.z = 100
P.x = 90
P.y = 50
P.z = 3
'---------------------------------------------------------------------------------------
' main loop
'---------------------------------------------------------------------------------------
do
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glRotatef(-camang, 0, 0, 1)
glTranslatef(0,0,-512)
drawblob(O,&HFF0000FF)
drawblob(P,&HFFFF0000)
glPushMatrix()
glTranslatef(O.x, O.y, O.z)
Z.x = P.x - O.x
Z.y = P.y - O.y
Z.z = P.z - O.z
'make it a unit
d = sqr(Z.x * Z.x + Z.y * Z.y + Z.z * Z.z)
'store the cylinder's length
length = d
Z.x = Z.x / d
Z.y = Z.y / d
Z.z = Z.z / d
Y.x = Z.y
Y.y = -Z.z
Y.z = 0
'make it a unit
d = sqr(Y.x * Y.x + Y.y * Y.y + Y.z * Y.z)
'check for special case
if d < 0.1 then
Y.x = -Z.z
Y.y = 0
Y.z = Z.x
d = sqr(Y.x * Y.x + Y.y * Y.y + Y.z * Y.z)
end if
Y.x = Y.x / d
Y.y = Y.y / d
Y.z = Y.z / d
'cross product
X.x = Y.y * Z.z - Y.z * Z.y
X.y = Y.z * Z.x - Y.x * Z.z
X.z = Y.x * Z.y - Y.y * Z.x
'make it a unit
d = sqr(X.x * X.x + X.y * X.y + X.z * X.z)
X.x = X.x / d
X.y = X.y / d
X.z = X.z / d
'cross product
Y2.x = X.y * Z.z - X.z * Z.y
Y2.y = X.z * Z.x - X.x * Z.z
Y2.z = X.x * Z.y - X.y * Z.x
matrix( 0)=X.x
matrix( 1)=X.y
matrix( 2)=X.z
matrix( 3)=0
matrix( 4)=Y2.x
matrix( 5)=Y2.y
matrix( 6)=Y2.z
matrix( 7)=0
matrix( 8)=Z.x
matrix( 9)=Z.y
matrix(10)=Z.z
matrix(11)=0
matrix(12)=0
matrix(13)=0
matrix(14)=0
matrix(15)=1
glMultMatrixf(@matrix(0))
glColor3f(1,1,1)
gluCylinder(cylinder, radius, radius, length, segments, stacks)
glPopMatrix()
flip
readinput()
loop until inkey$ = chr$(27)
gluDeleteQuadric(sphere)
gluDeleteQuadric(cylinder)
end
sub drawblob(byval p as vector, byval colour as uinteger)
glColor4ubv(cast(GLubyte ptr,@colour))
glPushMatrix()
glTranslatef(p.x, p.y, p.z)
gluSphere(sphere, 10, 10,10)
glPopMatrix()
end sub
sub readinput()
dim b1 as uinteger
dim b2 as uinteger
dim s as uinteger
dim m as POINT
dim dx as integer
dim dy as integer
b1 = GetAsyncKeyState(VK_LBUTTON)
b2 = GetAsyncKeyState(VK_RBUTTON)
s = GetAsyncKeyState(VK_SHIFT)
GetCursorPos(@m)
if init = 0 then
init = 1
ox = m.x
oy = m.y
end if
dx = m.x - ox
dy = -m.y + oy
ox = m.x
oy = m.y
if b1 <> 0 then
if s<>0 then
O.z = O.z + dy
else
O.x = O.x + dx
O.y = O.y + dy
end if
end if
if b2 <> 0 then
if s<>0 then
P.z = P.z + dy
else
P.x = P.x + dx
P.y = P.y + dy
end if
end if
end sub
I should explain this code a bit. The idea is to create 3 perpendicular (at right angles) vectors, each 1 unit long. Hold out your left hand and point your first finger (Peter Pointer) straight ahead. Point Tommy Thumb straight up, and your middle finder (Tony Tall) to the right. These are the 3 vectors we need, with Peter Pointer pointing along the Z axis of the cylinder.
So, step 1 is to create Peter Pointer, the Z axis, which is just
unit(P-O)
Step 2 is to create a vector which forms a plane with Z. It doesn't matter which one we pick, since no matter how you roll a cylinder around it's Z axis it always looks the same.
Given any vector in 3D, there are 3 vectors which are guaranteed not to lie along it (except in a special case).
These are (0,z,-y) or (-z,0,x) or (y,-z,0). These can easily be worked out by plugging (1,0,0) or (0,1,0) or (0,0,1) into the cross product calculation.
We need then to make this a unit vector, so we have
Y = unit(y,-z,0)
The special case sometimes means that length(Y)=0, so we spot that and pick one of the other two vectors
Y = unit(-z,0,x)
So now we have 2 unit length vectors which form a plane. To find the 3rd vector, Tony Tall, the X axis, we just perform the cross product.
X = cross(Y,Z)
The final step is to form the real Tommy Thumb, the Y axis. Since we have now guaranteed that X is perpendicular to Z, then we can create a new Y from that
Y2 = cross(X,Z)
This guarantees our matrix is going to be square (3 right angles at a corner make a cube, right

)
Y2 will be a unit vector already, because the cross product between 2 unit vectors which are perpendicular to one another is also a unit vector.
A rotation matrix is just three (unit length) axes in an array. The top row is the X axis, the middle row is the Y axis, and the bottom row is the Z axis. Since OpenGL uses 4x4 matrices, we have to pad with 0s and 1s.
X.x X.y X.z 0
Y2.x Y2.y Y2.z 0
Z.x Z.y Z.z 0
0 0 0 1
and you then just have to glMultMatrix that with the existing modelview to align your object with the axis.
Jim
<edit> updated the attachment to fix the extra line of debugging that got stuck in there, making the cylinders go fat and thin.