Author Topic: glucylinder?  (Read 10078 times)

0 Members and 1 Guest are viewing this topic.

Offline ScottyBrosious

  • C= 64
  • **
  • Posts: 25
  • Karma: 3
    • View Profile
glucylinder?
« on: June 25, 2007 »
I am useing opengl.
Is there a way to plot a cylinder from one 3d point to another?
I am getting confused always trying to translatef and rotatef.
Is there an easier way?

Offline taj

  • Bytes hurt
  • DBF Aficionado
  • ******
  • Posts: 4810
  • Karma: 189
  • Scene there, done that.
    • View Profile
Re: glucylinder?
« Reply #1 on: June 25, 2007 »
 :goodpost:Hi there,

no there isnt an easier way, you just have to do all the vector maths yourself. I don't have code for this, maybe someone does?

Chris
Challenge Trophies Won:

Offline ninogenio

  • Pentium
  • *****
  • Posts: 1668
  • Karma: 133
    • View Profile
Re: glucylinder?
« Reply #2 on: June 25, 2007 »
There is this technique i think its called axis angle and it replaces eulers or rotatef`s it points one entity at another sort of like glulookat.

http://dbfinteractive.com/index.php?topic=1874.0

there is even a link to an example in there where i point the camera at the cube but the cube could point to another entity or an invisable point somewhere in space.
Challenge Trophies Won:

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: glucylinder?
« Reply #3 on: June 26, 2007 »
Take the 2 3d points, subtract the beginning from the end and make it a unit vector.  ie.  if O is beginning and P is the end, then
Code: [Select]
Z.x = P.x - O.x
Z.y = P.y - O.y
Z.z = P.z - O.z

;make it a unit
len = sqrt(Z.x * Z.x + Z.y * Z.y + Z.z * Z.z)
Z.x = Z.x / len
Z.y = Z.y / len
Z.z = Z.z / len

That will give you the Z axis of the rotation matrix you need to set.
Then, make another vector which is
Code: [Select]
Y.x = Z.y
Y.y = -Z.z
Y.z = 0

and make that a unit too.
Code: [Select]
;make it a unit
len = sqrt(Y.x * Y.x + Y.y * Y.y + Y.z * Y.z)
Y.x = Y.x / len
Y.y = Y.y / len
Y.z = Y.z / len

Then make another vector which is
Code: [Select]
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
This is called a cross product.

That gives you a 4x4 OpenGl matrix which looks like this
Code: [Select]
X.x X.y X.z 0
Y.x Y.y Y.z 0
Z.x Z.y Z.z 0
0 0 0 1

That is then the orientation for the cylinder.

->nino - you might recognise this code - it's exactly the same as the lookat matrix stuff we did a few months ago.

Jim
« Last Edit: June 27, 2007 by Jim »
Challenge Trophies Won:

Offline taj

  • Bytes hurt
  • DBF Aficionado
  • ******
  • Posts: 4810
  • Karma: 189
  • Scene there, done that.
    • View Profile
Re: glucylinder?
« Reply #4 on: June 26, 2007 »
A karma up moment if there ever was one...
Challenge Trophies Won:

Offline ninogenio

  • Pentium
  • *****
  • Posts: 1668
  • Karma: 133
    • View Profile
Re: glucylinder?
« Reply #5 on: June 26, 2007 »
yep i thought this stuff was black magic or something at first  :D its great!
Challenge Trophies Won:

Offline ScottyBrosious

  • C= 64
  • **
  • Posts: 25
  • Karma: 3
    • View Profile
Re: glucylinder?
« Reply #6 on: June 26, 2007 »
Thanks for the explanation.
Could you code me up a small program
showing the code in action?
All's I need is to be able to draw a glucylinder from a 3d point to another.
Thanks

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: glucylinder?
« Reply #7 on: June 27, 2007 »
Actually, I missed a step...

Once you have X,Y and Z, you need to get the real Y axis
Code: [Select]
'make it a unit
len = sqr(X.x * X.x + X.y * X.y + X.z * X.z)
X.x = X.x / len
X.y = X.y / len
X.z = X.z / len

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
That gives you a 4x4 OpenGl matrix which looks like this
Code: [Select]
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

I realise it's complicated Scotty mate, I'm working on a demo for you...

Jim
« Last Edit: June 27, 2007 by Jim »
Challenge Trophies Won:

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: glucylinder?
« Reply #8 on: June 27, 2007 »
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.

Code: [Select]
'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.
Code: [Select]
  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.
« Last Edit: June 27, 2007 by Jim »
Challenge Trophies Won:

Offline ninogenio

  • Pentium
  • *****
  • Posts: 1668
  • Karma: 133
    • View Profile
Re: glucylinder?
« Reply #9 on: June 28, 2007 »
love it! excellent demo jim k+!
Challenge Trophies Won:

Offline DrewPee

  • I Toast Therefore I am
  • Pentium
  • *****
  • Posts: 563
  • Karma: 25
  • Eat Cheese - It's good for you!
    • View Profile
    • Retro Computer Museum
Re: glucylinder?
« Reply #10 on: June 29, 2007 »
Jim,
That sure is some excellent code! I haven't even looked at GL stuff yet - but holy shit you make it so understandable!
Everybody on this forum should thank guys like you for making things easier to understand and share code!

 :goodpost:

Drew

PS Karma+
DrewPee
aka Falcon of The Lost Boyz (Amiga)
Ex-Amiga Coder and Graphic Designer
Administrator of > www.retrocomputermuseum.co.uk