Picking, ctrl pts on nurbs surface

I’m a Newbie to OpenGL, and the list. Trying to pick control points for nurbs surface. Not having any luck with my example below. I seem to get ‘0’ hits, and only 1 name on the stack. Anyone happen to be working with nurbs, picking, and control points and could possibly help?

I’ve looked at the edit.c ex. which uses evaluators not nurbs, but does control point selection, also the picking.c ex. for picking, and the surface.c example for drawing nurbs.

Any help or pointers for how to pick points for nurbs surface greatly appreciated.

/*

  • from glut exs: surface.c, picksquare.c, and edit.c
  • This program draws a NURBS surface and shows control points
    */

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

GLfloat ctlpoints[4][4][3];
int showPoints = 1;

GLUnurbsObj *theNurb;

/*

  • Initializes the control points of the surface.
  • The control points range from -3 to +3 in x, y, and z
    /
    void drawSurface(GLenum mode)
    {
    int u, v;
    for (u = 0; u < 4; u++) {
    if (mode == GL_SELECT)
    glLoadName (u);
    for (v = 0; v < 4; v++) {
    if (mode == GL_SELECT)
    glPushName (v);
    ctlpoints[u][v][0] = 2.0
    ((GLfloat)u - 1.5);
    ctlpoints[u][v][1] = 2.0*((GLfloat)v - 1.5);
    if (mode == GL_SELECT)
    glPopName ();
    }
    }
    }

/* Initialize material property and depth buffer.
*/
void init(void)
{
GLfloat mat_diffuse[] = { 0.7, 0.7, 0.7, 1.0 };
GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat mat_shininess[] = { 100.0 };

glClearColor (0.0, 0.0, 0.0, 0.0);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);

glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
glEnable(GL_AUTO_NORMAL);
glEnable(GL_NORMALIZE);

drawSurface (GL_SELECT);

theNurb = gluNewNurbsRenderer();
gluNurbsProperty(theNurb, GLU_SAMPLING_TOLERANCE, 25.0);
gluNurbsProperty(theNurb, GLU_DISPLAY_MODE, GLU_OUTLINE_POLYGON);
}

void display(void)
{
GLfloat knots[8] = {0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0};
int i, j;

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glPushMatrix();
glRotatef(330.0, 1.,0.,0.);
glScalef (0.5, 0.5, 0.5);

gluBeginSurface(theNurb);
gluNurbsSurface(theNurb,
8, knots, 8, knots,
4 * 3, 3, &ctlpoints[0][0][0],
4, 4, GL_MAP2_VERTEX_3);
gluEndSurface(theNurb);

if (showPoints) {
glPointSize(8.0);
glDisable(GL_LIGHTING);
glColor3f(1.0, 0.0, 0.0);
glBegin(GL_POINTS);
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
glVertex3f(ctlpoints[i][j][0],
ctlpoints[i][j][1], ctlpoints[i][j][2]);
}
}
glEnd();
glEnable(GL_LIGHTING);
}
glPopMatrix();
glFlush();
}

void reshape(int w, int h)
{
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective (45.0, (GLdouble)w/(GLdouble)h, 3.0, 8.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef (0.0, 0.0, -5.0);
}

/* processHits prints out the contents of the

  • selection array.
    */
    void processHits (GLint hits, GLuint buffer[])
    {
    unsigned int i, j;
    GLuint ii, jj, names, *ptr;

printf (“hits = %d
“, hits);
ptr = (GLuint ) buffer;
for (i = 0; i < hits; i++) { /
for each hit */
names = *ptr;
printf (” number of names for this hit = %d
“, names); ptr++;
printf(” z1 is %g;”, (float) *ptr/0x7fffffff); ptr++;
printf(" z2 is %g
“, (float) ptr/0x7fffffff); ptr++;
printf (" names are ");
for (j = 0; j < names; j++) { /
for each name */
printf (”%d “, ptr);
if (j == 0) /
set row and column */
ii = *ptr;
else if (j == 1)
jj = *ptr;
ptr++;
}
printf (”
");
}
}

/* pickCtlPoints() sets up selection mode, name stack,

  • and projection matrix for picking.
    */
    #define BUFSIZE 512

void pickCtlPoints(int button, int state, int x, int y)
{
GLuint selectBuf[BUFSIZE];
GLint hits;
GLint viewport[4];

if (button != GLUT_LEFT_BUTTON || state != GLUT_DOWN)
return;

glGetIntegerv (GL_VIEWPORT, viewport);
glSelectBuffer (BUFSIZE, selectBuf);

(void) glRenderMode (GL_SELECT);
glInitNames();
glPushName(0);

glMatrixMode (GL_PROJECTION);
glPushMatrix ();
glLoadIdentity ();
/* create 5x5 pixel picking region near cursor location */
gluPickMatrix ((GLdouble) x, (GLdouble) (viewport[3] - y),
5.0, 5.0, viewport);
gluOrtho2D (0.0, 3.0, 0.0, 3.0);

drawSurface (GL_SELECT);

glMatrixMode (GL_PROJECTION);
glPopMatrix ();
glFlush ();

hits = glRenderMode (GL_RENDER);
processHits (hits, selectBuf);

//-----------------
GLint stackSize;
glGetIntegerv(GL_NAME_STACK_DEPTH, &stackSize);
//number of names on the slection stack:
printf("STACK_DEPTH = %d
", stackSize);
//-----------------

}

int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize (500, 500);
glutInitWindowPosition (100, 100);
glutCreateWindow(argv[0]);
init();
glutReshapeFunc(reshape);
glutMouseFunc (pickCtlPoints);
glutDisplayFunc(display);
glutMainLoop();
return 0;
}

You could really have stripped all the Nurbs-rendering to make your sample code a bit shorter and

 to make it easier to read.

I dont have a final answer, but to me it seems you are drawing the the control points with a different perspective (projection matrix) in GL_SELECT mode, which I think you actually don't want to (apart from the picking region scaling).

Alright, i digged deeper through that code and you seem to be misunderstanding the concept of picking.


void drawSurface(GLenum mode)
{
   int u, v;
   for (u = 0; u < 4; u++) {
      if (mode == GL_SELECT) glLoadName (u);
      
      for (v = 0; v < 4; v++) {
         if (mode == GL_SELECT)
         glPushName (v);
            ctlpoints[u][v][0] = 2.0*((GLfloat)u - 1.5);
            ctlpoints[u][v][1] = 2.0*((GLfloat)v - 1.5);
            if (mode == GL_SELECT)
         glPopName ();
      }
   } 
}

What you do here is initializing your control points and altering the stack. However there is no drawing going on, so whatever you do to the name stack here will show you no result.
When you’re drawin in GL_SELECT mode, the content of the name stack will be fed into your select buffer, whenever the primitive to be drawn intersects the “view”-volume.
The only effective action to the Namestack, which OpenGL will see is the glPushName(0); pickCtlPoints plus the additional replacement of that first element in drawSurface.

What you really should do is:
start GL_SELECT, gluPickMatrix, setup perspective (use the same Perspective as if drawing usual), initialize select buffer and then in a loop:

for every control point
Load Control-Point id on name stack
Draw Control-Point
end

And here’s a tutorial on picking, acutally easily found with your favourite search tool: http://www.lighthouse3d.com/opengl/picking/

Hi,
Thank you for the Lighthouse link. I’ve looked at it and it seems geared for picking objects, instead of control points on a nurbs surface. I understand the process should be similar as in the picksquares.c example. I’m working from that idea along with the editgrid.c example to try to understand how to pick control points associated with nurbs surfaces.

I modified my code a bit, but I’m still stuck and not getting any names loaded onto the stack. I’m able to draw the nurbs grid, and the control points, but cannot seem to select any control points. Any help with code examples very much appreciated.

 
/*
 *  from glut exs: surface.c, picksquare.c, and editgrid.c
 *  This program draws a NURBS surface and shows control points
*/


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

GLfloat ctlpoints[4][4][3];
int showPoints = 1;

GLUnurbsObj *theNurb;

void selectControlPoints(void)
{
   int u, v;
   glMatrixMode(GL_SELECT);
   for (u = 0; u < 4; u++) {
      for (v = 0; v < 4; v++) {
        glLoadName(u*4+v);
    glBegin(GL_POINTS);
      glVertex3f(ctlpoints[u][v][0], 
               ctlpoints[u][v][1], ctlpoints[u][v][2]); 
               //printf("[%d][%d] 
", u, v);      
      }
   }
   glEnd(); 
}
			
/*  Initialize material property and depth buffer,
 *  and grid surface
 */
void init(void)
{
   GLfloat mat_diffuse[] = { 0.7, 0.7, 0.7, 1.0 };
   GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
   GLfloat mat_shininess[] = { 100.0 };

   glClearColor (0.0, 0.0, 0.0, 0.0);
   glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
   glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
   glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);

   glEnable(GL_LIGHTING);
   glEnable(GL_LIGHT0);
   glEnable(GL_DEPTH_TEST);
   glEnable(GL_AUTO_NORMAL);
   glEnable(GL_NORMALIZE);
   
   //init grid surface
   int u, v;
   for (u = 0; u < 4; u++) {
      for (v = 0; v < 4; v++) {
         ctlpoints[u][v][0] = 2.0*((GLfloat)u - 1.5);
         ctlpoints[u][v][1] = 2.0*((GLfloat)v - 1.5);
      }
   }
 
   //nurbs properties
   theNurb = gluNewNurbsRenderer();
   gluNurbsProperty(theNurb, GLU_SAMPLING_TOLERANCE, 25.0);
   gluNurbsProperty(theNurb, GLU_DISPLAY_MODE, GLU_OUTLINE_POLYGON);
}

void display(void)
{
   GLfloat knots[8] = {0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0};
   int i, j;

   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

   glPushMatrix();
   glRotatef(330.0, 1.,0.,0.);
   glScalef (0.5, 0.5, 0.5);

   gluBeginSurface(theNurb);
   gluNurbsSurface(theNurb, 
                   8, knots, 8, knots,
                   4 * 3, 3, &ctlpoints[0][0][0], 
                   4, 4, GL_MAP2_VERTEX_3);
   gluEndSurface(theNurb);

   // create the control points
   if (showPoints) {
      glMatrixMode(GL_SELECT);
      glPointSize(8.0);
      glDisable(GL_LIGHTING);
      glColor3f(1.0, 0.0, 0.0);
      glBegin(GL_POINTS);
      for (i = 0; i < 4; i++) {
         for (j = 0; j < 4; j++) {
	    glVertex3f(ctlpoints[i][j][0], 
              ctlpoints[i][j][1], ctlpoints[i][j][2]);
         }
      }
      glEnd();
      glEnable(GL_LIGHTING);
   }
   glPopMatrix();
   glFlush();
}


void reshape(int w, int h)
{
   glViewport(0, 0, (GLsizei) w, (GLsizei) h);
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   gluPerspective (45.0, (GLdouble)w/(GLdouble)h, 3.0, 8.0);
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   glTranslatef (0.0, 0.0, -5.0);
}

/*  processHits prints out the contents of the 
 *  selection array.
 */
void processHits (GLint hits, GLuint buffer[])
{
   unsigned int i, j;
   GLuint ii, jj, names, *ptr;

   printf ("hits = %d
", hits);
   ptr = (GLuint *) buffer;
   for (i = 0; i < hits; i++) {	/*  for each hit  */
      names = *ptr;
      printf (" number of names for this hit = %d
", names); ptr++;
      printf("  z1 is %g;", (float) *ptr/0x7fffffff); ptr++;
      printf(" z2 is %g
", (float) *ptr/0x7fffffff); ptr++;
      printf ("   names are ");
      for (j = 0; j < names; j++) { /*  for each name */
         printf ("%d ", *ptr);
         if (j == 0)  /*  set row and column  */
            ii = *ptr;
         else if (j == 1)
            jj = *ptr;
         ptr++;
      }
      printf ("
");
   }
}

/*  pickCtlPoints() sets up selection mode, name stack, 
 *  and projection matrix for picking. 
 */
#define BUFSIZE 512

void pickCtlPoints(int button, int state, int x, int y)
{
   GLuint selectBuf[BUFSIZE];
   GLint hits;
   GLint viewport[4];

  if (button != GLUT_LEFT_BUTTON || state != GLUT_DOWN)
      return;

   glGetIntegerv (GL_VIEWPORT, viewport);
   glSelectBuffer (BUFSIZE, selectBuf);
   
   //change to render mode to use selection
   (void) glRenderMode (GL_SELECT);
   glInitNames();
   glPushName(0);

   //change to the projection matrix
   glMatrixMode (GL_PROJECTION);
   glPushMatrix ();
   glLoadIdentity ();
   
   //place view volume around the mouse pointer
/*  create 5x5 pixel picking region near cursor location	*/
   gluPickMatrix ((GLdouble) x, (GLdouble) (viewport[3] - y), 
                  5.0, 5.0, viewport);
   gluOrtho2D (0.0, 3.0, 0.0, 3.0);

     //change to modelview matrix
	//to select points
	glMatrixMode(GL_MODELVIEW);
    selectControlPoints();

   //restores original projection matrix
   glMatrixMode (GL_PROJECTION);
   glPopMatrix ();
   //glFlush ();

   //return to modelview matrix for rendering
   glMatrixMode(GL_MODELVIEW);
   
   hits = glRenderMode (GL_RENDER);
   processHits (hits, selectBuf);


//-----------------
GLint stackSize;
glGetIntegerv(GL_NAME_STACK_DEPTH, &stackSize);
//number of names on the slection stack:
printf("STACK_DEPTH = %d
", stackSize);
//-----------------

} 


int main(int argc, char** argv)
{
   glutInit(&argc, argv);
   glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
   glutInitWindowSize (500, 500);
   glutInitWindowPosition (100, 100);
   glutCreateWindow(argv[0]);
   init();
   glutReshapeFunc(reshape);
   glutMouseFunc (pickCtlPoints);
   glutDisplayFunc(display);
   glutMainLoop();
   return 0; 
}



In selectControlPoints() shouldn’t your glEnd() be inside the for loop at the same level as glBegin()?

Hi,
I think I finally got a rudimentary example working. There’s alot of small pitfalls to picking control points and nurbs surfaces. Wish there were more examples around for this kind of thing, instead of just selecting shapes or boxes etc. and/or using evaluators to draw the objects instead of using nurbs. Thanks.

/*
 *  from glut exs: surface.c, picksquare.c, and edit.c
 *  This program draws a NURBS surface and shows control points
*/


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


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

#define DEBUG

int antialiasing = 0;
int gridSize = 20;
GLuint selectedPoint = ~0;
int winWidth, winHeight;
GLdouble modelMatrix[16], projMatrix[16];
GLint viewport[4];

int showPoints = 1;
GLUnurbsObj *theNurb;

GLfloat grid4x4[4][4][3]; 
GLfloat *grid = &grid4x4[0][0][0];
int uSize = 4;
int vSize = 4;


void drawControlPoints(void)
{     
      int i,j;
      
      glPointSize(8.0);
      glDisable(GL_LIGHTING);
      glColor3f(1.0, 0.0, 0.0);
      glBegin(GL_POINTS);
      for (i = 0; i < 4; i++) {
          for (j = 0; j < 4; j++) {
         glVertex3f(grid4x4[i][j][0] = ((GLfloat)i - 1.5),
         grid4x4[i][j][1] = ((GLfloat)j - 1.7),
         grid4x4[i][j][2] = ((GLfloat)j - 1.5));
         }
      }
      glEnd();
      glEnable(GL_LIGHTING);
}

void
selectControlPoints(void)
{
  int i;

  for (i = 0; i < uSize * vSize; i++) {
    glLoadName(i);
    glBegin(GL_POINTS);
    glVertex3fv(&grid[i * 3]);
    glEnd();
  }
}
			
			
/*  Initialize material property and depth buffer,
 *  and grid surface
 */
void init(void)
{
   GLfloat mat_diffuse[] = { 0.7, 0.7, 0.7, 1.0 };
   GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
   GLfloat mat_shininess[] = { 100.0 };

   glClearColor (0.0, 0.0, 0.0, 0.0);
   glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
   glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
   glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);

   glEnable(GL_LIGHTING);
   glEnable(GL_LIGHT0);
   glEnable(GL_DEPTH_TEST);
   glEnable(GL_AUTO_NORMAL);
   glEnable(GL_NORMALIZE);
   
   //init grid surface
   int u, v;
   for (u = 0; u < 4; u++) {
      for (v = 0; v < 4; v++) {
         grid4x4[u][v][0] = 2.0*((GLfloat)u - 1.5);
         grid4x4[u][v][1] = 2.0*((GLfloat)v - 1.7);
      }
   }
 
   //nurbs properties
   theNurb = gluNewNurbsRenderer();
   gluNurbsProperty(theNurb, GLU_SAMPLING_TOLERANCE, 25.0);
   gluNurbsProperty(theNurb, GLU_DISPLAY_MODE, GLU_OUTLINE_POLYGON);
}

void display(void)
{
   GLfloat knots[8] = {0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0};
   int i, j;

   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

   glPushMatrix();
   glRotatef(330.0, 1.,0.,0.);
   glScalef (0.5, 0.5, 0.5);

   gluBeginSurface(theNurb);
   gluNurbsSurface(theNurb, 
                   8, knots, 8, knots,
                   4 * 3, 3, &grid4x4[0][0][0], 
                   4, 4, GL_MAP2_VERTEX_3);
   gluEndSurface(theNurb);
   glPopMatrix();
   glFlush();
   
   // create the control points
   drawControlPoints();
     
   glutSwapBuffers();

}

void
ortho(void)
{
  if (winWidth <= winHeight)
    glOrtho(-4.0, 4.0, -4.0 * (GLfloat) winHeight / (GLfloat) winWidth,
      4.0 * (GLfloat) winHeight / (GLfloat) winWidth, -4.0, 4.0);
  else
    glOrtho(-4.0 * (GLfloat) winWidth / (GLfloat) winHeight,
      4.0 * (GLfloat) winWidth / (GLfloat) winHeight, -4.0, 4.0, -4.0, 4.0);
}

void
reshape(int w, int h)
{
  glViewport(0, 0, w, h);
  winWidth = w;
  winHeight = h;

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  ortho();
  glGetDoublev(GL_PROJECTION_MATRIX, projMatrix);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);
  viewport[0] = 0;
  viewport[1] = 0;
  viewport[2] = winWidth;
  viewport[3] = winHeight;
}

/*  processHits prints out the contents of the 
 *  selection array.
 */
void processHits (GLint hits, GLuint buffer[])
{
   unsigned int i, j;
   GLuint ii, jj, names, *ptr;

   printf ("hits = %d
", hits);
   ptr = (GLuint *) buffer;
   for (i = 0; i < hits; i++) {	/*  for each hit  */
      names = *ptr;
      printf (" number of names for this hit = %d
", names); ptr++;
      printf("  z1 is %g;", (float) *ptr/0x7fffffff); ptr++;
      printf(" z2 is %g
", (float) *ptr/0x7fffffff); ptr++;
      printf ("   names are ");
      for (j = 0; j < names; j++) { /*  for each name */
         printf ("%d ", *ptr);
         if (j == 0)  /*  set row and column  */
            ii = *ptr;
         else if (j == 1)
            jj = *ptr;
         ptr++;
      }
      printf ("
");
   }
}


#define BUFSIZE 512

void pickCtlPoints(int button, int state, int x, int y)
{
   GLuint selectBuf[BUFSIZE];
   GLint hits;
   GLint viewport[4];

  if (button != GLUT_LEFT_BUTTON || state != GLUT_DOWN)
      return;

   glGetIntegerv (GL_VIEWPORT, viewport);
   glSelectBuffer (BUFSIZE, selectBuf);
   
   //change to render mode to use selection
   (void) glRenderMode (GL_SELECT);
   glInitNames();
   glPushName(0);

   //change to the projection matrix
   glMatrixMode (GL_PROJECTION);
   glPushMatrix ();
   glLoadIdentity ();
   
   //place view volume around the mouse pointer
/*  create 5x5 pixel picking region near cursor location	*/
   gluPickMatrix ((GLdouble) x, (GLdouble) (viewport[3] - y), 
                  5.0, 5.0, viewport);
  ortho();
     //change to modelview matrix
	//to select points
	glMatrixMode(GL_MODELVIEW);
    selectControlPoints();

   //restores original projection matrix
   glMatrixMode (GL_PROJECTION);
   glPopMatrix ();
   //glFlush ();

   //return to modelview matrix for rendering
   glMatrixMode(GL_MODELVIEW);
   
   hits = glRenderMode (GL_RENDER);
   processHits (hits, selectBuf);


} 


int main(int argc, char** argv)
{
   glutInit(&argc, argv);
   glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
   glutInitWindowSize (500, 500);
   glutInitWindowPosition (100, 100);
   glutCreateWindow(argv[0]);
   glutReshapeFunc(reshape);
   glutDisplayFunc(display);
   glutMouseFunc (pickCtlPoints);
   init();
   glutMainLoop();
   return 0; 
}