picking and camera projection.

hi,
im trying to merge a shadow example and a picking example but when I click on the screen it only picks at the center of the screen even though theres nothing at the center.

It’s for a music appication im developing. Light-Track Studio!

I know it has something to do with camera projection matrixes. something i have yet to learn.

heres my code, help would be great!

#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <stdio.h>
#include "GLee/GLee.h"	//GL header file, including extensions
#include <GL/glut.h>
#include "Maths/Maths.h"
#include "TIMER.h"
#include "FPS_COUNTER.h"
#include "main.h"

#include <iostream>

using namespace std;

#define EARTH   1
#define MARS    2
#define MOON1   3
#define MOON2   4
#define BUFFER_LENGTH 512

//Timer used for frame rate independent movement
TIMER timer;

//Frames per second counter
FPS_COUNTER fpsCounter;

//Camera & light positions
VECTOR3D cameraPosition(-2.5f, 3.5f,-2.5f);
VECTOR3D lightPosition(2.0f, 3.0f,-2.0f);

//Size of shadow map
const int shadowMapSize=512;

//Textures
GLuint shadowMapTexture;

//window size
int windowWidth, windowHeight;

//Matrices
MATRIX4X4 lightProjectionMatrix, lightViewMatrix;
MATRIX4X4 cameraProjectionMatrix, cameraViewMatrix;

//Called for initiation
bool Init(void)
{
    //Check for necessary extensions
    if (!GLEE_ARB_depth_texture || !GLEE_ARB_shadow)
    {
        printf("I require ARB_depth_texture and ARB_shadow extensionsn
");
        return false;
    }

    //Load identity modelview
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    //Shading states
    glShadeModel(GL_SMOOTH);
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

    //Depth states
    glClearDepth(1.0f);
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_DEPTH_TEST);

    glEnable(GL_CULL_FACE);

    //We use glScale when drawing the scene
    glEnable(GL_NORMALIZE);

    //Create the shadow map texture
    glGenTextures(1, &shadowMapTexture);
    glBindTexture(GL_TEXTURE_2D, shadowMapTexture);
    glTexImage2D(	GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, shadowMapSize, shadowMapSize, 0,
                  GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);

    //Use the color as the ambient and diffuse material
    glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
    glEnable(GL_COLOR_MATERIAL);

    //White specular material color, shininess 16
    glMaterialfv(GL_FRONT, GL_SPECULAR, white);
    glMaterialf(GL_FRONT, GL_SHININESS, 16.0f);

    //Calculate & save matrices
    glPushMatrix();

    glLoadIdentity();
    gluPerspective(45.0f, 1.0f, 1.0f, 100.0f);
    glGetFloatv(GL_MODELVIEW_MATRIX, cameraProjectionMatrix);

    glLoadIdentity();
    gluLookAt(cameraPosition.x, cameraPosition.y, cameraPosition.z,
              0.0f, 0.0f, 0.0f,
              0.0f, 1.0f, 0.0f);
    glGetFloatv(GL_MODELVIEW_MATRIX, cameraViewMatrix);

    glLoadIdentity();
    gluPerspective(45.0f, 1.0f, 2.0f, 8.0f);
    glGetFloatv(GL_MODELVIEW_MATRIX, lightProjectionMatrix);

    glLoadIdentity();
    gluLookAt(	lightPosition.x, lightPosition.y, lightPosition.z,
               0.0f, 0.0f, 0.0f,
               0.0f, 1.0f, 0.0f);
    glGetFloatv(GL_MODELVIEW_MATRIX, lightViewMatrix);

    glPopMatrix();

    //Reset timer
    timer.Reset();

    return true;
}

void DrawScene()
{
    glColor3f(0.0f, 1.0f, 0.0f);

    glInitNames();
    glPushName(0);
    glLoadName(2);
    glTranslatef(0.45f, 1.0f, 0.45f);
    glutSolidSphere(0.2, 24, 24);

    glTranslatef(-0.9f, 0.0f, 0.0f);
    glutSolidSphere(0.2, 24, 24);

    glTranslatef(0.0f, 0.0f,-0.9f);
    glutSolidSphere(0.2, 24, 24);

    glTranslatef(0.9f, 0.0f, 0.0f);
    glutSolidSphere(0.2, 24, 24);
    glPopName();
}

//Called to draw scene

//Called to draw scene
void Display(void)
{
    //angle of spheres in scene. Calculate from time
    float angle=timer.GetTime()/10;

    //First pass - from light's point of view
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_PROJECTION);
    glLoadMatrixf(lightProjectionMatrix);

    glMatrixMode(GL_MODELVIEW);
    glLoadMatrixf(lightViewMatrix);

    //Use viewport the same size as the shadow map
    glViewport(0, 0, shadowMapSize, shadowMapSize);

    //Draw back faces into the shadow map
    glCullFace(GL_FRONT);

    //Disable color writes, and use flat shading for speed
    glShadeModel(GL_FLAT);
    glColorMask(0, 0, 0, 0);

    //Draw the scene
    DrawScene();

    //Read the depth buffer into the shadow map texture
    glBindTexture(GL_TEXTURE_2D, shadowMapTexture);
    glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, shadowMapSize, shadowMapSize);

    //restore states
    glCullFace(GL_BACK);
    glShadeModel(GL_SMOOTH);
    glColorMask(1, 1, 1, 1);

    //2nd pass - Draw from camera's point of view
    glClear(GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_PROJECTION);
    glLoadMatrixf(cameraProjectionMatrix);

    glMatrixMode(GL_MODELVIEW);
    glLoadMatrixf(cameraViewMatrix);

    glViewport(0, 0, windowWidth, windowHeight);

    //Use dim light to represent shadowed areas
    glLightfv(GL_LIGHT1, GL_POSITION, VECTOR4D(lightPosition));
    glLightfv(GL_LIGHT1, GL_AMBIENT, white*0.2f);
    glLightfv(GL_LIGHT1, GL_DIFFUSE, white*0.2f);
    glLightfv(GL_LIGHT1, GL_SPECULAR, black);
    glEnable(GL_LIGHT1);
    glEnable(GL_LIGHTING);

    DrawScene();

    //3rd pass
    //Draw with bright light
    glLightfv(GL_LIGHT1, GL_DIFFUSE, white);
    glLightfv(GL_LIGHT1, GL_SPECULAR, white);

    //Calculate texture matrix for projection
    //This matrix takes us from eye space to the light's clip space
    //It is postmultiplied by the inverse of the current view matrix when specifying texgen
    static MATRIX4X4 biasMatrix(0.5f, 0.0f, 0.0f, 0.0f,
                                0.0f, 0.5f, 0.0f, 0.0f,
                                0.0f, 0.0f, 0.5f, 0.0f,
                                0.5f, 0.5f, 0.5f, 1.0f);	//bias from [-1, 1] to [0, 1]
    MATRIX4X4 textureMatrix=biasMatrix*lightProjectionMatrix*lightViewMatrix;

    //Set up texture coordinate generation.
    glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
    glTexGenfv(GL_S, GL_EYE_PLANE, textureMatrix.GetRow(0));
    glEnable(GL_TEXTURE_GEN_S);

    glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
    glTexGenfv(GL_T, GL_EYE_PLANE, textureMatrix.GetRow(1));
    glEnable(GL_TEXTURE_GEN_T);

    glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
    glTexGenfv(GL_R, GL_EYE_PLANE, textureMatrix.GetRow(2));
    glEnable(GL_TEXTURE_GEN_R);

    glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
    glTexGenfv(GL_Q, GL_EYE_PLANE, textureMatrix.GetRow(3));
    glEnable(GL_TEXTURE_GEN_Q);

    //Bind & enable shadow map texture
    glBindTexture(GL_TEXTURE_2D, shadowMapTexture);
    glEnable(GL_TEXTURE_2D);

    //Enable shadow comparison
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE);

    //Shadow comparison should be true (ie not in shadow) if r<=texture
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);

    //Shadow comparison should generate an INTENSITY result
    glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY);

    //Set alpha test to discard false comparisons
    glAlphaFunc(GL_GEQUAL, 0.99f);
    glEnable(GL_ALPHA_TEST);

    DrawScene();

    //Disable textures and texgen
    glDisable(GL_TEXTURE_2D);

    glDisable(GL_TEXTURE_GEN_S);
    glDisable(GL_TEXTURE_GEN_T);
    glDisable(GL_TEXTURE_GEN_R);
    glDisable(GL_TEXTURE_GEN_Q);

    //Restore other states
    glDisable(GL_LIGHTING);
    glDisable(GL_ALPHA_TEST);

    //Update frames per second counter
    fpsCounter.Update();

    //Print fps
    static char fpsString[32];
    sprintf(fpsString, "%.2f", fpsCounter.GetFps());

    //Set matrices for ortho
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();
    gluOrtho2D(-1.0f, 1.0f, -1.0f, 1.0f);

    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glLoadIdentity();

    //Print text
    glRasterPos2f(-1.0f, 0.9f);
    for (unsigned int i=0; i<strlen(fpsString); ++i)
        glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, fpsString[i]);

    //reset matrices
    glMatrixMode(GL_PROJECTION);
    glPopMatrix();
    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();

    glFinish();
    glutSwapBuffers();
    glutPostRedisplay();
}

//Called on window resize
void Reshape(int w, int h)
{
    //Save new window size
    windowWidth=w, windowHeight=h;

    //Update the camera's projection matrix
    glPushMatrix();
    glLoadIdentity();
    gluPerspective(45.0f, 1.0f, 1.0f, 100.0f);
    glGetFloatv(GL_MODELVIEW_MATRIX, cameraProjectionMatrix);
    glPopMatrix();
}

//Called when a key is pressed
void Keyboard(unsigned char key, int x, int y)
{
    //If escape is pressed, exit
    //if(key==27)
    //	exit(0);

    //Use P to pause the animation and U to unpause
    if (key=='P' || key=='p')
        timer.Pause();

    if (key=='U' || key=='u')
        timer.Unpause();
}

void pointerMotion(int x, int y)
{
    // Space for selection buffer
    GLuint selectBuff[BUFFER_LENGTH];

    // Hit counter and viewport storage
    GLint hits, viewport[4];

    // Get the viewport
    glGetIntegerv(GL_VIEWPORT, viewport);

    // Set up selection buffer
    glSelectBuffer(BUFFER_LENGTH, selectBuff);

    // Switch to projection and save the matrix
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();

    // Change render mode
    glRenderMode(GL_SELECT);

    // Establish new clipping volume to be unit cube around
    // mouse cursor point (xPos, yPos) and extending two pixels
    // in the vertical and horizontal direction
    glLoadIdentity();
    gluPickMatrix(x, 512 - y, 2,2, viewport);

    // Apply matrix
    gluPerspective(45.0f, 1.0f, 1.0f, 100.0f);

    glViewport(0, 0, windowWidth, windowHeight);

    DrawScene();

    // Collect the hits
    hits = glRenderMode(GL_RENDER);

    // If a single hit occurred, display the info.
    if (hits >= 1)
    {
        int id,count;
        char cMessage[64];

// How many names on the name stack
        count = selectBuff[0];

// Bottom of the name stack
        id = selectBuff[3];

// Select on earth or mars, whichever was picked
        switch (id)
        {
        case EARTH:
            cout << "You clicked Earth." << std::endl;
            break;

        case MARS:
            cout << "You clicked Mars." << std::endl;

            break;

            // If nothing was clicked we shouldn't be here!
        default:
            cout << "Error - Nothing was clicked on!" << std::endl;
            break;
        }
    }

    // Restore the projection matrix
    glMatrixMode(GL_PROJECTION);
    glPopMatrix();

    // Go back to modelview for normal rendering
    glMatrixMode(GL_MODELVIEW);
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(640, 512);
    glutCreateWindow("Light Track Studio");

    if (!Init())
        return 0;

    glutDisplayFunc(Display);
    glutReshapeFunc(Reshape);
    glutKeyboardFunc(Keyboard);
    glutMotionFunc(pointerMotion);
    glutMainLoop();

    return 0;
}

I would suggest that you take a look at the Ray Picking method which is detailed here…

http://www.opengl.org/resources/faq/technical/selection.htm

The method you are using is deprecated AFAIK in more recent OpenGL implementations, although it may be supported for some time to come.

But in any case doing selection on the CPU side is a better approach these days, and less complex really.

Whatever you decide the notes on the page linked above should lead you to your answer.

Thanks, looking now.

if your application is anything like mine, the CPU will only have access to approximations of the rendered geometry (bounding volumes), while the actual geometry will be stored on the GPU, or in fact procedurally generated on the GPU (displacement mapping, for example, or any kind of non-standard vertex/geometry shader).
Therefore ray picking on the CPU simply won’t be an option (especially these days). I’m hard pressed to think of an application where CPU ray picking would be an option, to be honest. You store your geometry twice, scratt?! You run vertex shaders on the CPU to get the triangles for the picking?!
Collision detection is another thing entirely, and rarely requires the same resolution of geometry as drawn to the screen. Decent picking always requires the exact geometry as drawn to the screen. Therefore you should use something like the colour buffer encoding solution, where you do a render pass into a small viewport around the mouse position encoding the batch number into the colour of the batch, then read back the pixel under the mouse position.

The OP’s project looked sufficiently simple to me for ray picking to be more than adequate. It’s certainly a step forward from deprecated GL picking name stacks.

As regards your question. I store geometry wherever it is best suited to be stored on a case by case basis. CPU side memory is cheap. Super cheap, and bounty-full. So a duplicate on the CPU side is not a problem at all. Of course if the geometry is on the GPU only then there are other methods. I didn’t really see the point of going into that detail and offering that many options here. :slight_smile:

But as knackered suggests, using the colour buffer is another option (assuming you are not on a device which has problems reading back from the colour buffer with any efficiency).

I can’t use color indexing for picking because of the amount of objects in my scene.

Does anyone know of a clean simple demo of shadow mapping and mouse picking?

Thanks.
Paul.

You really need to pick among more that 16 million objects ?

16 million objects visible in a 1x1 pixel viewport, too??!
You only need to store the batch number in the colour, not the…oh I don’t know what you’re thinking…the pointer to the scene object? Is that what you’re thinking? (even if you are, then it’s most likely a 32bit pointer, which will obviously fit into RGBA)
So you do your culling, with the frustum for that 1x1 pixel viewport (i.e. freekin tiny frustum), then go through each object that passed the cull test in a loop (for i=…) and the colour you use should just be that integer (i) cast to RGBA/UNSIGNED BYTE.
You’ll be happy to discover, by the way, that using this method also gives you the correct picking through objects that have been alpha-tested out - i.e. a polygon with a net texture would allow the user to click on the object behind the net, through the net…in a natural way. To get that functionality on the CPU picking, you’d have to also have the textures stored in system memory, and go through the hassle of calculating the uv intersection etc.

Lost of the GL_SELECTION render mode is one of the greatest lost of the new GL model. So far I didn’t find enough efficient replacement (although I must admit that I didn’t spend much time in the exploration, especially when realized that I didn’t get any acceleration after turning one of my applications to GL 3.2 Core … , and I lost a lot of functionality…) :frowning:

A mechanism of picking using GL_SELECTION mode and name-stack enables hierarchical selection on a very simple and elegant way. Coloring does not!

GL_SELECTION mode can easily be emulated with the colour buffer method, and also works with alpha-tested pixels - which GL_SELECTION does not.
If something can easily be emulated with existing API (or even improved) then it doesn’t belong in the core. You should really be arguing for an update of GLU, not GL itself.

May I ask you how it can be emulated?

As far as I know, GLU relies on GL (although I didn’t have an opportunity to take a look at the source code). I’m not sure that GLU can offer some functionality that is not exposed in GL, but on the higher level.