How to change object's position wrt camera in opengl? - c++

I need to change my object's position with respect to camera position. I mean, my object should always be just in front of the camera. It should follow camera movements.What do I need to add my object drawing function?

If you're using old-style fixed function matrices, the easiest way to position an object relative to the camera is to do it after removing the camera matrix from the stack. For example, you might have a matrix setup like this:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(...); //Or other camera functions.
for(/*each object*/)
{
glPushMatrix();
//Setup object matrices.
glTranslatef();
glRotatef();
//Setup object rendering.
glDrawElements(); //Draw the object
glPopMatrix();
}
Then switch it around into this:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPushMatrix();
gluLookAt(...); //Or other camera functions.
for(/*each object*/)
{
glPushMatrix();
//Setup object matrices.
glTranslatef();
glRotatef();
//Setup object rendering.
glDrawElements(); //Draw the object
glPopMatrix();
}
glPopMatrix(); //Remove camera matrix. MODELVIEW is now identity.
for(/*each camera-relative object*/)
{
glPushMatrix();
//Setup object matrices.
glTranslatef();
glRotatef();
//Setup object rendering.
glDrawElements(); //Draw the object
glPopMatrix();
}
If you're using shaders, this is even easier. If you have a matrix stack, just do the same stack-based operation as you see here. If you're doing something else to build your matrices, just don't factor the camera matrix into the transform.

Your object position should then always be at:
desiredPosition = cameraPosition + cameraDirection * offset;

Related

OpenGL switching between ortho and perspective

I have a tile engine using orthographic projection in immediate mode and I'm just trying to draw a 3d cube on top of my tile scene, in hopes that I can eventually incorporate 3d models into my engine instead of just sprites / textured quads. I would also like to make the tiles 3d for that slight bit of extra eye candy.. Hopefully I can eventually convert this to use modern OpenGL so I can take advantage of those extra features. Not on the top of my priority list at the moment. So on to the question.
I'm initializing OpenGL with this:
void initGL()
{
glDisable(GL_DEPTH_TEST);
glViewport( 0,0,SCREEN_WIDTH,SCREEN_HEIGHT);
//Initialize Projection Matrix
glMatrixMode( GL_PROJECTION );
glPushMatrix();
glLoadIdentity();
//Initialize Modelview Matrix
glMatrixMode( GL_MODELVIEW );
glPushMatrix();
glLoadIdentity();
glOrtho(0,SCREEN_WIDTH,SCREEN_HEIGHT,0,0,1);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
//...setting some various other attributes, omitted for brevity...
glEnable(GL_TEXTURE_2D);
glClearColor( 0, 0, 0, 0 );
}
I have a function for drawing a cube that works.
void draw_cube()
{
/* position object */
glRotatef(30.0F, 1.0F, 0.0F, 0.0F);
glRotatef(30.0F, 0.0F, 1.0F, 0.0F);
/* draw six faces of a cube */
glBegin(GL_QUADS);
...vertices... (removed for brevity)
glEnd();
}
I made 2 functions for setting the 2d and 3d projection modes.
void set3d()
{
glEnable(GL_DEPTH_TEST);
glClear(GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(0,SCREEN_WIDTH,0,SCREEN_HEIGHT, 0,1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void set2d()
{
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0,SCREEN_WIDTH,SCREEN_HEIGHT,0,0,1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
For the sake of completeness, some pseudocode of my textured quad drawing..
pushmatrix();
translate();
rotate();
-translate();
glbegin();
...vertices
glend();
popmatrix();
So far I have managed to get the cube to draw on top of the tiles, but it disappears after approximately 1 second to never be seen again until I run the program again.
Basically what I'm doing in the main loop is this:
move objects around, process collisions, etc.
set2d();
draw textured quads, lines, text, etc. in 2d mode.
set3d();
draw_cube();
My question is: Why is the cube disappearing, and are there any errors in my set2d() and set3d() functions?
You have quite a few problems in this code, too many to list in comments in fact.
Your projection matrices are changing the handedness of your post-projected coordinate space, which will affect polygon winding.
Stick to a single handedness, unless you want to reverse the direction used for front- / back-facing polygon facets (glFrontFace (...)) - it is CCW by default, but you will have to change it to CW when you use set3d (...) to maintain consistent behavior.
This problem arises because you have the Y-axis going different directions
The behavior your are describing, where the object appears briefly and then disappears is indicative of an issue with your matrix stack.
Are you calling initGL (...) more than once in your software? You will run into a stack overflow if you do this enough times since you needlessly push the current matrix onto the stack and never pop it off.
You cannot use 0.0 for zNear with a perspective projection matrix, this will result in wonky math during the perspective divide step that comes after transformation to clip-space; the depth buffer will not work correctly.
In fact, glFrustum (...) will generate a GL_INVALID_VALUE error and do exactly nothing if you pass a value ≤ 0.0 for zNear. On a related note, gluPerspective (...) will not do this since it is not actually part of OpenGL, but it is equally invalid behavior to pass such a value to gluPerspective (...).

How can I translate only one object of the scene in an OpenGL?

I have a wall pattern DrawWall and an airplane DrawAirplane in my OpenGL game. How can I push and pop the current matrix and translate only the wall in the scene?
I expect the airplane to be fixed.
private: void DrawWall(){
glPushMatrix();
glBegin(GL_POLYGON);
LeftWallPattern();
glEnd();
glBegin(GL_POLYGON);
RightWallPattern();
glEnd();
glPopMatrix();
}
private: void DrawAirplane(){
glPushMatrix();
glBegin(GL_LINE_LOOP);
//...
glEnd();
glPopMatrix();
}
public: void Display(){
glClear(GL_COLOR_BUFFER_BIT);
glTranslatef(0, -0.02, 0);
DrawWall();
DrawAirplane();
glFlush();
}
Use glPushMatrix() to push the current matrix, do glTranslate and draw the wall, then glPopMatrix() and draw the plane. This should only translate the wall. The problem is you seem to be doing the translate in display instead of in DrawWall where it should be.
A few things to expand on what Jesus was saying.
When drawing the airplane you don't want to apply any transformations to it, so you need to have the identity matrix loaded:
Push the current modelview matrix
Load the identity matrix <=== this is the step you're missing
Draw the airplane
Pop the modelview matrix
When drawing the wall you want the current transformations to apply, so you do not push the current matrix or else you've wiped out all of the translations you've built up.
Remove the Push/Pop operations from DrawWall()
At some point in your initialization, before Display is called for the first time, you need to set the modelview matrix to the identity matrix. For each subsequent call to Display, -0.02 will then be added to your translation in the y-direction.

OpenGL: GL_QUADS does not draw square

I'm trying to draw a square on the screen but it clearly draws a rectangle.
This is my render code:
glClear(GL_COLOR_BUFFER_BIT);
glTranslatef(0,0,-0.1);
glBegin(GL_QUADS);
glVertex3f(0,0,0);
glVertex3f(1,0,0);
glVertex3f(1,1,0);
glVertex3f(0,1,0);
glEnd();
SDL_GL_SwapBuffers();
And OpenGL Init code:
glClearColor(0,0,0,0.6f);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(30,640.0/480.0,.3f,200.0);
glMatrixMode(GL_MODELVIEW);
Why is this happening?
I don't see anywhere in your code where you have set-up the glViewport. I will rather write something like this in your init method:
glViewport(0,0,640,480); // Reset The Current Viewport
glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix
// Calculate The Aspect Ratio Of The Window
gluPerspective(30.0f,(GLfloat)640/(GLfloat)480,0.3f,200.0f);
glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity();
also check the second Nehe tutorial it will help you to start with OpenGL for very basic stuff like drawing primitives such as triangle, square etc...
Try using gluOrtho2D to generate a correct orthogonal projection matrix, in your case gluOrtho2D(0,640,0,480), this is assuming you want a square in 2D and not 3D.
This will of course change your coordinate system from (0,1),(0,1) to (0,640),(0,480).

static circle in openGL

I hope you can help me with a little problem...
I know how to draw a circle, that's not a problem - here is the code in c#
void DrawEllipse()
{
GL.Color3(0.5, 0.6, 0.2);
float x, y, z;
double t;
GL.Begin(BeginMode.Points);
for (t = 0; t <= 360; t += 0.25)
{
x = (float)(3*Math.Sin(t));
y = (float)(3*Math.Cos(t));
z = (float)0;
GL.Vertex3(x, y, z);
}
GL.End();
}
But there is a problem - when I Rotate 'Gl.Rotate(angle, axis)' and then redraw a circle - yeah, it's still circle in the 3D, but I want a circle in the screen - I mean static circle which is not rotating with 3D object in it... Is that possible? How to repair the code?
Are you trying to draw a 2D circle on top of a 3D scene to create a HUD or similar? If you are then you should research 2D OpenGL, glOrtho and using multiple viewports in a scene. There is a discussion around this here:
http://www.gamedev.net/topic/388298-opengl-hud/
Just draw it at a position before the camera!
Use pushMatrix() and popMatrix().
Or you can draw the other things between pushMatrix() and popMatrix(). Then draw the circle.
HUD (heads-up display): http://en.wikipedia.org/wiki/HUD_(video_gaming)
void setupScene ()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// set the perspective
glFrustum(...) // or glu's perspective
}
void loop ()
{
// main scene
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glViewport (...)
// push the camera position into GL_MODELVIEW
// (i.e. the inverse matrix of its object position)
// draw your normal 3D objects
// switch to 2D projection (for the HUD)
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(....)
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// draw the objects onto the HUD
// switch back to 3d projection (i.e. restore GL_PROJECTION)
// glEnable (GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
// glMatrixMode(GL_MODELVIEW);
// swap buffers
}
The commented code is optional, depending on what you're gonna do in the end. Take it as hints.

OpenGL gluLookAt() not working as intended

I am making a rollercoaster inside of a skybox in OpenGL, and without much background on it's functions or computer graphics it is proving to be very difficult. I drew a rollercoaster using Catmull-Rom spline interpolation, and drew each point with glVertex3f. Now I want to call an update() function every 50ms to move the camera around the track. gluLookAt() is producing weird results, either removing the track from the screen, producing a black screen, etc. I think I need to move some of the matrix functions around but I am not sure where to put each one. Here is my code so far:
int main(int argc, char** argc)
{
// ... load track, etc ...
// Init currpos, nextpos, iter, up
currpos = Vec3f(0, 0, 0);
nextpos = currpos;
iter = 0;
up = Vec3f(0, 1, 0);
deque<Vec3f> points;
Vec3f newpt;
// Loop through the points and interpolate
for (pointVectorIter pv = g_Track.points().begin(); pv != g_Track.points().end(); pv++)
{
Vec3f curr(*pv); // Initialize the current point and a new point (to be drawn)
points.push_back(curr); // Push the current point onto the stack
allpoints.push_back(curr); // Add current point to the total stack
if (points.size() == 4) // Check if there are 4 points in the stack, if so interpolate
{
for (float u = 0.0f; u < 1.0f; u += 0.01f)
{
newpt = interpolate(points[0], points[1], points[2], points[3], u);
glColor3f(1, 1, 1);
glVertex3f(newpt.x(), newpt.y(), newpt.z());
allpoints.push_back(newpt);
}
points.pop_front();
}
}
// glutInit, InitGL(), etc...
}
void InitGL(GLvoid)
{
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(100.0, (GLfloat)WINDOW_WIDTH / (GLfloat)WINDOW_HEIGHT, .0001, 999999);
glMatrixMode(GL_MODELVIEW);
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
}
void display (void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(currpos.x(), currpos.y(), currpos.z(), nextpos.x(), nextpos.y(), nextpos.z(), up.x(), up.y(), up.z());
glPushMatrix();
glEnable(GL_TEXTURE_2D); // Enable texturing from now on
/* draw skybox, this was from previous assignment and renders correctly */
glPopMatrix();
// now draw rollercoaster ...
glPushMatrix();
glBegin(GL_LINE_STRIP);
deque<Vec3f> points;
Vec3f newpt;
for each (Vec3f pt in allpoints)
{
glColor3f(1, 1, 1);
glVertex3f(pt.x(), pt.y(), pt.z());
}
glutTimerFunc(50, update, 1);
glEnd();
glPopMatrix();
// Swap buffers, so one we just drew is displayed
glutSwapBuffers();
}
void update(int a)
{
if (iter < allpoints.size())
{
currpos = allpoints[iter];
nextpos = allpoints[iter + 1];
gaze = nextpos - currpos;
gaze.Normalize();
Vec3f::Cross3(binorm, gaze, up);
binorm.Normalize();
Vec3f::Cross3(up, binorm, gaze);
up.Normalize();
glutPostRedisplay();
}
iter++;
}
The idea is that I am keeping a global deque allpoints that includes the control points of the spline and the interpolated points. Once that is complete, I call update() every 50ms, and move the camera along each point in allpoints. In a previous version of the project, I could see that the rollercoaster was being drawn correctly. It is gluLookAt() that doesn't seem to work how I want it to. With the code above, the program starts with the camera looking at one side of the skybox with a part of the rollercoaster, and then when update() is called, the rollercoaster disappears but the camera does not move. I have been messing around with where I am putting the OpenGL matrix functions, and depending on where they are sometimes update() will cause a blank screen as well.
Besides the absence of glPopMatrix (which user971377 already spotted), you call glLoadIdentity in your drawing routine, which of course overwrites any changes you did on the modelview matrix in the update method (using gluLookAt).
Always keep in mind: gluLookAt, glOrtho, gluPerspective, glTranslate, glRotate, and all other matrix and transformation functions always work on the top element (changed by glPush/PopMatrix) of the currently selected matrix stack (changed by glMatrixMode). And they always multiply the current matrix, istead of replacing it. So like for gluPerspective, you should call glLoadIdentity before calling gluLookAt. And the whole camera change should be done in the rendering routine, istead of the update routine.
Instead of doing any GL transformations in update you should rather change the variables on which the camera depends and set the camera (gluLookAt on the modelview matrix) in the display method. To demonstrate the standard use of these functions, your code should be something like:
void display()
{
<general state setup (glClear, ...)>
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glLookAt(camera); //view transformation (camera)
//object 1
glPushMatrix(); //save modelview
glTranslate/glRotate/glScale; //local model transformations
<draw object 1>
glPopMatrix();
...
//object n
glPushMatrix(); //save modelview
glTranslate/glRotate/glScale; //local model transformations
<draw object n>
glPopMatrix();
gluSwapBuffers();
}
void update()
{
camera = ...;
}
}
Noticed in your code glPushMatrix(); is called with no glPopMatrix();
Just a thought, this might have something to do with you issue.
gluLookAt always applies its result to current matrix, which in your case is GL_MODEL_VIEW. But when you render your roller coaster, you load identity in that matrix, which erase the value you put using gluLookAt.
In this case, you don't need to touch the model view. In fact, GL_MODEL_VIEW stands for model matrix multiply by view matrix. In this case, you can glPushMatrix() followed by glMulMatrix( myModelMatrix ) and after rendering glPopMatrix(). With this, you can keep your view matrix inside the GL_MODEL_VIEW and still use a different model matrix for each object
I also suggest you only change projection matrix once a frame, and not each frame.
It's been a long time since I touched OpenGL, but here are a few things to consider:
With each call to display(), you are drawing the skybox with the current matrix then loading the identity matrix to draw the roller coaster. Perhaps load the identity within the push/pop so that the skybox is constant, but your prevailing tranformations on the roller coaster are applied.
Do you need to call gluPerspective and glMatrixMode with every call to display()?
Repeatedly calculating binorm from up and then up from binorm will probably give you unexpected results in terms of rotation of the camera around the screen's z axis.
The call to gluLookAt appears to have nextpos and currpos reversed, pointing the camera in the opposite direction.
(Opinion only) It may still look wierd with a completely stationary skybox. Matching camera rotation (but not translation) when drawing the skybox and roller coaster may look better.