OpengGL教程(七)---摄像机

本章参考官方教程:摄像机

本系列历史文
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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/76371.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

安卓手机怎样开启双WiFi加速

1. 小米/Redmi手机 路径&#xff1a; 设置 → WLAN → 高级设置 → 双WLAN加速 操作&#xff1a; 开启功能后&#xff0c;可同时连接一个2.4GHz WiFi和一个5GHz WiFi&#xff08;或两个不同路由器&#xff09;。 可选择“智能选择”或手动指定辅助网络。 2. 华为/荣耀手机…

什么是八步工作法?

八步工作法&#xff0c;顾名思义&#xff0c;就是把一项工作拆分成八个步骤来完成。它的核心目的是让工作变得更有条理&#xff0c;更高效&#xff0c;避免忙而无序&#xff0c;做到事事有着落&#xff0c;件件有结果。这个方法在很多企业和单位中都有应用&#xff0c;尤其适合…

前端Node.js的包管理工具npm指令

‌npm&#xff08;Node Package Manager&#xff09;是Node.js的包管理工具&#xff0c;主要用于安装、更新、删除和管理JavaScript包。以下是前端开发中常用的npm命令及其用途‌&#xff1a; 基本命令 npm提供了一系列命令行工具&#xff0c;用于执行各种包管理操作。以下是一…

掌握C语言文件操作:从理论到实战指南

文件操作是C语言编程中不可或缺的一部分&#xff0c;它使得程序能够持久化存储数据&#xff0c;并在需要时高效读写。本文将从基础概念到实战技巧&#xff0c;系统讲解C语言文件操作的核心知识点&#xff0c;并结合代码示例帮助读者深入理解。 一. 为什么需要文件操作&#xf…

Linux 线程:从零构建多线程应用:系统化解析线程API与底层设计逻辑

线程 线程的概述 在之前&#xff0c;我们常把进程定义为 程序执行的实例&#xff0c;实际不然&#xff0c;进程实际上只是维护应用程序的各种资源&#xff0c;并不执行什么。真正执行具体任务的是线程。 那为什么之前直接执行a.out的时候&#xff0c;没有这种感受呢&#xf…

014_多线程

多线程 多线程创建线程方式一&#xff1a;继承Thread类方式二&#xff1a;实现Runable接口方式三&#xff1a;实现Callbale接口 Thread的常用方法线程安全线程同步方式一&#xff1a;同步代码块同步方法方式三&#xff1a;Lock锁 线性池创建线程池处理Runnable任务处理Callable…

机场跑道异物检测数据集VOC+YOLO格式33793张31类别

数据集分辨率都是300x300,都是贴近地面拍摄&#xff0c;具体看图片 据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;33793 标注数量(xml文件…

Spring Cloud 远程调用

4.OpenFeign的实现原理是什么&#xff1f; 在使用OpenFeign的时候&#xff0c;主要关心两个注解&#xff0c;EnableFeignClients和FeignClient。整体的流程分为以下几个部分&#xff1a; 启用Feign代理&#xff0c;通过在启动类上添加EnableFeignClients注解&#xff0c;开启F…

Unity中使用FMETP STREAM传输实时画面

一、客户端&#xff08;发送端&#xff09; 总体思路&#xff1a;先把画面编码Encoder&#xff0c;再发送给服务端 新建场景&#xff0c;创建一个实体&#xff0c;名为FMnet&#xff0c;添加组件FMNetworkManager&#xff0c;将NetworkType设置为客户端Client&#xff0c;设置…

Baklib三步构建企业内容中台

需求调研构建内容中台 企业内容中台建设的首要环节在于精准识别业务需求与知识管理痛点。通过Baklib 是什么类型的工具的定位分析可知&#xff0c;其作为知识管理中枢&#xff0c;能够系统梳理客户服务场景中的高频咨询、产品文档更新需求及跨部门协作流程。在需求调研阶段&am…

实现抗隐私泄漏的AI人工智能推理

目录 什么是私人AI? 什么是可信执行环境? TEE 如何在 AI 推理期间保护数据? 使用 TEE 是否存在风险? 有哪些风险? Atoma 如何应对这些风险 为什么去中心化网络是解决方案 人工智能推理过程中还有其他保护隐私的方法吗? 私人人工智能可以实现什么? 隐私驱动的应…

一、TorchRec里边的输入输出类型

TorchRec中的输入和输出格式 文章目录 TorchRec中的输入和输出格式前言一、JaggedTensor1.1 核心概念1.2 核心属性&#xff0c;也就是参数1.3 关键操作与方法 二、KeyedJaggedTensor2.1 核心概念2.2 核心属性&#xff0c;也就是参数 3、KeyedTensor总结 前言 TorchRec具有其特…

JAVA实现在H5页面中点击链接直接进入微信小程序

在普通的Html5页面中如何实现点击URL链接直接进入微信小程序&#xff0c;不需要扫描小程序二维码&#xff1f; 网上介绍的很多方法是在小程序后台设置Schema&#xff0c;不过我进入我的小程序后台在开发设置里面 没有找到设置小程序Schema的地方&#xff0c;我是通过调用API接口…

uniapp解决上架华为应用市场审核要求-监听权限的申请

支持android平台全局监听权限的申请。当申请权限时&#xff0c;会在页面顶部显示申请权限的目的。主要解决上架华为应用市场审核要求&#xff1a;APP在调用终端权限时&#xff0c;应同步告知用户申请该权限的目的。 因为如果不提示&#xff0c;你上架应用市场会被打打回来 Tip…

文件IO5(JPEG图像原理与应用)

JPEG图像原理与应用 ⦁ 基本概念 JPEG&#xff08;Joint Photographic Experts Group&#xff09;指的是联合图像专家组&#xff0c;是国际标准化组织ISO制订并于1992年发布的一种面向连续色调静止图像的压缩编码标准&#xff0c;所以也被称为JPEG标准。 同样&#xff0c;JP…

vue3 history路由模式刷新页面报错问题解决

在使用history路由模式时刷新网页提示404错误&#xff0c;这是改怎么办呢。 官方解决办法 https://router.vuejs.org/zh/guide/essentials/history-mode.html

3D激光轮廓仪知识整理(待完善)

文章目录 1.原理和应用场景1.1 相机原理1.1.1 测量原理1.1.2 相机激光器1.1.3 沙姆镜头1.1.4 相机标定1.1.5 中心线提取 1.2 应用场景1.2.1 测量相关应用1.2.2 缺陷检测相关应用 2.相机参数介绍及选型介绍2.1 成像原理2.2 原始图成像2.3 生成轮廓图2.4 相机规格参数2.4.1 单轮廓…

w285药店管理系统的设计与实现

&#x1f64a;作者简介&#xff1a;多年一线开发工作经验&#xff0c;原创团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339;赠送计算机毕业设计600个选题excel文…

Google Chrome Canary版官方下载及安装教程【适用于开发者与进阶用户】

谷歌浏览器&#xff08;Google Chrome&#xff09;以其高性能、强扩展性和良好的用户体验深受全球用户喜爱。在其多个版本中&#xff0c;Chrome Canary因具备最前沿的功能测试环境&#xff0c;成为开发者和技术探索者的首选。如果你希望第一时间体验Google Chrome最新功能&…

RocketMQ深度百科全书式解析

​一、核心架构与设计哲学​ ​1. 设计目标​ ​海量消息堆积​&#xff1a;单机支持百万级消息堆积&#xff0c;适合大数据场景&#xff08;如日志采集&#xff09;。​严格顺序性​&#xff1a;通过队列分区&#xff08;Queue&#xff09;和消费锁机制保证局部顺序。​事务…