欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

OpenGL视角LooAt及Perspective理解

程序员文章站 2022-03-26 11:29:32
...

在:
http://blog.csdn.net/yulinxx/article/details/59538755
的基础上,修改 main.cpp

理解 glm::perspective 和 glm::lookAt


相机竖立在50米开外, 用90度的视角去看0,0,0点的位置,

那么50米外原点中,高度为50的物体,正好看到, 超过50则会被截断!

OpenGL视角LooAt及Perspective理解

void
gluLookAt(GLdouble eyeX, GLdouble eyeY, GLdouble eyeZ,
GLdouble centerX, GLdouble centerY, GLdouble centerZ,
GLdouble upX, GLdouble upY, GLdouble upZ);

glm::mat4 projection =
glm::perspective(fovyInRadians, aspect, zNear, zFar);

相机视角,以侧视图观察, 在此处以90度为 fovyInRadians 值,
在图中,以45度角进行半分开来,予以剖析

相机离原点为50, 则原点处Y最大能显示为50, z=-50处Y最大能显示为100
若在原点绘图,
我们绘制一个 98*98的正方形,则在视图中,几乎填满视图 (X Y 值分别从-49 到 +49)
为显示边框,所以绘制一个稍小于100的正方形
OpenGL视角LooAt及Perspective理解
glm::lookAt 用于相机定位

glm::perspective用于相机视角设置


#define GLEW_STATIC
#include <GL/glew.h>

#include <GLFW/glfw3.h>

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#include <SOIL/SOIL.h>

#include "Shader.h"
#include <stdio.h>

#include <Windows.h>
#include <math.h>

#pragma comment(lib, "SOIL.lib")

#pragma comment (lib, "opengl32.lib")
#pragma comment (lib, "glew32s.lib")
#pragma comment (lib, "glfw3.lib") 
#pragma comment (lib, "glfw3dll.lib") 
#pragma comment (lib, "glew32mxs.lib")
#pragma comment (lib, "assimp.lib")

#define  WIDTH 500
#define  HEIGH 500


glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 50.0f); // 相机距离原点50
glm::vec3 cameraTarg = glm::vec3(0.0f, 0.0f, 0.0f);
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);

glm::vec4  mousePos;

GLfloat fRotateAngle = 0.0f;

void keyFun(GLFWwindow* pWnd, int nKey, int nScanCode, int nAction, int nMode);
void mouseFun(GLFWwindow* pWnd, int, int, int);
void cursorFun(GLFWwindow* window, double x, double y);


//////////////////////////////////
int main()
{
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);

    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

    GLFWwindow* pWnd = glfwCreateWindow(WIDTH, HEIGH, "OGL Geometry Shader", nullptr, nullptr);
    glfwMakeContextCurrent(pWnd);

    glfwSetKeyCallback(pWnd, keyFun);
    glfwSetCursorPosCallback(pWnd, cursorFun);
    glfwSetMouseButtonCallback(pWnd, mouseFun);

    glewExperimental = GL_TRUE;

    glewInit();

    glViewport(0, 0, WIDTH, HEIGH);

#if 0
    // 在原点处绘图,即离相机50, 将Y值稍微缩小,便于显示
    GLfloat cube[] = {
        -49.0f, -49.0f, -0.0f,   49.0f, -49.0f,-0.0f,
        49.0f, -49.0f,-0.0f,     49.0f, 49.0f,-0.0f,
        49.0f, 49.0f,-0.0f,     -49.0f, -49.0f, -0.0f,
        -49.0f, -49.0f, -0.0f,   -49.0f, 49.0f,-0.0f,
        -49.0f, 49.0f, -0.0f,   49.0f, 49.0f,-0.0f,
        -49.0f, 49.0f, -0.0f,  49.0f, -49.0f, -0.0f,
    };
#else
    // 在z -50 处绘图,即离相机100,将Y值稍微缩小,便于显示
    GLfloat cube[] = {
        -99.0f, -99.0f, -50.0f,   99.0f, -99.0f,-50.0f,
        99.0f, -99.0f,-50.0f,    99.0f, 99.0f,-50.0f,
        99.0f, 99.0f,-50.0f,        -99.0f, -99.0f, -50.0f,
        -99.0f, -99.0f, -50.0f,   -99.0f, 99.0f,-50.0f,
        -99.0f, 99.0f, -50.0f,   99.0f, 99.0f,-50.0f,
        -99.0f, 99.0f, -50.0f,  99.0f, -99.0f, -50.0f,
    };
#endif

    GLuint nVAO, nVBO;
    glGenVertexArrays(1, &nVAO);
    glBindVertexArray(nVAO);
    {
        glGenBuffers(1, &nVBO);
        glBindBuffer(GL_ARRAY_BUFFER, nVBO);
        {
            glBufferData(GL_ARRAY_BUFFER, sizeof(cube), &cube[0], GL_STATIC_DRAW);

            glEnableVertexAttribArray(0);   // vertex
            glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
        }
        glBindBuffer(GL_ARRAY_BUFFER, 0);
    }
    glBindVertexArray(0);

    Shader shader("./Shader/vertex.vx", "./Shader/frag.fg");
    shader.userShaderProg();

    glm::mat4 model;        // 模型矩阵
    glm::mat4 view;         // 视图矩阵

    // 投影矩阵                 视角      宽高比                     近        远截面
    // 侧视图
    glm::mat4 proj = glm::perspective(3.141592f/2.0f, GLfloat(WIDTH / HEIGH), 1.0f, 200.0f);

    GLint nModelLoc = glGetUniformLocation(shader.getProg(), "model");
    GLint nViewLoc = glGetUniformLocation(shader.getProg(), "view");
    GLint nProjLoc = glGetUniformLocation(shader.getProg(), "projection");

    // 将矩阵传至Shader
    glUniformMatrix4fv(nModelLoc, 1, GL_FALSE, glm::value_ptr(model));
    glUniformMatrix4fv(nViewLoc, 1, GL_FALSE, glm::value_ptr(view));
    glUniformMatrix4fv(nProjLoc, 1, GL_FALSE, glm::value_ptr(proj));

    while (!glfwWindowShouldClose(pWnd))
    {
        glfwPollEvents();

        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        view = glm::lookAt(cameraPos, cameraTarg, cameraUp);
        glUniformMatrix4fv(nViewLoc, 1, GL_FALSE, glm::value_ptr(view));

        glBindVertexArray(nVAO);
        {
            glDrawArrays(GL_LINES, 0, sizeof(cube)/sizeof(GLfloat)/3);
        }
        glBindVertexArray(0);

        glfwSwapBuffers(pWnd);
    }

    return 0;
}


void keyFun(GLFWwindow* pWnd, int nKey, int nScanCode, int nAction, int nMode)
{
    if (nAction == GLFW_PRESS)
    {
        if (nKey == GLFW_KEY_W)
        {
            // 物体到相机的单位向量
            glm::vec3 direction = glm::normalize(cameraTarg - cameraPos);
            direction *= 0.1;   // 移动0.1个单位向量
            cameraPos += direction;
        }
        else if (nKey == GLFW_KEY_S)
        {
            glm::vec3 direction = glm::normalize(cameraTarg - cameraPos);
            direction *= 0.1;
            cameraPos -= direction;
        }
        else if (nKey == GLFW_KEY_A)
        {
            // 物体到相机的单位向量
            glm::vec3 direction = glm::normalize(cameraTarg - cameraPos);
            // 物体到相机的单位向量 与 相机的向上向量相乘,得到垂直向量,即平移向量
            glm::vec3 vertical = glm::normalize(glm::cross(direction, cameraUp));
            vertical *= 0.1;
            cameraPos += vertical;  // 移动相机位置
            cameraTarg += vertical; //相机的指向位置也一起平衡(不平移则以原来的目标转圈)

        }
        else if (nKey == GLFW_KEY_D)
        {
            glm::vec3 direction = glm::normalize(cameraTarg - cameraPos);
            glm::vec3 vertical = glm::normalize(glm::cross(direction, cameraUp));
            vertical *= 0.1;
            cameraPos -= vertical;
            cameraTarg -= vertical;
        }
        else if (nKey == GLFW_KEY_Q)
        {
            GLfloat radius = glm::distance(cameraPos, cameraTarg);
            fRotateAngle += 0.1;

            GLfloat camX = sin(fRotateAngle) * radius + cameraTarg.x;
            GLfloat camZ = cos(fRotateAngle) * radius + cameraTarg.z;

            cameraPos = glm::vec3(camX, 0.0, camZ);
        }
        else if (nKey == GLFW_KEY_E)
        {
            GLfloat radius = glm::distance(cameraPos, cameraTarg);
            fRotateAngle -= 0.1;

            GLfloat camX = sin(fRotateAngle) * radius + cameraTarg.x;
            GLfloat camZ = cos(fRotateAngle) * radius + cameraTarg.z;

            cameraPos = glm::vec3(camX, 0.0, camZ);
        }
        else if (nKey == GLFW_KEY_X)    // 还原视图
        {
            cameraPos = glm::vec3(0.0f, 0.0f, 5.0f);
            cameraTarg = glm::vec3(0.0f, 0.0f, 0.0f);
        }
    }
}



void mouseFun(GLFWwindow* window, int button, int action, int mods)
{
    if (action == GLFW_PRESS)
    {
        switch (button)
        {
        case GLFW_MOUSE_BUTTON_LEFT:
        {
            //printf("Screen X:%.3f Y:%.3f\t\tOGL X:%.3f, Y:%.3f\t\t\tLeft button clicked!\n", mousePos.x, mousePos.y, mousePos.z, mousePos.w);

            float mouseX = mousePos.x / (WIDTH  * 0.5f) - 1.0f;
            float mouseY = mousePos.y / (HEIGH * 0.5f) - 1.0f;

            //mouseX = mousePos.z;
            //mouseY = -mousePos.w;

            //printf("mouse X:%.3f mouseY:%.3f \n", mouseX, mouseY);

            glm::mat4 proj = glm::perspective(45.0f, GLfloat(WIDTH / HEIGH), 1.0f, -100.0f);

            glm::mat4 view = glm::lookAt(cameraPos, cameraTarg, cameraUp);

            glm::mat4 invVP = glm::inverse(proj * view);
            glm::vec4 screenPos = glm::vec4(mouseX, -mouseY, 1.0f, 1.0f);
            glm::vec4 worldPos = invVP * screenPos;

            glm::vec3 dir = glm::normalize(glm::vec3(worldPos));
            printf("dir X:%.3f dir:%.3f dir:%.3f\n", dir.x, dir.y, dir.z);
        }
        break;
        case GLFW_MOUSE_BUTTON_MIDDLE:
            printf("Middle button clicked!\n");
            break;
        case GLFW_MOUSE_BUTTON_RIGHT:
            system("cls");
            printf("Right button clicked!\n");
            break;
        default:
            printf("Default \n");
            return;
        }
    }
    return;
}


void cursorFun(GLFWwindow* window, double x, double y)
{
    float xpos = float((x - WIDTH / 2) / WIDTH) * 2;
    float ypos = float(0 - (y - HEIGH / 2) / HEIGH) * 2;
    //printf("Mouse position move to [ %.3f : %.3f ]\n", xpos, ypos);

    mousePos = glm::vec4(x, y, xpos, ypos);

    return;
}

源码:
http://download.csdn.net/download/yulinxx/9975863

相关标签: opengl