I’m having some trouble implementing looking up and down using the mouse in openGl, I can get the camera to rotate about the x-axis, however when i move forward, i starting going up at an angle, this would be great if i was doing a free moving camera, however I simply want to be able to look side to side and up and down, etc.
I’ve included my core functions.
// SphereWorld.cpp
// OpenGL SuperBible
// New and improved (performance) sphere world
// Program by Richard S. Wright Jr.
#include <GLTools.h>
#include <GLShaderManager.h>
#include <GLFrustum.h>
#include <GLBatch.h>
#include <GLFrame.h>
#include <GLMatrixStack.h>
#include <GLGeometryTransform.h>
#include <StopWatch.h>
#include <math.h>
#include <stdio.h>
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif
#define NUM_SPHERES 50
GLFrame spheres[NUM_SPHERES];
int nWindowWidth = 800;
int nWindowHalfWidth = nWindowWidth/2;
int nWindowHeight = 600;
int nWindowHalfHeight = nWindowHeight/2;
GLShaderManager shaderManager; // Shader Manager
GLMatrixStack modelViewMatrix; // Modelview Matrix
GLMatrixStack projectionMatrix; // Projection Matrix
GLFrustum viewFrustum; // View Frustum
GLGeometryTransform transformPipeline; // Geometry Transform Pipeline
GLTriangleBatch torusBatch;
GLBatch floorBatch;
GLBatch grayFloorBatch;
GLTriangleBatch sphereBatch;
GLFrame cameraFrame;
GLfloat nCurrentMouseX = 0.0f;
GLfloat nCurrentMouseY = 0.0f;
float m_fAngular = 0.0f;
float _fXCameraAngRot = 0.0f;
//////////////////////////////////////////////////////////////////
// This function does any needed initialization on the rendering
// context.
void SetupRC()
{
// Initialze Shader Manager
shaderManager.InitializeStockShaders();
glEnable(GL_DEPTH_TEST);
glLineWidth(2.5f);
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// This makes a torus
gltMakeTorus(torusBatch, 0.4f, 0.15f, 30, 30);
// This make a sphere
gltMakeSphere(sphereBatch, 0.1f, 26, 13);
floorBatch.Begin(GL_LINES, 324);
for(GLfloat x = -20.0; x <= 20.0f; x+= 0.5)
{
floorBatch.Vertex3f(x, -0.55f, 20.0f);
floorBatch.Vertex3f(x, -0.55f, -20.0f);
floorBatch.Vertex3f(20.0f, -0.55f, x);
floorBatch.Vertex3f(-20.0f, -0.55f, x);
}
floorBatch.End();
grayFloorBatch.Begin(GL_TRIANGLE_STRIP,4);
grayFloorBatch.Vertex3f(-20.0f, -.56f,-20.0f);
grayFloorBatch.Vertex3f(20.0f, -.56f,-20.0f);
grayFloorBatch.Vertex3f(-20.0f, -.56f,20.0f);
grayFloorBatch.Vertex3f(20.0f, -.56f,20.0f);
grayFloorBatch.End();
// Randomly place the spheres
for(int i = 0; i < NUM_SPHERES; i++) {
GLfloat x = ((GLfloat)((rand() % 400) - 200) * 0.1f);
GLfloat z = ((GLfloat)((rand() % 400) - 200) * 0.1f);
spheres[i].SetOrigin(x, 0.0f, z);
}
}
///////////////////////////////////////////////////
// Screen changes size or is initialized
void ChangeSize(int nWidth, int nHeight)
{
nWindowWidth = nWidth;
nWindowHeight = nHeight;
nWindowHalfWidth = nWindowWidth/2;
nWindowHalfHeight = nWindowHeight/2;
glViewport(0, 0, nWidth, nHeight);
// Create the projection matrix, and load it on the projection matrix stack
viewFrustum.SetPerspective(35.0f, float(nWidth)/float(nHeight), 1.0f, 100.0f);
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
// Set the transformation pipeline to use the two matrix stacks
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}
// Called to draw scene
void RenderScene(void)
{
// Color values
//static GLfloat vFloorColor[] = { 0.0f, 1.0f, 0.0f, 1.0f};
static GLfloat vFloorColor[] = { (85.0f/255.0f), (186.0f/255.0f), (242.0f/255.0f), 1.0f};
static GLfloat vgrayFloorColor[] = { (100.0f/255.0f), (98.0f/255.0f), (111.0f/255.0f), 1.0f};
static GLfloat vTorusColor[] = { 1.0f, 0.0f, 0.0f, 1.0f };
static GLfloat vSphereColor[] = { (160.0f/255.0f), (41.0f/255.0f), (35.0f/255.0f), 1.0f };
// Time Based animation
static CStopWatch rotTimer;
float yRot = rotTimer.GetElapsedSeconds() * 60.0f;
cameraFrame.RotateWorld(-m_fAngular, 0.0f, 1.0f, 0.0f);
//cameraFrame.RotateWorld(_fXCameraAngRot,1.0f, 0.0f, 0.0f);
// Clear the color and depth buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Save the current modelview matrix (the identity matrix)
modelViewMatrix.PushMatrix();
M3DMatrix44f mCamera;
cameraFrame.GetCameraMatrix(mCamera);
modelViewMatrix.PushMatrix(mCamera);
// Draw the ground
shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vFloorColor);
floorBatch.Draw();
shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(), vgrayFloorColor);
grayFloorBatch.Draw();
for(int i = 0; i < NUM_SPHERES; i++)
{
modelViewMatrix.PushMatrix();
modelViewMatrix.MultMatrix(spheres[i]);
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(),vSphereColor);
sphereBatch.Draw();
modelViewMatrix.PopMatrix();
}
// Draw the spinning Torus
modelViewMatrix.Translate(0.0f, 0.0f, -2.5f);
// Save the Translation
modelViewMatrix.PushMatrix();
// Apply a rotation and draw the torus
modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(),vTorusColor);
torusBatch.Draw();
modelViewMatrix.PopMatrix(); // "Erase" the Rotation from before
// Apply another rotation, followed by a translation, then draw the sphere
modelViewMatrix.Rotate(yRot * -2.0f, 0.0f, 1.0f, 0.0f);
modelViewMatrix.Translate(0.8f, 0.0f, 0.0f);
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vSphereColor);
sphereBatch.Draw();
modelViewMatrix.Rotate(_fXCameraAngRot, 1.0,0,0);
// Restore the previous modleview matrix (the identity matrix)
//modelViewMatrix.PopMatrix();
modelViewMatrix.PopMatrix();
modelViewMatrix.PopMatrix();
// Do the buffer Swap
glutSwapBuffers();
// Tell GLUT to do it again
glutPostRedisplay();
}
// Respond to arrow keys by moving the camera frame of reference
void SpecialKeys(int key, int x, int y)
{
float linear = 0.1f;
float angular = float(m3dDegToRad(5.0f));
if(key == GLUT_KEY_UP)
cameraFrame.MoveForward(linear);
if(key == GLUT_KEY_DOWN)
cameraFrame.MoveForward(-linear);
if(key == GLUT_KEY_LEFT)
cameraFrame.RotateWorld(angular, 0.0f, 1.0f, 0.0f);
if(key == GLUT_KEY_RIGHT)
cameraFrame.RotateWorld(-angular, 0.0f, 1.0f, 0.0f);
}
void KeyPress(unsigned char key, int x, int y)
{
float linear = 0.1f;
if(key == 'W' || key == 'w' )
cameraFrame.MoveForward(linear);
if(key == 'S' || key == 's')
cameraFrame.MoveForward(-linear);
if(key == 'A' || key == 'a')
cameraFrame.MoveRight(linear);
if(key == 'D' || key == 'd')
cameraFrame.MoveRight(-linear);
}
void MouseMove(int x, int y)
{
GLfloat nXDelta = x-nWindowHalfWidth;
if(nXDelta >= -50 && nXDelta <= 50)
{
nXDelta = 0.0f;
}
GLfloat yRot = nXDelta * .005;// * .5f;
m_fAngular = float(m3dDegToRad(yRot));
GLfloat nYDelta = y - nWindowHalfHeight;
if(nYDelta >= -25 && nYDelta <= 25)
{
nYDelta = 0.0f;
}
GLfloat xRot = nYDelta;// * .005;
_fXCameraAngRot = float(m3dDegToRad(xRot));
printf("x value is: %d - xdelta is %1.00f xRot is %f\n", x, nXDelta, _fXCameraAngRot);
//cameraFrame.RotateLocalX(float(m3dDegToRad(xRot)));
//cameraFrame.RotateLocal(float(m3dDegToRad(xRot)),1.0f,0.0f,0.0f);
}
int main(int argc, char* argv[])
{
gltSetWorkingDirectory(argv[0]);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(nWindowWidth,nWindowHeight);
glutCreateWindow("OpenGL SphereWorld");
glutKeyboardFunc(KeyPress);
glutSpecialFunc(SpecialKeys);
glutReshapeFunc(ChangeSize);
glutDisplayFunc(RenderScene);
glutPassiveMotionFunc(MouseMove);
GLenum err = glewInit();
if (GLEW_OK != err)
{
fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
return 1;
}
SetupRC();
glutMainLoop();
return 0;
}
Judging by the implementation of GLFrame here:
http://code.google.com/p/oglsuperbible5/source/browse/trunk/Src/GLTools/include/GLFrame.h?r=160
It looks like you should be able to move forwards the way you want by calling
cameraFrame.TranslateWorld.The easiest way is probably to get the forward vector using
GetForwardVector, flatten it into the x-z plane by zeroing out itsycomponent, scale it to the right length and translate by it usingTranslateWorld. YMMV 🙂