OpenGL gluUnProject find wrong coordinate - c++

gluUnProject find wrong coordinates. I have greed drawing on black background with cell dimension 1x1. I try to detect click in cells and I getting wrong coordinates (not 1 - 1).
I know that is OpenGL 1.1 old, bud I must use it. I don't good with it, most time I use 2.1 or 3.1.
Render code:
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluPerspective(45.0f, width() / (float)height(), 0.1f, 100.0f);
gluLookAt(m_camera->getX(), m_camera->getY(), m_camera->getZ(),
m_camera->getX(), m_camera->getY(), m_camera->getZ() - 1.0f,
0.0f, 1.0f, 0.0f);
glPushMatrix();
int i;
/*
* Render grid
*/
for(i = 0; i <= m_mapProperties->getWidth(); i++)
{
glm::vec3 position(i * m_mapProperties->getGridWidth(), 0.0f, 0.0f);
glm::vec3 scale(0.05f, m_mapProperties->getHeight() * m_mapProperties->getGridHeight(), 0.0f);
RenderUtil::render(position, scale);
}
for(i = 0; i <= m_mapProperties->getHeight(); i++)
{
glm::vec3 position(0.0f, i * m_mapProperties->getGridHeight(), 0.0f);
glm::vec3 scale(m_mapProperties->getWidth() * m_mapProperties->getGridWidth(), 0.05f, 0.0f);
RenderUtil::render(position, scale);
}
for(i = 0; i < m_width * m_height; i++)
if(m_map[i])
m_map[i]->render();
glPopMatrix();
Click code:
QPoint cursorPos = event->pos();
GLint viewport[4];
GLdouble modelview[16];
GLdouble projection[16];
glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
glGetDoublev(GL_PROJECTION_MATRIX, projection);
glGetIntegerv(GL_VIEWPORT, viewport);
GLfloat winX, winY, winZ = 0.0f;
GLdouble x, y, z;
winX = (float)cursorPos.x();
winY = (float)viewport[3] - (float)cursorPos.y();
glReadPixels(winX, winY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ);
winZ = 0.0f;
winZ = -m_camera->getZ();
gluUnProject(winX, winY, winZ, modelview, projection, viewport, &x, &y, &z);
qDebug() << x
<< y;

glPopMatrix() is discarding your last matrix. glGetxxx() will return another matrix.

Related

OpenGL/Glut: Making the camera rotate around X axis with arrow keys?

I'm trying to make the gluLookAt() function so that when I press the up & down key the camera moves around the X axis
I'm trying a method I saw at: http://www.lighthouse3d.com/tutorials/glut-tutorial/keyboard-example-moving-around-the-world/
but it's not working for me. Anyone knows an easier way? and where should I put the gluLookAt() so on myDisplay() func?
#include"glut.h"
#include<cmath>
#include<iostream>
using namespace std;
float xr = 0, yr = 0; //to control the object's movement from left to right
// actual vector representing the camera's direction
float lx = 0.0f, lz = -1.0f;
// XZ position of the camera
float x = 0.0f, z = 5.0f;
GLfloat angle = 0.0f;
int refreshmill = 1;
void timer(int value) { //to control the rotation of the object
glutPostRedisplay();
glutTimerFunc(refreshmill, timer, 0);
}
void myDisplay(void) {
//Circle One
float theta;
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1, 0, 0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPushMatrix();
glBegin(GL_POLYGON);
for (int x = 0; x < 360; x++) {
theta = x * 3.142 / 180;
glVertex2f(150 * cos(theta)+xr,150 * sin(theta)+yr);
}
glEnd();
glPopMatrix();
//Circle Two
float theta2;
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPushMatrix();
glTranslatef(0.5f, 0.0f, 0.0f); // rotation
glRotatef(angle, 0.0f, 0.0f, -0.5f); // rotation
glBegin(GL_POLYGON);
glColor3f(0, 0, 1);
for (int x = 0; x < 360; x++) {
theta2 = x * 3.142 / 180;
glVertex2f(150 + 15 * cos(theta2) + xr, 15 * sin(theta2) + yr);
}
glutSwapBuffers();
angle += 0.2; // rotation
glEnd();
glPopMatrix();
//Draw Star
glColor3ub(119, 193, 15);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPushMatrix();
glBegin(GL_POLYGON);
glVertex2d(15+xr, 60+yr);
glVertex2d(75+xr, 75+yr); //right peak
glVertex2d(15+xr, 90+yr);
glVertex2d(0+xr, 150+yr); //Up-peak Changed
glVertex2d(-15+xr, 90+yr);
glVertex2d(-75+xr,75+yr);
glVertex2d(-15+xr, 60+yr);
glVertex2d(0+xr,0+yr);
glEnd();
glPopMatrix();
glFlush();
glutPostRedisplay();
glutSwapBuffers();
}
void renderScene(void) {
// Clear Color and Depth Buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Reset transformations
glLoadIdentity();
// Set the camera
gluLookAt(x, 1.0f, z,
x + lx, 1.0f, z + lz,
0.0f, 1.0f, 0.0f);
// Draw ground
glColor3f(0.9f, 0.9f, 0.9f);
glBegin(GL_QUADS);
glVertex3f(-100.0f, 0.0f, -100.0f);
glVertex3f(-100.0f, 0.0f, 100.0f);
glVertex3f(100.0f, 0.0f, 100.0f);
glVertex3f(100.0f, 0.0f, -100.0f);
glEnd();
myDisplay();
glutSwapBuffers();
}
//Move to left or right
void keyboard(int key, int x, int y) {
float fraction = 0.1f;
switch (key) {
case GLUT_KEY_RIGHT:
xr++;
cout << x << endl;
glutPostRedisplay();
break;
case GLUT_KEY_LEFT:
xr--;
cout << x << endl;
glutPostRedisplay();
break;
case GLUT_KEY_UP:
angle -= 0.01f;
lx = sin(angle);
lz = -cos(angle);
break;
case GLUT_KEY_DOWN:
angle += 0.01f;
lx = sin(angle);
lz = -cos(angle);
break;
}
}
void init() {
glClearColor(0, 0, 0, 1);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-250, 250, -250, 250); //IMPORTANT- Define from negative to positive
glMatrixMode(GL_MODELVIEW);
}
int main(int argc, char** argv) {
// init GLUT and create window
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(500, 500);
glutInitWindowPosition(0, 0);
glutCreateWindow("Homework: Circle");
// register callbacks
glutDisplayFunc(myDisplay);
glutDisplayFunc(renderScene);
glutIdleFunc(renderScene);
glutTimerFunc(0,timer,0);
glutSpecialFunc(keyboard);
// OpenGL init
init();
// enter GLUT event processing cycle
glutMainLoop();
}
First of all there should be only 1 display call back function:
int main(int argc, char** argv) {
// [...]
// glutDisplayFunc(myDisplay); <----- DELETE!!!
glutDisplayFunc(renderScene);
// glutIdleFunc(renderScene); <----- DELETE!!!
// [...]
}
Setup an an orthographic projection with an extended near and far plane. If the object is rotated around the X axis, it takes space in the 3 dimensions:
void init() {
glClearColor(0, 0, 0, 1);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-250, 250, -250, 250, -250, 250); // <----
glMatrixMode(GL_MODELVIEW);
}
Add a variable anglaX which is changed in the keyboard event:
float angleX = 0.0f;
void keyboard(int key, int x, int y) {
switch (key) {
case GLUT_KEY_RIGHT: xr++; break;
case GLUT_KEY_LEFT: xr--; break;
case GLUT_KEY_UP: angleX -= 1.0f; break;
case GLUT_KEY_DOWN: angleX += 1.0f; break;
}
}
Rotate the model, after the view was set:
gluLookAt(x, 0.0f, z, x, 0.0f, z-1.0f, 0.0f, 1.0f, 0.0f);
glRotatef(angleX, 1, 0, 0);
Don't do any calls to glutSwapBuffers(), glFlush() and glutPostRedisplay(), except at the end of renderScene:
void timer(int value) { //to control the rotation of the object
// glutPostRedisplay(); <--- DELETE
glutTimerFunc(refreshmill, timer, 0);
}
void myDisplay(void) {
//Circle One
float theta;
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1, 0, 0);
glPushMatrix();
glBegin(GL_POLYGON);
for (int x = 0; x < 360; x++) {
theta = x * 3.142 / 180;
glVertex2f(150 * cos(theta)+xr,150 * sin(theta)+yr);
}
glEnd();
glPopMatrix();
//Circle Two
float theta2;
glPushMatrix();
glTranslatef(0.5f, 0.0f, 0.0f); // rotation
glRotatef(angle, 0.0f, 0.0f, -0.5f); // rotation
glBegin(GL_POLYGON);
glColor3f(0, 0, 1);
for (int x = 0; x < 360; x++) {
theta2 = x * 3.142 / 180;
glVertex2f(150 + 15 * cos(theta2) + xr, 15 * sin(theta2) + yr);
}
angle += 0.2; // rotation
glEnd();
glPopMatrix();
//Draw Star
glColor3ub(119, 193, 15);
glPushMatrix();
glBegin(GL_POLYGON);
glVertex2d(15+xr, 60+yr);
glVertex2d(75+xr, 75+yr); //right peak
glVertex2d(15+xr, 90+yr);
glVertex2d(0+xr, 150+yr); //Up-peak Changed
glVertex2d(-15+xr, 90+yr);
glVertex2d(-75+xr,75+yr);
glVertex2d(-15+xr, 60+yr);
glVertex2d(0+xr,0+yr);
glEnd();
glPopMatrix();
}
void renderScene(void) {
// Clear Color and Depth Buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Reset transformations
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Set the camera
gluLookAt(x, 0.0f, z, x, 0.0f, z-1.0f, 0.0f, 1.0f, 0.0f);
glRotatef(angleX, 1, 0, 0);
// Draw ground
glColor3f(0.9f, 0.9f, 0.9f);
glBegin(GL_QUADS);
glVertex3f(-100.0f, 0.0f, -100.0f);
glVertex3f(-100.0f, 0.0f, 100.0f);
glVertex3f(100.0f, 0.0f, 100.0f);
glVertex3f(100.0f, 0.0f, -100.0f);
glEnd();
myDisplay();
glFlush();
glutPostRedisplay();
glutSwapBuffers();
}
Further I recommend to use double buffering:
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
You can init your camera with gluLookAt at init(), then rotate it when arrow keys pressed. If you want to rotate camera around it's local x axis, assume your initial modelview matrix is V, newly happened rotation around x axis is R, you need to set modelview matrix to R*V, not V*R.
case GLUT_KEY_UP:
GLfloat temp[16];
glGetFloatv(GL_MODELVIEW_MATRIX, temp);
glLoadIdentity();
glRotate(stepAngle, 1, 0, 0); // calculate stepAngle by your self
glMultMatrixf(temp);
break;
You don need to reset modelview matrix during rendering, view part is already done, make sure you restore it after rendering the whole scene:
glPushMatrix(GL_MODELVIEW_MATRIX)
// don't call glLoadIdentity() here, you don't need to reset view part.
...
...
glPopMatrix()

object drawing order in OpenGL

I created a sphere floating above a ground. The sphere is centered around (0,0,0). I have set up a camera with a twist, elevation, azimuth as well as moving in closer and farther from the sphere. The problem I have is that the sphere is always drawn on top of the ground. For example, if I move the camera below the ground I should see the ground be drawn on top of the sphere but that's not the case. Here are my ground and draw functions.
void init_ground()
{
GLfloat x = -static_cast<GLfloat>(NUM_GROUND_LINES/2);
GLfloat z = -static_cast<GLfloat>(NUM_GROUND_LINES/2);
for(int i=0; i<NUM_GROUND_LINES*2; i += 2)
{
GLfloat x = NUM_GROUND_LINES/2;
glm::vec3 vertex1 = glm::vec3(-x, -4.0, z);
glm::vec3 vertex2 = glm::vec3(x, -4.0, z);
ground[i] = vertex1;
ground[i+1] = vertex2;
z += 1.0;
}
for(int i=NUM_GROUND_LINES*2; i<NUM_GROUND_LINES*4; i += 2)
{
GLfloat z = NUM_GROUND_LINES/2;
glm::vec3 vertex1 = glm::vec3(x, -4.0, -z);
glm::vec3 vertex2 = glm::vec3(x, -4.0, z);
ground[i] = vertex1;
ground[i+1] = vertex2;
x += 1.0;
}
}
glm::vec3 cameraPos = glm::vec3(0.0, 0.0, 3.0);
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
void draw()
{
glm::mat4 view;
glm::mat4 projection;
glm::mat4 model;
view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
view = glm::rotate(view, glm::radians(GLfloat(twist)), glm::vec3(0.0, 0.0, 1.0));
view = glm::rotate(view, glm::radians(GLfloat(elevation)), glm::vec3(1.0, 0.0, 0.0));
view = glm::rotate(view, glm::radians(GLfloat(azimuth)), glm::vec3(0.0, 0.0, 1.0));
projection = glm::perspective(45.0f, (GLfloat)WIDTH/(GLfloat)HEIGHT, 0.1f, 100.0f);
glUseProgram(program_ground);
GLint ground_proj_loc = glGetUniformLocation(program_ground, "projection");
GLint ground_view_loc = glGetUniformLocation(program_ground, "view");
GLint ground_model_loc = glGetUniformLocation(program_ground, "model");
glUniformMatrix4fv(ground_proj_loc, 1, GL_FALSE, glm::value_ptr(projection));
glUniformMatrix4fv(ground_view_loc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(ground_model_loc, 1, GL_FALSE, glm::value_ptr(model));
glBindVertexArray(vao_ground);
glDrawArrays(GL_LINES, 0, NUM_GROUND_LINES*2*4);
glBindVertexArray(0);
glUseProgram(program_sphere);
GLint sphere_model_loc = glGetUniformLocation(program_sphere, "model");
GLint sphere_view_loc = glGetUniformLocation(program_sphere, "view");
GLint sphere_proj_loc = glGetUniformLocation(program_sphere, "projection");
glUniformMatrix4fv(sphere_view_loc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(sphere_proj_loc, 1, GL_FALSE, glm::value_ptr(projection));
glUniformMatrix4fv(sphere_model_loc, 1, GL_FALSE, glm::value_ptr(model));
glBindVertexArray(vao_sphere);
glDrawArrays(GL_LINE_LOOP, 0, 342);
glBindVertexArray(0);
glfwSwapBuffers(window);
}
To be able to remove hidden superficies, you need to enable the Depth Test.
To do that, first you must ask, at the context creation time, a buffer to store the relative z positional value of a vertex, in relation to the camera. If you are using GLFW library, this creation is done automatically.
The second step is to enable the depth test itself. To do that, you need to call:
glEnable(GL_DEPTH_TEST);
somewhere before you call your draw functions.
And, at last, at every frame draw, you must clear you depth buffer, calling:
glClear(GL_DEPTH_BUFFER_BIT);
but usually it is called as:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
to clear the color buffer as well.

using glm::ortho projection in OpenGL

I'm trying to simulate dropping a ball from 200 meters. I know I have to convert the coordinates from -1.0, 1.0 to 0, 200.
I draw my vertices of my ball like so:
for(int i=0; i < NUM_VERTICES; i++)
{
GLfloat angle = 2*M_PI/NUM_VERTICES * i;
GLfloat x = 10 * cos(angle);
GLfloat y = 10 * sin(angle);
vertices.push_back(x);
vertices.push_back(y);
}
then I have an orthographic projection like so:
glm:mat4 projection;
projection = glm::ortho(0.0f, 200.0f, 0.0f, 200.0f, 0.1f, 100.0f);
and a translation
glm::mat4 view;
view = glm::translate(view, glm::vec3(100.0f, 200.0f, 0.0f));
but nothing appears in my viewport.
You seem to draw at z=0, while your z range is [-0.1, -100], so the geometry is clipped because it lies in front of the near plane.

OpenGL texture not displayed (solid color instead texture) or displayed with artifacts

I'm using code to draw text as textures in OpenGL (Qt4.8.3 + Linux (debian-like)).
Code was ported from 2D project, where it is working good.
2D project was using gluOrtho2D, now I use gluLookAt for 3D.
The issue is that instead of text I'm seing colored rectangle.
If I turn on GL_DEPTH_TEST I see artifacts instead of text. BTW artifacts change if I move camera, which is quite strange.
Here's the code:
void GLWidget::paintGL() {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //Set blending function.
glEnable(GL_BLEND); //Enable blending.
glShadeModel(GL_SMOOTH);
glEnable(GL_MULTISAMPLE);
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glPushMatrix();
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( 60.0f, (GLdouble) width() / (GLdouble) height(), 0.001f, 10000.0f );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
// Set up current camera
gluLookAt( cameraDistance * sin(cameraTheta * M_PI / 180) * cos(cameraPhi * M_PI / 180),
cameraDistance * sin(cameraTheta * M_PI / 180) * sin(cameraPhi * M_PI / 180),
cameraDistance * cos(cameraTheta * M_PI / 180),
0.0, 0.0, 0.0,
0.0, 0.0, 1.0);
glTranslatef(-4.5355, -4.5355, 0.0);
glPushMatrix();
// draw text labels
drawLabel(1, 0, 90, "1");
drawLabel(2, 0, 90, "2");
drawLabel(3, 0, 90, "3");
drawLabel(4, 0, 90, "4");
drawLabel(5, 0, 90, "5");
glPopMatrix();
glGetIntegerv(GL_VIEWPORT, viewport);
glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
glGetDoublev(GL_PROJECTION_MATRIX, projection);
glPopMatrix();
}
void GLWidget::drawLabel(float xpos, float ypos, float angle, char *txt) {
float labelHeight = 0.3;
float labelWidth = labelHeight / 2;
float margin = labelWidth / 10;
float len = (float) strlen(txt);
glPushMatrix();
glRotatef(-angle, 0, 0, -1);
glTranslatef(xpos, ypos, 0.0f);
glRotatef(angle, 0, 0, -1);
glScalef(1.0, -1.0, 1.0);
glTranslatef(- len * labelWidth / 2, -labelHeight / 2 + margin, 0.0f);
// background
glColor3f(0.0f, 0.0f, 0.0f);
glBegin(GL_QUADS);
glVertex3f(-margin, -margin, 0);
glVertex3f(len * labelWidth + margin, -margin, 0);
glVertex3f(len * labelWidth + margin, labelHeight + margin, 0);
glVertex3f(-margin, labelHeight + margin, 0);
glEnd();
// text
glColor3f(0.5f, 0.5f, 0.5f);
glEnable(GL_TEXTURE_2D);
glBindTexture( GL_TEXTURE_2D, glFont->getTextureID() );
glFont->drawText(labelWidth, labelHeight, txt);
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
glPopMatrix();
}
void oglFont::drawText(GLfloat cw, GLfloat ch, char *txt)
{
glBegin(GL_QUADS);
//character location and dimensions
GLfloat cx = 0.0f;
GLfloat cy = 0.0f;
//calculate how wide each character is in term of texture coords
GLfloat dtx = float(c_width) / float(m_width);
GLfloat dty = float(c_height) / float(m_height);
for (char * c = txt; *c != 0; c++, cx += cw) {
int index = getCharIndex(c);
int row = index / c_per_row;
int col = index % c_per_row;
if (index < 0) {
//qDebug() << "glFont: Character outside of font! char: " << c;
}
// find the texture coords
GLfloat tx = float(col * c_width) / float(m_width);
GLfloat ty = float(row * c_height) / float(m_height);
glTexCoord2f(0, 0);
glVertex2f(cx, cy);
glTexCoord2f(1, 0);
glVertex2f(cx + cw, cy);
glTexCoord2f(1, 1);
glVertex2f(cx + cw, cy + ch);
glTexCoord2f(0, 1);
glVertex2f(cx, cy + ch);
}
glEnd();
}
The reason for the artifacts is Z fighting.
This problem can be solved by increasing the depth buffer precision OR by making the different objects further apart from each-other (the ones from drawlable ).
Also make sure that your generated text doesn't get culled by the far plane / near plane (maybe you generate the geometry very near the edges ? ).
It turns out that because texture was loaded in QGLWidget constructor, context was either not created or not set.
I moved texture loading in initializeGL() method and it works great.

OpenGL Triangle Strip Viewing Question

I'm having an awful time trying to get these triangle strips to show up.
Where am I going wrong?
InitGL:
InitGL()
{
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();//
gluPerspective(45, //view angle
WINDOW_WIDTH/WINDOW_HEIGHT, //aspect ratio
1.0, //near clip
2000.0);//far clip
glMatrixMode(GL_MODELVIEW);
glClearColor(0, 0, 0, 0);
}
and Display:
void display ( void ) // Create The Display Function
{
int height = sourceImage->nx;
int width = sourceImage->ny;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glScalef(.005, .004, .005); //all vertices are in the range x[0,200], y[0,255], z[0,200]
glTranslatef(0, 0, -2); //so scale to put all vertices in the range [0,1] and move the z coord from [0,1] to the -z axis [-1,-2]
glColor3f(0, 0, 0);
glPushMatrix(); //save this view
float cell_height = 0;
for(float z = 0; z < width; z++)
{
glBegin(GL_TRIANGLE_STRIP);
for(float x = 0; x < height; x++)
{
cell_height = cellHeight(x, z);
glVertex3f(x, cell_height, z);
cell_height = cellHeight(x, z+1);
glVertex3f(x, cell_height,(z+1));
cell_height = cellHeight(x+1, z);
glVertex3f(x+1, cell_height, z);
cell_height = cellHeight(x+1, z+1);
glVertex3f(x+1, cell_height, (z+1));
}
glEnd();
}
glPopMatrix(); //restore view
Set your color to something other than pure black:
glColor3f(1.0f, 1.0f, 1.0f);