[LearnOpenGL]照相機的變換、坐標系、攝像機


前言

跟着LearnOpenGL上學着做項目,的確對於知識掌握得更清晰一些了。

第一個項目

第一個項目,是關於簡單的熟悉矩陣變換的,創建了10個立方體,代碼如下。

 // 視圖矩陣,看作是一個照相機
glm::mat4 view;
view = glm::translate(view, glm::vec3(0.0f, 0.0f, -6.0f));
view = glm::rotate(view, glm::radians(15.0f), glm::vec3(0.0f, 0.0f, 1.0f));

// 模型矩陣
glm::mat4 projection;
projection = glm::perspective(glm::radians(45.0f), static_cast<GLfloat>(WIDTH) / static_cast<GLfloat>(HEIGHT), 0.001f, 100.0f);

glUniformMatrix4fv(glGetUniformLocation(shader.program, "view"), 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(glGetUniformLocation(shader.program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));

while (!glfwWindowShouldClose(window))
{
    glfwPollEvents();
    
    // 因為已經涉及到了3d,所以需要開啟深度測試,並且要每一幀都要清除顏色緩存和深度緩存
    
    glClearColor(0.298f, 0.451f, 0.773f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    glBindVertexArray(VAO);
    
    // 創建10個正方體
    for (GLuint i = 0; i < 10; ++i) {
        glm::mat4 model;
        model = glm::translate(model, cubePositions[i]);
        
        if (i % 2) {
            // 固定的旋轉的角度
            model = glm::rotate(model, glm::radians(20.0f * i), glm::vec3(0.0f, 0.3f, 0.5f));
        }
        else {
            // 隨時間旋轉的角度
            model = glm::rotate(model, glm::radians<GLfloat>(glfwGetTime() * 20.0f), glm::vec3(0.0f, 1.0f, 0.5f));
        }
        
        glUniformMatrix4fv(glGetUniformLocation(shader.program, "model"), 1, GL_FALSE, glm::value_ptr(model));
        
        // 一個四邊形由兩個三角形組成,兩個三角形則包括了6個索引,所以6個面則需要36個索引
        glDrawArrays(GL_TRIANGLES, 0, 36);
    }
    
    glBindVertexArray(0);

    glfwSwapBuffers(window);
}
 

第二個項目

這個項目稍微復雜,涉及到了坐標系,攝像機的知識。

#include <iostream>
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "SOIL.h"
#include "Shader.h"

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

const GLuint WIDTH = 800, HEIGHT = 600;
GLfloat mixValue = 0.2f;

//------------------------------------2.----------------------------------
glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f);
// 為什么是負的呢,因為要知道攝像機指向的是z軸的負方向
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);

//------------------------------------3.----------------------------------
bool keys[1024];//用來存儲哪些按鍵被按下

//------------------------------------4.----------------------------------
GLfloat deltaTime = 0.0f; //當前幀和上一幀的時間差
GLfloat lastFrame  = 0.0f; //上一幀時間

//------------------------------------5.----------------------------------
GLfloat yaw   = -90.0f;	// Yaw is initialized to -90.0 degrees since a yaw of 0.0 results in a direction vector pointing to the right (due to how Eular angles work) so we initially rotate a bit to the left.
//為偏航角
GLfloat pitch =   0.0f; //為俯仰角
GLfloat lastX =  WIDTH  / 2.0;
GLfloat lastY =  HEIGHT / 2.0;
bool firstMouse = true;

GLfloat fov = 1.0f;

void isDoMovement() {
    //------------------------------------3.----------------------------------
//    GLfloat speed = 0.2f;
    
    //------------------------------------4.----------------------------------
    GLfloat speed = 5.0f * deltaTime;
    
    // 照相機向z軸負方向移動
    if (keys[GLFW_KEY_W]) {
        cameraPos += cameraFront * speed;
    }
    // 照相機向z軸正方向移動
    else if (keys[GLFW_KEY_S]) {
        cameraPos -= cameraFront * speed;
    }
    // 照相機向x軸負方向
    else if (keys[GLFW_KEY_A]) {
        //cross表示叉乘,求出對於參數中的兩個向量都垂直的向量,求完了以后還需要進行歸一化得到向量
        cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * speed;
    }
    // 照相機向x軸正方向
    else if (keys[GLFW_KEY_D]) {
        cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * speed;
    }
}

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) {
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
		glfwSetWindowShouldClose(window, GL_TRUE);
    }
    
//	if (key == GLFW_KEY_UP && action == GLFW_PRESS)
//	{
//		mixValue += 0.1f;
//		if (mixValue >= 1.0f)
//			mixValue = 1.0f;
//	}
//	if (key == GLFW_KEY_DOWN && action == GLFW_PRESS)
//	{
//		mixValue -= 0.1f;
//		if (mixValue <= 0.0f)
//			mixValue = 0.0f;
//	}
    
    //------------------------------------2.----------------------------------
//    GLfloat speed = 0.2f;
//    
//    // 照相機向z軸負方向移動
//    if (key == GLFW_KEY_W) {
//        cameraPos += cameraFront * speed;
//    }
//    // 照相機向z軸正方向移動
//    else if (key == GLFW_KEY_S) {
//        cameraPos -= cameraFront * speed;
//    }
//    // 照相機向x軸負方向
//    else if (key == GLFW_KEY_A) {
//        //cross表示叉乘,求出對於參數中的兩個向量都垂直的向量,求完了以后還需要進行歸一化得到向量
//        cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * speed;
//    }
//    // 照相機向x軸正方向
//    else if (key == GLFW_KEY_D) {
//        cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * speed;
//    }
    

    //------------------------------------3.----------------------------------
    // 在第三種方法中,這個函數用來監聽
    // 先判斷有沒有按下,不再按下的時候,把該按下的按鍵進行重置
    if(action == GLFW_PRESS) {
        // 照相機向z軸負方向移動
        if (key == GLFW_KEY_W) {
            keys[key] = true;
        }
    // 照相機向z軸正方向移動
        else if (key == GLFW_KEY_S) {
            keys[key] = true;
        }
    // 照相機向x軸負方向
        else if (key == GLFW_KEY_A) {
            //cross表示叉乘,求出對於參數中的兩個向量都垂直的向量,求完了以后還需要進行歸一化得到向量
            keys[key] = true;
        }
    // 照相機向x軸正方向
        else if (key == GLFW_KEY_D) {
            keys[key] = true;
        }
    }
    else if(action == GLFW_RELEASE) {
        keys[key] = false;
    }
}

//------------------------------------5.----------------------------------
// 其中的xpos和ypos代表的是鼠標x和y的位置,攝像頭上下左右指向
void mouse_callback(GLFWwindow* window, double xpos, double ypos) {
    // 第一次移動鼠標
    if(firstMouse)
    {
        //對上一幀x和y的方向上的位置進行賦值
        lastX = xpos;
        lastY = ypos;
        firstMouse = false;
    }
    
    GLfloat xoffset = xpos - lastX;//計算x軸上的偏移量
    GLfloat yoffset = lastY - ypos;//計算y軸上的偏移量
    lastX = xpos;
    lastY = ypos;
    
    GLfloat sensitivity = 0.05;
    xoffset *= sensitivity;
    yoffset *= sensitivity;
    
    yaw   += xoffset;
    pitch += yoffset;
    
    if(pitch > 89.0f)
        pitch = 89.0f;
    if(pitch < -89.0f)
        pitch = -89.0f;
    
    glm::vec3 front;
    front.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));//同求z的原理
    front.y = sin(glm::radians(pitch)); // 以xz作為一個平面,y軸向上,形成一個三角形,可以用sin求出俯仰角的移動
    front.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch));// cos則可以求出xz平面,其中xz平面,z軸向上,x軸向右,可以根據sin偏航角計算出z
    cameraFront = glm::normalize(front); //歸一化
}

//攝像頭靠近或者進行遠離
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
    if(fov >= 1.0f && fov <= 45.0f)
        fov -= yoffset * 0.05f; //如果在規定的fov范圍,可以進行減小,超過則進行重置
    if(fov <= 1.0f)
        fov = 1.0f;
    if(fov >= 45.0f)
        fov = 45.0f;
}


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* window = glfwCreateWindow(WIDTH, HEIGHT, "OpenGL", nullptr, nullptr);
	if (window == nullptr)
	{
		std::cout << "Failed to create GLFW window" << std::endl;
		glfwTerminate();
		return -1;
	}
	glfwMakeContextCurrent(window);

	glfwSetKeyCallback(window, key_callback);
    
    glfwSetCursorPosCallback(window, mouse_callback);
    glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
    glfwSetScrollCallback(window, scroll_callback);

	glewExperimental = GL_TRUE;
	if (glewInit() != GLEW_OK)
	{
		std::cout << "Failed to initialize GLEW" << std::endl;
		return -1;
	}

	glViewport(0, 0, WIDTH, HEIGHT);

	// ¯ÂȉÂ˚
	Shader shader("/Users/staff/Desktop/practise/fgh/fgh/vertexShader.vsh", "/Users/staff/Desktop/practise/fgh/fgh/fragmentShader.fsh");

	// ÚÂÍÒÚÛ‡ 1
	GLuint texture1;
	glGenTextures(1, &texture1);
	glBindTexture(GL_TEXTURE_2D, texture1);

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	int width, height;
	unsigned char* image = SOIL_load_image("/Users/staff/Desktop/practise/fgh/fgh/wall.jpg", &width, &height, 0, SOIL_LOAD_RGB);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
	glGenerateMipmap(GL_TEXTURE_2D);
	SOIL_free_image_data(image);
	glBindTexture(GL_TEXTURE_2D, 0);

	// ÚÂÍÒÚÛ‡ 2
	GLuint texture2;
	glGenTextures(1, &texture2);
	glBindTexture(GL_TEXTURE_2D, texture2);

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	image = SOIL_load_image("/Users/staff/Desktop/practise/fgh/fgh/awesomeface.png", &width, &height, 0, SOIL_LOAD_RGBA);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
	glGenerateMipmap(GL_TEXTURE_2D);
	SOIL_free_image_data(image);
	glBindTexture(GL_TEXTURE_2D, 0);

    // 6個面上的頂點信息
    GLfloat vertices[] = {
        // Positions          // Texture Coords    //colors
        -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,     1.0f, 1.0f, 1.0f,
        0.5f, -0.5f, -0.5f,  1.0f, 0.0f,      1.0f, 1.0f, 1.0f,
        0.5f,  0.5f, -0.5f,  1.0f, 1.0f,      1.0f, 1.0f, 1.0f,
        0.5f,  0.5f, -0.5f,  1.0f, 1.0f,      1.0f, 1.0f, 1.0f,
        -0.5f,  0.5f, -0.5f,  0.0f, 1.0f,     1.0f, 1.0f, 1.0f,
        -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,     1.0f, 1.0f, 1.0f,
        
        -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,     1.0f, 1.0f, 1.0f,
        0.5f, -0.5f,  0.5f,  1.0f, 0.0f,      1.0f, 1.0f, 1.0f,
        0.5f,  0.5f,  0.5f,  1.0f, 1.0f,      1.0f, 1.0f, 1.0f,
        0.5f,  0.5f,  0.5f,  1.0f, 1.0f,      1.0f, 1.0f, 1.0f,
        -0.5f,  0.5f,  0.5f,  0.0f, 1.0f,     1.0f, 1.0f, 1.0f,
        -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,     1.0f, 1.0f, 1.0f,
        
        -0.5f,  0.5f,  0.5f,  1.0f, 0.0f,     1.0f, 1.0f, 1.0f,
        -0.5f,  0.5f, -0.5f,  1.0f, 1.0f,     1.0f, 1.0f, 1.0f,
        -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,     1.0f, 1.0f, 1.0f,
        -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,     1.0f, 1.0f, 1.0f,
        -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,     1.0f, 1.0f, 1.0f,
        -0.5f,  0.5f,  0.5f,  1.0f, 0.0f,     1.0f, 1.0f, 1.0f,
        
        0.5f,  0.5f,  0.5f,  1.0f, 0.0f,      1.0f, 1.0f, 1.0f,
        0.5f,  0.5f, -0.5f,  1.0f, 1.0f,      1.0f, 1.0f, 1.0f,
        0.5f, -0.5f, -0.5f,  0.0f, 1.0f,      1.0f, 1.0f, 1.0f,
        0.5f, -0.5f, -0.5f,  0.0f, 1.0f,      1.0f, 1.0f, 1.0f,
        0.5f, -0.5f,  0.5f,  0.0f, 0.0f,      1.0f, 1.0f, 1.0f,
        0.5f,  0.5f,  0.5f,  1.0f, 0.0f,      1.0f, 1.0f, 1.0f,
        
        -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,     1.0f, 1.0f, 1.0f,
        0.5f, -0.5f, -0.5f,  1.0f, 1.0f,      1.0f, 1.0f, 1.0f,
        0.5f, -0.5f,  0.5f,  1.0f, 0.0f,      1.0f, 1.0f, 1.0f,
        0.5f, -0.5f,  0.5f,  1.0f, 0.0f,      1.0f, 1.0f, 1.0f,
        -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,     1.0f, 1.0f, 1.0f,
        -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,     1.0f, 1.0f, 1.0f,
        
        -0.5f,  0.5f, -0.5f,  0.0f, 1.0f,     1.0f, 1.0f, 1.0f,
        0.5f,  0.5f, -0.5f,  1.0f, 1.0f,      1.0f, 1.0f, 1.0f,
        0.5f,  0.5f,  0.5f,  1.0f, 0.0f,      1.0f, 1.0f, 1.0f,
        0.5f,  0.5f,  0.5f,  1.0f, 0.0f,      1.0f, 1.0f, 1.0f,
        -0.5f,  0.5f,  0.5f,  0.0f, 0.0f,     1.0f, 1.0f, 1.0f,
        -0.5f,  0.5f, -0.5f,  0.0f, 1.0f,     1.0f, 1.0f, 1.0f
    };

    
	GLuint VBO, VAO, EBO;
	glGenVertexArrays(1, &VAO);
	glGenBuffers(1, &VBO);
	glGenBuffers(1, &EBO);

	glBindVertexArray(VAO);

	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    GLuint _positionSlot = glGetAttribLocation(shader.program, "position");
    GLuint _colorSlot = glGetAttribLocation(shader.program, "color");
    GLuint _textureCoordsSlot = glGetAttribLocation(shader.program, "texCoord");
    //GLuint _textureSlot = glGetUniformLocation(shader.program, "ourTexture");
    
	glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0);
	glEnableVertexAttribArray(_positionSlot);

    glVertexAttribPointer(_textureCoordsSlot, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(_textureCoordsSlot);
    
    glVertexAttribPointer(_colorSlot, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat)));
    glEnableVertexAttribArray(_colorSlot);
    
	glBindVertexArray(0);
    
    // 10個立方體的位置
    glm::vec3 cubePositions[] = {
        glm::vec3(0.0f,  0.0f,  0.0f),
        glm::vec3(2.0f,  5.0f, -15.0f),
        glm::vec3(-1.5f, -2.2f, -2.5f),
        glm::vec3(-3.8f, -2.0f, -12.3f),
        glm::vec3(2.4f, -0.4f, -3.5f),
        glm::vec3(-1.7f,  3.0f, -7.5f),
        glm::vec3(1.3f, -2.0f, -2.5f),
        glm::vec3(1.5f,  2.0f, -2.5f),
        glm::vec3(1.5f,  0.2f, -1.5f),
        glm::vec3(-1.3f,  1.0f, -1.5f)
    };

	while (!glfwWindowShouldClose(window))
	{
		glfwPollEvents();
        //------------------------------------4.----------------------------------
        GLfloat curTime = glfwGetTime();
        deltaTime = curTime - lastFrame;
        lastFrame = curTime;
        
        //------------------------------------3.----------------------------------
        isDoMovement();
        
        // 因為已經涉及到了3d,所以需要開啟深度測試,並且要每一幀都要清除顏色緩存和深度緩存
        
		glClearColor(0.298f, 0.451f, 0.773f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        
        shader.use();
        
        glEnable(GL_DEPTH_TEST);
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, texture1);
        glUniform1i(glGetUniformLocation(shader.program, "ourTexture1"), 0);
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D, texture2);
        glUniform1i(glGetUniformLocation(shader.program, "ourTexture2"), 1);
        glUniform1f(glGetUniformLocation(shader.program, "mixValue"), mixValue);
        
        //----------------------------------------1.-------------------------------------------
        glm::mat4 view;
        // 照相機向量
//        GLfloat radius = 20.0f;
//        GLfloat camX = sinf(glfwGetTime()) * radius;
//        GLfloat camZ = cosf(glfwGetTime()) * radius;
//        // 首先要知道lookAt函數的參數的意思,分別是eye,center,up,分別代表的是攝像機的位置向量,目標,上向量
//        // 這里實現的是照相機繞着頂點(0,0,0)進行旋轉
//        view = glm::lookAt(glm::vec3(camX, 0.0f, camZ), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
        
        //----------------------------------------2.-------------------------------------------
        //view = glm::lookAt(cameraPos, glm::vec3(0.0f, 0.0f, 0.0f), cameraUp);
        
        //----------------------------------------5.-------------------------------------------
        view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
        
        // 模型矩陣
        glm::mat4 projection;
        
        
//        projection = glm::perspective(glm::radians(45.0f), static_cast<GLfloat>(WIDTH) / static_cast<GLfloat>(HEIGHT), 0.001f, 100.0f);
        
        //----------------------------------------5.-------------------------------------------
        projection = glm::perspective(fov, (GLfloat)WIDTH/(GLfloat)HEIGHT, 0.1f, 100.0f);
        
        glUniformMatrix4fv(glGetUniformLocation(shader.program, "view"), 1, GL_FALSE, glm::value_ptr(view));
        glUniformMatrix4fv(glGetUniformLocation(shader.program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
        
        glBindVertexArray(VAO);
        // 創建10個正方體
        for (GLuint i = 0; i < 10; ++i) {
            glm::mat4 model;
            model = glm::translate(model, cubePositions[i]);
            
            if (i % 2) {
                // 固定的旋轉的角度
                model = glm::rotate(model, glm::radians(20.0f * i), glm::vec3(0.0f, 0.3f, 0.5f));
            }
            else {
                // 隨時間旋轉的角度
                model = glm::rotate(model, glm::radians<GLfloat>(glfwGetTime() * 20.0f), glm::vec3(0.0f, 1.0f, 0.5f));
            }
            
            glUniformMatrix4fv(glGetUniformLocation(shader.program, "model"), 1, GL_FALSE, glm::value_ptr(model));
            
            // 一個四邊形由兩個三角形組成,兩個三角形則包括了6個索引,所以6個面則需要36個索引
            glDrawArrays(GL_TRIANGLES, 0, 36);
        }
        
		glBindVertexArray(0);

		glfwSwapBuffers(window);
	}

	// Û‰‡ÎˇÂÏ, Á‡‚Â¯‡ÂÏ
	glDeleteVertexArrays(1, &VAO);
	glDeleteBuffers(1, &VBO);
	glDeleteBuffers(1, &EBO);

	glfwTerminate();

	return 0;
}

這里面的1,2,3,4,5分別是版本的演化;

  1. 其中1是最開始的版本:增加了照相機向量,不過是固定的;
  2. 其中2是增加了攝像機移動的功能;
  3. 其中3是因為2無法實現同時按下兩個按鍵進行移動的功能,因為用數組進行記錄,最后統一處理;
  4. 其中4是因為3中的移動距離在每個機器上都不太一樣,有的會在同一時間段內比其他人繪制更多幀,導致運動速度會變得大,造成效果不好,因此,增加時間差,記錄時間差,乘以固定的值,如果時間差變大時,意味着上一幀渲染時間多,那就會得到更高的移動速度,否之,則相反。這樣就會和上一幀平衡了。這就好比走路和跑步,跑步的移動速度肯定是要高於走路,總不能要求走路和跑步的移動速度是一樣的吧。
  5. 其中5則在之前的基礎上增加了上下左右移動攝像機,以及通過滾輪實現靠近和遠離的功能。這里面涉及到了許多的數學知識,不過不是很難,仔細看看教程還是能看懂的。

教程地址

第二個項目的延伸

之所以說是延伸是因為,第二個項目所有東西都堆在了一起,耦合程度高,因此教程把這些都封裝了起來。

.h文件

#pragma once
#include <vector>
#include <GL/glew.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>

enum Camera_Movement {
	FORWARD,
	BACKWARD,
	LEFT,
	RIGHT
};

const GLfloat YAW = -90.0f;
const GLfloat PITCH = 0.0f;
const GLfloat SPEED = 3.0f;
const GLfloat SENSITIVTY = 0.25f;
const GLfloat ZOOM = 45.0f;

class Camera {
public:
	glm::vec3 Position;
	glm::vec3 Front;
	glm::vec3 Up;
	glm::vec3 Right;
	glm::vec3 WorldUp;
	GLfloat Yaw;
	GLfloat Pitch;
	GLfloat MovementSpeed;
	GLfloat MouseSensitivity;
	GLfloat Zoom;

	Camera(glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f), GLfloat yaw = YAW, GLfloat pitch = PITCH);
	Camera(GLfloat posX, GLfloat posY, GLfloat posZ, GLfloat upX, GLfloat upY, GLfloat upZ, GLfloat yaw, GLfloat pitch);
	glm::mat4 GetViewMatrix();
	// 處理按鍵事件
	void ProcessKeyboard(Camera_Movement direction, GLfloat deltaTime);
	// 處理鼠標移動事件
	void ProcessMouseMovement(GLfloat xoffset, GLfloat yoffset, GLboolean constrainPitch = true);
	// 處理鼠標滾動事件
	void ProcessMouseScroll(GLfloat yoffset);
private:
	void updateCameraVectors();
};

.cpp文件

#include "Camera.h"

Camera::Camera(glm::vec3 position, glm::vec3 up, GLfloat yaw, GLfloat pitch)
	: Front(glm::vec3(0.0f, 0.0f, -1.0f))
	, MovementSpeed(SPEED)
	, MouseSensitivity(SENSITIVTY)
	, Zoom(ZOOM)
{
	Position = position;
	WorldUp = up;
	Yaw = yaw;
	Pitch = pitch;
	updateCameraVectors();
}

Camera::Camera(GLfloat posX, GLfloat posY, GLfloat posZ, GLfloat upX, GLfloat upY, GLfloat upZ, GLfloat yaw, GLfloat pitch) : Front(glm::vec3(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVTY), Zoom(ZOOM)
{
	Position = glm::vec3(posX, posY, posZ);
	WorldUp = glm::vec3(upX, upY, upZ);
	Yaw = yaw;
	Pitch = pitch;
	updateCameraVectors();
}

glm::mat4 Camera::GetViewMatrix() {
	return glm::lookAt(Position, Position + Front, Up);
}

void Camera::ProcessKeyboard(Camera_Movement direction, GLfloat deltaTime) {
	GLfloat velocity = MovementSpeed * deltaTime;
	if (direction == FORWARD)
		Position += glm::normalize(glm::cross(WorldUp, Right)) * velocity;
	if (direction == BACKWARD)
		Position -= glm::normalize(glm::cross(WorldUp, Right)) * velocity;
	if (direction == LEFT)
		Position -= Right * velocity;
	if (direction == RIGHT)
		Position += Right * velocity;
}

void Camera::ProcessMouseMovement(GLfloat xoffset, GLfloat yoffset, GLboolean constrainPitch) {
	xoffset *= MouseSensitivity;
	yoffset *= MouseSensitivity;

	Yaw += xoffset;
	Pitch += yoffset;

	if (constrainPitch) {
		if (Pitch > 89.0f)
			Pitch = 89.0f;
		if (Pitch < -89.0f)
			Pitch = -89.0f;
	}

	updateCameraVectors();
}

void Camera::ProcessMouseScroll(GLfloat yoffset) {
	if (Zoom >= 1.0f && Zoom <= 45.0f)
		Zoom -= yoffset;
	if (Zoom <= 1.0f)
		Zoom = 1.0f;
	if (Zoom >= 45.0f)
		Zoom = 45.0f;
}

void Camera::updateCameraVectors() {
	glm::vec3 front;
	front.x = cos(glm::radians(Yaw)) * cos(glm::radians(Pitch));
	front.y = sin(glm::radians(Pitch));
	front.z = sin(glm::radians(Yaw)) * cos(glm::radians(Pitch));
	Front = glm::normalize(front);
	Right = glm::normalize(glm::cross(Front, WorldUp));
	Up = glm::normalize(glm::cross(Right, Front));
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM