Help Regarding Matrix Transforms

Started by
9 comments, last by ma_hty 16 years, 6 months ago
Hey guys, I am new to OpenGl. I wish to draw a cylinder between two 3D points. I did a lot of googling but to no avail. This question has been asked many times before but not one answer has been satisfactory. Could any experienced one from you post the algo (code snippet would b a gr8 help). This should not be a big thing for you guys. Plz help me out Thanx in advance..
Advertisement
a cylinder is a circle with height

to draw a circle

glBegin( GL_POINTS );
for ( j=0;j<10;j++)
for ( i=0; i<2*PI; i+=0.1 );
glVertex3f(sin(i)*radius,j,cos(i)*radius);
glEnd();

its up to you to connect the dots
There is actually a gluCylinder function that will do the above code snippet for you pretty easily. I forget the exact syntax, but it's easy enough to look up. I think it renders along the z-axis, but a simple extra rotation matrix will fix that.

As for the transformation part, that isn't too hard once you understand how to do it. You need to do three things:

1) move the coordinate system so that (0,0) is at point a
2) rotate the coordinate system so the y-axis is pointing at point b
3) scale the y-axis vertically so that a unit of one is the distance from a to b

Then all you have to do is render a cylinder with a height of one, and you'll get a cylinder from point a to point b.

Steps one and three are easy, but I think it's the middle part that is probably tripping you up.

There is a very easy way to make "up" in world coordinates point in any direction you want, though. Basically, you need to construct three vectors, one each for a new x, y, and z. The y vector should point from point a to point b, and x and z should be orthogonal to the new y vector and each other. Since a cylinder is symmetrical around the y-axis, x and z can point any which way so long as they are orthogonal to y.

Here is a psuedo-code example (adapted from one of my projects). The CVector class is a utiliy class that I developed, but you should be able to duplicate the functionality pretty easily.

//first, translate the matrix so that vertex a is the new world center  glTranslatef(a.x, a.y, a.z);//apply a rotation matrix so that the cylinder renders along the y-axis//(remember, gluCylinder renders along the z-axis)  glRotate(90, 1.0f, 0, 0);//apply a scale matrix to scale from a to b  glScalef(cylinderWidth, a.distanceTo(b), 0);//next, move the axes so that the y-axis points towards vertex b//static, so we don't have to reinitialize it every time//your world up may be different  static CVector worldUpVector(0, 1, 0);      upVector a - b;  upVector.Normalize();  CVector leftVector = upVector.CrossProduct(worlldUpVector);  leftVector.Normalize();  CVector frontVector = frontVector.CrossProduct(leftVector);  frontVector.Normalize();  GLfloat matrix[16];  //left vector is the new x-axis  matrix[0] = leftVector.x;  matrix[1] = leftVector.y;  matrix[2] = leftVector.z;  matrix[3] = 0;  //upVector is the new y-axis  matrix[4] = upVector.x;  matrix[5] = upVector.y;  matrix[6] = upVector.z;  matrix[7] = 0;  //frontVector is the new z-axis  matrix[8] = frontVector.x;  matrix[9] = frontVector.y;  matrix[10] = frontVector.z;  matrix[11] = 0;  matrix[12] = 0;  matrix[13] = 0;  matrix[14] = 0;  matrix[15] = 1;  glMultMatrixf(matrix);//and put your code to render the cylinder here//a cylinder of 1 unit height will stretch from a to bGLUquadricObj *quadric = gluNewQuadric();void gluCylinder(  quadric,  GLdouble baseRadius,  GLdouble topRadius,  GLdouble height,  //should be 1  GLint slices,  GLint stacks);


And that's it!

[Edited by - kuroioranda on October 10, 2007 6:07:08 PM]
Thnx kuroioranda and zedz for your reply.
But kuroioranda the code u provided didnt work!!
All that i can see is probably a sheared cylinder
this is my code in C# (exactly same as yours except the starred line):






Gl.glPushMatrix();
{

Vector3 a = new Vector3(50, 0, 0);
Vector3 b = new Vector3(0, 50, 0);

//first, translate the matrix so that vertex a is the new world center
Gl.glTranslated(a.X, a.Y, a.Z);

//apply a rotation matrix so that the cylinder renders along the y-axis
//(remember, gluCylinder renders along the z-axis)
Gl.glRotatef(90, 1.0f, 0, 0);

//apply a scale matrix to scale from a to b
Gl.glScaled(10, Vector3.Distance(a, b), 0);

//next, move the axes so that the y-axis points towards vertex b

//static, so we don't have to reinitialize it every time
//your world up may be different
Vector3 worldUpVector = new Vector3(0, 1, 0);

Vector3 upVector = new Vector3();
upVector = a - b;

upVector.Normalize();
Vector3 leftVector = upVector.CrossProduct(worldUpVector);
leftVector.Normalize();
***You provided "frontVector.CrossProduct(...)" but c# throws exception as frontVector was still undefined so changed it to upVector***
Vector3 frontVector = upVector.CrossProduct(leftVector);
frontVector.Normalize();

double[] matrix = new double[16];

//left vector is the new x-axis
matrix[0] = leftVector.X;
matrix[1] = leftVector.Y;
matrix[2] = leftVector.Z;
matrix[3] = 0;

//upVector is the new y-axis
matrix[4] = upVector.X;
matrix[5] = upVector.Y;
matrix[6] = upVector.Z;
matrix[7] = 0;

//frontVector is the new z-axis
matrix[8] = frontVector.X;
matrix[9] = frontVector.Y;
matrix[10] = frontVector.Z;
matrix[11] = 0;

matrix[12] = 0;
matrix[13] = 0;
matrix[14] = 0;
matrix[15] = 1;
Gl.glMultMatrixd(matrix);

//and put your code to render the cylinder here
//a cylinder of 1 unit height will stretch from a to b
Gl.glColor3d(0.9, 0.3, 0.2);
Glu.gluCylinder(quadratic, 5, 5, 1, 20, 20);
}
Gl.glPopMatrix();


Could you plz chk what might be causing the trouble..

Thnx
Mike Popoloski | Journal | SlimDX
I created a cylinder class for my OpenGL game engine. You could take a look at that if you like in VMK #29
Move this line

//apply a scale matrix to scale from a to b
Gl.glScaled(10, Vector3.Distance(a, b), 0);

to after all the rotation. And correct the z-scale to 10.

Therefore,

//...
matrix[13] = 0;
matrix[14] = 0;
matrix[15] = 1;
Gl.glMultMatrixd(matrix);

Gl.glScaled(10, Vector3.Distance(a, b), 10); // move here

This topic is closed to new replies.

Advertisement