Having trouble controling camera FPS style - c++

I've started openGL with C++ recently. I don't have that much experience in C++ but a good experience in other language.
I'm currently working on controlling a camera FPS style to start a small game and add things one by one while I learn. I know this question has been asked often and I read trough a lot of tutorial/Forum.
I did good with gluLookAt(); but I've seen it's not the best way to control FPS camera. I've been working using matrix stack lately and I'm a bit lost.
I have a code working but my rotation seems to be around the central axis or something like that. I also get some weird control that might be linked to Gimbal Locking. I'm experience with them and will use them as soon as I have something good enough.
Why am I rotating around the central axis instead of my camera axis ?
Any insight on how to use glPopMatrix() and glPushMatrix() in the context of my code? I understand the functions but can't understand how to use them when controlling camera.
I tried to keep the most important code and leave the rest, the render and the main. Mouse and keyboard controls are working as intented :
void renderScene(void) {
if(init==1){
glTranslatef(0.0f,-1.0f,-5.0f);
init = 0;
}
// Clear Color and Depth BuffersWDW
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Reset transformations
//glLoadIdentity();
// Set the camera
glTranslatef(-deltaStrafe,0,-deltaMove);
glRotatef(Pitch,1.0f,0.0f,0.0f);
glRotatef(Yaw,0.0f,1.0f,0.0f);
// Draw ground
glColor3f(0.9f, 0.9f, 0.9f);
glBegin(GL_QUADS);
glVertex3f(-50.0f, 0.0f, -50.0f);
glVertex3f(-50.0f, 0.0f, 50.0f);
glVertex3f( 50.0f, 0.0f, 50.0f);
glVertex3f( 50.0f, 0.0f, -50.0f);
glEnd();
// Draw 36 SnowMan
for(int i = -3; i < 3; i++)
for(int j=-3; j < 3; j++) {
glPushMatrix();
glTranslatef(i*10.0,0,j * 10.0);
if(i==j){
drawSnowMan();
}
else{
drawTree();
}
glPopMatrix();
}
glutSwapBuffers();
printConsole();
}
and the main function :
int main(int argc, char **argv) {
// init GLUT and create window
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(780,0);
glutInitWindowSize(800,800);
glutCreateWindow("Physic Engine");
// register callbacks
glutDisplayFunc(renderScene);
glutReshapeFunc(changeSize);
glutIdleFunc(renderScene);
// OpenGL init
glEnable(GL_DEPTH_TEST);
// enter GLUT event processing cycle
glutMainLoop();
return 1;
}
Thanks!
Edit : Changed the order of rotation/translation as suggested to :
glRotatef(Yaw,0.0f,1.0f,0.0f);
glRotatef(Pitch,1.0f,0.0f,0.0f);
glTranslatef(-deltaStrafe,0,-deltaMove);
However my camera aren't rotation on their own axis. They seems to be rotation around center axis and I'm poiting toward (0,0,0) if I don't move. How can I rotate around the camera axis as a standard FPS ? Thanks.

What you did is translate then rotate.
Rotate Camera, translate camera, and then draw your scene. Rotation is always applied around the origin, so if you rotate and then translate, you apply the rotation, and then translate the rotated frame of reference.
You should also reverse the order of pitch and yaw, for similar reasons.
You should also limit pitch such that you don't rotate more than 90 degrees upward or downward, or it might be disorientating.
Also, quaternions are not necessary unless you are applying rotations on arbitrary axis.

Related

OpenGL showing more/less of the world through resize

So a lot of questions online about resizing have been about maintaining the right ratios and avoid stretching etc. From what I understand, this would be done by setting the new ratio with gluOrtho2D.
However, I wasn't sure exactly how to go about showing MORE and LESS of the world upon resize. E.g. you have a plane that could travel from 0 to 100 along the x axis. Upon resizing, it should now (still same size) travel from 0 to 200.
EDIT: so what I mean is, I want everything in my game to stay the same size as before, but the "sky" if you will, should be bigger upon the resize, and my plane should be able to fly into that sky (since currently I have code that limits it to within the screen).
Similarly, if my screen is smaller, then the plane should no longer be able to fly to the section of the 'sky' that no longer exists
Initially, I'm setting up my program using the following lines, where everything about the game is stored in 'game', and XSize, YSize returns the size of the screen.
void init(void) {
glClearColor(0.0, 0.0, 0.3, 0.0); /* set background color to a dark blue */
glColor3f(1.0, 1.0, 1.0); /* set drawing color to white */
glMatrixMode(GL_PROJECTION);
glEnable (GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glLoadIdentity();
gluOrtho2D(0, game.getXSize()*game.getAspect(), 0, game.getYSize() / game.getAspect()); /* defines world window */
}
int main(int argc, char *argv[]) {
game = GameManager(GAMENAME, 1000, 750, 60);
/*SETUP*/
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(game.getXSize(), game.getYSize());
glutCreateWindow(GAMENAME);
/*Other GLUT main function lines here */
glutReshapeFunc(resize);
}
When I try to set up the gluOrtho2D in resize, however, the program sets up the background and stops drawing anything at all.
void resize(int w, int h){
game.setScreenSize(w,h);
glViewport(0,0,width,height)
const GLfloat aspectRatio = (GLfloat)game.getXSize() / (GLfloat)game.getYSize();
gluOrtho2D(0, game.getXSize()*game.getAspect(), 0, game.getYSize() / game.getAspect());
}
I have, of course, managed to just use glViewport(0,0,w,h) by itself, but that's pretty much the same as not doing anything at all (the graphics just stretch, and functions I'm using to move objects to the mouse position no longer work properly), since glViewport is called by default if I don't create a Reshape function.
The general way world coordinates get mapped to screen in OpenGL is:
world coordinates --> clip space coordinates --> device coordinates
The "world coordinates" are just whatever you feed to OpenGL as vertex data. They can be whatever you want, there are no rules.
The vertex shader (or matrix stack, if you are time traveling to the 1990s) is what transforms world coordinates to clip space coordinates.
The clip space coordinates go from –1…+1. So (–1,–1) is the lower-left corner of the window, (–1,+1) is the top left, (+1,+1) is the top right, etc. This is the same no matter what size your window is. So if your window gets larger, the picture will also get larger, unless you scale down the clip space coordinates at the same time.
So if you want to keep the same world coordinates and keep the same size in pixels, you have to change the way world coordinates are transformed to clip space. In general, this means that if your window gets twice as big, your clip space coordinates should get half as big, in order to keep everything the same size.
Typically, to achieve this, you'll end up multiplying in a matrix that looks something like this:
int windowWidth = ..., windowHeight = ...;
double matrix[2][2] = {
{ 1.0 / windowWidth, 0.0 },
{ 0.0, 1.0 / windowHeight },
};
That's if you're using a 2D matrix. Change this appropriately if you are using glOrtho or for your particular vertex shader. Or just read the manual for glOrtho.
By using:
gluOrtho2D(-1.0f, 1.0f, -1.0f, 1.0f);
Which would be the same as:
glOrtho(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
Then I'm assuming your problem is that when you scale a scene like this, then it ends up looking like this:
As you say this can be fixed by taking the aspect ratio into account. Given the width and height of your screen. Then you can calculate the aspect ratio and set the proper orthographic projection:
const GLfloat aspectRatio = (GLfloat)width / (GLfloat)height;
gluOrtho2D(-aspectRatio, aspectRatio, -1.0f, 1.0f);
This now results in everything scaling in relation to the aspect ratio, and subsequently allowing you to see more.
Since the above is actually a sphere in 3D, setting the near and far values is also needed:
glOrtho(-aspectRatio, aspectRatio, -1.0f, 1.0f, 1.0f, 100.0f);

Rotating triangle & changing its color in opengl

I'm new to openGL, I need help with animate a triangle that rotates 1 degree every 25 milliseconds. I want to program this triangle to gradually change color from blue to green to red.
float rAngle=0.0;
void handleResize(int w,int h)
{
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0,(double)w/(double)h,1.0,200.0);
}
void drawscene()
{
glColor3f(0.0f,1.0f,0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(-rAngle,0.0f,0.0f,0.1f);
glBegin(GL_TRIANGLES);
glVertex3f(-0.5f,0.5f,-5.0f);
glVertex3f(-1.0f,1.5f,-5.0f);
glVertex3f(-1.5f,0.5f,-5.0f);
glEnd();
glFlush();
}
void update(int value)
{
rAngle+=1.0f;
glutPostRedisplay();
glutTimerFunc(25,update,0);
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glutInitWindowSize(500, 500);
glutInitWindowPosition(0, 0);
glutCreateWindow("OpenGL");
glutDisplayFunc(drawscene);
glutReshapeFunc(handleResize);
glutTimerFunc(25,update,0);
glutMainLoop();
return 0;
}
This way of using OpenGL is deprecated.
Let me start off by pointing out that there is no reason to dabble with old outdated OpenGL. Immediate mode has been deprecated for about 10 years now.
Learn modern OpenGL instead.
Although the question is very unclear, I will try to give you the info you need.
Push/Pop Matrix:
glPushMatrix():
There is a stack of matrices for each of the matrix modes. In GL_MODELVIEW mode, the stack depth is at least 32. In the other modes, GL_COLOR, GL_PROJECTION, and GL_TEXTURE, the depth is at least 2. The current matrix in any mode is the matrix on the top of the stack for that mode.
glPushMatrix pushes the current matrix stack down by one, duplicating the current matrix. That is, after a glPushMatrix call, the matrix on top of the stack is identical to the one below it.
glPopMatrix pops the current matrix stack, replacing the current matrix with the one below it on the stack.
Initially, each of the stacks contains one matrix, an identity matrix.
Rotation:
To rotate the current matrix, call glRotate().
Color:
Use these to select rendering color.
Usually, glColor3f() or glColor4f() is used.
Your scenario:
Call glColor3f() or glColor4f() to select rendering color.
Call glPushMatrix() to avoid rotating everything.
Call glRotate() to rotate the matrix.
Render mesh.
Call glPopMatrix() to revert out of the rotated matrix.
To modify per time unit:
Just modify the data sent into the GL functions over time. Increase the rotation/color values a bit each frame.
I suggest reading up on matrix math, and how graphics incorporates this.

Adding gluPerspective and gluLookAt made my drawing disappear

I'm currently working on a basic GUI that create and draw a robot in a 3d space, I'm using OpenGL and freeglut to deal with the 3d part.
Until last week, I was ignoring all the perspective stuff like 'gluLookAt' or 'gluPerspective' ...
Now, I would like to add those things in order to get basic camera movement (rotation, zoom, translation) with user input.
But i'm stuck cause whenever I try to add the perspective part to my code, I'm not able to get my beautiful robot anymore.
here's my current code :
void drawScene(void) {
glClearColor(1.0f,1.0f,1.0f,0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glMatrixMode(GL_MODELVIEW);
glColor3f(0.0f, 0.0f, 0.0f);
ortho();
robot.draw(); // only sone basic lines and quads
glLoadIdentity();
sprintf(title, "robot creation link:%i/joint:%i", robot.linkNumber, robot.jointNumber);
glutSetWindowTitle(title);
glFlush();
}
int main(int argc, char **argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA|GLUT_SINGLE|GLUT_MULTISAMPLE);
glutInitWindowPosition(0,0);
glutInitWindowSize(1360,768);
glEnable(GL_MULTISAMPLE_ARB | GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
id = glutCreateWindow("robot creation");
glutDisplayFunc (drawScene);
glutKeyboardFunc(keyboardHandler);
glutSpecialFunc (specialKeyHandler);
glutMouseFunc (mouseHandler);
glutReshapeFunc (reshapeHandler);
glutMainLoop();
return 0;
}
I wonder if my code need to be completly re-done to work properly with such things or if I'm not using them properly.
Atm I've tried to add this after the window creation :
glViewport(0, 0, 1360, 768);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(180.0f,1360.0f/768.0f,0.1f,1000.0f);
and this in the drawScene function after the drawing part :
gluLookAt(
10.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f
);
I know I'm facing the object because I can see a dot in the center of the screen that came from the robot.
You have both matrix modes (model view and projection. It is better to activate one. For gmu perspective try something like gluPerspective(170, 1.33, 0.00001, 1000); or put the camera closer to check if you can see a difference in the object. If you are not able to see the object your matrices are overwriting each other. You can check their values by:Gl.glGetDoublev(Gl.GL_MODELVIEW_MATRIX, modelMatrix);
Gl.glGetDoublev(Gl.GL_PROJECTION_MATRIX, projMatrix);.
Another option is also gluunproject which is easier to work than look at function (in my opinion)

Using GLUT to simply print text

For the entire night, I've been looking around the internet, both stackoverflow and elsewhere, to find something to say how to print text on GLUT. While I've found places that say how, none have explained it well, saying which parts of the function is neccessary, which parts aren't. I've also tried to copy in some of the code with the closest to a success is something that made my entire screen white except for some blue pixels. So I've given up, and I'm hoping this will clear up confusion for me and the many people who are confused, like me.
So, I have found this code:
glColor3f(1.0f, 0.0f, 0.0f);
glRasterPos2f(1280, 720);
int len = menu.length();
for (int i = 0; i < len; i++) {
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10, menu[i]);
}
and I have placed it in my code:
void drawScene() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(-_cameraAngle, 0.0f, 1.0f, 0.0f);
glTranslatef(0.0f, 0.0f, -9.0f + zoom);
glTranslatef(0.0f, -1.0f, 0.0f);
string menu = "Hello!";
glColor3f(1.0f, 0.0f, 0.0f);
glRasterPos2f(1280, 720);
int len = menu.length();
for (int i = 0; i < len; i++) {
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10, menu[i]);
} /*if I need to post the rest of drawScene(), which is the function delegated
as the Display Func, tell me. I don't want to because it's long
What I want to know is what am I doing wrong, and what do future readers in my position need to do in order to get good results.
You don't say what's specifically wrong, but I'm suspecting that your text is not showing up. The reason is likely that the raster position is being clipped, and this is causing your text to not be rendered.
The raster position is the "anchor point" of where a bitmap will be drawn. Usually, this is the lower-left corner of the bitmap (the glBitmap can change that with by setting the x and y parameters to something other than zero, but assume you're not doing that). The raster position is transformed by the model-view matrix, just like a vertex in a geometric primitive. And just like a vertex, if the transformed raster position lies outside of the viewport, it's clipped, and nothing is rendered. What's important to know here is that any rendering of a bitmap - regardless of its size - is predicated on the raster position being inside of the viewport.
In your example, you don't show the viewport you're using, nor the projection transformation (the matrix on the GL_PROJECTION stack), but you set the raster position to (1280, 720), which may well be outside of the viewport.
Let's say you want to render your text in the lower-left corner of your window (and for the sake of argument, let's say your window is 1280 x 1024). When it's time to render your text, drop the following into your rendering routine:
glMatrixMode( GL_PROJECTION );
glPushMatrix();
glLoadIdentity();
gluOrtho2D( 0, 1280, 0, 1024 );
glMatrixMode( GL_MODELVIEW );
glPushMatrix();
glLoadIdentity();
glRasterPos2i( 10, 1014 ); // move in 10 pixels from the left and bottom edges
for ( int i = 0; i < len; ++i ) {
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10, menu[i]);
}
glPopMatrix();
glMatrixMode( GL_PROJECTION );
glPopMatrix();
glMatrixMode( GL_MODELVIEW );
Depending on which version of OpenGL you're using, you may be able to use a simpler routine glWindowPos2i() (the 2i can be replaced with other dimension-type pairs like other OpenGL functions), which bypasses transforming the raster position by the model-view and projection matrices, and works directly in window coordinates. In that case, you'd write the above code as:
glWindowPos2i( 10, 1014 ); // move in 10 pixels from the left and bottom edges
for ( int i = 0; i < len; ++i ) {
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10, menu[i]);
}

Using glRotate and glTranslate with collision detection

Say I use glRotate to translate the current view based on some arbitrary user input (i.e, if key left is pressed then rtri+=2.5f)
glRotatef(rtri,0.0f,1.0f,0.0f);
Then I draw the triangle in the rotated position:
glBegin(GL_TRIANGLES); // Drawing Using Triangles
glVertex3f( 0.0f, 1.0f, 0.0f); // Top
glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left
glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right
glEnd(); // Finished Drawing The Triangle
How do I get the resulting translated vertexes for use in collision detection? Or will I have to manually apply the transform myself and thus doubling up the work?
The reason I ask is that I wouldn't mind implementing display lists.
The objects you use for collision detection are usually not the objects you use for display. They are usually simpler and faster.
So yes, the way to do it is to maintain the transformation you're using manually but you wouldn't be doubling up the work because the objects are different.
Your game loop should look like (with c++ syntax) :
void Scene::Draw()
{
this->setClearColor(0.0f, 0.0f, 0.0f);
for(std::vector<GameObject*>::iterator it = this->begin(); it != this->end(); ++it)
{
this->updateColliders(it);
glPushMatrix();
glRotatef(it->rotation.angle, it->rotation.x, it->rotation.y, it->rotation.z);
glTranslatef(it->position.x, it->position.y, it->position.z);
glScalef(it->scale.x, it->scale.y, it->scale.z);
it->Draw();
glPopMatrix();
}
this->runNextFrame(this->Draw, Scene::MAX_FPS);
}
So, for instance, if i use a basic box collider with a cube the draw method will :
Fill the screen with a black color (rgb : (0,0,0))
For each object
Compute the collisions with position and size informations
Save the actual ModelView matrix state
Transform the ModelView matrix (rotate, translate, scale)
Draw the cube
Restore the ModelView matrix state
Check the FPS and run the next frame at the right time
** The class Scene inherits from the vector class
I hope it will help ! :)