I'm trying to do selection in opengl but it is not working.
I draw objects I receive from a .obj file (v, vn, f, o and such indices). Each object consists from "groups" and each group is a group of GL_POLYGON.
Here is the draw function:
void draw(GLenum mode) {
glBegin(GL_LINES);
glColor3f(1, 0, 0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(100.0, 0.0, 0.0);
glColor3f(0, 0, 1);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(0.0, 100.0, 0.0);
glColor3f(0, 1, 0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(0.0, 0.0, 100.0);
glEnd();
glColor4f(1.0, 1.0, 1.0, 1.0);
if (changeFOV) {
fovAngle += fovScale;
changeFOV = false;
setTransformations();
}
for (unsigned int i = 0; i < objects.size(); i++) {
objectItem currObject = objects[i];
for (unsigned int j = 0; j < currObject.getGroups().size(); j++) {
group currGroup = currObject.getGroups().at(j);
for (unsigned int k = 0; k < currGroup.getFs().size(); k++) {
if (mode == GL_SELECT)
glPushName(currGroup.getName());
glPushMatrix();
vector<pair<int, int> > currF = currGroup.getFs()[k];
glBegin(GL_POLYGON);
for (unsigned int kk = 0; kk < currF.size(); kk++) {
Vector3f currVertex = vertexes.at(
(currF.at(kk).first - 1 >= 0) ?
currF.at(kk).first - 1 : 0);
Vector3f currNormal = vertexesNormal.at(
(currF.at(kk).second - 1 >= 0) ?
currF.at(kk).second - 1 : 0);
glNormal3f(currNormal.x, currNormal.y, currNormal.z);
glVertex3f(currVertex.x / 1, currVertex.y / 1,
currVertex.z / 1);
}
glEnd();
glPopMatrix();
}
}
}
}
The drawing works ok and I see the object on the screen.
This is all the picking procedure
/* PICKING */
void processHits(GLint hits, GLuint *buffer) {
float z1, z2;
for (int i = 0; buffer[i] > 0; i += 5) {
z1 = buffer[i + 1] / 4294967295.0;
z2 = buffer[i + 2] / 4294967295.0;
printf("z1 = %f ,z2 = %f zValue = %f\n", z1, z2, zValue[0]);
if ((zValue[0] <= z1 + 0.0001 && zValue[0] >= z2 - 0.0001)
|| (zValue[0] >= z1 - 0.0001 && zValue[0] <= z2 + 0.0001)) { //try to locate which name is correlated with the pressed pixel according to z value
ii = buffer[i + 3];
jj = buffer[i + 4];
}
}
}
void startPicking(GLuint *selectionBuf) {
glSelectBuffer(bufSize, selectionBuf); //declare buffer for input in selection mode
glRenderMode(GL_SELECT); //change to selecting mode
glInitNames(); //initialize names stack
glPushName(-1); //push name
}
void pick(int button, int x, int y) {
//use selection mode to pick
glReadPixels(x, viewport[3] - y, 1, 1, GL_RGBA, GL_FLOAT, pix);
//printf("depth = %f, x = %d, y = %d\n",pixels[(viewport[3]-y)*512+x],x,viewport[3]-y);
glMatrixMode(GL_PROJECTION);
glReadPixels((GLdouble) x, (GLdouble) viewport[3] - y, 2, 2,
GL_DEPTH_COMPONENT, GL_FLOAT, zValue);
glPushMatrix(); //saves current projection matrix
startPicking(selectionBuf); //preper selection mode
glLoadIdentity();
gluPickMatrix((GLdouble) x, (GLdouble) viewport[3] - y, 1, 1, viewport); //change matrices so only the area of the picking pixel can be seen.
gluPerspective(fovAngle, 1, near, far); //return to perspective state
glMatrixMode(GL_MODELVIEW);
draw(GL_SELECT); //draws board on background
hits = glRenderMode(GL_RENDER); //gets hits number
glMatrixMode(GL_PROJECTION);
glPopMatrix(); //restores projection matrix
glMatrixMode(GL_MODELVIEW);
processHits(hits, selectionBuf); //check hits
if(hits > 0)
printf("touched: %d\n",selectionBuf[3]);
//printf("depth %f hits: %d\n\n",pixels[(viewport[3]-y)*512+x], hits);
if (zValue[0] < 1.0) {
isPick = true;
xx = x;
yy = y;
if (button == GLUT_RIGHT_BUTTON)
zMove = true;
else
zMove = false;
}
}
the pick function is called when the mouse is clicked (using opengl mouse function).
The error I'm receiving is that no objects appears to be hit when clicking on an object.
I'm using Ubuntu 14.04 LTS with Opengl 3.0
I don't know how to ask or what specifically ask, I would appreciate some inputs on the code if you see something wrong..
You seemed to have missed using glPopName()
GLNames used in the selection buffer are pushed on a stack. So unless you call glPopName() the stack would never unwind. The working of this is similar to the calls glPushMatrix() and glPopMatrix().
Typically this is what the code flow looks like.
//Push the name of the primitives on top of selection stack
glPushName(...)
//Set Transformations / Draw the primitives
..
..
//Pop the name (Clear the stack for pushing another name)
glPopName();
Related
I have this weird problem in which the object that I'm trying to rotate just suddenly disappears. The way I am looking to rotate the object is with a keypress, which turns a global variable rotateAnimation to true. When the variable rotateAnimation is false, the object is visible, but once it's true the object disappears.
Here is the code:
bool rotateAnimation = false;
bool moveAnimation = false;
int moveDirX = 1, moveDirY = 1;
void DrawSpiral(int x, int y)
{
float tx, ty;
float i;
float a = 0, b = 0;
glPointSize(3);
glBegin(GL_LINE_STRIP);
for (i = 0; i < 20; i = i + 0.025)
{
a = a + .05;
b = b + .05;
tx = x + b * cos(i);
ty = y + a * sin(i);
glVertex2f(tx, ty);
}
glEnd();
}
void DrawSquare(int x, int y, int size)
{
glBegin(GL_POLYGON);
glVertex2f(x, y);
glVertex2f(x - size, y);
glVertex2f(x - size, y - size);
glVertex2f(x, y - size);
glEnd();
}
void DrawPolygon(int x, int y)
{
glBegin(GL_POLYGON);
glVertex2f(x, y);
glVertex2f(x - 25, y - 25);
glVertex2f(x - 15, y - 53);
glVertex2f(x + 15, y - 53);
glVertex2f(x + 25, y - 25);
glEnd();
}
void init()
{
glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
glMatrixMode(GL_PROJECTION); // Since I want to do rotation in 2D
glLoadIdentity();
glClearColor(1.0, 1.0, 1.0, 0);
glColor3f(0.0f, 0.0f, 0.0f);
gluOrtho2D(0, WINDOW_WIDTH, 0, WINDOW_HEIGHT);
}
void Keypress(int key, int x, int y)
{
switch (key)
{
case 'm':
moveAnimation = !moveAnimation;
break;
case 'o':
rotateAnimation = !rotateAnimation;
break;
}
}
void Display()
{
glClear(GL_COLOR_BUFFER_BIT);
staticScene(); // Some other drawings that should always be there on the screen
glPushMatrix();
if (rotateAnimation)
{
glRotatef(60, 1.0, 0.0, 0.0);
}
glColor3f(0.0f, 0.0f, 0.0f);
glPointSize(2);
if (shape == "square")
DrawSquare(X, Y, 40);
else if (shape == "polygon")
DrawPolygon(X, Y);
else if (shape == "spiral")
DrawSpiral(X, Y);
glPopMatrix();
glutSwapBuffers();
}
void timer(int value)
{
glutPostRedisplay();
glutTimerFunc(1000 / 60, timer, 0);
if (moveAnimation)
{
int dx = 2, dy = 2;
if (X - dx < 0) // Add from X
X += dx, moveDirX = 1;
else if (X + dx > drawingWindow[0].first) // Subtract to X
X -= dx, moveDirX = -1;
else
X += (dx * moveDirX);
if (Y - dy < drawingWindow[2].second) // Add from Y
Y += dy, moveDirY = 1;
else if (Y + dy > drawingWindow[0].second) // Subtract to Y
Y -= dy, moveDirY = -1;
else
Y += (dy * moveDirY);
}
}
When rotateAnimation is false:
When rotateAnimation is true:
EDIT: I tried to scale the object too, but the same thing happens, when the toggle is on the object disappears, and when off it appears. One thing I noted is that when I comment out the TimerFunc then nothing happens. Neither does the object scale or rotate depending on what is toggled on.
Edited: You didn't switch the matrix mode to GL_MODELVIEW.
void init()
{
glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
glMatrixMode(GL_PROJECTION); // Since I want to do rotation in 2D
glLoadIdentity();
glClearColor(1.0, 1.0, 1.0, 0);
glColor3f(0.0f, 0.0f, 0.0f);
gluOrtho2D(0, WINDOW_WIDTH, 0, WINDOW_HEIGHT);
glMatrixMode(GL_MODELVIEW); //<--here
}
I've got a taks from university and have to make a small example of solar system, the objects have to rotate etc. The problem is that when I do not call GluLookAt() everything looks fine, but I would like to change the view and when I call the function, there occurs that one orbit renders completely strangely.
I do not know if problem is with wrong creation of the first orbit, or with the proper values in gluLookAt parameters. Can anyone help?
Here's how it looks without calling gluLookAt():
Here's how it looks after gluLookAt():
Here's the code:
#include "stdafx.h"
#include <GL\glut.h>
#include <math.h>
GLfloat yRotated=1;
GLfloat movement = 0;
void drawCircle(float r) { // radius
glBegin(GL_LINE_LOOP);
for (int i = 0; i <= 300; i++) {
double angle = 2 * 3.14 * i / 300;
double x = r*cos(angle);
double y = r*sin(angle);
glVertex3d(x, y, -5.5);
}
glEnd();
}
void display(void) {
glMatrixMode(GL_MODELVIEW);
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
//gluLookAt(5, 5, 5, 0, 0, -8, 0, 1, 0); // 3rd coordinate - depth
float radius1 = 6;
float radius2 = 1;
//first orbit
glColor3f(1, 1, 1);
glPushMatrix();
glTranslatef(0, 0, -5.5);
drawCircle(radius1);
glPopMatrix();
//second orbit with rotation
glPushMatrix();
glRotatef(yRotated, 0, 0, 1);
glPushMatrix();
glTranslatef(radius1 / 2, 0, 0);
drawCircle(radius2);
glPopMatrix();
glPopMatrix();
//first czajnik
glColor3f(0.8, 0.2, 0.1);
glPushMatrix();
glTranslatef(0.0, 0.0, -5.5);
// glScalef(1.0, 1.0, 1.0);
glRotatef(yRotated, 0, 0, 1);
glRotatef(90, 1, 0, 0);
glutSolidSphere(1,20,20);
//second czajnik
glPushMatrix();
glColor3f(0, 0, 1);
glTranslatef(radius1/2, 0, 0);
glRotatef(yRotated, 0, 1, 0);
glutSolidSphere(0.5, 20, 20);
//third czajnik
glPushMatrix();
glTranslatef(radius2, 0, 0);
glColor3f(1, 1, 0);
glRotatef(yRotated, 0, 1, 0);
glutSolidSphere(0.2, 20, 20);
glPopMatrix();
//second czajnik pop
glPopMatrix();
//first czajnik pop
glPopMatrix();
glFlush();
}
void idle() {
yRotated += 0.1;
Sleep(2);
display();
}
void myReshape(int w, int h) {
if (w == 0 || h == 0) return;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(70.0, (GLdouble)w / (GLdouble)h, 0.5, 20.0);
glViewport(0, 0, w, h);
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(900, 600);
glutCreateWindow("Solar system");
//window with a title
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glClearColor(0, 0, 0, 1.0);
glutDisplayFunc(display);
glutReshapeFunc(myReshape);
glutIdleFunc(idle);
glutMainLoop();
return 0;
}
Some of your objects are at different z values, e.g. 1st orbit at -5.5, second at 0, because you "popped" the matrix.
In general, do not do so many push\pops nested into each other, matrix stack isn't made of rubber.
There is more efficient circle drawing procedure than to calculate sine and cosine for each step, e.g. to get advantage of circle being a figure of rotation:
inline void circle(F32 r, U32 quality)
{
if (r < F_ALMOST_ZERO) return;
F32 th = M_PI /(quality-1);
F32 s = sinf(th);
F32 c = cosf(th);
F32 t;
F32 x = r;
F32 y = 0;
::glBegin (GL_LINE_LOOP);
for(U32 i = 0; i < quality; i++)
{
glVertex2f(x, y);
t = x;
x = c*x + s*y;
y = -s*t + c*y;
}
::glEnd();
}
it can be optimized further by using symmetry, but this one is the basis.
I have set up a mouse function which is called in my main() like so:
struct point
{
int x;
int y;
};
std::vector <point> points;
point OnePoint;
void processMouse(int button, int state, int x, int y)
{
if ((button == GLUT_LEFT_BUTTON) && (state == GLUT_DOWN))
{
int yy;
yy = glutGet(GLUT_WINDOW_HEIGHT);
y = yy - y; /* In Glut, Y coordinate increases from top to bottom */
OnePoint.x = x;
OnePoint.y = y;
points.push_back(OnePoint);
}
glutPostRedisplay();
}
and to print a line through the vertices I have written some code in my display function that allows me to do just that:
glBegin(GL_LINES);
glColor3f(1.0, 0.0, 0.0);
for (int i = 0; i < points.size();i++)
{
glVertex2i(points[i].x, points[i].y);
}
glEnd();
However now what I want to do is move all the lines either left or right when I click the correct arrow keys to do so, but I can't figure out how.
I'm aware that it could possibly be something like:
glVertex2i(points[i].x + 10, points[i].y); // moving points 10 along the x axis
However since i is out of the for loop, I get error messages
You should introduce a new variable:
std::vector <point> points;
point offset; // <- how much to offset points
Make sure to set it to zero during initialization.
Then in the drawing code you add that offset to each point:
glBegin(GL_LINES);
glColor3f(1.0, 0.0, 0.0);
for (int i = 0; i < points.size();i++)
glVertex2i(points[i].x + offset.x, points[i].y + offset.y);
glEnd();
Or use a translation matrix to do that automagically:
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glTranslatef(offset.x, offset.y, 0);
glBegin(GL_LINES);
glColor3f(1.0, 0.0, 0.0);
for (int i = 0; i < points.size();i++)
glVertex2i(points[i].x, points[i].y);
glEnd();
glPopMatrix();
On the key-press handler you just change the offset:
// left-arrow:
offset.x -= 1;
// right-arrow:
offset.x += 1;
...
I am working on an nbody simulator and I want to display it with OpenGL. I want to always be looking at the centre of mass reference frame. I have the following code. I calculate the COM and I set the center coordinate in the gluLookAt function to be the center of mass. I then subtract the "zoom" from the z coordinate to get the eye position. By logic this should ensure that I am always looking at whatever value the center of mass is. The only issue is that I marked where the center of mass should be on the screen with a red dot and it is moving. Shouldn't it never move if I am always looking at it from the same relative position? Here is my code. Focus on the display function since I assume that is where the error will be. I had similar code working in another project and I can't really find any differences.
#include "Universe.cuh"
#include <iostream>
#include <cstdlib>
#include <ctime>
#include "timer.hpp"
#include <GL/glut.h>
Universe u;
float* vbuf;
double angle = 0.0, zoom = 1000;
void display()
{
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
float3 c = u.getCenterOfMass();
gluLookAt(c.x, c.y, c.z - zoom, c.x, c.y, c.z, 0, 1, 0);
glScalef(0.1, 0.1, 0.1);
glRotated(angle, 1, 0, 0);
glColor4f(1, 1, 1, 0.25);
glBegin(GL_POINTS);
{
glColor3f(1.0, 0.0, 0.0);
glVertex3d(c.x, c.y, c.z);
}
glEnd();
glutSwapBuffers();
}
void reshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60, (double)w / (double)h, 1.0, zoom * 1e9);
glMatrixMode(GL_MODELVIEW);
}
void copy_to_vbuf()
{
for(int i = 0; i < u.size(); i++)
{
vbuf[3 * i + 0] = u.getObjects()[i].p.x;
vbuf[3 * i + 1] = u.getObjects()[i].p.y;
vbuf[3 * i + 2] = u.getObjects()[i].p.z;
}
}
void keyboard(unsigned char c, int x, int y)
{
if(c == 'w')
angle += 1;
else if(c == 's')
angle -= 1;
else if(c == '=')
zoom /= 1.2;
else if(c == '-')
zoom *= 1.2;
glutPostRedisplay();
}
void idle()
{
u.timeStep();
copy_to_vbuf();
glutPostRedisplay();
}
int main(int argc, char** argv)
{
cudaSetDevice(0);
srand(time(0));
u.getConfiguration().max_velocity = 10;
u.getConfiguration().softening_factor = 0.01;
u.getConfiguration().threshold_angle = 35;
u.getConfiguration().time_step = 0.1;
const int N = 5;
vbuf = new float[3 * N];
for(int i = 0; i < N; i++)
{
Object o;
o.m = rand() % 100 + 1;
o.p.x = 500.0 * rand() / RAND_MAX - 250.0;
o.p.y = 500.0 * rand() / RAND_MAX - 250.0;
o.p.z = 500.0 * rand() / RAND_MAX - 250.0;
u.addObject(o);
}
copy_to_vbuf();
glutInit(&argc, argv);
glutInitDisplayMode(GL_DOUBLE);
glutInitWindowSize(1000, 1000);
glutCreateWindow("N-Body");
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutIdleFunc(idle);
glutKeyboardFunc(keyboard);
glEnable(GL_POINT_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glPointSize(1.0);
glutMainLoop();
return 0;
}
Two points regarding:
glScalef(0.1, 0.1, 0.1);
glRotated(angle, 1, 0, 0);
Since your axis is not centered on the 'COM', when you apply rotation the COM point will not stay in place and logically would move around the screen.
AFIK the normal order is scale,rotate,translate for transformations. This will apply the rotation and then scale.
EDIT:
To expand on that: Currently you take an arbitrary point rotate it, scale it and then focus on the point where it used to be. If you want to rotate your model (e.g. point marking the 'COM') around itself, it needs to be centered at (0,0,0).
I'm following the xoax.net tutorials for OpenGL in C++, and I am stuck on drawing the stripes in the U.S. flag using a for loop. I just get a blue screen (since I set the background colour to blue). Here is the code for the 'DrawStripes' function:
void DrawStripes() {
for (int x = 0; x < 13; ++x) {
if (x % 2 == 0) {
glColor3f(204/255, 0, 0);
} else {
glColor3f(1, 1, 1);
}
float fStartX = 0;
float fEndX = 1;
float fStartY = x * (1/13);
float fEndY = (x + 1) * (1/13);
if (x > 5) {
fStartX = .76/1.9;
}
glBegin(GL_QUADS);
glVertex3f(fStartX, fStartY, 0);
glVertex3f(fEndX, fStartY, 0);
glVertex3f(fEndX, fEndY, 0);
glVertex3f(fStartX, fEndY, 0);
glEnd();
}
}
(I have put this function in the 'draw' function so it isn't just I'm not telling it to use the function)
Any ideas?
--- EDIT ---
Here are the 'Draw' and 'Initialize' functions:
void Draw() {
glClear(GL_COLOR_BUFFER_BIT);
DrawStripes();
glFlush();
}
void Initialize() {
glClearColor(0.0, 0.0, 0.5, 0.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
}
1/13 is 0 in C++. Been there, done that. For float constants you want to use 1.0f/13.0f.