Picking Vertices
#1
Posted 04 January 2007 - 06:43 PM
I am an OpenGL newbie and am having some difficulty using OpenGL to select specific vertices in a rendered image. First question, can Display Lists be used with OpenGL picking through a mouse?
I am rendering a model through Display Lists with a large amount of vertices (~58,000 points) and would like to know the easiest/most efficient way to allow the user to click on a specific point in the image with the mouse to select it.
Please help, I have received different info about using feedback mode or selection mode and need to know what is the best/most typical way when all I want to know is what vertex a user has selected with the mouse.
Some simple example code would be best, but at this point ANY hints would be greatly appreciated.
Thanks in advance.
#2
Posted 04 January 2007 - 07:07 PM
Here is a tutorial of what it does do
If you want to pick a point you need to draw a ray from the eye point projected through the cursor, and test to see if any vertices lie on that line. But because a vertex is a single point in space the chances of you actually being able to click an exact one are slim. You need to test against spheres round each vertex. The wiki has some info here
And 58k vertices sounds like a lot. You'll need to do some sort of spatial subdivision, such as, BSP tree or octree. Which method of subdivision is best? That depends on your data.
#3
Posted 04 January 2007 - 07:20 PM
I appreciate the information.
#4
Posted 04 January 2007 - 10:39 PM
I know this sounds like more than a hack, but do you think it would be too slow?
Just an idea, since I am a newbie I am unsure as to the actual speed of the OpenGL calls for picking.
Thanks in advance.
#5
Posted 04 January 2007 - 11:20 PM
You could use gluUnproject to create the ray to test in 3D space. Thats a lot cheaper and you can do things to optimise it.
#6
Posted 05 January 2007 - 12:40 AM
You're right. The expense of using the gluProject would be too expensive.
#7
Posted 05 January 2007 - 08:34 AM
#8
Posted 05 January 2007 - 09:59 AM
that way you can grab any vertex that is visible on the screen.
pretty cool ay.
#9
Posted 05 January 2007 - 10:31 AM
rouncer said:
that way you can grab any vertex that is visible on the screen.
pretty cool ay.
#10
Posted 05 January 2007 - 05:00 PM
bombardier said:
I don't think so, maybe - I am new to OpenGL. I would certainly be open to the idea if I knew more of it. Can you explain in some kind of pseudo-code? This is all so new to me, sometimes it is even hard to know what to ask and I always appreciate any help I can get.
To help explain my problem, a snippet of my code is shown below (it is not exact because I am only trying to show the idea):
...
// The array of Triangles is read-in from a file:
int triangles[58,000];
// The array of Nodes (X, Y, Z Coordinates) are read-in from the same file
// and are used to indicate connectivity of each triangle:
// e.g., Triangle1 is made-up of Node1, Node2, and Node3
float nodes[26,000];
for (int i = 0; i < Number_of_Triangles; i++) {
// Get the Vector of node connections for this triangle
Vector nodeConns = triangles[i].getConnections();
glBegin(GL_TRIANGLE);
for (int j = 0; j < nodeConns.size(); j++) {
// Get the index of the node used in nodal connection
int nIDX = nodeConns.get(j);
glVertex3f(node[nIDX].getX(), node[nIDX].getY(), node[nIDX].getZ());
}
glEnd();
}
...
The above code is done to create the total image for a Display List. Any help/input/suggestion for how to select a given vertex/node using a mouse and OpenGL would be great.
Thanks.
#11
Posted 05 January 2007 - 05:20 PM
#12
Posted 05 January 2007 - 06:27 PM
int SelectElement(const unsigned int cursorX, const unsigned int cursorY)
{
#define PICK_BUFF_SIZE 512
GLuint selectBuffer[PICK_BUFF_SIZE];
GLint viewport[4];
glSelectBuffer(PICK_BUFF_SIZE, selectBuffer);
glRenderMode(GL_SELECT);
// set projection matrix
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glGetIntegerv(GL_VIEWPORT, viewport);
gluPickMatrix(cursorX, cursorY, 10, 10, viewport);
gluPerspective(45.0f, (float)viewport[2]/viewport[3], 0.01, 100);
// name rendering
glInitNames();
RenderNames();
// end picking
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glFlush();
// returning to normal rendering mode
int hitCount = glRenderMode(GL_RENDER);
// if there are hits process them
int hit = -1;
if (hitCount != 0)
{
hit = ProcessHits(hitCount, selectBuffer);
}
return hit;
#undef PICK_BUFF_SIZE
}
void RenderNames()
{
// set model transformation matrix
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glMultMatrixf(modelMatrix);
glPointSize(pointSize); // set some point size
// render all vertices with appropriate name sent to OpenGL
// name of each vertex will correspond to it's index in vertex array
for(unsigned int i=0; i<vertexCount; i++)
{
glPushName(i);
glBegin(GL_POINTS);
glVertexV3(vertex[i].pos);
glEnd();
glPopName();
}
// restore matrix
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
}
The idea is to render vertices and tell OpenGL to associate name with each one. Name can be any number, but it seems really obvious to set that name to the vertex index number. On the beginning of the SelectElement function you set the viewport to render only small area around the mouse coordinates, so it will contain only vertices close to a location you clicked on. You can see what is going on if you remove
glRenderMode(GL_SELECT);and try to execute SelectElement function from your game loop. It will only render small area around (cursorX, cursorY) screen position.
ProcessHit function processes entries in OpenGL select buffer, wich contains list of all the vertices rendered in the viewport, but I was only interested in first one.
unsigned int ProcessHits(const unsigned int hitCount, const GLuint *buffer)
{
unsigned int i;
GLuint names, *ptr, minZ,*ptrNames, numberOfNames;
ptr = (GLuint *) buffer;
minZ = 0xffffffff;
for (i = 0; i < hitCount; i++) {
names = *ptr;
ptr++;
if (*ptr < minZ) {
numberOfNames = names;
minZ = *ptr;
ptrNames = ptr+2;
}
ptr += names+2;
}
return (unsigned int) *ptrNames;
}
If you missed it before, dave_ sent you a nice link.
#13
Posted 05 January 2007 - 08:02 PM
not making a ray vector for christs sake, thats what
it looks like, correct me if im wrong.
you dont even need it.
-=-
just draw the points with a colour that is the same as
the index of its place in the array.
then you can select whatever you want from it.
its just on a texture remember.
#14
Posted 05 January 2007 - 08:06 PM
rouncer said:
not making a ray vector for christs sake, thats what
it looks like, correct me if im wrong.
you dont even need it.
-=-
just draw the points with a colour that is the same as
the index of its place in the array.
then you can select whatever you want from it.
its just on a texture remember.
Its the effectively the same as using the select buffer!
#15
Posted 05 January 2007 - 08:18 PM
#16
Posted 05 January 2007 - 08:20 PM
use, and its what shaders are meant for.
the select buffer in open gl just looks like it complicates
simple matters.
#17
Posted 06 January 2007 - 02:39 PM
I finally got it working with everyone's help :worthy: However, I just discovered another issue - probably simple but, being a newbie, I am still trying to figure it out. I am rotating, scaling, and transforming the image and when I do, selection no longer works.
Can anyone offer any ideas/hints as to why this would be occurring?
Below is a snippet of the code (Thanks to bombardier):
// Called when in SELECTION MODE
private void displaySelection(GL gl, GLU glu) {
int[] viewport = new int[4];
int hits = 0;
gl.glGetIntegerv(GL.GL_VIEWPORT, viewport, 0);
gl.glSelectBuffer(selectionBuffer.capacity(), selectionBuffer);
gl.glRenderMode(GL.GL_SELECT);
gl.glInitNames();
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glPushMatrix();
gl.glLoadIdentity();
glu.gluPickMatrix((double)this.mouseX, (double)(viewport[3] - this.mouseY), 5.0d, 5.0d, viewport, 0);
glu.gluPerspective(45.0f, this.ratio, 1.0f, 1000.0f);
gl.glMatrixMode(GL.GL_MODELVIEW);
// Render The NAMES for the Vertices
// on the NAME STACK
renderNames(gl);
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glPopMatrix();
gl.glMatrixMode(GL.GL_MODELVIEW);
hits = gl.glRenderMode(GL.GL_RENDER);
mode = GL.GL_RENDER;
// Process any hits that occured and were stored
// in the selection Buffer
processHits(hits, selectionBuffer);
}
private void renderNames(GL gl) {
// The "dm" Object is a Class that stores Data to be used for rendering
// (such as Hashtables, Trees, lists, ...)
Hashtable nodes = this.dm.getNodes();
Enumeration enum = nodes.keys();
gl.glPointSize(5.0f);
while(enum.hasMoreElements()) {
Integer nodeID = (Integer)enum.nextElement();
Node node = (Node)nodes.get(nodeID);
gl.glPushName(nodeID.intValue());
gl.glBegin(GL.GL_POINTS);
gl.glVertex3f(node.getX(), node.getY(), node.getZ());
gl.glEnd();
gl.glPopName();
}// End of WHILE-LOOP
}
public void processHits(int hits, IntBuffer buffer) {
System.out.println("---------------------------------");
System.out.println(" HITS: " + hits);
int offset = 0;
int names;
float z1, z2;
for (int i = 0; i < hits; i++) {
System.out.println("- - - - - - - - - - - -");
System.out.println(" hit: " + (i + 1));
names = buffer.get(offset);
offset++;
z1 = (float) buffer.get(offset) / 0x7fffffff;
offset++;
z2 = (float) buffer.get(offset) / 0x7fffffff;
offset++;
System.out.println(" number of names: " + names);
System.out.println(" z1: " + z1);
System.out.println(" z2: " + z2);
System.out.println(" names: ");
for (int j = 0; j < names; j++) {
System.out.print(" " + buffer.get(offset));
if (j == (names - 1)) {
System.out.println("<-");
} else {
System.out.println();
}
offset++;
}// End of INNER FOR-LOOP
System.out.println("- - - - - - - - - - - -");
}// End of OUTER FOR-LOOP
System.out.println("--------------------------------- ");
}
In just the GL_RENDER Mode, I am transforming, scaling, and rotating using code:
... gl.glPushMatrix(); // Rotate around the X, Y, and Z axes gl.glRotatef(view_rotx, 1.0f, 0.0f, 0.0f); gl.glRotatef(view_roty, 0.0f, 1.0f, 0.0f); gl.glRotatef(view_rotz, 0.0f, 0.0f, 1.0f); // "Center" the model gl.glTranslatef(-this.dm.getCenterX(), -this.dm.getCenterY(), -this.dm.getCenterZ()); // Set the scaleing to reflect the ZOOM that // the client has entered gl.glScalef(this.zoom, this.zoom, this.zoom); drawImage(); gl.glPopMatrix(); gl.glFlush(); ...
Once again, thanks to everyone. I am learning so much about OpenGL thanks to you guys.
#18
Posted 06 January 2007 - 03:29 PM
I made the needed changes in the displaySelection() and renderNames():
private void displaySelection(GL gl, GLU glu) {
int[] viewport = new int[4];
int hits = 0;
gl.glGetIntegerv(GL.GL_VIEWPORT, viewport, 0);
gl.glSelectBuffer(selectionBuffer.capacity(), selectionBuffer);
gl.glRenderMode(GL.GL_SELECT);
gl.glInitNames();
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glPushMatrix();
gl.glLoadIdentity();
glu.gluPickMatrix((double)this.mouseX, (double)(viewport[3] - this.mouseY), 5.0d, 5.0d, viewport, 0);
glu.gluPerspective(45.0f, this.ratio, 1.0f, 1000.0f);
gl.glMatrixMode(GL.GL_MODELVIEW);
// Had to ADD the following, to save the ModelView Matrix
// PRIOR to rendering to the Name Stack via renderNames()
gl.glPushMatrix();
// Render The NAMES for the Vertices
// on the NAME STACK
renderNames(gl);
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glPopMatrix();
gl.glMatrixMode(GL.GL_MODELVIEW);
// Had to ADD the following to Pop the Saved ModelView Matrix
// back off the matrix stack
gl.glPopMatrix();
hits = gl.glRenderMode(GL.GL_RENDER);
mode = GL.GL_RENDER;
processHits(hits, selectionBuffer);
}
private void renderNames(GL gl) {
// Had to ADD the rotations, transformations, and scaling here
//
// Rotate around the X, Y, and Z axes
gl.glRotatef(view_rotx, 1.0f, 0.0f, 0.0f);
gl.glRotatef(view_roty, 0.0f, 1.0f, 0.0f);
gl.glRotatef(view_rotz, 0.0f, 0.0f, 1.0f);
// "Center" the model
gl.glTranslatef(-this.dm.getCenterX(), -this.dm.getCenterY(), -this.dm.getCenterZ());
// Set the scaleing to reflect the ZOOM that
// the client has entered
gl.glScalef(this.zoom, this.zoom, this.zoom);
Hashtable nodes = this.dm.getNodes();
Enumeration enum = nodes.keys();
gl.glPointSize(5.0f);
while(enum.hasMoreElements()) {
Integer nodeID = (Integer)enum.nextElement();
Node node = (Node)nodes.get(nodeID);
gl.glPushName(nodeID.intValue());
gl.glBegin(GL.GL_POINTS);
gl.glVertex3f(node.getX(), node.getY(), node.getZ());
gl.glEnd();
gl.glPopName();
}// End of WHILE-LOOP
}
It can't be said enough, how much you guys help and support us newbies:worthy: Thanks for everything.
#19
Posted 06 January 2007 - 03:56 PM
I think at this point it would have been a lot simpler to go by Ray-Triangle intersection in the first place.
You would use the returned U and V baricentric coords to determine what Vertex (in the hit Triangle) is closer to the intersection point.
Also, no OpenGL knowledge is required to do it.
Ciao ciao : )
(readin' this? perhaps you should get out more -- give it a thought)
#20
Posted 06 January 2007 - 07:20 PM
1 user(s) are reading this topic
0 members, 1 guests, 0 anonymous users












