OpenGl SuperBible实现相机俯仰(向上和向下看)

OpenGl SuperBible implementing camera Pitch (Looking up and down)

本文关键字:向下看 SuperBible 实现 相机 OpenGl      更新时间:2023-10-16

我在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 %fn", 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: %sn", glewGetErrorString(err));
        return 1;
    }

    SetupRC();
    glutMainLoop();    
    return 0;
}

从这里GLFrame的实现来看:

http://code.google.com/p/oglsuperbible5/source/browse/trunk/Src/GLTools/include/GLFrame.h?r=160

看起来你应该能够通过调用cameraFrame.TranslateWorld来按照你想要的方式前进。

最简单的方法可能是使用GetForwardVector获得正向向量,通过将其y分量归零将其平展到x-z平面,将其缩放到合适的长度并使用TranslateWorld进行平移。YMMV:)