Blinn-Phong光照
1|0颜色
颜色是由光的颜色乘物品的颜色得到的
光的颜色值不是比例,如果值大就亮,值小就暗。比如(1.0f, 1.0f, 1.0f)就比(0.2f, 0.2f, 0.2f)亮
fragmentshader
#version 330 core
out vec4 fragColor;
uniform vec3 lightcolor, objectcolor;
void main()
{
fragColor = vec4(lightcolor * objectcolor, 1.0f);
}
在main函数里,先定位location,再use那个program,然后再改uniform的值
unsigned int lightLoc = glGetUniformLocation(Cubeshader.ID, "lightcolor");
unsigned int objectLoc = glGetUniformLocation(Cubeshader.ID, "objectcolor");
Cubeshader.use();
glUniform3f(lightLoc, 1.0f, 1.0f, 1.0f);
glUniform3f(objectLoc, 0.5f, 1.0f, 0.4f);
或者在Shader函数里定义修改Uniform的方法:
void setMat4(const std::string &name, const glm::mat4 &mat)
{
glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, glm::value_ptr(mat));
}
void setvec3(const std::string &name, const glm::vec3 &vec)
{
glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, glm::value_ptr(vec));
}
void setvec3(const std::string &name, float x, float y, float z) const
{
glUniform3f(glGetUniformLocation(ID, name.c_str()), x, y, z);
}
main.cpp
Cubeshader.use();
Cubeshader.setvec3("lightcolor", 1.0f, 1.0f, 1.0f);
Cubeshader.setvec3("objectcolor", 0.5f, 1.0f, 0.4f);
然后VAO只记录了glBindBuffer绑定了的VBO的glVertexAttribPointer和glEnableVertexAttribArray的值,在使用这个着色器前需要先shader.use(),然后再改这个shader的uniform值
lightshader.use();
glm::mat4 model(1.0f);
model = glm::translate(model, lightPos);
view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
projection = glm::perspective(glm::radians(45.0f), (float)800 / (float)600, 0.1f, 100.0f);
lightshader.setMat4("model", model);
lightshader.setMat4("view", view);
lightshader.setMat4("projection", projection);
glBindVertexArray(lightVAO);
glDrawArrays(GL_TRIANGLES, 0, 36);
2|0光照
2|1漫反射diffuse
获得每个点的法向量,写在vertices属性里,光照不用法向量属性,物体用
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); //第一个是类型,第二个是大小,第三个是数据
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1);
glBindVertexArray(lightVAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
在顶点着色器里把顶点坐标转化到世界坐标系以备与法向量点积
FragPos = vec3(model * vec4(aPos, 1.0));
然后把法向量进行操作使之与view无关
Normal = mat3(transpose(inverse(model))) * aNormal;
并传到fragment shader里。
标准化的法向量与标准化了的(光源-顶点)做点积,得到cos
然后乘光照,就是这个点获得的光照强度
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(lightPos - FragPos);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = diff * lightcolor;
2|2镜面反射specular
视线向量(摄像机-物体)点积反射向量(vec3 reflectDir = reflect(-lightDir, norm);)函数,这个0-1之间的值再乘《高光度》次幂,就是高光分量
reflect函数第一个参数必须是光照的方向,需要上面的lightDir取反,第二个是标准化了的法线方向
fragmentshader
uniform viewPos;
float specularStrength = 0.5;
vec3 ViewDir = normalize(viewPos-FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(ViewDir, reflectDir),0.0), 32);
vec3 specular = specularStrength * spec * lightcolor;
3|0所有程序
#include<glad/glad.h>
#include<GLFW/glfw3.h>
#include<iostream>
#include<Shader.cpp>
#define STB_IMAGE_IMPLEMENTATION
#include<stb_image.h>
#include<glm/glm.hpp>
#include<glm/gtc/matrix_transform.hpp>
#include<glm/gtc/type_ptr.hpp>
glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f);
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
void processInput(GLFWwindow* window)
{
if (glfwGetKey(window, GLFW_KEY_KP_ENTER) == GLFW_PRESS or glfwGetKey(window, GLFW_KEY_ENTER) == GLFW_PRESS or glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
float cameraSpeed = 0.05f;
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 += cameraSpeed * glm::normalize(glm::cross(cameraUp, cameraFront));
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
cameraPos -= cameraSpeed * glm::normalize(glm::cross(cameraUp, cameraFront));
}
int main()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
//创建窗口对象
GLFWwindow* window = glfwCreateWindow(800, 600, "LJHyyds", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
//初始化GLAD管理指针,加载系统OpenGL函数指针
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to init GLAD" << std::endl;
return -1;
}
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
Shader Cubeshader("shader.vs", "shader.fs");
Shader lightshader("shader.vs", "lightshader.fs");
float vertices[] = {
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f
};
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)
};
unsigned int VBO, VAO, lightVAO;
glGenBuffers(1, &VBO);
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); //第一个是类型,第二个是大小,第三个是数据
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1);
glEnable(GL_DEPTH_TEST);
glGenVertexArrays(1, &lightVAO);
glBindVertexArray(lightVAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glm::vec3 lightPos(0.2f, 0.5f, 0.0f);
glm::mat4 view = glm::mat4(1.0f), projection = glm::mat4(1.0f);
while (!glfwWindowShouldClose(window))
{
processInput(window);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
Cubeshader.use();
Cubeshader.setvec3("lightcolor", 1.0f, 1.0f, 1.0f);
Cubeshader.setvec3("objectcolor", 0.5f, 1.0f, 0.4f);
Cubeshader.setvec3("lightPos", 0.2f, 0.5f, 0.0f);
Cubeshader.setvec3("viewPos", cameraPos);
for (unsigned int i = 0; i < 10; i++)
{
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, cubePositions[i]);
model = glm::rotate(model, glm::radians(20.0f*i), glm::vec3(1.0f, 0.2f, 0.3f));
view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
projection = glm::perspective(glm::radians(45.0f), (float)800 / (float)600, 0.1f, 100.0f);
Cubeshader.setMat4("model", model);
Cubeshader.setMat4("view", view);
Cubeshader.setMat4("projection", projection);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 36);
}
lightshader.use();
glm::mat4 model(1.0f);
model = glm::translate(model, lightPos);
view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
projection = glm::perspective(glm::radians(45.0f), (float)800 / (float)600, 0.1f, 100.0f);
lightshader.setMat4("model", model);
lightshader.setMat4("view", view);
lightshader.setMat4("projection", projection);
glBindVertexArray(lightVAO);
glDrawArrays(GL_TRIANGLES, 0, 36);
glfwSwapBuffers(window);
glfwPollEvents();
}
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
//关闭窗口
glfwTerminate();
return 0;
}
vertexshader
#version 330 core
layout (location=0) in vec3 aPos;
layout (location=1) in vec3 aNormal;
uniform mat4 transform, model, view, projection;
out vec3 Normal, FragPos;
void main()
{
gl_Position = projection * view * model * vec4(aPos, 1.0);
FragPos = vec3(model * vec4(aPos, 1.0));
Normal = mat3(transpose(inverse(model))) * aNormal;
}
fragment shader
#version 330 core
out vec4 fragColor;
in vec3 Normal, FragPos;
uniform vec3 lightcolor, objectcolor, lightPos, viewPos;
void main()
{
float ambientstrength = 0.1;
vec3 ambient = ambientstrength * lightcolor;
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(lightPos - FragPos);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = diff * lightcolor;
float specularStrength = 0.5;
vec3 ViewDir = normalize(viewPos-FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(ViewDir, reflectDir),0.0), 32);
vec3 specular = specularStrength * spec * lightcolor;
vec3 result = (ambient + diffuse + specular) * objectcolor;
fragColor = vec4(result, 1.0f);
}
shader类
#ifndef SHADER_H
#endif SHADER_H
#include<glad/glad.h>
#include<string>
#include<fstream>
#include<sstream>
#include<iostream>
#include<glm/glm.hpp>
#include<glm/gtc/matrix_transform.hpp>
#include<glm/gtc/type_ptr.hpp>
class Shader
{
public:
unsigned int ID;
Shader(const char* vertexPath, const char* fragmentPath)
{
using namespace std;
string vertexCode;
string fragmentCode;
ifstream vShaderFile;
ifstream fShaderFile;
vShaderFile.exceptions(ifstream::failbit | ifstream::badbit);
fShaderFile.exceptions(ifstream::failbit | ifstream::badbit);
try
{
vShaderFile.open(vertexPath);
fShaderFile.open(fragmentPath);
stringstream vShaderStream, fShaderStream;
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
vShaderFile.close();
fShaderFile.close();
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
}
catch (ifstream::failure e)
{
cout << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ" << endl;
}
const char* vShaderCode = vertexCode.c_str();
const char* fShaderCode = fragmentCode.c_str();
unsigned int vertexShader, fragmentShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vShaderCode, NULL);
glCompileShader(vertexShader);
int success;
char infolog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infolog);
cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infolog << endl;
}
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fShaderCode, NULL);
glCompileShader(fragmentShader);
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragmentShader, 512, NULL, infolog);
cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infolog << endl;
}
ID = glCreateProgram();
glAttachShader(ID, vertexShader);
glAttachShader(ID, fragmentShader);
glLinkProgram(ID);
glGetProgramiv(ID, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(ID, 512, NULL, infolog);
cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infolog << endl;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
}
void use()
{
glUseProgram(ID);
}
void setMat4(const std::string &name, const glm::mat4 &mat)
{
glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, glm::value_ptr(mat));
}
void setvec3(const std::string &name, const glm::vec3 &vec)
{
glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, glm::value_ptr(vec));
}
void setvec3(const std::string &name, float x, float y, float z) const
{
glUniform3f(glGetUniformLocation(ID, name.c_str()), x, y, z);
}
};
4|0材质
物体材质:
struct Material {
vec3 ambient;
vec3 diffuse;
vec3 specular;
float shininess;
};
uniform Material material;
光照参数:
struct Light {
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
uniform Light light;
最后的计算就要直接用material的颜色乘光的颜色
void main()
{
vec3 ambient = light.ambient * material.ambient;
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(light.position - FragPos);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = diff * light.diffuse * material.diffuse;
vec3 ViewDir = normalize(viewPos-FragPos);
vec3 reflectDir = reflect(-light.position, norm);
float spec = pow(max(dot(ViewDir, reflectDir),0.0), material.shininess);
vec3 specular = spec * light.specular * material.specular;
vec3 result = ambient + diffuse + specular;
fragColor = vec4(result, 1.0f);
}
fragmentshader
#version 330 core
struct Material{
vec3 ambient;
vec3 diffuse;
vec3 specular;
float shininess;
};
struct Light {
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
uniform Light light;
uniform Material material;
out vec4 fragColor;
in vec3 Normal, FragPos;
in vec2 TexCoords;
uniform vec3 viewPos;
void main()
{
vec3 ambient = light.ambient * material.ambient;
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(light.position - FragPos);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = diff * light.diffuse * material.diffuse;
vec3 ViewDir = normalize(viewPos-FragPos);
vec3 reflectDir = reflect(-lightDir, norm); //哭死,之前写成reflect(-light.position, norm)调了一天的bug
float spec = pow(max(dot(ViewDir, reflectDir),0.0), material.shininess);
vec3 specular = spec * light.specular * material.specular;
vec3 result = ambient + diffuse + specular;
fragColor = vec4(result, 1.0f);
}
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
__EOF__

本文链接:https://www.cnblogs.com/IamIron-Man/p/16616743.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端