跟着LearnOpenGL学习9--光照

news/2024/12/5 9:46:35/

文章目录

  • 一、颜色
  • 二、创建光照场景

一、颜色

显示世界中有无数种颜色,每一个物体都有它们自己的颜色。我们需要使用(有限的)数值来模拟现实世界中(无限的)的颜色,所以并不是所有现实世界中的颜色都可以用数值来表示。然而我们仍然能通过数值来表现非常多的颜色,甚至你可能都不会注意到与现实的颜色有任何差异。

颜色可以数字化的由红色(red)、绿色(green)、蓝色(blue)三个分量组成,它们通常被缩写为RGB,也就是我们学过的三原色。仅仅用这三个值就可以组合出任意一种颜色。

例如,要获取一个珊瑚红(Coral)色的话,可以定义如下颜色向量:

glm::vec3 coral(1.0f, 0.5f, 0.31f);

我们在现实生活中看到的某一物体的颜色并不是这个物体真正拥有的颜色,而是它所反射的颜色。
也就是说,那些不能被物体所吸收的颜色(被拒绝的颜色)就是我们能够感知到的物体的颜色。

例如,太阳光能被看见的白光其实是由许多不同的颜色组合而成的(如下图所示)。如果我们将白光照在一个蓝色的玩具上,这个蓝色的玩具会吸收白光中除了蓝色以外的所有子颜色,不被吸收的蓝色光被反射到我们的眼中,让这个玩具看起来是蓝色的。下图显示的是一个珊瑚红的玩具,它以不同强度反射了多个颜色。
在这里插入图片描述
你可以看到,白色的阳光实际上是所有可见颜色的集合,物体吸收了其中的大部分颜色。它仅反射了代表物体颜色的部分,被反射颜色的组合就是我们所感知到的颜色(此例中为珊瑚红)。

这些颜色反射的定律被直接地运用在图形领域,当我们把光源的颜色与物体的颜色值相乘,所得到的就是这个物体所反射的颜色(也就是我们所感知到的颜色)。
让我们再次审视我们的玩具(这一次它还是珊瑚红),看看如何在图形学中计算出它的反射颜色。我们将这两个颜色向量作分量相乘,结果就是最终的颜色向量了:

glm::vec3 lightColor(1.0f, 1.0f, 1.0f);
glm::vec3 toyColor(1.0f, 0.5f, 0.31f);
//作分量相乘,对应相乘
glm::vec3 result = lightColor * toyColor; // = (1.0f, 0.5f, 0.31f);

我们可以看到玩具的颜色吸收了白色光源中很大一部分的颜色,但它根据自身的颜色值对红、绿、蓝三个分量都做出了一定的反射。这也表现了现实中颜色的工作原理。由此,我们可以定义物体的颜色为物体从一个光源反射各个颜色分量的大小。现在,如果我们使用绿色的光源又会发生什么呢?

glm::vec3 lightColor(0.0f, 1.0f, 0.0f);
glm::vec3 toyColor(1.0f, 0.5f, 0.31f);
//作分量相乘,对应相乘
glm::vec3 result = lightColor * toyColor; // = (0.0f, 0.5f, 0.0f);

可以看到,我们可以使用不同的光源颜色来让物体显现出意想不到的颜色。有创意地利用颜色其实并不难。

这些颜色的理论已经足够了,下面我们来构造一个实验用的场景吧。


二、创建光照场景

我们需要创建:一个被投光对象、一个光源,如下所示:

在这里插入图片描述
我们创建了两个立方体,珊瑚红的立方体当做被投光对象,白色的立方体当做光源

绘制立方体的流程在之前已经学习过来,流程大致如下:
在这里插入图片描述
顶点数据:都是NDC下的正方体坐标,可以共用;

VBO:顶点数据都一样,也可以共用;

VAO:因为光照教程后期会频繁的对顶点数据和属性指针做修改,我们只关心光源的位置,并不想这些修改影响到灯,所以为光源立方体单独创建一个VAO;

//物体
//----------------------------------------------------------------
unsigned int VBO, objectVAO;
glGenVertexArrays(1, &objectVAO);     //创建顶点数组对象
glGenBuffers(1, &VBO);          //创建顶点缓冲对象glBindBuffer(GL_ARRAY_BUFFER, VBO);     //将VBO与GL_ARRAY_BUFFER缓冲区绑定
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);  //将顶点数据复制到GL_ARRAY_BUFFER缓冲区,之后可通过VBO进行操作glBindVertexArray(objectVAO);         //绑定VAO//设定顶点属性指针
//位置属性
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);//光源(VBO用上面的)
//----------------------------------------------------------------
unsigned int lightVAO;
glGenVertexArrays(1, &lightVAO);     //创建顶点数组对象
glBindVertexArray(lightVAO);         //绑定VAOglBindBuffer(GL_ARRAY_BUFFER, VBO);     //将VBO与GL_ARRAY_BUFFER缓冲区绑定//设定顶点属性指针
//位置属性
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);

着色器:

要注意的是,当我们修改顶点或者片段着色器后,灯的位置或颜色也会随之改变,这并不是我们想要的效果。我们不希望灯的颜色在接下来的教程中因光照计算的结果而受到影响,而是希望它能够与其它的计算分离。我们希望灯一直保持明亮,不受其它颜色变化的影响(这样它才更像是一个真实的光源)。

为了实现这个目标,我们需要为灯的绘制创建另外的一套着色器,从而能保证它能够在其它光照着色器发生改变的时候不受影响。顶点着色器与我们当前的顶点着色器是一样的,所以你可以直接把现在的顶点着色器用在灯上。灯的片段着色器给灯定义了一个不变的常量白色,保证了灯的颜色一直是亮的:

光源的颜色始终保持为白色,被投光物体的颜色应该是:光源颜色 * 物体颜色;

当我们想要绘制我们的物体的时候,我们需要使用刚刚定义的光照着色器来绘制箱子(或者可能是其它的物体)。当我们想要绘制灯的时候,我们会使用灯的着色器;


全部代码如下

在这里插入图片描述


1、物体着色器

顶点着色器:shader.vs

#version 330 core
layout (location = 0) in vec3 aPos;uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;void main()
{gl_Position = projection * view * model * vec4(aPos, 1.0f);
}

片段着色器:shader.fs

#version 330 core
out vec4 FragColor;uniform vec3 objectColor;
uniform vec3 lightColor;void main()
{FragColor = vec4(lightColor * objectColor, 1.0);
}

2、光源着色器

顶点着色器:shader.vs

#version 330 core
layout (location = 0) in vec3 aPos;uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;void main()
{gl_Position = projection * view * model * vec4(aPos, 1.0);
}

片段着色器:shader.fs

#version 330 core
out vec4 FragColor;void main()
{FragColor = vec4(1.0); // set all 4 vector values to 1.0
}

3、摄像机类

#ifndef CAMERA_H
#define CAMERA_H#include <glad/glad.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>#include <vector>enum Camera_Movement {FORWARD,BACKWARD,LEFT,RIGHT
};// Default camera values
const float YAW         = -90.0f;
const float PITCH       =  0.0f;
const float SPEED       =  2.5f;
const float SENSITIVITY =  0.1f;
const float ZOOM        =  45.0f;class Camera
{
public:Camera(glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f), float yaw = YAW, float pitch = PITCH);Camera(float posX, float posY, float posZ, float upX, float upY, float upZ, float yaw, float pitch);public:glm::mat4 GetViewMatrix();void ProcessKeyboard(Camera_Movement direction, float deltaTime);void ProcessMouseMovement(float xoffset, float yoffset, GLboolean constrainPitch = true);void ProcessMouseScroll(float yoffset);private:void updateCameraVectors();public:// camera Attributesglm::vec3 Position;glm::vec3 Front;glm::vec3 Up;glm::vec3 Right;glm::vec3 WorldUp;// euler Anglesfloat Yaw;float Pitch;// camera optionsfloat MovementSpeed;float MouseSensitivity;float Zoom;};#endif // CAMERA_H

#include "camera.h"// constructor with vectors
Camera::Camera(glm::vec3 position, glm::vec3 up, float yaw, float pitch) : Front(glm::vec3(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVITY), Zoom(ZOOM)
{Position = position;WorldUp = up;Yaw = yaw;Pitch = pitch;updateCameraVectors();
}
// constructor with scalar values
Camera::Camera(float posX, float posY, float posZ, float upX, float upY, float upZ, float yaw, float pitch) : Front(glm::vec3(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVITY), Zoom(ZOOM)
{Position = glm::vec3(posX, posY, posZ);WorldUp = glm::vec3(upX, upY, upZ);Yaw = yaw;Pitch = pitch;updateCameraVectors();
}// returns the view matrix calculated using Euler Angles and the LookAt Matrix
glm::mat4 Camera::GetViewMatrix()
{return glm::lookAt(Position, Position + Front, Up);
}// processes input received from any keyboard-like input system. Accepts input parameter in the form of camera defined ENUM (to abstract it from windowing systems)
void Camera::ProcessKeyboard(Camera_Movement direction, float deltaTime)
{float velocity = MovementSpeed * deltaTime;if (direction == FORWARD)Position -= Front * velocity;if (direction == BACKWARD)Position += Front * velocity;if (direction == LEFT)Position += Right * velocity;if (direction == RIGHT)Position -= Right * velocity;
}// processes input received from a mouse input system. Expects the offset value in both the x and y direction.
void Camera::ProcessMouseMovement(float xoffset, float yoffset, GLboolean constrainPitch)
{xoffset *= MouseSensitivity;yoffset *= MouseSensitivity;Yaw   += xoffset;Pitch += yoffset;// make sure that when pitch is out of bounds, screen doesn't get flippedif (constrainPitch){if (Pitch > 89.0f)Pitch = 89.0f;if (Pitch < -89.0f)Pitch = -89.0f;}// update Front, Right and Up Vectors using the updated Euler anglesupdateCameraVectors();
}// processes input received from a mouse scroll-wheel event. Only requires input on the vertical wheel-axis
void Camera::ProcessMouseScroll(float yoffset)
{Zoom -= (float)yoffset;if (Zoom < 1.0f)Zoom = 1.0f;if (Zoom > 45.0f)Zoom = 45.0f;
}void Camera::updateCameraVectors()
{// calculate the new Front vectorglm::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);// also re-calculate the Right and Up vectorRight = glm::normalize(glm::cross(Front, WorldUp));  // normalize the vectors, because their length gets closer to 0 the more you look up or down which results in slower movement.Up    = glm::normalize(glm::cross(Right, Front));
}

3、着色器类

#ifndef SHADER_H
#define SHADER_H#include <glad/glad.h>; // 包含glad来获取所有的必须OpenGL头文件//GLM
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>#include <string>
#include <fstream>
#include <sstream>
#include <iostream>class Shader
{
public:// 程序IDunsigned int ID;// 构造器读取并构建着色器Shader(const char* vertexPath, const char* fragmentPath);// 使用/激活程序void use();// uniform工具函数void setBool(const std::string &name, bool value) const;void setInt(const std::string &name, int value) const;void setFloat(const std::string &name, float value) const;void setVec3(const std::string &name, float valueX, float valueY, float valueZ) const;void setMat4(const std::string &name, glm::mat4 value) const;void checkCompileErrors(unsigned int shader, std::string type);
};#endif

#include "shader.h"// 构造器读取并构建着色器
Shader::Shader(const char* vertexPath, const char* fragmentPath)
{// 1. 读取顶点着色器和片段着色器源码//================================================================================std::string vertexCode;     //顶点着色器源码std::string fragmentCode;   //片段着色器源码std::ifstream vShaderFile;std::ifstream fShaderFile;// ensure ifstream objects can throw exceptions:vShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);fShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);try{// open filesvShaderFile.open(vertexPath);fShaderFile.open(fragmentPath);std::stringstream vShaderStream, fShaderStream;// read file's buffer contents into streamsvShaderStream << vShaderFile.rdbuf();fShaderStream << fShaderFile.rdbuf();// close file handlersvShaderFile.close();fShaderFile.close();// convert stream into stringvertexCode   = vShaderStream.str();fragmentCode = fShaderStream.str();}catch (std::ifstream::failure& e){std::cout << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ: " << e.what() << std::endl;}const char* vShaderCode = vertexCode.c_str();const char * fShaderCode = fragmentCode.c_str();// 2. 编译着色器//================================================================================unsigned int vertex, fragment;// 顶点着色器vertex = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertex, 1, &vShaderCode, NULL);glCompileShader(vertex);checkCompileErrors(vertex, "VERTEX");// 片段着色器fragment = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragment, 1, &fShaderCode, NULL);glCompileShader(fragment);checkCompileErrors(fragment, "FRAGMENT");// 链接着色器程序ID = glCreateProgram();glAttachShader(ID, vertex);glAttachShader(ID, fragment);glLinkProgram(ID);checkCompileErrors(ID, "PROGRAM");// 链接完成之后删除顶点着色器对象和片段着色器对象glDeleteShader(vertex);glDeleteShader(fragment);
}// 使用/激活程序
void Shader::use()
{glUseProgram(ID);
}// uniform工具函数
void Shader::setBool(const std::string &name, bool value) const
{glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
}
void Shader::setInt(const std::string &name, int value) const
{glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
}
void Shader::setFloat(const std::string &name, float value) const
{glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
}
void Shader::setVec3(const std::string &name, float valueX, float valueY, float valueZ) const
{glUniform3f(glGetUniformLocation(ID, name.c_str()), valueX, valueY, valueZ);
}
void Shader::setMat4(const std::string &name, glm::mat4 value) const
{glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, glm::value_ptr(value));
}void Shader::checkCompileErrors(unsigned int shader, std::string type)
{int success;char infoLog[1024];if (type != "PROGRAM"){glGetShaderiv(shader, GL_COMPILE_STATUS, &success);if (!success){glGetShaderInfoLog(shader, 1024, NULL, infoLog);std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;}}else{glGetProgramiv(shader, GL_LINK_STATUS, &success);if (!success){glGetProgramInfoLog(shader, 1024, NULL, infoLog);std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;}}
}

4、main

#include "mainwindow.h"
#include <QApplication>//在包含GLFW的头文件之前包含了GLAD的头文件;
//GLAD的头文件包含了正确的OpenGL头文件(例如GL/gl.h);
//所以需要在其它依赖于OpenGL的头文件之前包含GLAD;
#include <glad/glad.h>
#include <GLFW/glfw3.h>//GLM
//#include <glm/glm.hpp>
//#include <glm/gtc/matrix_transform.hpp>
//#include <glm/gtc/type_ptr.hpp>#include <iostream>
#include <QDebug>#include "shader.h"
#include "stb_image.h"
#include "camera.h"void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void mouse_callback(GLFWwindow* window, double xposIn, double yposIn);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void processInput(GLFWwindow *window);// settings
const unsigned int SCR_WIDTH = 1920;
const unsigned int SCR_HEIGHT = 1080;//Camera
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
float lastX =  SCR_WIDTH / 2.0;
float lastY =  SCR_HEIGHT / 2.0;
bool firstMouse = true;float deltaTime = 0.0f; // 当前帧与上一帧的时间差
float lastFrame = 0.0f; // 上一帧的时间//Light
glm::vec3 lightPos(1.2f, 1.0f, 2.0f);using namespace std;int main(int argc, char *argv[])
{QApplication a(argc, argv);//MainWindow w;//w.show();//初始化GLFW//--------------------glfwInit();//配置GLFW//--------------------//告诉GLFW使用的OpenGL本是3.3glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//告诉GLFW使用的是核心模式(Core-profile)glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);//创建一个新的OpenGL环境和窗口//-----------------------------------GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);if (window == NULL){std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate();    //glfw销毁窗口和OpenGL环境,并释放资源return -1;}//设置参数window中的窗口所关联的OpenGL环境为当前环境//-----------------------------------glfwMakeContextCurrent(window);//设置窗口尺寸改变大小时的回调函数(窗口尺寸发送改变时会自动调用)//-----------------------------------glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);//设置鼠标事件的回调函数(鼠标移动时会自动调用)//-----------------------------------glfwSetCursorPosCallback(window, mouse_callback);//设置鼠标滚轮事件的回调函数(鼠标滚轮移动时会自动调用)//-----------------------------------glfwSetScrollCallback(window, scroll_callback);//告诉GLFW捕捉鼠标glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);//glad加载系统相关的OpenGL函数指针//---------------------------------------if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){std::cout << "Failed to initialize GLAD" << std::endl;return -1;}//开启深度测试glEnable(GL_DEPTH_TEST);Shader objectShader("C:/Qt_Pro/OpenGL_GLFW/shader/shader.vs","C:/Qt_Pro/OpenGL_GLFW/shader/shader.fs");Shader lightShader("C:/Qt_Pro/OpenGL_GLFW/shader/light_cube.vs","C:/Qt_Pro/OpenGL_GLFW/shader/light_cube.fs");//顶点数据//---------------------------------------------------------------------float vertices[] = {//坐标-0.5f, -0.5f, -0.5f,0.5f, -0.5f, -0.5f,0.5f,  0.5f, -0.5f,0.5f,  0.5f, -0.5f,-0.5f,  0.5f, -0.5f,-0.5f, -0.5f, -0.5f,-0.5f, -0.5f,  0.5f,0.5f, -0.5f,  0.5f,0.5f,  0.5f,  0.5f,0.5f,  0.5f,  0.5f,-0.5f,  0.5f,  0.5f,-0.5f, -0.5f,  0.5f,-0.5f,  0.5f,  0.5f,-0.5f,  0.5f, -0.5f,-0.5f, -0.5f, -0.5f,-0.5f, -0.5f, -0.5f,-0.5f, -0.5f,  0.5f,-0.5f,  0.5f,  0.5f,0.5f,  0.5f,  0.5f,0.5f,  0.5f, -0.5f,0.5f, -0.5f, -0.5f,0.5f, -0.5f, -0.5f,0.5f, -0.5f,  0.5f,0.5f,  0.5f,  0.5f,-0.5f, -0.5f, -0.5f,0.5f, -0.5f, -0.5f,0.5f, -0.5f,  0.5f,0.5f, -0.5f,  0.5f,-0.5f, -0.5f,  0.5f,-0.5f, -0.5f, -0.5f,-0.5f,  0.5f, -0.5f,0.5f,  0.5f, -0.5f,0.5f,  0.5f,  0.5f,0.5f,  0.5f,  0.5f,-0.5f,  0.5f,  0.5f,-0.5f,  0.5f, -0.5f};//物体//----------------------------------------------------------------unsigned int VBO, objectVAO;glGenVertexArrays(1, &objectVAO);     //创建顶点数组对象glGenBuffers(1, &VBO);          //创建顶点缓冲对象glBindBuffer(GL_ARRAY_BUFFER, VBO);     //将VBO与GL_ARRAY_BUFFER缓冲区绑定glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);  //将顶点数据复制到GL_ARRAY_BUFFER缓冲区,之后可通过VBO进行操作glBindVertexArray(objectVAO);         //绑定VAO//设定顶点属性指针//位置属性glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);//光源(VBO用上面的)//----------------------------------------------------------------unsigned int lightVAO;glGenVertexArrays(1, &lightVAO);     //创建顶点数组对象glBindVertexArray(lightVAO);         //绑定VAOglBindBuffer(GL_ARRAY_BUFFER, VBO);     //将VBO与GL_ARRAY_BUFFER缓冲区绑定glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);//渲染循环//我们可不希望只绘制一个图像之后我们的应用程序就立即退出并关闭窗口;//我们希望程序在我们主动关闭它之前不断绘制图像并能够接受用户输入;//因此,我们需要在程序中添加一个while循环,它能在我们让GLFW退出前一直保持运行;//------------------------------------------------------------------------------while (!glfwWindowShouldClose(window))  //如果用户准备关闭参数window所指定的窗口,那么此接口将会返回GL_TRUE,否则将会返回GL_FALSE{//更新时间差float currentFrame = static_cast<float>(glfwGetTime());deltaTime = currentFrame - lastFrame;lastFrame = currentFrame;//用户输入//------------------------------------------------------------------------------processInput(window);   //检测是否有输入//渲染指令//------------------------------------------------------------------------------glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//被投光物体//============================================================//激活着色器程序对象objectShader.use();objectShader.setVec3("objectColor", 1.0f, 0.5f, 0.31f);objectShader.setVec3("lightColor", 1.0f, 1.0f, 1.0f);//创建变换矩阵glm::mat4 model = glm::mat4(1.0f);objectShader.setMat4("model", model);glm::mat4 view = camera.GetViewMatrix();objectShader.setMat4("view", view);glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);objectShader.setMat4("projection", projection);//绘制三角形glBindVertexArray(objectVAO);             //绑定VAOglDrawArrays(GL_TRIANGLES, 0, 36);//============================================================//光源//============================================================//激活着色器程序对象lightShader.use();lightShader.setMat4("view", view);lightShader.setMat4("projection", projection);model = glm::mat4(1.0f);model = glm::translate(model, lightPos);model = glm::scale(model, glm::vec3(0.2f));lightShader.setMat4("model", model);//绘制三角形glBindVertexArray(lightVAO);             //绑定VAOglDrawArrays(GL_TRIANGLES, 0, 36);//============================================================//告诉GLFW检查所有等待处理的事件和消息,包括操作系统和窗口系统中应当处理的消息。如果有消息正在等待,它会先处理这些消息再返回;否则该函数会立即返回//---------------------------------------------------------------------------------------------------------------------------------glfwPollEvents();//请求窗口系统将参数window关联的后缓存画面呈现给用户(双缓冲绘图)//------------------------------------------------------------------------------glfwSwapBuffers(window);}//释放资源glDeleteVertexArrays(1, &objectVAO);glDeleteVertexArrays(1, &lightVAO);glDeleteBuffers(1, &VBO);//glDeleteProgram(objectShader);//glDeleteProgram(lightShader);//glfw销毁窗口和OpenGL环境,并释放资源(之后必须再次调用glfwInit()才能使用大多数GLFW函数)//------------------------------------------------------------------glfwTerminate();return a.exec();
}//检测是否有输入
//---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow *window)
{if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)   //ESC键,退出glfwSetWindowShouldClose(window, true);float cameraSpeed = static_cast<float>(2.5 * deltaTime);if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)camera.ProcessKeyboard(FORWARD, deltaTime);if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)camera.ProcessKeyboard(BACKWARD, deltaTime);if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)camera.ProcessKeyboard(LEFT, deltaTime);if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)camera.ProcessKeyboard(RIGHT, deltaTime);
}//给glfw窗口注册的尺寸改变回调函数
//---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{//确保视口匹配新的窗口尺寸,请注意:宽度和高度将比视网膜显示器上指定的大得多glViewport(0, 0, width, height);
}
// 鼠标移动时的回调函数
// -------------------------------------------------------
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 = lastX - xpos;float yoffset = ypos - lastY;   //翻转,因为Y轴是从下到上越来越大lastX = xpos;lastY = ypos;camera.ProcessMouseMovement(xoffset, yoffset);
}//鼠标滚轮的回调函数
// ----------------------------------------------------------------------
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{camera.ProcessMouseScroll(static_cast<float>(yoffset));
}

http://www.ppmy.cn/news/1278741.html

相关文章

Git常用命令及解释说明

目录 前言1 git config2 git init3 git status4 git add5 git commit6 git reflog7 git log8 git reset结语 前言 Git是一种分布式版本控制系统&#xff0c;广泛用于协作开发和管理项目代码。了解并熟练使用Git的常用命令对于有效地管理项目版本和历史记录至关重要。下面是一些…

从零学算法334

334.给你一个整数数组 nums &#xff0c;判断这个数组中是否存在长度为 3 的递增子序列。 如果存在这样的三元组下标 (i, j, k) 且满足 i < j < k &#xff0c;使得 nums[i] < nums[j] < nums[k] &#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。…

golang开发--beego入门

Beego 是一个基于 Go 语言的开源框架&#xff0c;用于构建 Web 应用程序和 API。它采用了一些常见的设计模式&#xff0c;以提高开发效率、代码可维护性和可扩展性。 一&#xff0c;MVC设计模式 Beego 框架采用了经典的 MVC&#xff08;Model-View-Controller&#xff09;设计…

临床医学VR仿真情景实训教学应用

一、VR医学仿真情景教学应用 临床医学VR仿真情景实训教学是一种将VR虚拟技术应用于医学教育的新型教学方法。通过模拟真实的医疗环境&#xff0c;学生可以在虚拟场景中进行实践操作&#xff0c;从而更好地理解和掌握医学知识。与传统医学教育方式相比&#xff0c;VR技术为医学…

odoo17核心概念——env

env在odoo中是一个非常重要的概念&#xff0c;它是一个全局变量&#xff0c;保存了odoo运行环境的重要信息&#xff0c;env分为前端和后端 一、环境(env) 1、前端的env 在web\static\src\env.js中定义&#xff0c;包含两个重要的对象&#xff1a; 全局数据总线bus&#xff…

pr插件|特殊编码.mkv/mov/flv/webm/avi/wmv/vob等多种格式视频素材直接导入pr的插件 Influx v1.2.5

适用于Adobe的一体式原生导入器插件&#xff08;Premiere Pro、After Effects和Media Encoder&#xff09;。支持多种格式和编解码器。 主要特点 直接在Adobe CC Video中进行本机导入 不再需要通过外部转码软件&#xff01;节省时间、磁盘空间和麻烦 在Premiere Pro中导入和编辑…

【大数据存储与处理】实验一 HBase 的基本操作

一、实验目的&#xff1a; 1. 掌握 Hbase 创建数据库表及删除数据库表 2. 掌握 Hbase 对数据库表数据的增、删、改、查。 二、实验内容&#xff1a; 1、题目 0&#xff1a;进入 hbase shell 2、题目 1&#xff1a;Hbase 创建数据库表 创建数据库表的命令&#xff1a;create 表…

【ECMAScript】DOM节点类型知识点的梳理和总结

1. 前言 本篇梳理和总结一下DOM相关知识点。 2. Node类型 属性和方法说明 Node.ELEMENT_NODE - 1 Node.ATTRIBUTE_NODE - 2 Node.TEXT_NODE - 3 Node.CDATA_SECTION_NODE - 4 Node.ENTITY_REFERENCE_NODE - 5 Node.ENTITY_NODE - 6 Node.PROCESSING_INSTRUCTION_NODE-7 Node.…