PDA

View Full Version : selection and feedback in ogl



Goroner
05-04-2011, 07:52 AM
Hi im new to this forum and this post is about a problem im having with selection and feedback, more likely is the feedback then selection, here is my prob:

First i shot in the code and then i tell you what i need to do

Code:


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

#define SELECT_BUFF 64
#define FEEDBACK_BUFF 512
#define cube 1

struct Rect
{
float left;
float right;
float bottom;
float top;
float near;
float far;
} typedef Rect;


int selectedObject = 0;
Rect box;

void unproject(float x, float y, float z, GLdouble *dest)
{
GLint viewport[4];
GLdouble modelview[16];
GLdouble projection[16];
GLfloat wx = x, wy, wz = z;

glGetIntegerv(GL_VIEWPORT,viewport);
glGetDoublev(GL_MODELVIEW_MATRIX,modelview);
glGetDoublev(GL_PROJECTION_MATRIX,projection);

wy = y = viewport[3]-y;
gluUnProject(wx, wy, wz, modelview, projection, viewport, &amp;dest[0], &amp;dest[1], &amp;dest[2]);
}

void kocka (int color)
{
glColor3f(0.5, 0.5, 0.5);

if(color == 1)
{
glColor3f(1,1,1);
}

glBegin(GL_QUADS);
// Front face
glVertex3f(-1.0, -1.0, 1.0);
glVertex3f( 1.0, -1.0, 1.0);
glVertex3f( 1.0, 1.0, 1.0);
glVertex3f(-1.0, 1.0, 1.0);

// Back face
glVertex3f(-1.0, -1.0, -1.0);
glVertex3f(-1.0, 1.0, -1.0);
glVertex3f(1.0, 1.0, -1.0);
glVertex3f( 1.0, -1.0, -1.0);

// Top face
glVertex3f(-1.0, 1.0, -1.0);
glVertex3f(-1.0, 1.0, 1.0);
glVertex3f( 1.0, 1.0, 1.0);
glVertex3f(1.0, 1.0, -1.0);

// Bottom face
glVertex3f(-1.0, -1.0, -1.0);
glVertex3f( 1.0, -1.0, -1.0);
glVertex3f( 1.0, -1.0, 1.0);
glVertex3f(-1.0, -1.0, 1.0);

// Right face
glVertex3f(1.0, -1.0, -1.0);
glVertex3f(1.0, 1.0, -1.0);
glVertex3f(1.0, 1.0, 1.0);
glVertex3f(1.0, -1.0, 1.0);

// Left face
glVertex3f(-1.0, -1.0, -1.0);
glVertex3f(-1.0, -1.0, 1.0);
glVertex3f(-1.0, 1.0, 1.0);
glVertex3f(-1.0, 1.0, -1.0);
glEnd();
}

void drawScene(GLenum mode)
{
if(mode == GL_RENDER || mode == GL_FEEDBACK)
{
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluPerspective(65, 800/600, 1, 100);
}

glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
gluLookAt(2, 5, 4, 0, 0, 0, 0, 1, 0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
if(mode == GL_SELECT) glLoadName(cube);
if(mode == GL_FEEDBACK) glPassThrough((GLfloat)cube);

glPushMatrix();
glTranslatef(-2, 1, 1);
kocka(selectedObject);
glPopMatrix();
}

void makeSelection(int object)
{
static GLfloat feedbackBuffer[FEEDBACK_BUFF];
int size, i, j, count;

glFeedbackBuffer(FEEDBACK_BUFF, GL_3D, feedbackBuffer);

glRenderMode(GL_FEEDBACK);

drawScene(GL_FEEDBACK);

size = glRenderMode(GL_RENDER);

i = 0;

while(i < size)
{
if(feedbackBuffer[i] == GL_PASS_THROUGH_TOKEN)
{
if(feedbackBuffer[i+1] == (GLfloat)object)
{
i += 2;

while(i < size &amp;&amp; feedbackBuffer[i] != GL_PASS_THROUGH_TOKEN)
{
if(feedbackBuffer[i] == GL_POLYGON_TOKEN)
{
count = (int)feedbackBuffer[++i];
i++;

for(j = 0; j < count; j++)
{
//min x , max x
if(feedbackBuffer[i] < box.left) box.left = feedbackBuffer[i];
if(feedbackBuffer[i] > box.right) box.right = feedbackBuffer[i++];

//min y, max y
if(feedbackBuffer[i] < box.bottom) box.bottom = feedbackBuffer[i];
if(feedbackBuffer[i] > box.top) box.top = feedbackBuffer[i++];

//min z, max z (depth)
if(feedbackBuffer[i] < box.near) box.near = feedbackBuffer[i];
if(feedbackBuffer[i] > box.far) box.far = feedbackBuffer[i++];
}
}
else
{
i++;
}
}

break;
}
}

i++;
}

glutPostRedisplay();
}

void processSelection(float x, float y)
{
static GLuint selectBuffer[SELECT_BUFF];

GLint hits, viewport[4];

glSelectBuffer(SELECT_BUFF, selectBuffer);
glGetIntegerv(GL_VIEWPORT, viewport);

glRenderMode(GL_SELECT);

glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluPickMatrix((GLdouble)x, viewport[3] - (GLdouble)y, 0.5, 0.5, viewport);
gluPerspective(65, 800/600, 1, 100);

glInitNames();
glPushName(0);
drawScene(GL_SELECT);
glPopName();

glMatrixMode(GL_PROJECTION);
glPopMatrix();

hits = glRenderMode(GL_RENDER);

if(hits > 0)
{
makeSelection(selectBuffer[3]);

if(selectedObject == 0) selectedObject = 1;
else selectedObject = 0;
}
}

void display()
{
drawScene(GL_RENDER);

if(selectedObject != 0)
{
GLdouble vk1[3], vk2[3];

unproject(box.left, box.bottom, box.near, vk1);
unproject(box.right, box.top, box.far, vk2);

printf("********************\n");
printf("x: %f, y: %f, z: %f\n", vk1[0], vk1[1], vk1[2]);
printf("x: %f, y: %f, z: %f\n", vk2[0], vk2[1], vk2[2]);
printf("********************\n");

glPushMatrix();
glTranslatef(vk1[0], vk1[1], vk1[2]);
glScalef(0.5, 0.5, 0.5);
kocka(selectedObject);
glPopMatrix();
}

glFlush();
glutSwapBuffers();
}

void init(void)
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_SMOOTH);

box.left = 9999;
box.right = -9999;
box.bottom = 9999;
box.top = -9999;
box.near = 9999;
box.far = -9999;
}


void mouseCallback(int button, int state, int x, int y)
{
if(button == GLUT_LEFT_BUTTON &amp;&amp; state == GLUT_DOWN)
{
processSelection((float)x, (float)y);
}
}

int main(int argc, char** argv)
{
glutInit(&amp;argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowSize (800, 600);
glutInitWindowPosition (100, 100);
glutCreateWindow ("Test");
init();
glutDisplayFunc(display);
glutMouseFunc(mouseCallback);
glutMainLoop();
return 0;
}



So im supposed to make when i select the cube to draw box around it on the same spot where it is, as you can see i got function as default mouse function called mouseCallback, when i click with the mouse on the screen that function calls the processSelection function which takes the (x,y) position of the mouse currently being clicked and then here i do the GL_SELECT mode drawing in this case i draw in just tiny cube around the mouse position with width and height of 0.5 with center at (x,y) the mouse position, and as usual draw everything that is inside that new drawing-volume giving corresponding names to the objects being drawn in the drawing-volume that is the objects that were intersecting the new drawing-volume i have made with making new clean identity projection matrix and then multiplying that one with the gluPickMatrix with the given parameters and last multiplying that with perspective matrix with the given parameters and finally i get the new draw-volume (new world space for selection mode), so far going good i think well what i do next in the same function i get the first item being drawn on the selection buffer i previously defined in on the top in the function that's selectionBuffer, the id of the first item on the buffer is located on the 4 spot actually 3 cause starting from 0, so i fetch that id with selectionBuffer[3] and send it to the makeSelection function which now represents the feedbackBuffer browsing function, as usual i draw everthing i drew in GL_RENDER mode but now in GL_FEEDBACK mode and i put in tokens for the objects in this case one token defined on the top of the .c file named cube with value 1, so i passThrough((GLfloat)cube) (my feedbackBuffer is of type GLfloat) and now with everthing put on the buffer i get the size and start looking for the id that shares both the feedback and selection buffers and thus i get the selected item to be found in the feedback buffer as well, so when i reach it i just find the min and max values for x and y and the min and max depth for z coords of the object drawn after the id token for the same object i selected previously and those min and max values i set in struct to hold them named Rect, when i get those info cause i get those in screen coords i use the unproject function which now uses gluUnproject function to determine the actual world coords for the object so i can draw the bounding box there...

After all this i wrote i still have to say "THIS DAMN THING DOESNT WORK!!"

So help please, thanks!! :))))

elanthis
05-04-2011, 04:09 PM
Two things:

First, you're using a ton of deprecated, ancient OpenGL functionality that modern programs shouldn't use: feedback mode, matrix stack, immediate mode rendering, etc. If you're trying to build what will eventually be a Real Program(tm) you should avoid that functionality so your app will actually run at decent speed with real data. If you're building a toy app to learn graphics programming, you should avoid that functionality so you don't learn a ton of things totally wrong. Basically, you should avoid that functionality, period.

Second, you didn't give any information at all about how "this damn thing doesn't work." Does it fail to compile? Does it fail to render? Is your bounding algorithm wrong? Is it not selecting? What exactly is actually wrong with it?

mhagain
05-04-2011, 04:38 PM
http://www.opengl.org/wiki/Common_Mistakes#Selection_and_Picking_and_Feedback _Mode

Not only should you not use them in a modern program, but they might drop you back to software emulation.

Goroner
05-05-2011, 09:49 AM
Ok lemme explain things more clear now..

1.

I study Computer Graphics on faculty and we are using ogl 2 i think, and i know there's v 4 already and a lot of stuff is changed but i need to study all this stuff with push pop and other things cause i study that on faculty..

2.
My "app" here is not rly app it's just stuff to learn some concepts in CG and some ogl stuff and ofc pass my exams, but i see more in to it cause i got rly interested in CG ofc when i have more time i might start learning gl 4 but for now i just learn what i need (i know you'll say you are going wrong way, but that's what my proffesor ask for )

3.

My prog. compiles and run well, but the prob is next:

i got one cube drawn in 0,0,0 (unit cube) now when i click i go in selection mode and use pickMatrix to draw in volume around the mouse, when i do that after i register hits i call the very first hit record, actually i take it's id that i previously in select mode gave to the cube in this case so the there's only one hit record just for that cube, when i get the id i send that over to makeSelection function which is actually drawing in feedback mode so i can find the screen cords of the cube and when i get those i keep those in struct that has left right bottom top and near far for depth, after that in the display func in render mode drawing i just check if the cube got selected and if so than i use the fatched screen coords from feedback mode and the depth ofc to unproject those and get the real coords so i can draw rectangle around the cube on the actual coords of the cube itself..

Now i noted some stuff, actually the unproject func that i made that uses gluUnProject func get's the current modelview matrix and pass it to the gluUnProject but that's wrong cause in the display func i draw the cube after i make local translation (push before draw make the transf and then pop after it) and that transformation is not saved in the mv matrix so in the unprojecting process i dont really use the real mv matrix so i get the rectangle drawn in 0,0,0 no matter where my cube is drawn on the screen that's cause im using the identity mv matrix multiplied by lookAt matrix and multiplied by frustum matrix, so now i have other question, if i do push pop matrix can i keep global matrix so when i do push pop i save the transformation in that matrix so later i can use that global matrix to serve me as mv matrix in the process of unprojecting.. i tried that but im not sure if i can use glGetDoublev(GL_MODELVIEW_MATRIX, dest) inside push pop block cause it seems like this method doesnt work so i need some info on how do i keep track of all the transformations ive done so i can use those to unproject screen coords , actually do the inverse transforms...

Thanks, and if u need some more info ask for i shot right away!!