本章参考官方教程:摄像机
本系列历史文
OpengGL教程(一)—OpenGL环境的配置(GLFW3,GLAD)
OpengGL教程(二)—渲染一个简单的窗体
OpengGL教程(三)—使用VAO和VBO方式绘制三角形
OpengGL教程(四)—使用EBO方式绘制矩形
OpengGL教程(五)—纹理的应用
OpengGL教程(六)—坐标的变换和坐标系的变换
本章主要讲述了MVP矩阵中的V矩阵。
需要了解:格拉姆—施密特正交化
OpenGL本身没有摄像机(Camera)的概念,但我们可以通过把场景中的所有物体往相反方向移动的方式来模拟出摄像机,产生一种我们在移动的感觉,而不是场景在移动。
官网中有上面这样一段话,不要去纠结有无摄像机,就默认为有,对于此章节我们一切矩阵操作的对象都是摄像机。
摄像机看一个物体有哪些需要注意点地方呢?
1、摄像机的位置:摄像机不同的位置,拍摄的角度不同,则看到的画面就不同。
2、摄像机的注视点:摄像机位置不动,但是我可以控制对着哪拍阿,看的地方不动,画面肯定也不一样。
3、摄像机的姿态: 摄像机位置不动,摄像机上下反过来,最终拍出的照片不就颠倒了莫。
那么对于此章我们要注意的不就是上面这三点嘛,下面我们对于这三点分别分析。
摄像机的位置
摄像机的注视点
摄像机的姿态
图中绿色的箭头为摄像头的上向量(0,1,0),上向量的不同,摄像头的姿态是不是也是不同。如果给图中绿色箭头朝向改为向下(0,-1,0).那么拍摄的画面就倒过来咯。
上诉这三个要点,每个要点都可以通过矩阵的方式来表示,具体推导见官网教案,这里不做详细表述。下面是一些简单的推导。
下面举个例子:
根据上诉例子在结合下面内容就好理解。
GLM已经提供了这些支持。我们要做的只是定义一个摄像机位置,一个目标位置和一个表示世界空间中的上向量的向量(我们计算右向量使用的那个上向量)。接着GLM就会创建一个LookAt矩阵,我们可以把它当作我们的观察矩阵:
glm::mat4 view;
view = glm::lookAt(glm::vec3(0.0f, 0.0f, 3.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
glm::LookAt函数需要一个位置、目标和上向量。它会创建一个和在上一节使用的一样的观察矩阵。
演示demo
main.cpp
#include <iostream>
#include <string>
#include <vector>
#include "glew.h"
#include "glfw3.h"
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "glm/gtc/type_ptr.hpp"#include "log.h"
#include "GlslDealConfig.h"GLfloat vertices[] = {-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,0.5f, -0.5f, -0.5f, 1.0f, 0.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 1.0f,0.5f, 0.5f, 0.5f, 1.0f, 1.0f,-0.5f, 0.5f, 0.5f, 0.0f, 1.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,-0.5f, 0.5f, -0.5f, 1.0f, 1.0f,-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f,0.5f, -0.5f, -0.5f, 0.0f, 1.0f,0.5f, -0.5f, -0.5f, 0.0f, 1.0f,0.5f, -0.5f, 0.5f, 0.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f,-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,0.5f, -0.5f, -0.5f, 1.0f, 1.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f,-0.5f, 0.5f, 0.5f, 0.0f, 0.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f
};std::vector<glm::vec3> cubePositions = {glm::vec3( 0.0f, 0.0f, 0.0f), glm::vec3( 0.0f, 1.2f, 0.0f),glm::vec3( 1.2f, 1.2f, 0.0f),glm::vec3( 0.0f, -1.2f, 0.0f),glm::vec3( 1.2f, -1.2f, 0.0f),glm::vec3( 1.2f, 0.0f, 0.0f), glm::vec3( -1.2f, 0.0f, 0.0f), glm::vec3( -1.2f, 1.2f, 0.0f), glm::vec3( -1.2f, -1.2f, 0.0f), glm::vec3(-1.5f, -2.2f, -2.5f), glm::vec3( 2.4f, -0.4f, -3.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)
};// 主函数
int main() {GlslDealConfig glslConfig;// 初始化 GLFWif (!glfwInit()) {LOGE("Failed to initialize GLFW");return -1;}glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);// 创建窗口GLFWwindow* window = glfwCreateWindow(1000, 1000, "3D Demo", nullptr, nullptr);if (!window) {LOGE("Failed to create GLFW window");glfwTerminate();return -1;}glfwMakeContextCurrent(window);// 初始化 GLEWGLenum err = glewInit();if (err != GLEW_OK) {LOGE("Failed to initialize GLEW: %s", reinterpret_cast<const char*>(glewGetErrorString(err)));return -1;}glfwSwapInterval(1);// 加载着色器std::string vertexShaderCode = glslConfig.ReadGlslFile("/home/ryan/zxp/Rendering/demo/glsl/Trans/VertexShader.glsl");std::string fragmentShaderCode = glslConfig.ReadGlslFile("/home/ryan/zxp/Rendering/demo/glsl/Trans/FragmentShader.glsl");GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);const GLchar* vShaderSource = vertexShaderCode.c_str();const GLchar* fShaderSource = fragmentShaderCode.c_str();glShaderSource(vertexShader, 1, &vShaderSource, nullptr);glShaderSource(fragmentShader, 1, &fShaderSource, nullptr);glCompileShader(vertexShader);glCompileShader(fragmentShader);glslConfig.CheckShaderCompileV(vertexShader);glslConfig.CheckShaderCompileF(fragmentShader);GLuint shaderProgram = glCreateProgram();glAttachShader(shaderProgram, vertexShader);glAttachShader(shaderProgram, fragmentShader);glLinkProgram(shaderProgram);glslConfig.CheckProgmaLinkStatus(shaderProgram);glDeleteShader(vertexShader);glDeleteShader(fragmentShader);// 配置 VAO, VBO, EBOGLuint VAO, VBO[2];glGenVertexArrays(1, &VAO);glGenBuffers(2, VBO);glBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)0);glEnableVertexAttribArray(0);glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)(3*sizeof(GLfloat)));glEnableVertexAttribArray(1);// 加载纹理GLuint texture[2];texture[0] = glslConfig.loadTexture("/home/ryan/zxp/Rendering/demo/resource/brickwall.jpg", GL_RGB);texture[1] = glslConfig.loadTexture("/home/ryan/zxp/Rendering/demo/resource/awesomeface.png", GL_RGBA);// 设置投影矩阵glm::mat4 projection = glm::mat4(1.0f);glUseProgram(shaderProgram);GLuint projLoc = glGetUniformLocation(shaderProgram, "projection");glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));// 激活纹理单元glActiveTexture(GL_TEXTURE3);GLuint textureLocation = glGetUniformLocation(shaderProgram, "textureClass");glUniform1i(textureLocation, 3);glActiveTexture(GL_TEXTURE6);GLuint textureLocation2 = glGetUniformLocation(shaderProgram, "textureClass2");glUniform1i(textureLocation2, 6);glm::mat4 Mmatrix = glm::mat4(1.0f);glm::mat4 Vmatrix = glm::mat4(1.0f);glm::mat4 Pmatrix = glm::mat4(1.0f);Pmatrix = glm::perspective(glm::radians(45.0f), 1000.0f/1000.0f, 0.1f, 100.0f);GLuint TransM = glGetUniformLocation(shaderProgram, "Mtrans");GLuint TransV = glGetUniformLocation(shaderProgram, "Vtrans");GLuint TransP = glGetUniformLocation(shaderProgram, "Ptrans");glUniformMatrix4fv(TransM, 1, GL_FALSE, glm::value_ptr(Mmatrix));glUniformMatrix4fv(TransV, 1, GL_FALSE, glm::value_ptr(Vmatrix));glUniformMatrix4fv(TransP, 1, GL_FALSE, glm::value_ptr(Pmatrix));glEnable(GL_DEPTH_TEST);// 渲染循环while (!glfwWindowShouldClose(window)){glViewport(0, 0, 1000, 1000);glClearColor(0.0f, 0.0f, 0.0f, 1.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glUseProgram(shaderProgram);glBindVertexArray(VAO);glActiveTexture(GL_TEXTURE3);glBindTexture(GL_TEXTURE_2D, texture[0]);glActiveTexture(GL_TEXTURE6);glBindTexture(GL_TEXTURE_2D, texture[1]);glm::mat4 view = glm::mat4(1.0f); float radius = 10.0f;float camX = static_cast<float>(sin(glfwGetTime()) * radius);float camZ = static_cast<float>(cos(glfwGetTime()) * radius);//一个位置、目标和上向量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));glUniformMatrix4fv(TransV, 1, GL_FALSE, glm::value_ptr(view));for(unsigned int i = 0; i < cubePositions.size(); i++){glm::mat4 model = glm::mat4(1.0f);model = glm::translate(model, cubePositions[i]);glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "Mtrans"), 1, GL_FALSE, glm::value_ptr(model));glDrawArrays(GL_TRIANGLES, 0, 36);}glBindVertexArray(0);glBindTexture(GL_TEXTURE_2D, 0);glfwSwapBuffers(window);glfwPollEvents();}// 清理资源glDeleteVertexArrays(1, &VAO);glDeleteBuffers(2, VBO);glDeleteProgram(shaderProgram);glfwTerminate();return 0;
}
核心代码
glm::mat4 view = glm::mat4(1.0f); float radius = 10.0f;float camX = static_cast<float>(sin(glfwGetTime()) * radius);float camZ = static_cast<float>(cos(glfwGetTime()) * radius);//一个位置、目标和上向量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));
相机位置 :glm::vec3(camX, 0.0f, camZ)
相机注视点 :glm::vec3(0.0f, 0.0f, 0.0f)
相机姿态 :glm::vec3(0.0f, 1.0f, 0.0f)
需要注意,是通过相机的位置和相机的注视点来确定相机看向的位置的。注视点向量 - 相机位置向量 = 相机看向的方向
ps:看向的方向,并不是看向某一个点,是方向!
运行效果
基于上面内容,我们修改以下代码实现键盘WASD控制摄像头移动的效果。
glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f);
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);void processInput(GLFWwindow *window)
{float cameraSpeed = 0.05f; // adjust accordinglyif (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)cameraPos += cameraSpeed * cameraFront;if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)cameraPos -= cameraSpeed * cameraFront;if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
}
将processInput添加到循环渲染中去。
// 渲染循环while (!glfwWindowShouldClose(window)){............processInput(window);............}
补充叉积数学定义
视角移动
为了能够改变视角,我们需要根据鼠标的输入改变cameraFront向量,这就引入了一个新的知识点欧拉角。欧拉角(Euler angles)是一种用来描述三维空间中物体方向(姿态)的方式,通过绕固定顺序的三个轴的旋转来表示一个方向或旋转。
即由俯仰角(上下看)、偏转角(左右看)、旋转角(打滚看)。
如何运用欧拉角实现改变视角:这部分建议看官网有一点点掌握即可
官网中给出的改变视角的方法就下面这三行代码
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));
下面解释这段代码是怎么来的。这三行代码的实质就是将球面坐标系转换成笛卡尔坐标系。如下图的点A。设OA的距离为R,
则在球面坐标系中A点的坐标可以表示为 A(R, pitch, yaw)。pitch是俯仰角,yaw是偏转角。
我们将A(R, pitch, yaw)转换为笛卡尔坐标系下的坐标:
注意:我的坐标系是按照OpenGL建造的,即Z轴正半轴指向屏幕前的你。
y = R * sin(pitch)
x = OK = OB * cos(yaw) = R * cos(pitch) * cos(yaw)
z = KB = OB * sin(yaw) = R * cos(pitch) * sin(yaw)
视角移动完整代码
#include <iostream>
#include <string>
#include <vector>
#include "glew.h"
#include "glfw3.h"
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "glm/gtc/type_ptr.hpp"#include "log.h"
#include "GlslDealConfig.h"GLfloat vertices[] = {-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,0.5f, -0.5f, -0.5f, 1.0f, 0.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 1.0f,0.5f, 0.5f, 0.5f, 1.0f, 1.0f,-0.5f, 0.5f, 0.5f, 0.0f, 1.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,-0.5f, 0.5f, -0.5f, 1.0f, 1.0f,-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f,0.5f, -0.5f, -0.5f, 0.0f, 1.0f,0.5f, -0.5f, -0.5f, 0.0f, 1.0f,0.5f, -0.5f, 0.5f, 0.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f,-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,0.5f, -0.5f, -0.5f, 1.0f, 1.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f,-0.5f, 0.5f, 0.5f, 0.0f, 0.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f
};std::vector<glm::vec3> cubePositions = {glm::vec3( 0.0f, 0.0f, 0.0f), glm::vec3( 0.0f, 1.2f, 0.0f),glm::vec3( 1.2f, 1.2f, 0.0f),glm::vec3( 0.0f, -1.2f, 0.0f),glm::vec3( 1.2f, -1.2f, 0.0f),glm::vec3( 1.2f, 0.0f, 0.0f), glm::vec3( -1.2f, 0.0f, 0.0f), glm::vec3( -1.2f, 1.2f, 0.0f), glm::vec3( -1.2f, -1.2f, 0.0f), glm::vec3(-1.5f, -2.2f, -2.5f), glm::vec3( 2.4f, -0.4f, -3.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)
};glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f);
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);bool firstMouse = true;
float yaw = -90.0f;
float pitch = 0.0f;
float lastX = 800.0f / 2.0;
float lastY = 600.0 / 2.0;
float fov = 45.0f;void processInput(GLFWwindow *window)
{float cameraSpeed = 0.05f; // adjust accordinglyif (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)cameraPos += cameraSpeed * cameraFront;if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)cameraPos -= cameraSpeed * cameraFront;if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
}void mouse_callback(GLFWwindow* window, double xposIn, double yposIn)
{float xpos = static_cast<float>(xposIn);float ypos = static_cast<float>(yposIn);if (firstMouse){lastX = xpos;lastY = ypos;firstMouse = false;}float xoffset = xpos - lastX;float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to toplastX = xpos;lastY = ypos;float sensitivity = 0.1f; // change this value to your likingxoffset *= sensitivity;yoffset *= sensitivity;yaw += xoffset;pitch += yoffset;printf("pitch : %f\n", pitch);printf("yaw : %f\n", yaw);// make sure that when pitch is out of bounds, screen doesn't get flippedif (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));front.y = sin(glm::radians(pitch));front.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch));cameraFront = glm::normalize(front);
}// glfw: whenever the mouse scroll wheel scrolls, this callback is called
// ----------------------------------------------------------------------
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{fov -= (float)yoffset;if (fov < 1.0f)fov = 1.0f;if (fov > 45.0f)fov = 45.0f;
}// 主函数
int main() {GlslDealConfig glslConfig;// 初始化 GLFWif (!glfwInit()) {LOGE("Failed to initialize GLFW");return -1;}glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);// 创建窗口GLFWwindow* window = glfwCreateWindow(1000, 1000, "3D Demo", nullptr, nullptr);if (!window) {LOGE("Failed to create GLFW window");glfwTerminate();return -1;}glfwMakeContextCurrent(window);glfwSetCursorPosCallback(window, mouse_callback);glfwSetScrollCallback(window, scroll_callback);glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);// 初始化 GLEWGLenum err = glewInit();if (err != GLEW_OK) {LOGE("Failed to initialize GLEW: %s", reinterpret_cast<const char*>(glewGetErrorString(err)));return -1;}glfwSwapInterval(1);// 加载着色器std::string vertexShaderCode = glslConfig.ReadGlslFile("/home/ryan/zxp/Rendering/demo/glsl/Trans/VertexShader.glsl");std::string fragmentShaderCode = glslConfig.ReadGlslFile("/home/ryan/zxp/Rendering/demo/glsl/Trans/FragmentShader.glsl");GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);const GLchar* vShaderSource = vertexShaderCode.c_str();const GLchar* fShaderSource = fragmentShaderCode.c_str();glShaderSource(vertexShader, 1, &vShaderSource, nullptr);glShaderSource(fragmentShader, 1, &fShaderSource, nullptr);glCompileShader(vertexShader);glCompileShader(fragmentShader);glslConfig.CheckShaderCompileV(vertexShader);glslConfig.CheckShaderCompileF(fragmentShader);GLuint shaderProgram = glCreateProgram();glAttachShader(shaderProgram, vertexShader);glAttachShader(shaderProgram, fragmentShader);glLinkProgram(shaderProgram);glslConfig.CheckProgmaLinkStatus(shaderProgram);glDeleteShader(vertexShader);glDeleteShader(fragmentShader);// 配置 VAO, VBO, EBOGLuint VAO, VBO[2];glGenVertexArrays(1, &VAO);glGenBuffers(2, VBO);glBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)0);glEnableVertexAttribArray(0);glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)(3*sizeof(GLfloat)));glEnableVertexAttribArray(1);// 加载纹理GLuint texture[2];texture[0] = glslConfig.loadTexture("/home/ryan/zxp/Rendering/demo/resource/brickwall.jpg", GL_RGB);texture[1] = glslConfig.loadTexture("/home/ryan/zxp/Rendering/demo/resource/awesomeface.png", GL_RGBA);// 设置投影矩阵glm::mat4 projection = glm::mat4(1.0f);glUseProgram(shaderProgram);GLuint projLoc = glGetUniformLocation(shaderProgram, "projection");glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));// 激活纹理单元glActiveTexture(GL_TEXTURE3);GLuint textureLocation = glGetUniformLocation(shaderProgram, "textureClass");glUniform1i(textureLocation, 3);glActiveTexture(GL_TEXTURE6);GLuint textureLocation2 = glGetUniformLocation(shaderProgram, "textureClass2");glUniform1i(textureLocation2, 6);glm::mat4 Mmatrix = glm::mat4(1.0f);glm::mat4 Vmatrix = glm::mat4(1.0f);glm::mat4 Pmatrix = glm::mat4(1.0f);Pmatrix = glm::perspective(glm::radians(45.0f), 1000.0f/1000.0f, 0.1f, 100.0f);GLuint TransM = glGetUniformLocation(shaderProgram, "Mtrans");GLuint TransV = glGetUniformLocation(shaderProgram, "Vtrans");GLuint TransP = glGetUniformLocation(shaderProgram, "Ptrans");glUniformMatrix4fv(TransM, 1, GL_FALSE, glm::value_ptr(Mmatrix));glUniformMatrix4fv(TransV, 1, GL_FALSE, glm::value_ptr(Vmatrix));glUniformMatrix4fv(TransP, 1, GL_FALSE, glm::value_ptr(Pmatrix));glEnable(GL_DEPTH_TEST);// 渲染循环while (!glfwWindowShouldClose(window)){glViewport(0, 0, 1000, 1000);glClearColor(0.0f, 0.0f, 0.0f, 1.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glUseProgram(shaderProgram);glBindVertexArray(VAO);glActiveTexture(GL_TEXTURE3);glBindTexture(GL_TEXTURE_2D, texture[0]);glActiveTexture(GL_TEXTURE6);glBindTexture(GL_TEXTURE_2D, texture[1]);processInput(window);Pmatrix = glm::perspective(glm::radians(fov), 1000.0f/1000.0f, 0.1f, 100.0f);glUniformMatrix4fv(TransP, 1, GL_FALSE, glm::value_ptr(Pmatrix));glm::mat4 view = glm::mat4(1.0f); //始终注释相机正前方view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);// view = glm::lookAt(cameraPos, glm::vec3(0.0f, 0.0f, 0.0f), cameraUp);glUniformMatrix4fv(TransV, 1, GL_FALSE, glm::value_ptr(view));for(unsigned int i = 0; i < cubePositions.size(); i++){glm::mat4 model = glm::mat4(1.0f);model = glm::translate(model, cubePositions[i]);glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "Mtrans"), 1, GL_FALSE, glm::value_ptr(model));glDrawArrays(GL_TRIANGLES, 0, 36);}glBindVertexArray(0);glBindTexture(GL_TEXTURE_2D, 0);glfwSwapBuffers(window);glfwPollEvents();}// 清理资源glDeleteVertexArrays(1, &VAO);glDeleteBuffers(2, VBO);glDeleteProgram(shaderProgram);glfwTerminate();return 0;
}