投射光源的物体就是投光物
平行光(Directional Light)
点光源(Point Light)
聚光(Spotlight)
平行光
由于平行光所有光源都是平行的所以"光源和物体的相对位置"并不是那么重要,
我们只需要定义一个"方向向量direction"来模拟平行光
//directionLight.fs
#version 330 core
out vec4 FragColor;
struct Material {
sampler2D diffuse;
sampler2D specular;
float shininess;
};
struct Light {
//vec3 position;
vec3 direction;//定义一个"方向向量direction"来模拟平行光
vec3 ambient;//光的环境光分量
vec3 diffuse;//光的漫反射分量
vec3 specular;//光的镜面反射分量
};
in vec3 FragPos;
in vec3 Normal;
in vec2 TexCoords;
uniform vec3 viewPos;
uniform Material material;//创建结构体对象
uniform Light light;//创建结构体对象
void main()
{
// ambient
vec3 ambient = light.ambient * texture(material.diffuse, TexCoords).rgb;
//环境光分量=光的初始环境光分量*漫反射材质纹理 相当于告诉着色器环境光会受到material.diffuse材质的影响
//材质在主函数里面由set传入
// diffuse
vec3 norm = normalize(Normal);//标准化法向量
// vec3 lightDir = normalize(light.position - FragPos);
vec3 lightDir = normalize(-light.direction); //方向向量direction"来模拟平行光 对light.direction向量取反。
//我们目前使用的光照计算需求一个从片段至光源的光线方向,但人们更习惯定义定向光为一个从光源出发的全局方向。
float diff = max(dot(norm, lightDir), 0.0);//点乘算出法线和反射光线夹角
vec3 diffuse = light.diffuse * diff * texture(material.diffuse, TexCoords).rgb;
//告诉着色器漫反射会受到material.diffuse材质的影响
// specular
vec3 viewDir = normalize(viewPos - FragPos);//人的视角方向 是从物体指向观察者
vec3 reflectDir = reflect(-lightDir, norm);//告诉入射光和法线 reflect计算出反射光的向量
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);//material.shininess高光级别2 4 8 16 32 64 128等级越低光圈越模糊
vec3 specular = light.specular * spec * texture(material.specular, TexCoords).rgb;
//告诉着色器高光会受到material.diffuse材质的影响
vec3 result = ambient + diffuse + specular;
FragColor = vec4(result, 1.0);
}
//directionLight.vs
#version 330 core
layout (location = 0) in vec3 aPos;//初始位置为0的属性为顶点位置
layout (location = 1) in vec3 aNormal;//初始位置为1的属性为法线位置
layout (location = 2) in vec2 aTexCoords;//初始位置为2的属性为贴图坐标
out vec3 FragPos;//输出物体的位置
out vec3 Normal;//输出法线
out vec2 TexCoords;//输出贴图
uniform mat4 model;//定义全局变量model 在主函数中设置
uniform mat4 view;//定义全局变量view 在主函数中设置
uniform mat4 projection;//定义全局变量projection 在主函数中设置
void main()
{
FragPos = vec3(model * vec4(aPos, 1.0));
//物体经过模型变换后在世界坐标的位置
Normal = mat3(transpose(inverse(model))) * aNormal;
//法线变换矩阵=逆矩阵的转置*法线矩阵
TexCoords = aTexCoords;
//贴图坐标
gl_Position = projection * view * vec4(FragPos, 1.0);//最后在视锥里面你看到的位置
}
//LightingMaps
#include "Shader.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#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>
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void processInput(GLFWwindow* window);
// settings
const unsigned int SCR_WIDTH = 800; //定义屏幕空间的大小
const unsigned int SCR_HEIGHT = 600;
// camera
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; // 偏航初始化为-90.0度,因为偏航为0.0会导致指向右边的方向向量,所以我们最初向左旋转了一点。
float pitch = 0.0f; //初始化俯仰角
float lastX = 800.0f / 2.0;//为了把初始位置设置为屏幕中心所以取屏幕空间大小的一半
float lastY = 600.0 / 2.0;
float fov = 45.0f;//初始的视场角
// timing
float deltaTime = 0.0f; // time between current frame and last frame
float lastFrame = 0.0f;
glm::vec3 lightPos(1.2f, 1.0f, 2.0f);
//glm::vec3 lightPos(1.2f, 1.0f, 2.0f);
void processInput(GLFWwindow* window);
float vertices[] = {
// positions // normals // texture coords
-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
};
//定义一个vec3类型的数组来存位移矩阵
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),
};
int main()
{
//Glfw:初始化和配置
// ------------------------------
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
//glfw窗口创建
// --------------------
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);//使用定义的屏幕空间的大小
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetCursorPosCallback(window, mouse_callback);
glfwSetScrollCallback(window, scroll_callback);
//首先我们要告诉GLFW,它应该隐藏光标,并捕捉(Capture)它。
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
//加载所有OpenGL函数指针
// ---------------------------------------
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// 配置全局opengl状态
// -----------------------------
glEnable(GL_DEPTH_TEST);
// 构建并编译我们的shader程序
// ------------------------------------
Shader ourShader("shaderSampler.vs", "shaderSampler.fs");
Shader modelShader("directionLight.vs", "directionLight.fs");
Shader lightShader("lightShader.vs", "lightShader.fs");
//建立和编译顶点数据(和缓冲区),配置顶点属性
// ------------------------------------------------------------------
unsigned int VBO, VAO, VAO2;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindVertexArray(VAO);
//位置属性
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
//之后在顶点着色器layout (location = 1) in vec3 aNormal;//告诉GPU位置1的属性
glGenVertexArrays(1, &VAO2);
glBindVertexArray(VAO2);
//glBindBuffer(GL_ARRAY_BUFFER, VBO);
//位置属性
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*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
// 加载并创建一个纹理
// -------------------------
unsigned int texture1, texture2;
// texture 1
// ---------
glGenTextures(1, &texture1);
glBindTexture(GL_TEXTURE_2D, texture1);
// 设置纹理wrapping参数
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// 设置纹理filtering参数
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//加载图像,创建纹理和生成mipmaps //多级原理纹理
int width, height, nrChannels;
stbi_set_flip_vertically_on_load(true); // 告诉stb_image.h在y轴上翻转已加载的纹理。
//为什么需要翻转Y轴是因为纹理图片开始位置是右上而我们顶点的坐标(0,0)点是左下
unsigned char* data = stbi_load("container2.png", &width, &height, &nrChannels, 0);
if (data)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
std::cout << "Failed to load texture" << std::endl;
}
stbi_image_free(data);
// texture 2
// ---------
glGenTextures(1, &texture2);
glBindTexture(GL_TEXTURE_2D, texture2);
// 设置纹理wrapping参数
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// 设置纹理filtering参数
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// load image, create texture and generate mipmaps
//data = stbi_load(("aotu.jpg"), &width, &height, &nrChannels, 0);
//data = stbi_load(("shanshui.jpg"), &width, &height, &nrChannels, 0);
data = stbi_load(("container2_specular.png"), &width, &height, &nrChannels, 0);
if (data)
{
//如果没有贴图请优先注意这个RGBA中的alpha(A)通道 如果你的贴图有alpha通道请务必使用RGBA模式否则无法显示贴图
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
std::cout << "Failed to load texture" << std::endl;
}
stbi_image_free(data);
// 为每个采样器告诉opengl它属于哪个纹理单元(只需要做一次)
// -------------------------------------------------------------------------------------------
modelShader.use();
modelShader.setInt("material.diffuse", 0);
modelShader.setInt("material.specular", 1);
// ourShader.setVec3("lightPos", lightPos);
//渲染循环
// -----------
while (!glfwWindowShouldClose(window))
{
float currentFrame = 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); // 清除上一帧的颜色缓冲 以及 深度测试缓冲
//激活着色器
float angle = 20.0f * 0 * (float)glfwGetTime();//给一个glfwGetTime让模型旋转起来
glm::mat4 projection = glm::mat4(1.0f);
glm::mat4 view = glm::mat4(1.0f);
glm::mat4 model = glm::mat4(1.0f);
//glm::vec3 lightPos = glm::vec3(cubePositions[10]);//光源位置
projection = glm::perspective(glm::radians(fov), 800.0f / 600.0f, 0.1f, 100.0f);//投影矩阵 参数:视口大小,屏幕宽高比,以及near和far
view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);//lookAt矩阵 参数:摄像机位置 ,观察目标的位置 ,竖直向上的方向
model = glm::translate(model, cubePositions[0]);//把数组传进去给每一个新建的模型在世界坐标下有不同的位移
model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));
//lightShader.use();
lightPos.x = 1.0f + sin(glfwGetTime()) * 2.0f;
lightPos.y = sin(glfwGetTime() / 2.0f) * 1.0f;
//model = glm::mat4(1.0f);
//model = glm::translate(model, lightPos);//把数组传进去给每一个新建的模型在世界坐标下有不同的位移
//angle = 20.0f * 2 * (float)glfwGetTime();//给一个glfwGetTime让模型旋转起来
//model = glm::rotate(model, glm::radians(angle) , glm::vec3(1.0f, 0.3f, 0.5f));//旋转物体
//model = glm::scale(model, glm::vec3(0.2f));//把物体在每个轴上缩小至0.2倍
//lightShader.setMat4("model", model);
//lightShader.setMat4("projection", projection);
//lightShader.setMat4("view", view);
//glBindVertexArray(VAO);
//glDrawArrays(GL_TRIANGLES, 0, 36);
modelShader.use();
model = glm::mat4(1.0f);
model = glm::translate(model, cubePositions[0]);//把数组传进去给每一个新建的模型在世界坐标下有不同的位移
angle = 20.0f * 1 * (float)glfwGetTime();//给一个glfwGetTime让模型旋转起来
model = glm::rotate(model, glm::radians(angle) * 0, glm::vec3(1.0f, 0.5f, 0.5f));//rotate 模型位置 旋转角 旋转轴
modelShader.setMat4("model", model);//设置模型变换矩阵
modelShader.setMat4("projection", projection);//设置投影变化矩阵
modelShader.setMat4("view", view);//设置视图变化矩阵
modelShader.setVec3("objectColor", 1, 0.5, 0.5);//设置物体的颜色
modelShader.setVec3("lightColor", 1, 1, 1);//设置光源的颜色当然也可以设置一个uniform来设置变量进行设置
//modelShader.setVec3("lightPos", lightPos);//设置光源位置
modelShader.setVec3("viewPos", cameraPos);//将相机的位置设置为观察位置
//设置材质的每个uniform分量
modelShader.setVec3("material.ambient", 1.0f, 1.0f, 1.0f);
/*modelShader.setVec3("material.diffuse", 1.0f, 0.5f, 0.31f);
modelShader.setVec3("material.specular", 0.5f, 0.5f, 0.5f);*/
modelShader.setFloat("material.shininess", 32.0f);
//设置光照uniform分量
modelShader.setVec3("light.ambient", 0.2f, 0.2f, 0.2f);
modelShader.setVec3("light.diffuse", 0.5f, 0.5f, 0.5f);
modelShader.setVec3("light.specular", 1.0f, 1.0f, 1.0f);
modelShader.setVec3("light.direction", -0.2f, -1.0f, -0.3f);//设置平行光
modelShader.setVec3("light.position", lightPos);
//设置物体颜色随着时间变化而变化
//glm::vec3 lightColor;
//lightColor.x = sin(glfwGetTime() * 2.0f);
//lightColor.y = sin(glfwGetTime() * 0.7f);
//lightColor.z = sin(glfwGetTime() * 1.3f);
//glm::vec3 diffuseColor = lightColor * glm::vec3(0.5f); // 降低影响
//glm::vec3 ambientColor = diffuseColor * glm::vec3(0.2f); // 很低的影响
//modelShader.setVec3("light.ambient", ambientColor);
//modelShader.setVec3("light.diffuse", diffuseColor);
//点光源光衰弱系数
modelShader.setFloat("light.constant", 1.0f);
modelShader.setFloat("light.linear", 0.14f);
modelShader.setFloat("light.quadratic", 0.07f);
//激活纹理
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2);
for (unsigned int i = 0; i < 10; i++)
{
glm::mat4 model;
model = glm::translate(model, cubePositions[i]);
float angle = 20.0f * i;
model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));
modelShader.setMat4("model", model);
glBindVertexArray(VAO2);
glDrawArrays(GL_TRIANGLES, 0, 36);
}
glfwSwapBuffers(window);
glfwPollEvents();
}
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glfwTerminate();
return 0;
}
void processInput(GLFWwindow* window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
float cameraSpeed = 5.5f * deltaTime;; // adjust accordingly
if (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;
if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS)//这里给了一个空格键使我们可以在Y轴上移动
cameraPos += cameraUp * cameraSpeed;
//cameraPos.y = 0.0f;
//可以通过把Y方向上的向量设置为0来使他成为一个FPS类型的摄像机只能在XZ平面上移动
}
void mouse_callback(GLFWwindow* window, double xposIn, double yposIn)
{
float xpos = static_cast<float>(xposIn);
float ypos = static_cast<float>(yposIn);
// 这个bool变量初始时是设定为true的
//我们在一开始的时候需要把他设为屏幕的中心点
//如果不这样干 程序一开始就会调用回调函数指向你鼠标进去的时候所在屏幕的位置
//这样就离中心点很远了
if (firstMouse)
{
lastX = xpos;
lastY = ypos;
firstMouse = false;
}
//然后在鼠标的回调函数中我们计算当前帧和上一帧鼠标位置的偏移量:
float xoffset = xpos - lastX;
float yoffset = lastY - ypos; // y坐标是从下到上
lastX = xpos;
lastY = ypos;
float sensitivity = 0.1f; // sensitivity这个值可以随便设置
xoffset *= sensitivity;
yoffset *= sensitivity;
yaw += xoffset;
pitch += yoffset;
// 为了保证摄像机不会整个翻车
if (pitch > 89.0f)
pitch = 89.0f;
if (pitch < -89.0f)
pitch = -89.0f;
//在xz平面上看向Y轴
//这里我们只更新了y值,仔细观察x和z分量也被影响了。从三角形中我们可以看到它们的值等于:
//direction.x = cos(glm::radians(pitch));
//direction.y = sin(glm::radians(pitch)); // 注意我们先把角度转为弧度
//direction.z = cos(glm::radians(pitch));//这里Y轴更新确实会影响到Z轴但是不是很懂为什么直接等于cos(pitch)
//
//
//
//这里我们只更新了y值,仔细观察x和z分量也被影响了。从三角形中我们可以看到它们的值等于:
//direction.x = cos(glm::radians(yaw));
//direction.y =1 // Y不变
//direction.z = sin(glm::radians(yaw));
//
//下面的等式相当于是先俯仰角的旋转变换完成之后再乘以这个偏航角
//把上面两步合起来
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)
{
//yoffset就是我们滚轮竖直滚动的方向
if (fov >= 1.0f && fov <= 45.0f)
fov -= yoffset;
//为他设定一个边界 在1到45之间
if (fov < 1.0f)
fov = 1.0f;
if (fov > 45.0f)
fov = 45.0f;
}
点光源
衰减公式看着吓人其实我们只需要用那个公式 然后根据那个衰减表调整参数即可 点光源就是一个能够配置位置和衰减的光源 ![在这里插入图片描述](https://img-blog.csdnimg.cn/a0554982287840e9ba4e9031f25da8b5.png) ![在这里插入图片描述](https://img-blog.csdnimg.cn/7bce6b8afc314c90bb1efc6217c006f6.png) ![在这里插入图片描述](https://img-blog.csdnimg.cn/6f561dca16f5486e9e7e49d5d4fbc477.png) ![在这里插入图片描述](https://img-blog.csdnimg.cn/0d137ae72b144135a7dd0088fb0af240.png)//PointLight.fs 得到第1种图的效果
#version 330 core
out vec4 FragColor;
struct Material {
sampler2D diffuse;
sampler2D specular;
float shininess;
};
struct Light {
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
float constant;//常数项
float linear;//一次项
float quadratic;//二次项
float cutOff;//SpotDir(聚光所指向)的方向与LightDir(从片段指向光源的向量)夹角的余弦值
};
in vec3 FragPos;
in vec3 Normal;
in vec2 TexCoords;
uniform vec3 viewPos;
uniform Material material;
uniform Light light;
void main()
{
// ambient
vec3 ambient = texture(material.diffuse, TexCoords).rgb;
//环境光分量=光的初始环境光分量*漫反射材质纹理 相当于告诉着色器环境光会受到material.diffuse材质的影响
//材质在主函数里面由set传入
// diffuse
vec3 norm = normalize(Normal);//标准化法向量
vec3 lightDir = normalize(light.position - FragPos);
//vec3 lightDir = normalize(-light.direction); //方向向量direction"来模拟平行光 对light.direction向量取反。
//我们目前使用的光照计算需求一个从片段至光源的光线方向,但人们更习惯定义定向光为一个从光源出发的全局方向。
float diff = max(dot(norm, lightDir), 0.0);//点乘算出法线和反射光线夹角
vec3 diffuse = light.diffuse * diff * texture(material.diffuse, TexCoords).rgb;
//告诉着色器漫反射会受到material.diffuse材质的影响
// specular
vec3 viewDir = normalize(viewPos - FragPos);//人的视角方向 是从物体指向观察者
vec3 reflectDir = reflect(-lightDir, norm);//告诉入射光和法线 reflect计算出反射光的向量
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);//material.shininess高光级别2 4 8 16 32 64 128等级越低光圈越模糊
vec3 specular = light.specular * spec * texture(material.specular, TexCoords).rgb;
//告诉着色器高光会受到material.diffuse材质的影响
float distance = length(light.position - FragPos);//衰减距离
float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));//光照衰减公式
//分母:要求前面为线性衰减快一点 后面为二次项越到后面衰减越慢 常项+一次项+二次项 距离越大二次项对这个函数影响越大
ambient *= attenuation;
diffuse *= attenuation;
specular *= attenuation;
vec3 result = ambient + diffuse + specular;
FragColor = vec4(result, 1.0);
}
//PointLight.fs2得到第2种图的效果
#version 330 core
out vec4 FragColor;
struct Material {
sampler2D diffuse;
sampler2D specular;
float shininess;
};
struct Light {
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
float constant;//常数项
float linear;//一次项
float quadratic;//二次项
float cutOff;//SpotDir(聚光所指向)的方向与LightDir(从片段指向光源的向量)夹角的余弦值
};
in vec3 FragPos;
in vec3 Normal;
in vec2 TexCoords;
uniform vec3 viewPos;
uniform Material material;
uniform Light light;
void main()
{
// ambient
vec3 ambient = light.ambient * texture(material.diffuse, TexCoords).rgb;
//环境光分量=光的初始环境光分量*漫反射材质纹理 相当于告诉着色器环境光会受到material.diffuse材质的影响
//材质在主函数里面由set传入
// diffuse
vec3 norm = normalize(Normal);//标准化法向量
vec3 lightDir = normalize(light.position - FragPos);
//vec3 lightDir = normalize(-light.direction); //方向向量direction"来模拟平行光 对light.direction向量取反。
//我们目前使用的光照计算需求一个从片段至光源的光线方向,但人们更习惯定义定向光为一个从光源出发的全局方向。
float diff = max(dot(norm, lightDir), 0.0);//点乘算出法线和反射光线夹角
vec3 diffuse = light.diffuse * diff * texture(material.diffuse, TexCoords).rgb;
//告诉着色器漫反射会受到material.diffuse材质的影响
// specular
vec3 viewDir = normalize(viewPos - FragPos);//人的视角方向 是从物体指向观察者
vec3 reflectDir = reflect(-lightDir, norm);//告诉入射光和法线 reflect计算出反射光的向量
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);//material.shininess高光级别2 4 8 16 32 64 128等级越低光圈越模糊
vec3 specular = light.specular * spec * texture(material.specular, TexCoords).rgb;
//告诉着色器高光会受到material.diffuse材质的影响
float distance = length(light.position - FragPos);//衰减距离
float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));//光照衰减公式
//分母:要求前面为线性衰减快一点 后面为二次项越到后面衰减越慢 常项+一次项+二次项 距离越大二次项对这个函数影响越大
ambient *= attenuation;
diffuse *= attenuation;
specular *= attenuation;
vec3 result = ambient + diffuse + specular;
FragColor = vec4(result, 1.0);
}
//LightingMaps
#include "Shader.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#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>
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void processInput(GLFWwindow* window);
// settings
const unsigned int SCR_WIDTH = 800; //定义屏幕空间的大小
const unsigned int SCR_HEIGHT = 600;
// camera
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; // 偏航初始化为-90.0度,因为偏航为0.0会导致指向右边的方向向量,所以我们最初向左旋转了一点。
float pitch = 0.0f; //初始化俯仰角
float lastX = 800.0f / 2.0;//为了把初始位置设置为屏幕中心所以取屏幕空间大小的一半
float lastY = 600.0 / 2.0;
float fov = 45.0f;//初始的视场角
// timing
float deltaTime = 0.0f; // time between current frame and last frame
float lastFrame = 0.0f;
glm::vec3 lightPos(1.2f, 1.0f, 2.0f);
//glm::vec3 lightPos(1.2f, 1.0f, 2.0f);
void processInput(GLFWwindow* window);
float vertices[] = {
// positions // normals // texture coords
-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
};
//定义一个vec3类型的数组来存位移矩阵
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),
};
int main()
{
//Glfw:初始化和配置
// ------------------------------
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
//glfw窗口创建
// --------------------
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);//使用定义的屏幕空间的大小
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetCursorPosCallback(window, mouse_callback);
glfwSetScrollCallback(window, scroll_callback);
//首先我们要告诉GLFW,它应该隐藏光标,并捕捉(Capture)它。
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
//加载所有OpenGL函数指针
// ---------------------------------------
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// 配置全局opengl状态
// -----------------------------
glEnable(GL_DEPTH_TEST);
// 构建并编译我们的shader程序
// ------------------------------------
Shader ourShader("shaderSampler.vs", "shaderSampler.fs");
Shader modelShader("PointLight.vs", "PointLight.fs");
Shader lightShader("lightShader.vs", "lightShader.fs");
//建立和编译顶点数据(和缓冲区),配置顶点属性
// ------------------------------------------------------------------
unsigned int VBO, VAO, VAO2;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindVertexArray(VAO);
//位置属性
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
//之后在顶点着色器layout (location = 1) in vec3 aNormal;//告诉GPU位置1的属性
glGenVertexArrays(1, &VAO2);
glBindVertexArray(VAO2);
//glBindBuffer(GL_ARRAY_BUFFER, VBO);
//位置属性
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*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
// 加载并创建一个纹理
// -------------------------
unsigned int texture1, texture2;
// texture 1
// ---------
glGenTextures(1, &texture1);
glBindTexture(GL_TEXTURE_2D, texture1);
// 设置纹理wrapping参数
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// 设置纹理filtering参数
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//加载图像,创建纹理和生成mipmaps //多级原理纹理
int width, height, nrChannels;
stbi_set_flip_vertically_on_load(true); // 告诉stb_image.h在y轴上翻转已加载的纹理。
//为什么需要翻转Y轴是因为纹理图片开始位置是右上而我们顶点的坐标(0,0)点是左下
unsigned char* data = stbi_load("container2.png", &width, &height, &nrChannels, 0);
if (data)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
std::cout << "Failed to load texture" << std::endl;
}
stbi_image_free(data);
// texture 2
// ---------
glGenTextures(1, &texture2);
glBindTexture(GL_TEXTURE_2D, texture2);
// 设置纹理wrapping参数
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// 设置纹理filtering参数
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// load image, create texture and generate mipmaps
//data = stbi_load(("aotu.jpg"), &width, &height, &nrChannels, 0);
//data = stbi_load(("shanshui.jpg"), &width, &height, &nrChannels, 0);
data = stbi_load(("container2_specular.png"), &width, &height, &nrChannels, 0);
if (data)
{
//如果没有贴图请优先注意这个RGBA中的alpha(A)通道 如果你的贴图有alpha通道请务必使用RGBA模式否则无法显示贴图
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
std::cout << "Failed to load texture" << std::endl;
}
stbi_image_free(data);
// 为每个采样器告诉opengl它属于哪个纹理单元(只需要做一次)
// -------------------------------------------------------------------------------------------
modelShader.use();
modelShader.setInt("material.diffuse", 0);
modelShader.setInt("material.specular", 1);
// ourShader.setVec3("lightPos", lightPos);
//渲染循环
// -----------
while (!glfwWindowShouldClose(window))
{
float currentFrame = 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); // 清除上一帧的颜色缓冲 以及 深度测试缓冲
//激活着色器
float angle = 20.0f * 0 * (float)glfwGetTime();//给一个glfwGetTime让模型旋转起来
glm::mat4 projection = glm::mat4(1.0f);
glm::mat4 view = glm::mat4(1.0f);
glm::mat4 model = glm::mat4(1.0f);
//glm::vec3 lightPos = glm::vec3(cubePositions[10]);//光源位置
projection = glm::perspective(glm::radians(fov), 800.0f / 600.0f, 0.1f, 100.0f);//投影矩阵 参数:视口大小,屏幕宽高比,以及near和far
view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);//lookAt矩阵 参数:摄像机位置 ,观察目标的位置 ,竖直向上的方向
model = glm::translate(model, cubePositions[0]);//把数组传进去给每一个新建的模型在世界坐标下有不同的位移
model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));
lightShader.use();
//lightPos.x = 1.0f + sin(glfwGetTime()) * 2.0f;
//lightPos.y = sin(glfwGetTime() / 2.0f) * 1.0f;
model = glm::mat4(1.0f);
model = glm::translate(model, lightPos);//把数组传进去给每一个新建的模型在世界坐标下有不同的位移
angle = 20.0f * 2 * (float)glfwGetTime();//给一个glfwGetTime让模型旋转起来
model = glm::rotate(model, glm::radians(angle) , glm::vec3(1.0f, 0.3f, 0.5f));//旋转物体
model = glm::scale(model, glm::vec3(0.2f));//把物体在每个轴上缩小至0.2倍
lightShader.setMat4("model", model);
lightShader.setMat4("projection", projection);
lightShader.setMat4("view", view);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 36);
modelShader.use();
model = glm::mat4(1.0f);
model = glm::translate(model, cubePositions[0]);//把数组传进去给每一个新建的模型在世界坐标下有不同的位移
angle = 20.0f * 1 * (float)glfwGetTime();//给一个glfwGetTime让模型旋转起来
model = glm::rotate(model, glm::radians(angle) * 0, glm::vec3(1.0f, 0.5f, 0.5f));//rotate 模型位置 旋转角 旋转轴
modelShader.setMat4("model", model);//设置模型变换矩阵
modelShader.setMat4("projection", projection);//设置投影变化矩阵
modelShader.setMat4("view", view);//设置视图变化矩阵
modelShader.setVec3("objectColor", 1, 0.5, 0.5);//设置物体的颜色
modelShader.setVec3("lightColor", 1, 1, 1);//设置光源的颜色当然也可以设置一个uniform来设置变量进行设置
//modelShader.setVec3("lightPos", lightPos);//设置光源位置
modelShader.setVec3("viewPos", cameraPos);//将相机的位置设置为观察位置
//设置材质的每个uniform分量
modelShader.setVec3("material.ambient", 1.0f, 1.0f, 1.0f);
/*modelShader.setVec3("material.diffuse", 1.0f, 0.5f, 0.31f);
modelShader.setVec3("material.specular", 0.5f, 0.5f, 0.5f);*/
modelShader.setFloat("material.shininess", 32.0f);
//设置光照uniform分量
modelShader.setVec3("light.ambient", 0.2f, 0.2f, 0.2f);
modelShader.setVec3("light.diffuse", 0.5f, 0.5f, 0.5f);
modelShader.setVec3("light.specular", 1.0f, 1.0f, 1.0f);
modelShader.setVec3("light.direction", -0.2f, -1.0f, -0.3f);//设置平行光
modelShader.setVec3("light.position", lightPos);
//设置物体颜色随着时间变化而变化
//glm::vec3 lightColor;
//lightColor.x = sin(glfwGetTime() * 2.0f);
//lightColor.y = sin(glfwGetTime() * 0.7f);
//lightColor.z = sin(glfwGetTime() * 1.3f);
//glm::vec3 diffuseColor = lightColor * glm::vec3(0.5f); // 降低影响
//glm::vec3 ambientColor = diffuseColor * glm::vec3(0.2f); // 很低的影响
//modelShader.setVec3("light.ambient", ambientColor);
//modelShader.setVec3("light.diffuse", diffuseColor);
//点光源光衰弱系数
modelShader.setFloat("light.constant", 1.0f);
modelShader.setFloat("light.linear", 0.14f);
modelShader.setFloat("light.quadratic", 0.07f);
//激活纹理
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2);
for (unsigned int i = 0; i < 10; i++)
{
glm::mat4 model;
model = glm::translate(model, cubePositions[i]);
float angle = 20.0f * i;
model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));
modelShader.setMat4("model", model);
glBindVertexArray(VAO2);
glDrawArrays(GL_TRIANGLES, 0, 36);
}
glfwSwapBuffers(window);
glfwPollEvents();
}
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glfwTerminate();
return 0;
}
void processInput(GLFWwindow* window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
float cameraSpeed = 5.5f * deltaTime;; // adjust accordingly
if (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;
if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS)//这里给了一个空格键使我们可以在Y轴上移动
cameraPos += cameraUp * cameraSpeed;
//cameraPos.y = 0.0f;
//可以通过把Y方向上的向量设置为0来使他成为一个FPS类型的摄像机只能在XZ平面上移动
}
void mouse_callback(GLFWwindow* window, double xposIn, double yposIn)
{
float xpos = static_cast<float>(xposIn);
float ypos = static_cast<float>(yposIn);
// 这个bool变量初始时是设定为true的
//我们在一开始的时候需要把他设为屏幕的中心点
//如果不这样干 程序一开始就会调用回调函数指向你鼠标进去的时候所在屏幕的位置
//这样就离中心点很远了
if (firstMouse)
{
lastX = xpos;
lastY = ypos;
firstMouse = false;
}
//然后在鼠标的回调函数中我们计算当前帧和上一帧鼠标位置的偏移量:
float xoffset = xpos - lastX;
float yoffset = lastY - ypos; // y坐标是从下到上
lastX = xpos;
lastY = ypos;
float sensitivity = 0.1f; // sensitivity这个值可以随便设置
xoffset *= sensitivity;
yoffset *= sensitivity;
yaw += xoffset;
pitch += yoffset;
// 为了保证摄像机不会整个翻车
if (pitch > 89.0f)
pitch = 89.0f;
if (pitch < -89.0f)
pitch = -89.0f;
//在xz平面上看向Y轴
//这里我们只更新了y值,仔细观察x和z分量也被影响了。从三角形中我们可以看到它们的值等于:
//direction.x = cos(glm::radians(pitch));
//direction.y = sin(glm::radians(pitch)); // 注意我们先把角度转为弧度
//direction.z = cos(glm::radians(pitch));//这里Y轴更新确实会影响到Z轴但是不是很懂为什么直接等于cos(pitch)
//
//
//
//这里我们只更新了y值,仔细观察x和z分量也被影响了。从三角形中我们可以看到它们的值等于:
//direction.x = cos(glm::radians(yaw));
//direction.y =1 // Y不变
//direction.z = sin(glm::radians(yaw));
//
//下面的等式相当于是先俯仰角的旋转变换完成之后再乘以这个偏航角
//把上面两步合起来
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)
{
//yoffset就是我们滚轮竖直滚动的方向
if (fov >= 1.0f && fov <= 45.0f)
fov -= yoffset;
//为他设定一个边界 在1到45之间
if (fov < 1.0f)
fov = 1.0f;
if (fov > 45.0f)
fov = 45.0f;
}
聚光(Spotlight)
//Spotlight.vs
#version 330 core
layout (location = 0) in vec3 aPos;//初始位置为0的属性为顶点位置
layout (location = 1) in vec3 aNormal;//初始位置为1的属性为法线位置
layout (location = 2) in vec2 aTexCoords;//初始位置为2的属性为贴图坐标
out vec3 FragPos;//输出物体的位置
out vec3 Normal;//输出法线
out vec2 TexCoords;//输出贴图
uniform mat4 model;//定义全局变量model 在主函数中设置
uniform mat4 view;//定义全局变量view 在主函数中设置
uniform mat4 projection;//定义全局变量projection 在主函数中设置
void main()
{
FragPos = vec3(model * vec4(aPos, 1.0));
//物体经过模型变换后在世界坐标的位置
Normal = mat3(transpose(inverse(model))) * aNormal;
//法线变换矩阵=逆矩阵的转置*法线矩阵
TexCoords = aTexCoords;
//贴图坐标
gl_Position = projection * view * vec4(FragPos, 1.0);//最后在视锥里面你看到的位置
}
//Spotlight.fs
#version 330 core
out vec4 FragColor;
struct Material {
sampler2D diffuse;
sampler2D specular;
float shininess;
};
struct Light {
vec3 position;
vec3 direction;
float cutOff;//定义一个内圆锥
float outerCutOff;//定义一个外圆锥
vec3 ambient;
vec3 diffuse;
vec3 specular;
float constant;//常数项
float linear;//一次项
float quadratic;//二次项
};
in vec3 FragPos;
in vec3 Normal;
in vec2 TexCoords;
uniform vec3 viewPos;
uniform Material material;
uniform Light light;
void main()
{
vec3 lightDir = normalize(light.position - FragPos);//计算lightDir 物体指向光源的向量
//之后使用这个向量来计算theta角
// check if lighting is inside the spotlight cone
float theta = dot(lightDir, normalize(-light.direction)); //点成出来的theta余弦值
if(theta > light.cutOff) // 这里比较的是余弦值大小角度在0-90度越大余弦值越小所以这里是>符号
{
//下面的就和前面一样了
// ambient
vec3 ambient = light.ambient * texture(material.diffuse, TexCoords).rgb;
// diffuse
vec3 norm = normalize(Normal);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = light.diffuse * diff * texture(material.diffuse, TexCoords).rgb;
// specular
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
vec3 specular = light.specular * spec * texture(material.specular, TexCoords).rgb;
// attenuation衰减项
float distance = length(light.position - FragPos);
float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));
// ambient *= attenuation;
// 从环境中去除衰减,否则在大的距离上,由于在else分支中的环境项,光将比聚光灯内部更暗
diffuse *= attenuation;
specular *= attenuation;
vec3 result = ambient + diffuse + specular;
FragColor = vec4(result, 1.0);
}
else
{
//如果在圆锥外面就用环境光照
FragColor = vec4(light.ambient * texture(material.diffuse, TexCoords).rgb, 1.0);
}
}
//LightingMaps
#include "Shader.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#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>
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void processInput(GLFWwindow* window);
// settings
const unsigned int SCR_WIDTH = 800; //定义屏幕空间的大小
const unsigned int SCR_HEIGHT = 600;
// camera
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; // 偏航初始化为-90.0度,因为偏航为0.0会导致指向右边的方向向量,所以我们最初向左旋转了一点。
float pitch = 0.0f; //初始化俯仰角
float lastX = 800.0f / 2.0;//为了把初始位置设置为屏幕中心所以取屏幕空间大小的一半
float lastY = 600.0 / 2.0;
float fov = 45.0f;//初始的视场角
// timing
float deltaTime = 0.0f; // time between current frame and last frame
float lastFrame = 0.0f;
glm::vec3 lightPos(1.2f, 1.0f, 2.0f);
//glm::vec3 lightPos(1.2f, 1.0f, 2.0f);
void processInput(GLFWwindow* window);
float vertices[] = {
// positions // normals // texture coords
-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
};
//定义一个vec3类型的数组来存位移矩阵
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),
};
int main()
{
//Glfw:初始化和配置
// ------------------------------
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
//glfw窗口创建
// --------------------
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);//使用定义的屏幕空间的大小
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetCursorPosCallback(window, mouse_callback);
glfwSetScrollCallback(window, scroll_callback);
//首先我们要告诉GLFW,它应该隐藏光标,并捕捉(Capture)它。
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
//加载所有OpenGL函数指针
// ---------------------------------------
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// 配置全局opengl状态
// -----------------------------
glEnable(GL_DEPTH_TEST);
// 构建并编译我们的shader程序
// ------------------------------------
Shader ourShader("shaderSampler.vs", "shaderSampler.fs");
Shader modelShader("Spotlight.vs", "Spotlight.fs");
Shader lightShader("lightShader.vs", "lightShader.fs");
//建立和编译顶点数据(和缓冲区),配置顶点属性
// ------------------------------------------------------------------
unsigned int VBO, VAO, VAO2;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindVertexArray(VAO);
//位置属性
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
//之后在顶点着色器layout (location = 1) in vec3 aNormal;//告诉GPU位置1的属性
glGenVertexArrays(1, &VAO2);
glBindVertexArray(VAO2);
//glBindBuffer(GL_ARRAY_BUFFER, VBO);
//位置属性
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*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
// 加载并创建一个纹理
// -------------------------
unsigned int texture1, texture2;
// texture 1
// ---------
glGenTextures(1, &texture1);
glBindTexture(GL_TEXTURE_2D, texture1);
// 设置纹理wrapping参数
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// 设置纹理filtering参数
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//加载图像,创建纹理和生成mipmaps //多级原理纹理
int width, height, nrChannels;
stbi_set_flip_vertically_on_load(true); // 告诉stb_image.h在y轴上翻转已加载的纹理。
//为什么需要翻转Y轴是因为纹理图片开始位置是右上而我们顶点的坐标(0,0)点是左下
unsigned char* data = stbi_load("container2.png", &width, &height, &nrChannels, 0);
if (data)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
std::cout << "Failed to load texture" << std::endl;
}
stbi_image_free(data);
// texture 2
// ---------
glGenTextures(1, &texture2);
glBindTexture(GL_TEXTURE_2D, texture2);
// 设置纹理wrapping参数
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// 设置纹理filtering参数
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// load image, create texture and generate mipmaps
//data = stbi_load(("aotu.jpg"), &width, &height, &nrChannels, 0);
//data = stbi_load(("shanshui.jpg"), &width, &height, &nrChannels, 0);
data = stbi_load(("container2_specular.png"), &width, &height, &nrChannels, 0);
if (data)
{
//如果没有贴图请优先注意这个RGBA中的alpha(A)通道 如果你的贴图有alpha通道请务必使用RGBA模式否则无法显示贴图
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
std::cout << "Failed to load texture" << std::endl;
}
stbi_image_free(data);
// 为每个采样器告诉opengl它属于哪个纹理单元(只需要做一次)
// -------------------------------------------------------------------------------------------
modelShader.use();
modelShader.setInt("material.diffuse", 0);
modelShader.setInt("material.specular", 1);
// ourShader.setVec3("lightPos", lightPos);
//渲染循环
// -----------
while (!glfwWindowShouldClose(window))
{
float currentFrame = 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); // 清除上一帧的颜色缓冲 以及 深度测试缓冲
//激活着色器
float angle = 20.0f * 0 * (float)glfwGetTime();//给一个glfwGetTime让模型旋转起来
glm::mat4 projection = glm::mat4(1.0f);
glm::mat4 view = glm::mat4(1.0f);
glm::mat4 model = glm::mat4(1.0f);
//glm::vec3 lightPos = glm::vec3(cubePositions[10]);//光源位置
projection = glm::perspective(glm::radians(fov), 800.0f / 600.0f, 0.1f, 100.0f);//投影矩阵 参数:视口大小,屏幕宽高比,以及near和far
view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);//lookAt矩阵 参数:摄像机位置 ,观察目标的位置 ,竖直向上的方向
model = glm::translate(model, cubePositions[0]);//把数组传进去给每一个新建的模型在世界坐标下有不同的位移
model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));
//lightShader.use();
lightPos.x = 1.0f + sin(glfwGetTime()) * 2.0f;
lightPos.y = sin(glfwGetTime() / 2.0f) * 1.0f;
//model = glm::mat4(1.0f);
//model = glm::translate(model, lightPos);//把数组传进去给每一个新建的模型在世界坐标下有不同的位移
//angle = 20.0f * 2 * (float)glfwGetTime();//给一个glfwGetTime让模型旋转起来
//model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));//旋转物体
//model = glm::scale(model, glm::vec3(0.2f));//把物体在每个轴上缩小至0.2倍
//lightShader.setMat4("model", model);
//lightShader.setMat4("projection", projection);
//lightShader.setMat4("view", view);
//glBindVertexArray(VAO);
//glDrawArrays(GL_TRIANGLES, 0, 36);
modelShader.use();
model = glm::mat4(1.0f);
model = glm::translate(model, cubePositions[0]);//把数组传进去给每一个新建的模型在世界坐标下有不同的位移
angle = 20.0f * 1 * (float)glfwGetTime();//给一个glfwGetTime让模型旋转起来
model = glm::rotate(model, glm::radians(angle) * 0, glm::vec3(1.0f, 0.5f, 0.5f));//rotate 模型位置 旋转角 旋转轴
modelShader.setMat4("model", model);//设置模型变换矩阵
modelShader.setMat4("projection", projection);//设置投影变化矩阵
modelShader.setMat4("view", view);//设置视图变化矩阵
modelShader.setVec3("objectColor", 1, 0.5, 0.5);//设置物体的颜色
modelShader.setVec3("lightColor", 1, 1, 1);//设置光源的颜色当然也可以设置一个uniform来设置变量进行设置
//modelShader.setVec3("lightPos", lightPos);//设置光源位置
modelShader.setVec3("viewPos", cameraPos);//将相机的位置设置为观察位置
//设置材质的每个uniform分量
modelShader.setVec3("material.ambient", 1.0f, 1.0f, 1.0f);
/*modelShader.setVec3("material.diffuse", 1.0f, 0.5f, 0.31f);
modelShader.setVec3("material.specular", 0.5f, 0.5f, 0.5f);*/
modelShader.setFloat("material.shininess", 32.0f);
//设置光照uniform分量
modelShader.setVec3("light.ambient", 0.1f, 0.1f, 0.1f);
modelShader.setVec3("light.diffuse", 0.8f, 0.8f, 0.8f);
modelShader.setVec3("light.specular", 1.0f, 1.0f, 1.0f);
modelShader.setVec3("light.direction", 0.0f, 0.0f, -1.0f);//设置平行光
modelShader.setVec3("light.position", 0.0f,0.0f,5.0f);//可以调整光的位置来调整圆锥的范围
modelShader.setFloat("light.cutOff", glm::cos(glm::radians(12.5f)));//设置内圆锥
modelShader.setFloat("light.outerCutOff", glm::cos(glm::radians(17.5f)));//设置外圆锥
//设置物体颜色随着时间变化而变化
//glm::vec3 lightColor;
//lightColor.x = sin(glfwGetTime() * 2.0f);
//lightColor.y = sin(glfwGetTime() * 0.7f);
//lightColor.z = sin(glfwGetTime() * 1.3f);
//glm::vec3 diffuseColor = lightColor * glm::vec3(0.5f); // 降低影响
//glm::vec3 ambientColor = diffuseColor * glm::vec3(0.2f); // 很低的影响
//modelShader.setVec3("light.ambient", ambientColor);
//modelShader.setVec3("light.diffuse", diffuseColor);
//点光源光衰弱系数
modelShader.setFloat("light.constant", 1.0f);
modelShader.setFloat("light.linear", 0.09f);
modelShader.setFloat("light.quadratic", 0.032f);
//激活纹理
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2);
for (unsigned int i = 0; i < 10; i++)
{
glm::mat4 model;
model = glm::translate(model, cubePositions[i]);
float angle = 20.0f * i;
model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));
modelShader.setMat4("model", model);
glBindVertexArray(VAO2);
glDrawArrays(GL_TRIANGLES, 0, 36);
}
glfwSwapBuffers(window);
glfwPollEvents();
}
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glfwTerminate();
return 0;
}
void processInput(GLFWwindow* window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
float cameraSpeed = 5.5f * deltaTime;; // adjust accordingly
if (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;
if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS)//这里给了一个空格键使我们可以在Y轴上移动
cameraPos += cameraUp * cameraSpeed;
//cameraPos.y = 0.0f;
//可以通过把Y方向上的向量设置为0来使他成为一个FPS类型的摄像机只能在XZ平面上移动
}
void mouse_callback(GLFWwindow* window, double xposIn, double yposIn)
{
float xpos = static_cast<float>(xposIn);
float ypos = static_cast<float>(yposIn);
// 这个bool变量初始时是设定为true的
//我们在一开始的时候需要把他设为屏幕的中心点
//如果不这样干 程序一开始就会调用回调函数指向你鼠标进去的时候所在屏幕的位置
//这样就离中心点很远了
if (firstMouse)
{
lastX = xpos;
lastY = ypos;
firstMouse = false;
}
//然后在鼠标的回调函数中我们计算当前帧和上一帧鼠标位置的偏移量:
float xoffset = xpos - lastX;
float yoffset = lastY - ypos; // y坐标是从下到上
lastX = xpos;
lastY = ypos;
float sensitivity = 0.1f; // sensitivity这个值可以随便设置
xoffset *= sensitivity;
yoffset *= sensitivity;
yaw += xoffset;
pitch += yoffset;
// 为了保证摄像机不会整个翻车
if (pitch > 89.0f)
pitch = 89.0f;
if (pitch < -89.0f)
pitch = -89.0f;
//在xz平面上看向Y轴
//这里我们只更新了y值,仔细观察x和z分量也被影响了。从三角形中我们可以看到它们的值等于:
//direction.x = cos(glm::radians(pitch));
//direction.y = sin(glm::radians(pitch)); // 注意我们先把角度转为弧度
//direction.z = cos(glm::radians(pitch));//这里Y轴更新确实会影响到Z轴但是不是很懂为什么直接等于cos(pitch)
//
//
//
//这里我们只更新了y值,仔细观察x和z分量也被影响了。从三角形中我们可以看到它们的值等于:
//direction.x = cos(glm::radians(yaw));
//direction.y =1 // Y不变
//direction.z = sin(glm::radians(yaw));
//
//下面的等式相当于是先俯仰角的旋转变换完成之后再乘以这个偏航角
//把上面两步合起来
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)
{
//yoffset就是我们滚轮竖直滚动的方向
if (fov >= 1.0f && fov <= 45.0f)
fov -= yoffset;
//为他设定一个边界 在1到45之间
if (fov < 1.0f)
fov = 1.0f;
if (fov > 45.0f)
fov = 45.0f;
}
边缘模糊化处理
只需要使用这个公式即可 改变fs
//Spotlight.fs
#version 330 core
out vec4 FragColor;
struct Material {
sampler2D diffuse;
sampler2D specular;
float shininess;
};
struct Light {
vec3 position;
vec3 direction;
float cutOff;
float outerCutOff;
vec3 ambient;
vec3 diffuse;
vec3 specular;
float constant;
float linear;
float quadratic;
};
in vec3 FragPos;
in vec3 Normal;
in vec2 TexCoords;
uniform vec3 viewPos;
uniform Material material;
uniform Light light;
void main()
{
// ambient
vec3 ambient = light.ambient * texture(material.diffuse, TexCoords).rgb;
// diffuse
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(light.position - FragPos);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = light.diffuse * diff * texture(material.diffuse, TexCoords).rgb;
// specular
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
vec3 specular = light.specular * spec * texture(material.specular, TexCoords).rgb;
// spotlight (soft edges)
//直接乘上这个影响公式 利用算出的theta和epsilon
float theta = dot(lightDir, normalize(-light.direction));
float epsilon = (light.cutOff - light.outerCutOff);
float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0);
diffuse *= intensity;
specular *= intensity;
// attenuation
float distance = length(light.position - FragPos);
float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));
ambient *= attenuation;
diffuse *= attenuation;
specular *= attenuation;
vec3 result = ambient + diffuse + specular;
FragColor = vec4(result, 1.0);
}