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

发布于 2024-12-04 14:04:08 字数 8861 浏览 0 评论 0原文

我在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

可爱咩 2024-12-11 14:04:08

从 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 its y component, scale it to the right length and translate by it using TranslateWorld. YMMV :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文