Been integrating this camera tutorial http://www.swiftless.com/tutorials/opengl/camera2.html and having a bit of trouble centering the camera in the skybox.
Using this code below makes my camera inside the box:
void reshape(int w, int h)
{
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho(-1.0, 1.0, -1.0*(GLfloat)h/(GLfloat)w,
1.0*(GLfloat)h/(GLfloat)w, -10.0, 10.0);
else
glOrtho(-1.0*(GLfloat)w/(GLfloat)h,
1.0*(GLfloat)w/(GLfloat)h, -1.0, 1.0, -10.0, 10.0);
glMatrixMode(GL_MODELVIEW);
}
To draw the skybox, I followed this tutorial: http://sidvind.com/wiki/Skybox_tutorial
I've been trying to translate objects closer to the camera, but didn't work as I expected. Now I'm not sure what I need to do.
Appreciate any help.
First: Don'y apply the projection in the reshape handler. Otherwise simple things appear impossible (like doing a skybox). Second: For a skybox to work you must use the very same projection like for the rendering of the rest of the scene. What you should change is the translation of the modelview to 0, yet keeping the camera orientation.
You can do this by setting the last column of the modelview matrix to (0,0,0,1).
So this makes your rendering code like this:
void render_skybox()
{
push_modelview();
set_modelview_column(3, 0, 0, 1);
draw_skybox();
pop_modelview();
}
void render()
{
set_viewport();
set_projection();
apply_camera_transform();
render_skybox();
render_scene();
}
Related
I need to draw a cube and project it with the default projection matrix. Also, I want to draw a hud controlling the orientation of the sphere. The hud is projected with another projection matrix.
render()
{
DrawGUI(); // project GUI with another projection matrix
glPushMatrix();
glutSolidCube(); // project the cube with the default projection matrix
glPopMatrix();
glutSwapBuffers();
}
reshape()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(...);
...
}
DrawGUI()
{
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(...); // project the GUI with this matrix
glMatrixMode(GL_MODELVEIW);
glPushMatrix();
glLoadIdentity();
glBegin();
//... drawing GUI
glEnd();
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
#define BUFFER_LENGTH 64
void processSelection(int xPos, int yPos)
{
static GLuint selectBuff[BUFFER_LENGTH];
GLint hits, viewport[4];
glSelectBuffer(BUFFER_LENGTH, selectBuff);
glGetIntegerv(GL_VIEWPORT, viewport);
// Switch to projection and save the matrix
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glRenderMode(GL_SELECT);
glLoadIdentity();
gluPickMatrix(xPos, viewport[3] - yPos, 2,2, viewport);
glOrtho (-100, 100, -100, 100, -100, 100); // this line of code is the most
glMatrixMode(GL_MODELVIEW);
render();
hits = glRenderMode(GL_RENDER);
//...process hits
// Restore the projection matrix
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
The render part works well. Both the GUI and the cube are drawn without problem. However, the selection does not work as intended.
My question is: Since I project 3D models with different projection matrix, how should I deal with selection? I try to implement the typical selection buffer approach, but every time I click in the window, the selection buffer always contains the GUI even if I do not click on the GUI. Also, if I click on the cube, the selection buffer ends up with both the cube and the GUI.
If you use the selection buffer approach, you render with mixed projections as you do when doing the usual render. The only difference, is, that you apply that pick matrix as well. Also don't try to be too clever with the matrix pushing / poping. It rarely makes sense to use that in the projection matrix stack (hence it requires to have only 2 push levels, instead of the 32 for the modelview). Also don't use the reshape function to define the projection matrix.
DrawCube()
{
glMatrixMode(GL_MODELVEIW);
glLoadIdentity();
glutSolidCube();
}
DrawGUI()
{
glMatrixMode(GL_MODELVEIW);
glLoadIdentity();
glBegin();
//... drawing GUI
glEnd();
}
void render()
{
// base the projection on whats already in the projection
// matrix stack. For normal render this is identity, for
// selection it is a pick matrix.
glMatrixMode(GL_PROJECTION);
glPushMatrix();
gluOrtho2D(...); // project the GUI with this matrix
DrawGUI();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
gluPerspective(...);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
}
void display()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
render();
glutSwapBuffers();
}
#define BUFFER_LENGTH 64
void select(int xPos, int yPos)
{
static GLuint selectBuff[BUFFER_LENGTH];
GLint hits, viewport[4];
glSelectBuffer(BUFFER_LENGTH, selectBuff);
glGetIntegerv(GL_VIEWPORT, viewport);
// Switch to projection and augment it with a picking matrix
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPickMatrix(xPos, viewport[3] - yPos, 2,2, viewport);
glRenderMode(GL_SELECT);
render();
hits = glRenderMode(GL_RENDER);
//...process hits
}
Note that OpenGL selection mode is usually not GPU accelerated and hence very slow. Also it's been deprecated and removed from modern OpenGL versions. It's highly recommended to use either index buffer selection (i.e. render each object with a dedicated index "color") or perform manual ray-intersection picking into the scene data.
I have a studying project which represents simple 3D scene. I want to draw sphere in some non-origin point. Later I'm going implement this as separate function or method.
I'm setting point of view using gluLookAt() then I'm transforming model-view matrix using glTranslatef() with little offset and drawing sphere. Unfortunately, the sphere isn't shown. Am I right with model-view matrix approaching?
void display(void){
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
gluLookAt(1, 0 ,1, 0, 0, 0, 0, 1, 0);
glColor3b(197, 96, 63);
glPushMatrix();
glLoadIdentity();
glTranslatef(0.1, 0, 0);
glutWireSphere(0.2, 20, 10);
glPopMatrix();
glFlush();
}
void reshape(int w, int h){
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho ((float)w/(float)h, (float)-w/(float)h, -1, 1, 0.8, 100);
glMatrixMode(GL_MODELVIEW);
}
No, you aren't.
gluLookAt(1, 0 ,1, 0, 0, 0, 0, 1, 0);
glColor3b(197, 96, 63);
glPushMatrix();
glLoadIdentity(); // why it should be there?
By zeroing the view matrix there, you are drawing your object relatively to the origin coordinates, not taking your glLookAt into account. The call to it is effectively ignored. It should be coded as:
Set up the "camera matrix"
Push the matrix on the stack
Translate to the object's position
Draw the object
Pop and go back to 2.
So if you want to set up hypothetical "camera", you have to combine positions of objects with the camera matrix itself.
Your approach doesn't look that unreasonable. The problem is here:
glPushMatrix();
glLoadIdentity();
glTranslatef(0.1, 0, 0);
The pushing (and later popping) is a good idea, but by setting the matrix to identity before the translation, you loose any transformations done before, in particular the viewing transformations established with gluLookAt. So just remove this glLoadIdentity to properly concatenate the individual transformations.
Always keep in mind that all the matrix transformation functions, like glTranslate, glOrtho, or gluLookat always modify the currently selected (with glMatrixMode) matrix and don't just replace it. This is also the reason why you do a glLoadIdentity before the calls to glOrtho and gluLookAt.
I have the following code that takes snapshots to the framebuffer. I verified the framebuffer works correctly and the camera is facing the object correctly. I used to get pictures done correctly, but it was based on faulty code, using the wrong frustum. So I decided to start fresh (with the frustums).
The object is centered at the middle and is 32*32 blocks with each block 2*2, so 64 * 64.
My distance is 100 and my viewport is 128x256. My frustum is 1 to 1000.0.
I'm relatively new to Opengl so I'm having trouble understanding the concepts of frustrums and perspectives fully.
I do not get a picture at all.
saveGLState();
const int nrPics = 360 / DEGREES_BETWEEN_PICTURES;
for (int i = 0; i < nrPics; i++) {
catchFbo->bind();
glViewport(0, 0, PICTURE_WIDTH, PICTURE_HEIGHT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
float rat = PICTURE_WIDTH / PICTURE_HEIGHT;
glFrustum(- 1.0, + 1.0, - rat, + rat, 1.0, 1000.0);
gluPerspective(90.0f,rat,CAPT_FRUSTRUM_NEAR,CAPT_FRUSTRUM_FAR);
glColorMask(true, true, true, true);
glClearColor(0,0,0,0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glEnable(GL_MULTISAMPLE);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
drawScreenshot(i);
catchFbo->release();
QImage catchImage = catchFbo->toImage();
catchImage.save("object/test" + QString::number(i) + ".png");
}
glDisable(GL_MULTISAMPLE);
restoreGLState();
void VoxelEditor::saveGLState()
{
glPushAttrib(GL_ALL_ATTRIB_BITS);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
}
void VoxelEditor::restoreGLState()
{
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glPopAttrib();
}
EDIT: I tried using only glFrustum or glPerspective. No luck.
You shouldn't use both glFrustum and gluProjection. They both are operations which setup the projection matrix, and if you use them together you'll multiply them together and get a weird result. Generally you'd just apply glFrustum OR gluProjection on an identity matrix, not both.
If that doesn't solve the problem, what are your values of NEAR, FAR, WIDTH, and HEIGHT?
Also make sure you're not doing integer divide for your screen ratio (a common bug).
Most of this code should be fairly self explanatory. I got an display function and my view port function. There are two modes which is 4 small view ports in the window or one large.
I got one camera which can be moved and if in 4 view port mode just 3 fixed angles. The thing is I want the free moving cameras position to be displayed in the 3 other view ports. I tried doing it by drawing spheres using opengl but the problem is that then the position gets draw in the free roaming camera too as it shows the same scene.
It doesn't have to be a sphere, just something simple that represents the cameras spacial position in these three other views.
Drawing the scene once with camera object showing for the three viewports, render to texture. Clear and draw scene without camera object render to texture and then stitch these together before actually drawing the scene seems like a lot o work for something that should be easy.
void display(int what)
{
if(what==5){
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
camControll();}
if(what==1){
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(75,15,-5,0,5,-5,0,1,0);}
if(what==2){
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0,110,0,0,0,0,1,0,0);}
if(what==3){
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, float(320) / float(240), 0.1f, 100.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
camControll();}
if(what==4){
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(185,75,25,0,28,0,0,1,0);}
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
drawScene();
drawCamera();
glutSwapBuffers();
}
void viewport(){
glEnable(GL_SCISSOR_TEST);
if(!divided_view_port)
{
glViewport(0, 0, w, h);
glScissor(0,0,640,480);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, w / h, 0.1f, 100.0f);
display(5);
}
else
{
////////////////////// bottom left - working
glViewport(0, 0, w/2, h/2);
glScissor(0,0,w/2,h/2);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, w / h, 0.1f, 300.0f);
display(1);
//////////////////////
////////////////////// top right - working
glViewport(w/2, h/2, w/2, h/2);
glScissor(w/2,h/2,w/2,h/2);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, w / h, 0.1f, 300.0f);
display(2);
//////////////////////
////////////////////// bottom right -working
glViewport(w/2, 0, w/2, h/2);
glScissor(w/2,0,w/2,h/2);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, w / h, 0.1f, 300.0f);
display(3);
////////////////////////
////////////////////////// top left
glViewport(0, h/2, w/2, h/2);
glScissor(0,h/2,w/2,h/2);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, w / h, 0.1f, 300.0f);
display(4);
///////////////////////////
}
glDisable(GL_SCISSOR_TEST);
glMatrixMode(GL_MODELVIEW);
}
So what I basically need is to hide this object in specific viewport.
Why not make that single Sphere object (or the entity responsible for drawing the sphere) aware of the "current viewport" (which happens to be the what variable in your code) and let it be invisible if it's the given viewport?
This solution exactly corresponds to the logic involved here sounds both simple and correct.
A more general solution would be to give each "camera" a GUID and make it available for the entity responsible for drawing Cameras to check the GUID of the "camera" bound to the viewport which is being rendered at the moment. If they happen to be equal, ignore the camera object during this draw pass.
I think that should be easy if you would just draw point, because if you want to see point in viewport, its center have to be in viewport, otherwise nothing of it is displayed even if you set huge point size. Then you have 2 options to eliminate flickering effect (as when you put 2 squares in the very same possition they will flicker one over another). You can just move that point little behind camera, or use nonzero value for near clipping plane in glFrustrum/gluPerspective call.. and well if you update point position every time you move camera you have no chance of seeing that point in your moving camera and you can use single scene.
And second option, I don't know if you can update just single viewport, but maybe just setting scene, displaying it to moving camera, drawing camera position and displaying it for other 3 viewports should be easy also..
Why don't you draw the sphere behind the moving camera's near plane? That should ensure that the moving camera doesn't see the sphere at all, but its position is clearly marked for the others.
When looking at the reshape examples in the redbook, I usually find something like:
void reshape(int w, int h)
{
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-1.0, 1.0, -1.0, 1.0, 1.5, 20.0);
glMatrixMode(GL_MODELVIEW);
}
I understand that calling glMatrixMode(GL_PROJECTION); followed by glLoadIdentity(); resets the projection matrix but I don't understand why glMatrixMode(GL_MODELVIEW) is usually called at the end of reshape.
In this particular example glFrustum affects the projection matrix, right? Why is GL_MODELVIEW called later? Would it make a difference if the last call to glMatrixMode(GL_MODELVIEW) is omitted?
Most of your rendering code is going to affect GL_MODELVIEW, because it's what affects object translation and camera position. However, the resizing code works on GL_PROJECTION. The programmer probably assumes the current matrix is the modelview one in most of his code, and when a different one needs to be affected, he/she would change the matrix, update it, and then change the target back to GL_MODELVIEW so the rest of the code doesn't target the wrong matrix.
Generally, OpenGL functions affect whatever matrix is currently being targeted, which is why you change the matrix.