OpenGL视角LooAt及Perspective理解

版权声明:----------------------------未经博主允许, 随意转载---------------------------- https://blog.csdn.net/yulinxx/article/details/77959484

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

理解 glm::perspective 和 glm::lookAt


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

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

这里写图片描述

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的正方形
这里写图片描述
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

猜你喜欢

转载自blog.csdn.net/yulinxx/article/details/77959484