OpenGL SuperBible 实现相机俯仰(向上和向下看)
我在 openGl 中使用鼠标实现上下查找时遇到一些麻烦,我可以让相机绕 x 轴旋转,但是当我向前移动时,我开始以一定角度向上移动,如果我正在做一个自由移动的相机,但我只是希望能够左右、上下等查看。
我已经包含了我的核心功能。
// 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;
}
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;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
从 GLFrame 的实现来看:
http://code.google.com/p/oglsuperbible5/source/browse/trunk/Src/GLTools/include/GLFrame.h?r=160
看起来您应该能够通过调用cameraFrame.TranslateWorld 来按照您想要的方式前进。
最简单的方法可能是使用 GetForwardVector 获取前向向量,通过将其 y 分量归零将其展平到 xz 平面,将其缩放到正确的长度并通过它进行平移使用
TranslateWorld
。嗯嗯:)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 itsy
component, scale it to the right length and translate by it usingTranslateWorld
. YMMV :)