#version 460
out vec4 FragColor;
// 定义一个名为Material的结构体,用于存储3D物体的材质信息。
struct Material {
// 漫反射纹理贴图,用于存储物体表面在漫反射下的颜色信息。
// sampler2D表示这是一个二维纹理贴图,一般在图形渲染中使用。
sampler2D diffuse;
// 镜面纹理贴图,用于存储物体表面在镜面反射下的高光区域的颜色信息。
// sampler2D表示这是一个二维纹理贴图,一般在图形渲染中使用。
sampler2D specular;
// 反光度,用于控制物体表面的镜面反射效果的程度。
// 通常这个值越大,物体表面的镜面反射效果越强烈。
float shininess;
};
// 方向光结构体
struct DirLight {
// 光线方向,表示从光源出发射向物体的方向
vec3 direction; // 表示方向的光线向量
// 环境光,表示物体表面被照亮的程度,不受光照角度影响
vec3 ambient; // 表示环境光的颜色
// 漫反射光,表示物体表面在漫反射下的颜色分布
vec3 diffuse; // 表示漫反射光的颜色
// 镜面反射光,表示物体表面在镜面反射下的颜色分布
vec3 specular; // 表示镜面反射光的颜色
};
// 定义一个名为PointLight的结构体
struct PointLight {
// 表示点光源的位置。使用vec3表示三维坐标,x、y和z分别代表横轴、纵轴和竖轴。
vec3 position;
// 表示光照衰减的常数项。在光照计算中,这个值用于决定光源距离物体越远,其亮度衰减的程度。
float constant;
// 表示光照衰减的线性项。这个值通常与光源距离物体的距离线性相关,用于增强光照衰减的效果。
float linear;
// 表示光照衰减的二次项。这个值通常与光源距离物体的距离的平方相关,用于增强光照衰减的效果。
float quadratic;
// 表示环境光的颜色。环境光是均匀分布在场景中的光线,不依赖于物体的位置或朝向。
vec3 ambient;
// 表示漫反射光的颜色。漫反射是光线在物体表面反射时,朝各个方向均匀散射的现象。
vec3 diffuse;
// 表示镜面反射光的颜色。镜面反射是光线在物体表面反射时,朝特定方向集中反射的现象。
vec3 specular;
};
// 聚光灯结构体用于存储一个聚光灯的相关属性
struct SpotLight {
// 聚光灯的位置,以三维向量 (x, y, z) 表示。这个向量通常用于确定灯在三维空间中的位置。
vec3 position;
// 聚光灯的方向,以三维向量 (x, y, z) 表示。这个向量通常用于确定灯照射的方向。
vec3 direction;
// 聚光灯的内锥角度(以弧度为单位)。这个值用于描述灯的照射范围,即光线在内部的角度。
float cutOff;
// 聚光灯的外锥角度(以弧度为单位)。这个值用于描述灯的外部照射范围,即光线在外部的角度。
float outerCutOff;
// 表示光照衰减的常数项。在光照计算中,这个值用于决定光源距离物体越远,其亮度衰减的程度。
float constant;
// 表示光照衰减的线性项。这个值通常与光源距离物体的距离线性相关,用于增强光照衰减的效果。
float linear;
// 表示光照衰减的二次项。这个值通常与光源距离物体的距离的平方相关,用于增强光照衰减的效果。
float quadratic;
// 表示环境光的颜色。环境光是均匀分布在场景中的光线,不依赖于物体的位置或朝向。
vec3 ambient;
// 表示漫反射光的颜色。漫反射是光线在物体表面反射时,朝各个方向均匀散射的现象。
vec3 diffuse;
// 表示镜面反射光的颜色。镜面反射是光线在物体表面反射时,朝特定方向集中反射的现象。
vec3 specular;
};
// 定义NR_POINT_LIGHTS常量,表示点光源的数量为4
#define NR_POINT_LIGHTS 4
// 定义一个包含NR_POINT_LIGHTS个元素的PointLight数组,存储点光源的信息
uniform PointLight pointLights[NR_POINT_LIGHTS];
// 定义一个DirLight变量,存储方向光源的信息
uniform DirLight dirLight;
// 定义一个Material变量,存储材质的信息
uniform Material material;
// 定义一个SpotLight变量,存储聚光灯的信息
uniform SpotLight spotLight;
// 定义一个vec3类型的viewPos变量,表示摄像机的位置
uniform vec3 viewPos; // 摄像机位置
// 定义一个in变量FragPos,表示顶点坐标(世界空间)
in vec3 FragPos; // 顶点坐标(世界空间)
// 定义一个in变量Normal,表示顶点的法线向量
in vec3 Normal; // 顶点法线
// 定义一个in变量TexCoords,表示纹理坐标
in vec2 TexCoords; // 纹理坐标
// CalcDirLight函数用于计算方向光对给定表面的影响
// 输入参数:
// light - 方向光信息,包括颜色、方向等
// normal - 表面法向量,表示表面朝向和角度
// viewDir - 视线方向,表示观察者的朝向
// 返回值:
// 返回一个vec3类型的值,表示方向光对表面特定点的照射颜色
vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir);
// calcPointLight函数用于计算点光源对给定表面的影响
// 输入参数:
// light - 点光源信息,包括位置、衰减系数以及颜色等信息
// normal - 表面法向量,表示表面朝向和角度
// fragPos - 片段位置,表示表面上的某一点
// viewDir - 视线方向,表示观察者的朝向
// 返回值:
// 返回一个vec3类型的值,表示点光源对表面特定点的照射颜色
vec3 calcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir);
// 计算聚光灯对物体表面的影响
// 参数:
// light:聚光灯的参数
// normal:物体表面的法线向量
// fragPos:物体表面的一个点
// viewDir:视线方向向量
// 返回值:
// 聚光灯对物体表面的光照结果,以颜色向量的形式表示
vec3 CalcSpotLight(SpotLight light, vec3 normal, vec3 fragPos, vec3 viewDir);
void main() {
// 计算法向量N,这里假设Normal是给定的法向量
// 通常Normal是从顶点数据或模型数据中获取的,表示表面的法线方向
vec3 N = normalize(Normal);
// 计算视线向量V,viewPos是视点的位置,FragPos是当前片段的位置
// normalize函数确保V是一个单位向量,即长度为1的向量
vec3 V = normalize(viewPos - FragPos);
// 计算方向光对物体表面的影响,并将结果存储在result变量中
// CalcDirLight是一个函数,它接受方向光、法向量和视线向量作为参数
// 这个函数可能包含一些计算,如计算光线与表面的角度等,以确定方向光的照射强度
vec3 result = CalcDirLight(dirLight, N, V);
// 遍历所有的点光源
// NR_POINT_LIGHTS是一个常量,表示场景中点光源的数量
for(int i = 0; i < NR_POINT_LIGHTS; i++) {
// 对于每个点光源,调用calcPointLight函数来计算其对物体表面的影响
// 这个函数可能涉及到距离计算、光照衰减等计算
result += calcPointLight(pointLights[i], N, FragPos, V);
}
// 计算聚光灯对物体表面的影响,并将结果累加到result中
// CalcSpotLight是一个函数,它接受聚光灯、法向量、片段位置和视线向量作为参数
// 这个函数可能包含对聚光灯的照射范围、角度等的计算
result += CalcSpotLight(spotLight, N, FragPos, V);
// 将最终的光照结果赋值给FragColor,这是一个vec4类型的变量,其中result是颜色,1.0是透明度
// vec4(result, 1.0)表示将result作为颜色的RGBA值,并将透明度设置为1.0(完全不透明)
FragColor = vec4(result, 1.0);
}
// 计算方向光对物体表面的影响
vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir) {
// 计算从物体表面点到方向光源的光线方向,由于是方向光,所以光源方向是固定的
vec3 lightDir = normalize(-light.direction);
// 计算漫反射光照强度
float diff = max(dot(normal, lightDir), 0.0);
// dot(normal, lightDir) 计算法向量和光线方向的点积,max(dot(normal, lightDir), 0.0) 确保当光线方向与法线方向相反时,漫反射光照强度为0
// 计算反射方向
vec3 reflectDir = reflect(-lightDir, normal);
// reflect函数计算光线在物体表面的反射方向,-lightDir是入射光线的反方向,normal是物体的法向量
// 计算高光反射光照强度
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
// max(dot(viewDir, reflectDir), 0.0) 确保当反射光线与视线方向相反时,高光反射光照强度为0
// pow(…, material.shininess) 根据物体的粗糙度(或高光反射度)调整高光反射强度
// 从纹理中获取物体的漫反射颜色
vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords));
// diffuse * diff 调整漫反射光的强度,因为diff是漫反射光照强度
// 从纹理中获取物体的漫反射颜色
vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords));
// 从纹理中获取物体的高光反射颜色
vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords));
// specular * spec 调整高光反射光的强度,因为spec是高光反射光照强度
// 返回总的光照结果,即环境光、漫反射光和高光反射光的和
return (ambient + diffuse + specular);
}
// 计算点光源对物体表面的影响
vec3 calcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir) {
// 计算从物体表面点到点光源的光线方向
vec3 lightDir = normalize(light.position - fragPos);
// 计算漫反射光照强度
float diff = max(dot(normal, lightDir), 0.0);
// dot(normal, lightDir) 计算法向量和光线方向的点积,max(dot(normal, lightDir), 0.0) 确保当光线方向与法线方向相反时,漫反射光照强度为0
// 计算反射方向
vec3 reflectDir = reflect(-lightDir, normal);
// reflect函数计算光线在物体表面的反射方向,-lightDir是入射光线的反方向,normal是物体的法向量
// 计算高光反射光照强度
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
// max(dot(viewDir, reflectDir), 0.0) 确保当反射光线与视线方向相反时,高光反射光照强度为0
// pow(…, material.shininess) 根据物体的粗糙度(或高光反射度)调整高光反射强度
// 计算从点光源到物体表面的距离
float distance = length(light.position - fragPos);
// length函数计算两点之间的距离
// 计算光照衰减
float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));
// 根据点光源的属性(常数、线性、二次项)和物体表面点到点光源的距离计算光照衰减
// 从纹理中获取物体的漫反射和镜面反射颜色
vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords));
vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords));
// diffuse * diff 调整漫反射光的强度,因为diff是漫反射光照强度
vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords));
// specular * spec 调整高光反射光的强度,因为spec是高光反射光照强度
// 根据光照衰减调整环境光、漫反射光和镜面反射光的强度
ambient *= attenuation;
diffuse *= attenuation;
specular *= attenuation;
// 返回总的光照结果,即环境光、漫反射光和镜面反射光的和
return (ambient + diffuse + specular);
}
// 计算聚光灯对物体表面的影响
vec3 CalcSpotLight(SpotLight light, vec3 normal, vec3 fragPos, vec3 viewDir) {
// 计算从物体表面点到聚光灯的光线方向
vec3 lightDir = normalize(light.position - fragPos);
// 计算漫反射光照强度
float diff = max(dot(normal, lightDir), 0.0);
// dot(normal, lightDir) 计算法向量和光线方向的点积,max(dot(normal, lightDir), 0.0) 确保当光线方向与法线方向相反时,漫反射光照强度为0
// 计算反射方向
vec3 reflectDir = reflect(-lightDir, normal);
// reflect函数计算光线在物体表面的反射方向,-lightDir是入射光线的反方向,normal是物体的法向量
// 计算高光反射光照强度
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
// max(dot(viewDir, reflectDir), 0.0) 确保当反射光线与视线方向相反时,高光反射光照强度为0
// pow(…, material.shininess) 根据物体的粗糙度(或高光反射度)调整高光反射强度
// 计算从聚光灯到物体表面的距离
float distance = length(light.position - fragPos);
// length函数计算两点之间的距离
// 计算光照衰减
float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));
// 根据聚光灯的属性(常数、线性、二次项)和物体表面点到聚光灯的距离计算光照衰减
// 从纹理中获取物体的漫反射和镜面反射颜色
vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords));
vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords));
// diffuse * diff 调整漫反射光的强度,因为diff是漫反射光照强度
vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords));
// specular * spec 调整高光反射光的强度,因为spec是高光反射光照强度
// 计算光线与聚光灯锥体的角度差
float theta = dot(lightDir,normalize(-light.direction));
// normalize(-light.direction) 将聚光灯的方向归一化,以便与光线方向进行点积运算
// 计算聚光灯的内外锥体角度差
float epsilon = light.cutOff - light.outerCutOff;
// cutOff和outerCutOff分别是聚光灯的内锥体和外锥体角度
// 计算光照强度权重
float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0);
// (theta - light.outerCutOff) / epsilon 计算光照强度权重,clamp函数确保其值在0到1之间
// 根据光照衰减和光照强度权重对环境光、漫反射光和镜面反射光进行缩放
ambient *= attenuation * intensity;
diffuse *= attenuation * intensity;
specular *= attenuation * intensity;
// 返回总的光照结果,即环境光、漫反射光和镜面反射光的和
return (ambient + diffuse + specular);
}
main.cpp
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <iostream>
#include <assert.h>
#include <cmath>
#include <stack>
#include <vector>
#include <Class/Shader/Shader.h>
#include <Class/Camera/Camera.h>
// 创建多少个 VAO VBO
#define ARRAYMAXCOUNT 1
// 创建 vao 变量
GLuint vao[ARRAYMAXCOUNT+1];
// 创建 vbo
GLuint vbo[ARRAYMAXCOUNT];
// 创建着色器类
Shader shader1;
Shader shader2;
// 摄像机
Camera myCamera(glm::vec3(0.0f, 0.0f, 3.0f),glm::vec3(0.0f, 0.0f, -1.0f),glm::vec3(0.0f, 1.0f, 0.0f));
GLuint
texture1,// 纹理
texture2,// 纹理
vLoad,// 视图矩阵
mLoad,// 模型矩阵
pLoad;// 透视矩阵
glm::mat4
mMat, // 模型矩阵
pMat, // 透视矩阵
vMat; // 视图矩阵
// 光源位置
glm::vec3 lightPos(1.2f, 1.0f, 2.0f);
// 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)
};
// 点光源位置
glm::vec3 pointLightPositions[] = {
glm::vec3(0.7f, 0.2f, 2.0f),
glm::vec3(2.3f, -3.3f, -4.0f),
glm::vec3(-4.0f, 2.0f, -12.0f),
glm::vec3(0.0f, 0.0f, -3.0f)
};
// 初始自定义代码
void init(GLFWwindow* window);
// 渲染自定义代码
void display(GLFWwindow* window, double currentTime);
// 销毁
void destroy(GLFWwindow* window);
// 窗口改变事件
void window_reshape_callback(GLFWwindow* window, int width, int height);
// 注册了鼠标移动事件
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
// 注册了鼠标移动事件
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
// 监听按键,鼠标事件
void ProcessInput(GLFWwindow* window);
int main() {
// 初始化 glfw
if (!glfwInit()) { exit(EXIT_FAILURE); }
// 设置 opengl 版本 (4.6 核心)
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// 创建 window 窗口
GLFWwindow* window = glfwCreateWindow(600, 600, "LearOpenGL 1.10", NULL, NULL);
// 链接 opengl 上下文
glfwMakeContextCurrent(window);
// 初始化 glad 获取 opengl api 函数 地址
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { exit(EXIT_FAILURE); }
// 开启垂直
glfwSwapInterval(1);
// 注册窗口改变事件
glfwSetWindowSizeCallback(window, window_reshape_callback);
// 隐藏光标
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
// 注册了鼠标移动事件
glfwSetCursorPosCallback(window, mouse_callback);
// 注册了鼠标滚动事件
glfwSetScrollCallback(window, scroll_callback);
// 初始化着色器类
shader1.init("vertShader1.glsl","fragShader1.glsl");
shader2.init("vertShader2.glsl","fragShader2.glsl");
// 初始自定义代码
init(window);
myCamera.fov = 45.0f;
// 循环渲染
while (!glfwWindowShouldClose(window))
{
// 监听键盘
ProcessInput(window);
// 渲染自定义代码
display(window, glfwGetTime());
// 交换缓存和轮询IO事件
glfwSwapBuffers(window);
glfwPollEvents();
}
// 释放内存
destroy(window);
// 成功退出程序
exit(EXIT_SUCCESS);
}
void init(GLFWwindow* window) {
// 创建 vao
glGenVertexArrays(ARRAYMAXCOUNT + 1, vao);
// 创建 vbo
glGenBuffers(ARRAYMAXCOUNT, vbo);
float vertices[] = {
// 顶点 // 法向量 // 纹理
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 0.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, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.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, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f
};
// 绑定 vao
glBindVertexArray(vao[0]);
// 把顶点数据绑定到 vbo
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 设置属性指针
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(sizeof(float) * 3));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(sizeof(float) * 6));
glEnableVertexAttribArray(2);
// 绑定 vao
glBindVertexArray(vao[1]);
// 把顶点数据绑定到 vbo
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 设置属性指针
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// 创建纹理
glGenTextures(1, &texture1);
Utils::image image;
image.imagePath = "dm\\container2.png";
image.Isreversed = true;
image.type = GL_RGBA;
// 绑定纹理
glBindTexture(GL_TEXTURE_2D, texture1);
Utils::getImage(image);
glGenTextures(1, &texture2);
image.imagePath = "dm\\container2_specular.png";
glBindTexture(GL_TEXTURE_2D, texture2);
Utils::getImage(image);
// 开启着色器程序
shader1.useProgram();
mLoad = shader1.getULocation("m_matrix");
vLoad = shader1.getULocation("v_matrix");
pLoad = shader1.getULocation("p_matrix");
// 3D物体的材质信息
shader1.setPUInt("material.diffuse", 0); // 漫反射光照
shader1.setPUInt("material.specular", 1); // 镜面光照
shader1.setPUFloat("material.shininess", 32.0f); // 反光度
// 方向光结构体
shader1.setPUF3fv_t("dirLight.direction", glm::value_ptr(glm::vec3(-0.2f, -1.0f, -0.3f)));// 光线位置
shader1.setPUF3fv_t("dirLight.ambient", glm::value_ptr(glm::vec3(0.05f, 0.05f, 0.05f)));// 环境光照
shader1.setPUF3fv_t("dirLight.diffuse", glm::value_ptr(glm::vec3(0.4f, 0.4f, 0.4f)));// 漫反射光照
shader1.setPUF3fv_t("dirLight.specular", glm::value_ptr(glm::vec3(0.5f, 0.5f, 0.5f)));// 镜面光照
// 点光源
for (int i = 0; i < 4; i++)
{
std::string position = "pointLights[0].position";
std::string ambient = "pointLights[0].ambient";
std::string diffuse = "pointLights[0].diffuse";
std::string specular = "pointLights[0].specular";
std::string constant = "pointLights[0].constant";
std::string linear = "pointLights[0].linear";
std::string quadratic = "pointLights[0].quadratic";
position.replace(12, 1, std::to_string(i));
ambient.replace(12, 1, std::to_string(i));
diffuse.replace(12, 1, std::to_string(i));
specular.replace(12, 1, std::to_string(i));
constant.replace(12, 1, std::to_string(i));
linear.replace(12, 1, std::to_string(i));
quadratic.replace(12, 1, std::to_string(i));
glm::vec3 lightColor;
lightColor.x = std::sin(2.0f * (i + 1));
lightColor.y = std::sin(0.7f * (i + 1));
lightColor.z = std::sin(1.3f * (i + 1));
glm::vec3 diffuseColor = lightColor * glm::vec3(0.5f); // 降低影响
glm::vec3 ambientColor = diffuseColor * glm::vec3(0.2f); // 很低的影响
shader1.setPUF3fv_t(position.c_str(), glm::value_ptr(pointLightPositions[i]));// 光线位置
shader1.setPUF3fv_t(ambient.c_str(), glm::value_ptr(ambientColor));// 环境光照
shader1.setPUF3fv_t(diffuse.c_str(), glm::value_ptr(diffuseColor));// 漫反射光照
shader1.setPUF3fv_t(specular.c_str(), glm::value_ptr(glm::vec3(1.0f, 1.0f, 1.0f)));// 镜面光照
// 实现光的衰弱
shader1.setPUFloat(constant.c_str(), 1.0f);// 常数项
shader1.setPUFloat(linear.c_str(), 0.09f);// 一次项
shader1.setPUFloat(quadratic.c_str(), 0.032f);// 二次项
}
shader1.setPUF3fv_t("spotLight.ambient", glm::value_ptr(glm::vec3(0.0f, 0.0f, 0.0f)));// 环境光照
shader1.setPUF3fv_t("spotLight.diffuse", glm::value_ptr(glm::vec3(1.0f, 1.0f, 1.0f)));// 漫反射光照
shader1.setPUF3fv_t("spotLight.specular", glm::value_ptr(glm::vec3(1.0f, 1.0f, 1.0f)));// 镜面光照
// 实现光的衰弱
shader1.setPUFloat("spotLight.constant", 1.0f);// 常数项
shader1.setPUFloat("spotLight.linear", 0.09f);// 一次项
shader1.setPUFloat("spotLight.quadratic", 0.032f);// 二次项
shader1.setPUFloat("spotLight.cutOff", glm::cos(glm::radians(12.5f)));
shader1.setPUFloat("spotLight.outerCutOff", glm::cos(glm::radians(15.0f)));
// 获取窗口的宽高
int width, height;
glfwGetFramebufferSize(window, &width, &height);// 获取屏幕宽,高
// 计算宽高比
float aspect = (float)width / (float)height;//获取屏幕比例
// 创建透视矩阵 / 设置投影矩阵
pMat = glm::perspective(glm::radians(myCamera.fov), aspect, 0.1f, 1000.0f);
}
void display(GLFWwindow* window, double currentTime) {
// 填充颜色缓冲区
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
// 清除深度缓冲区
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
// 创建透视矩阵 / 设置投影矩阵
pMat = glm::perspective(glm::radians(myCamera.fov), (float)600 / (float)600, 0.1f, 1000.0f);
// 将视图矩阵压入栈
vMat = myCamera.getLookAt();
// 开启着色器程序
shader1.useProgram();
shader1.setPUF3fv_t("spotLight.position", glm::value_ptr(myCamera.cameraPos));// 光线位置
shader1.setPUF3fv_t("spotLight.direction", glm::value_ptr(myCamera.cameraFront));// 光线位置
// 摄像机位置
shader1.setPUF3fv_t("viewPos", glm::value_ptr(myCamera.cameraPos));
// 视图矩阵
shader1.setPUFMat4(vLoad, glm::value_ptr(vMat));
// 透视矩阵
shader1.setPUFMat4(pLoad, glm::value_ptr(pMat));
// 将纹理绑定到相应的纹理单元上
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2);
// 开启深度测试
glEnable(GL_DEPTH_TEST);
// 设置深度测试的比较方式
glDepthFunc(GL_LEQUAL);
// 绑定 vao
glBindVertexArray(vao[0]);
for (int i = 0; i < 10; i++)
{
// 模型矩阵
mMat = glm::translate(glm::mat4(1.0f), cubePositions[i]);
float angle = 20.0f * i;
mMat = glm::rotate(mMat, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));
// 模型矩阵
shader1.setPUFMat4(mLoad, glm::value_ptr(mMat));
// 绘制模型
glDrawArrays(GL_TRIANGLES, 0, 36);
}
// 开启着色器程序
shader2.useProgram();
// 开启深度测试
glEnable(GL_DEPTH_TEST);
// 设置深度测试的比较方式
glDepthFunc(GL_LEQUAL);
// 绑定 vao
glBindVertexArray(vao[1]);
for (int i = 0; i < 4; i++)
{
// 模型矩阵
mMat = glm::translate(glm::mat4(1.0f), pointLightPositions[i]);
mMat = glm::rotate(mMat, (float)currentTime * glm::radians(45.0f), glm::vec3(1.0f, 0.5f, 0.0f));
mMat = glm::scale(mMat, glm::vec3(0.2f, 0.2f, 0.2f));
glm::vec3 lightColor;
lightColor.x = std::sin(2.0f * (i + 1));
lightColor.y = std::sin(0.7f * (i + 1));
lightColor.z = std::sin(1.3f * (i + 1));
glm::vec3 diffuseColor = lightColor * glm::vec3(0.5f); // 降低影响
glm::vec3 ambientColor = diffuseColor * glm::vec3(0.2f); // 很低的影响
lightColor = diffuseColor;
shader2.setPUFMat4("mv_matrix", glm::value_ptr(vMat * mMat));
shader2.setPUFMat4("p_matrix", glm::value_ptr(pMat));
shader2.setPUFloat("lightColor", lightColor.x, lightColor.y, lightColor.z);
// 绘制模型
glDrawArrays(GL_TRIANGLES, 0, 36);
}
}
void destroy(GLFWwindow* window) {
// 销毁 vao vbo
glDeleteVertexArrays(ARRAYMAXCOUNT, vao);
glDeleteBuffers(ARRAYMAXCOUNT, vbo);
// 销毁着色器
shader1.deleteProgram();
// 销毁窗口
glfwDestroyWindow(window);
glfwTerminate();
}
void window_reshape_callback(GLFWwindow* window, int width, int height)
{
// 设置和帧缓冲区相关的屏幕区域
glViewport(0, 0, width, height);
}
// 监听按键,鼠标事件
void ProcessInput(GLFWwindow* window)
{
// 检查用户是否按下了返回键(Esc)
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
{
// 下一次while循环的条件检测将会失败,程序将会关闭
glfwSetWindowShouldClose(window, true);
}
static float deltaTime = 0.0f;
static float lastFrame = 0.0f;
float currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame; // 当前帧与上一帧的时间差
lastFrame = currentFrame; // 上一帧的时间
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
myCamera.ProcessKeyboard(FORWARD, deltaTime);
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
myCamera.ProcessKeyboard(BACKWARD, deltaTime);
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
myCamera.ProcessKeyboard(LEFT, deltaTime);
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
myCamera.ProcessKeyboard(RIGHT, deltaTime);
}
// 回调函数,鼠标进入程序窗口,获取焦点
void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{
static bool firstMouse = true;
static float lastX = 0.0f;
static float lastY = 0.0f;
static float xoffset = 0.0f;
static float yoffset = 0.0f;
if (firstMouse)
{
lastX = xpos;
lastY = ypos;
firstMouse = false;
}
// 获取 x 坐标
xoffset = xpos - lastX;
// 注意这里是相反的,因为y坐标是从底部往顶部依次增大的
yoffset = lastY - ypos;
// 更新鼠标坐标
lastX = xpos;
lastY = ypos;
myCamera.mouse_callback(xoffset, yoffset);
}
// 监听鼠标滚动
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
myCamera.scroll_callback(xoffset, yoffset);
}