OpenGL视角LooAt及Perspective理解

时间:2022-09-10 17:56:52

在:
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