Really need your help... gluUnProject and revolving bsplines around axis...

I had a simple project in mind: user clicks on screen and bspline is generated. Then that b-spline is swept around (the middle of screen) and a b-spline surface is made. I have done the b-spline functions are they work perfectly. The gluUnProject also works… (but the z values returned are around -93). The problem starts when I try to rotate the curve. I understand that I can just rotate the control points and pass them again to b-spline drawing function and they will draw them correctly.
NOTE: I’m writing my own b-spline routines, not using Opengl ones…
My problem: the spline is rotated weirdly and disappears from the view… Here are my functions:

//
/
Multiply a point by a matrix /
/
/
Point3d multPointByMatrix (Point3d p, Matrix3x3 mat) {

float tempZ;
Point3d rp;

/* Get the z value of point */
//tempZ = p.z;
//p.z = 0.0;

rp.x = p.x * mat.n00 + p.y * mat.n01 + p.z * mat.n02;
rp.y = p.x * mat.n10 + p.y * mat.n11 + p.z * mat.n12;
rp.z = p.x * mat.n20 + p.y * mat.n21 + p.z * mat.n22;

/* Add the original z back to the new one */
//p.z += tempZ;

return rp;

}

/*****************************************************************************************/
/
Rotate a set of points around y axis, given the rotation in degrees /
/
*****************************************************************************************/
void rotatePointsOnY ( float degRotY, Point3d origPts[], Point3d rotatedPts[], int numOfPoints) {

int i;
/* Build rotation matrix */
Matrix3x3 mat;	

mat.n00 = cos(degRotY);
mat.n01 = 0.0;
mat.n02 = sin(degRotY);
mat.n10 = 0.0;
mat.n11 = 1.0;
mat.n12 = 0.0;
mat.n20 = -sin(degRotY);
mat.n21 = 0.0;
mat.n22 = cos(degRotY);

for (i = 0; i < numOfPoints; i++) {
	rotatedPts[i] = multPointByMatrix (origPts[i], mat);
}

}

My gluUnProject is use just like described in RedBook: (part of my mouse callback function)
case GLUT_LEFT_BUTTON:
if (state == GLUT_DOWN) {

			glGetIntegerv (GL_VIEWPORT, viewport);
			glGetDoublev (GL_MODELVIEW_MATRIX, mvmatrix);
			glGetDoublev (GL_PROJECTION_MATRIX, projmatrix);

			/*viewport [3] is height of window in pixels */
			/* bottom left of viewport is 0.0, top right is width-1, height -1 */
			real_y = viewport[3] - (GLint) y -1;
			/*printf ("Coordinates at cursor are (%4d, %4d)

", x, real_y);*/

			/* assume world z coordinate is z = 1.0 */
			gluUnProject ((GLdouble) x, (GLdouble) real_y, 1.0, mvmatrix, projmatrix, viewport, &wx, &wy, &wz);
			/*printf ("world coords at z=1.0 are (%f, %f, %f)

", wx, wy, wz);*/

wz, wy and wz are then used to create the new points in control point array that is used to calculate b-splines

Matrix and point definitions are as following:

typedef struct {
float x, y, z;
} Point3d;

typedef struct {
float n00, n01, n02;
float n10, n11, n12;
float n20, n21, n22;
} Matrix3x3;

I’ve spent two days trying to find the bug…
I know it must be in the way I’m handling either the unProject or doing the rotation…

Your help is invaluable to me…
Thank you,
Luke

Just to add to this, the b-spline is actually rotated (swept) 360 degrees around y axis. For instance, a wine glass profile when quickly rotated would generate a ‘trace’ of a wine glass.
Please help :frowning:

Shoot, one more thing…
I CAN’T USE OPENGL glRotated(…) function. I must actually rotate the control points on the bspline as they will be then used to calculate triangles that would make up the surface.
I.e. the algorithm would be

  • 2 curves
  • trace both changing the t values and write out the coordinates of the points etc…
    So I must actually write my own rotation…
    At least I think I do :slight_smile:
    ?
    Thanks again,
    Luke

And for those who really want to help, but the code gives is not enough, here’s the full source code of my mini project :slight_smile:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <GL/glut.h>

#define MAX_CTRL_POINTS 50 /* Maximum control points for b-spline curve /
#define WIN_WIDTH 640 /
Dimentions of Opengl window /
#define WIN_HEIGHT 480
#define CURVE_STEP 0.005 /
This represents the resolution of the b-spline on screen. The smaller the value, the smoother the curve */

/* Helper macros /
#define PI (3.14159265359f)
#define DEG2RAD(a) (PI/180
(a))
#define RAD2DEG(a) (180/PI*(a))

/********************************************************************/
/
Structure to hold 3d point /
/
********************************************************************/
typedef struct {
float x, y, z;
} Point3d;

/********************************************************************/
/
Structure to hold a triangle /
/
*******************************************************************/
typedef struct {
/
3 points that make up the triangle /
/
POINTS MUST BE IN COUNTER CLOCKWISE ORDER !!! /
Point3d p1;
Point3d p2;
Point3d p3;
/
Triangle normal - represented as point, but is really a 3d vector, which is normalized */
Point3d normal;
} Triangle;

/********************************************************************/
/
Structure defining a 3x3 matrix /
/
********************************************************************/
typedef struct {
float n00, n01, n02;
float n10, n11, n12;
float n20, n21, n22;
} Matrix3x3;

/********************************************************************/
/
GLOBAL VARIABLES /
/
********************************************************************/

int numOfCtrlPoints = 0;
Point3d ctrlPoints [MAX_CTRL_POINTS];
Point3d rotatedCtrlPoints[MAX_CTRL_POINTS];
Point3d newPoint;

float max_t; /* holds the maximum t value from the knot vector /
int order = 4; /
Holds the order of the spline */

/* function prototypes */
void drawPoints ();
void drawBspline (float tInit, float tEnd, float stepInT, Point3d ctrls[], int numOfCtrls);
Point3d triangleNormal(Triangle tri);
void rotatePointsOnY ( float degY, Point3d origPts[], Point3d rotatedPts[], int numOfPoints);

/*********************************************************************/
void glInit(void) {

/****** FOR PROGRAM 2 ******/
/*	Setup for the lights: */
float ambientLight[] = { 0.5f, 0.5f, 0.5f, 1.0f};	/* Redish ambient light */
float diffuseLight[] = { 0.7f, 0.7f, 0.7f, 1.0f};
/* Position is the same as the camera position */
float lightPosition[] = { 0.0f, 0.0f, 5.0f, 0.0f};	
/* Setup materials*/
float matAmbient[] = { 0.5f, 0.5f, 0.5f, 1.0f };
float matDiff[] = { 0.8f, 0.6f, 0.8f, 1.0f };
/****** END FOR PROGRAM 2 ****/

glClearColor (0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_SMOOTH);
glPointSize(5.0f);

/****** FOR PROGRAM 2 ******/
/*	Turn on z-buffer */
glEnable(GL_DEPTH_TEST);
/*	Turn on the backface culling */
glEnable(GL_CULL_FACE);
/* COUTERCLOCKWISE polygons and triangle faces are kept */
glFrontFace(GL_CCW);

glEnable(GL_LIGHTING);
glMaterialfv(GL_FRONT, GL_AMBIENT, matAmbient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, matDiff);

/* Setup LIGHT0 */
glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);
glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);

/*	Enable the light */
glEnable(GL_LIGHT0);

/* Turn on auto normalization of normal vectors for Opengl */
glEnable(GL_NORMALIZE);
/****** END FOR PROGRAM 2 ****/


printf("

Welcome to this amazing b-spline drawing program!
");
printf("It currently allows for up to 50 control points.
");
printf("Pressing ‘2’, ‘3’, ‘4’, or ‘5’ on keyboard
“);
printf(” will make the spline change to that order.
“);
printf(” The default order is 4, making the spline cubic.
");
printf("Notice that spline of order 5 will need at least 5 control points to be visible
");
printf("To make a curve sharp at a certain point (to interpolate through that point
“);
printf(” click a few times on that point. The more you click it,the sharper it gets! :slight_smile:
");
printf("Pressing ‘d’ on the keyboard while drawing the curve
“);
printf(” will delete the last point of curve.
");
printf("Pressing ‘q’ will quit the program.
");

}

/*********************************************************************/
void display(void) {

Triangle tri;

/*Clear the screen */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glColor3f(1.0, 1.0, 1.0);
glLoadIdentity();
gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

/* These are for testing only */
glutWireCube(3.0);

/***************************** Testing code for triangles ************************/

tri.p1.x = -5.0;
tri.p1.y = 5.0;
tri.p1.z = -50.0;

tri.p2.x = -5.0;
tri.p2.y = -5.0;
tri.p2.z = -50.0;

tri.p3.x = 5.0;
tri.p3.y = -5.0;
tri.p3.z = -40.0; 

tri.normal = triangleNormal( tri);

glBegin(GL_TRIANGLES);
	glNormal3f(tri.normal.x, tri.normal.y, tri.normal.z);
	glVertex3f(tri.p1.x, tri.p1.y, tri.p1.z);
	glVertex3f(tri.p2.x, tri.p2.y, tri.p2.z);
	glVertex3f(tri.p3.x, tri.p3.y, tri.p3.z);
glEnd();

/*********************  End of Testing code for triangles ************************/

/*Draw points in red, spline in blue */
glColor3f(1.0, 0.0, 0.0);
drawPoints();
glColor3f(0.0, 0.0, 1.0);
drawBspline ( 0.0,  max_t, CURVE_STEP, ctrlPoints,  numOfCtrlPoints);


/********************** Test code for rotation on curve **************************/

rotatePointsOnY ( 100.0,  ctrlPoints,  rotatedCtrlPoints,  numOfCtrlPoints);
drawBspline ( 0.0,  max_t, CURVE_STEP, rotatedCtrlPoints,  numOfCtrlPoints);

/************** End of Test code for rotation on curve **************************/

glFlush();

glutSwapBuffers();
glutPostRedisplay();

}
/********************************************************************/
/
callback function to handle keyboard input /
/
********************************************************************/
void keyboard(unsigned char key, int x, int y) {

/* Quit on any key */

switch (key) {

  case 'q':
	   exit(0);
  case '2':
	  order = 2;
	  break;
  case '3':
	  order = 3;
	  break;
  case '4':
	  order = 4;
	  break;
  case '5':
	  order = 5;
	  break;
  case 'd':
	  if (numOfCtrlPoints &gt; order) 
		  numOfCtrlPoints -= 1;
	  else
		  printf("

Can’t delete a point where number of control points < order of curve!
");
break;
default:
break;
}

}
/********************************************************************/
/
Callback function to handle the mouse /
/
********************************************************************/
void mouse (int button, int state, int x, int y) {

GLint viewport [4];		/*holds the viewport data*/
GLdouble mvmatrix[16], projmatrix[16];
GLint real_y;			/*OpenGL y coordinate position */
GLdouble wx, wy, wz;	/* returned world x, y, z coords */

switch (button) {
	case GLUT_LEFT_BUTTON:
		if (state == GLUT_DOWN) {

			glGetIntegerv (GL_VIEWPORT, viewport);
			glGetDoublev (GL_MODELVIEW_MATRIX, mvmatrix);
			glGetDoublev (GL_PROJECTION_MATRIX, projmatrix);

			/*viewport [3] is height of window in pixels */
			/* bottom left of viewport is 0.0, top right is width-1, height -1 */
			real_y = viewport[3] - (GLint) y -1;
			/*printf ("Coordinates at cursor are (%4d, %4d)

", x, real_y);*/

			/* assume world z coordinate is z = 1.0 */
			gluUnProject ((GLdouble) x, (GLdouble) real_y, 1.0, mvmatrix, projmatrix, viewport, &wx, &wy, &wz);
			/*printf ("world coords at z=1.0 are (%f, %f, %f)

", wx, wy, wz);*/

			/* check to see if not max number of control points */
			if (numOfCtrlPoints &lt; MAX_CTRL_POINTS ) {

				numOfCtrlPoints++;

				/* write to newPoint */
				newPoint.x = wx;
				newPoint.y = wy;
				newPoint.z = wz;

				/* add to array of control points */

				ctrlPoints[numOfCtrlPoints-1] = newPoint;
			}
			else
				printf ("

MAXIMUM NUMBER OF CONTROL POINTS (%d) REACHED !
", MAX_CTRL_POINTS);

		}
		break;
	default:
		break;
}

}

/********************************************************************/
/
Callback function to change the Viewport on resizing the screen /
/
********************************************************************/
void reshape ( int w, int h) {

glViewport (0,0, (GLsizei)w, (GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, (GLfloat) w / (GLfloat) h, 1.0, 100);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

}

/********************************************************************/
/
draw points /
/
********************************************************************/
void drawPoints () {

int i;
glBegin (GL_POINTS);
	for (i = 0; i &lt; numOfCtrlPoints; i++) {
			glVertex3f(ctrlPoints[i].x, ctrlPoints[i].y, ctrlPoints[i].z);
	}
glEnd();

}

/********************************************************************/
/
Generates standard knot vector for given values of m and L /
/
Source of code: ‘Computer graphics using Opengl’ by F.S.Hill /
/
*******************************************************************/
void buildKnots (int m, int L, float knotV []) {
/
Builds the standard knot vector for L + 1 control points
and b-spline of order m /
int i;
/
For a given m, there must be a sufficient number of control point /
if (L < (m - 1)) return; /
Too few control points */
for ( i = 0; i <= L + m; i++ ) {
if (i < m) knotV[i] = 0.0;
else if (i <= L)
knotV[i] = i - m + 1; /i is at least m /
else knotV[i] = L - m + 2; /
i exceeds L /
}
/
set the gloabal variable holding maximum value of t in knot vector
/
max_t = knotV[L+m];
}

/********************************************************************/
/
Function to calculate recursive formulation of Nk,m(t) /
/
Source of code: ‘Computer graphics using Opengl’ by F.S.Hill /
/
********************************************************************/
float bSpline (int k, int m, float t, float knotV []) {

float denom1, denom2, sum = 0.0;
if (m == 1)
	return (t &gt;= knotV[k] && t &lt; knotV[k+1]); /* return 1 or 0 */
/* if m exceeds 1, use recursion */
denom1 = knotV[k+m-1] - knotV[k];
if (denom1 != 0.0)
	sum = (t - knotV[k]) * bSpline (k, m-1, t, knotV) / denom1;
denom2 = knotV[k+m] - knotV[k+1];
if (denom2 != 0.0)
	sum += (knotV[k+m] - t) * bSpline(k+1, m-1, t, knotV) / denom2;
return sum;

}

/********************************************************************/
/
Calculates a 3d point given t and array of control points /
/
********************************************************************/
Point3d pointOnBspline (float t, Point3d ctrls[], int numOfCtrls) {

Point3d calculatedPoint;
int k;
float bsplineVal;
float knots[MAX_CTRL_POINTS+10];

buildKnots (order, numOfCtrls-1,knots);

calculatedPoint.x = 0.0;
calculatedPoint.y = 0.0;

for (k = 0; k &lt; numOfCtrls; k++ ) {

	bsplineVal = bSpline(k, order, t, knots);
	calculatedPoint.x += ctrls[k].x * bsplineVal;
	calculatedPoint.y += ctrls[k].y * bsplineVal;

}

calculatedPoint.z = ctrls[0].z;		/* Should be able to get any value of z points. Assuming they will all line up on z axis */
return calculatedPoint;

}

//
/
Draw a bSpline curve, given range of t, step - resolution, and control points /
/
/
void drawBspline (float tInit, float tEnd, float stepInT, Point3d ctrls[], int numOfCtrls) {

Point3d tempPoint;

glBegin(GL_LINE_STRIP);
	while (tInit &lt;= tEnd) {
		tempPoint = pointOnBspline(tInit,  ctrls,  numOfCtrls);
		glVertex3f(tempPoint.x, tempPoint.y, tempPoint.z);
		tInit += stepInT;
	}
glEnd();

}

/********************************************************************************************/
/
Take cross product of 2 vectors - in this example Point 3d structur is treated as vector /
/
********************************************************************************************/
Point3d crossProd (Point3d a, Point3d b) {

Point3d crossPVec;
crossPVec.x = a.y*b.z - a.z*b.y;
crossPVec.y = a.z*b.x - a.x*b.z;
crossPVec.z = a.x*b.y - a.y*b.x;

/* Note, normally this would have to be normalized, but we will use the GL_NORMALIZE to do it for us */
return crossPVec;

}

//
/* Calculate normal of a triangle */
/
/
Point3d triangleNormal(Triangle tri) {

Point3d vector1, vector2, normal;

/* Calculate the two vector that we need to calculate the cross product */
vector1.x = tri.p1.x - tri.p2.x;
vector1.y = tri.p1.y - tri.p2.y;
vector1.z = tri.p1.z - tri.p2.z;

vector2.x = tri.p2.x - tri.p3.x;
vector2.y = tri.p2.y - tri.p3.y;
vector2.z = tri.p2.z - tri.p3.z;

normal = crossProd(vector1, vector2);

return normal;

}

//
/
Multiply a point by a matrix /
/
/
Point3d multPointByMatrix (Point3d p, Matrix3x3 mat) {

float tempZ;
Point3d rp;

/* Get the z value of point */
//tempZ = p.z;
//p.z = 0.0;

rp.x = p.x * mat.n00 + p.y * mat.n01 + p.z * mat.n02;
rp.y = p.x * mat.n10 + p.y * mat.n11 + p.z * mat.n12;
rp.z = p.x * mat.n20 + p.y * mat.n21 + p.z * mat.n22;

/* Add the original z back to the new one */
//p.z += tempZ;

return rp;

}

/*****************************************************************************************/
/
Rotate a set of points around y axis, given the rotation in degrees /
/
*****************************************************************************************/
void rotatePointsOnY ( float degRotY, Point3d origPts[], Point3d rotatedPts[], int numOfPoints) {

int i;
/* Build rotation matrix */
Matrix3x3 mat;	

/* Convert degrees to radians */
/* degY = DEG2RAD(degRotY); */

mat.n00 = cos(degRotY);
mat.n01 = 0.0;
mat.n02 = sin(degRotY);
mat.n10 = 0.0;
mat.n11 = 1.0;
mat.n12 = 0.0;
mat.n20 = -sin(degRotY);
mat.n21 = 0.0;
mat.n22 = cos(degRotY);

//mat.n00 = cos(degRotY);
//mat.n01 = 0.0;
//mat.n02 = -sin(degRotY);
//mat.n10 = 0.0;
//mat.n11 = 1.0;
//mat.n12 = 0.0;
//mat.n20 = sin(degRotY);
//mat.n21 = 0.0;
//mat.n22 = cos(degRotY);

for (i = 0; i &lt; numOfPoints; i++) {
	rotatedPts[i] = multPointByMatrix (origPts[i], mat);
}

}

/*******************************************************************/
int main(int argc, char
argv) {

/* Standard glut application framework */

glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize (WIN_WIDTH, WIN_HEIGHT);
glutInitWindowPosition (100, 100);
glutCreateWindow(“CS 388 Assignment#3 by Luke Piasecki and Grzesiek Stozek”);
glInit();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutMouseFunc(mouse);

glutMainLoop();

return 0;

}
/*********************************************************************/
/*********************************************************************/

(“CS 388 Assignment#3 by Luke Piasecki and Grzesiek Stozek”);

Ah, so you want someone else to do your homework?

No, I’ve done most of the homework.
I’m asking for someone to help me and point out what am I doing wrong :slight_smile:
BTW, it’s not the assignment anymore. I’ve done much more in this one that was requested…

Please disregard this post. I’ve found what I’ve done wrong! :slight_smile:
IT was here:
/* Get the z value of point */
tempZ = p.z;
p.z = 0.0;

rp.x = p.x * mat.n00 + p.y * mat.n01 + p.z * mat.n02;
rp.y = p.x * mat.n10 + p.y * mat.n11 + p.z * mat.n12;
rp.z = p.x * mat.n20 + p.y * mat.n21 + p.z * mat.n22;

/* Add the original z back to the new one */
p.z += tempZ; <- I should be adding this to rp, not p :slight_smile:

Originally posted by gator:
Ah, so you want someone else to do your homework?

No, they want an answer to a maths question on an Advanced OpenGL forum.

BigShooter, what’s this glut.h you’re using?
Please post the contents of this file so we can resolve your problem.

glut.h comes from here:
http://www.opengl.org/developers/documentation/glut/

I’m using the latest glut I’ve downloaded from the web. Ogl is on WinXP.
As I said though, I’ve fixed the problem.
For those who made sarcastic comments about my question. First of all, yet it was a math question on ogl forum, but a lot of math questions pop up here as graphics and math usually go together. I thought that a lot of people here could help me. Sorry for that.
As to someone doing my homework, it wasn’t a homework. The window title was simply bacause I compied the glut backbone from previous assignment. But wheather or not it is homework, I don’t think it makes a difference.
I wasn’t asking for anyone to do it for me. I was asking a question, related to graphics. I was having trouble. I really don’t think that wheather it is an assignments, project, exam, commerical project or personal, should make any difference. For those who think otherwise, simply don’t reply :slight_smile:

Sorry, had to say that. For others, thank you for your constant help with my questions.

Luke

Originally posted by BigShooter:
I really don’t think that wheather it is an assignments, project, exam, commerical project or personal, should make any difference. For those who think otherwise, simply don’t reply :slight_smile:
Luke

I agree with you 100%, and that’s why I am replying. It doesn’t matter whether it is an assignment or not. When someone posts two-hundred lines of code and asks for help, I simply won’t look at it at all. For those who think otherwise, simply don’t reply.