Modern OpenGL :光照shader
程序员文章站
2023-12-27 10:29:33
...
1. 前言
采用shader实现了标准? 冯氏光照模型。
2. 数学背景
老生长谈了。
- 光照模型:冯氏光照模型(环境光+漫反射+镜面反射)
- 光源类型:点光源
环境光通常是一个常量
漫反射与面的法向量N和光线向量L有关
镜面反射与面的法向量N和光线向量L以及视线向量V有关
不同于平行光,点光源还有一个属性。其光照强度随距离D缩减
但是此公式在物体及其接近光源的时候亮度会及其高,因此一般采用如下变种
3. 实现
矩阵库是我自己的渣渣实现这里就不献丑放出来了,读者用glm就可以了。
特别地,当我使用vec3.data()、mat4.data()时,意指获取储存在当前向量或矩阵的元素的数组指针。
顶点类型
class vertex
{
public:
vec3 position;
vec3 normal;
vec2 coord;
vec4 color;
};
顶点着色器
#version 430
layout (location = 0) uniform mat4 pvm;
layout (location = 1) uniform mat4 model;
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
layout (location = 2) in vec2 coord;
layout (location = 3) in vec4 color;
struct v2f{
vec3 normal;
vec2 coord;
vec4 color;
vec3 position;
};
out v2f vert_out;
void main(){
vec4 position_ = vec4(position,1);
vert_out.normal = mat3(transpose(inverse(model))) * normal;
vert_out.coord = coord;
vert_out.color = color;
vert_out.position = (model * position_).xyz;
gl_Position = pvm * position_;
}
片段着色器
#version 430
//layout (location = 1) uniform sampler2D sampler;
layout (location = 2) uniform vec4 light_position;
layout (location = 3) uniform vec4 light_ambient;
layout (location = 4) uniform vec4 light_diffuse;
layout (location = 5) uniform vec4 light_specular;
layout (location = 6) uniform vec3 eye;
float specular_intensity = 32.0;
out vec4 o;
struct v2f{
vec3 normal;
vec2 coord;
vec4 color;
vec3 position;
};
in v2f vert_out;
void main() {
vec3 normal = normalize(vert_out.normal);
vec3 ambient = light_ambient.xyz;
vec3 light_direction = normalize(light_position.xyz - vert_out.position);
float diffuse_factor = dot(normal,light_direction);
vec3 diffuse = vec3(0,0,0);
vec3 specular = vec3(0,0,0);
if (diffuse_factor > 0)
{
diffuse = light_diffuse.xyz * diffuse_factor ;
vec3 vertex_eye = normalize(eye -vert_out.position );
vec3 light_reflect = normalize(reflect(-light_direction, normal));
float specular_factor = dot(vertex_eye,light_reflect);
if (specular_factor > 0)
{
specular_factor = pow(specular_factor, specular_intensity);
specular = light_specular.xyz * specular_factor;
}
}
float distance = length(light_position.xyz - vert_out.position);
float attenuation = 10.0 / ( 1 + (distance*distance));
o = vert_out.color * vec4(ambient + (diffuse + specular) *attenuation,1);
}
全部实现
vec4 light_position = vec4(1, -1, 3, 0);
vec4 light_ambient(0.2, 0.2,0.2, 1);
vec4 light_diffuse(0.5, 0.5, 0.5,1);
vec4 light_specular(0.5, 0.5,0.5, 1);
vec3 eye(0, -3,3);
mat4 view = mat4::view(eye, vec3(0,0,0), vec3(0,1 ,0));
mat4 model_1(1.0);
mat4 model_2 = mat4::translate(0,0,0.5);
mat4 persp = matrix4::perspective(45.0*math::PId180, 800.0F/600.0F, 1.0F,1000.0f);
GLuint plane_vao;
GLuint cube_vao;
GLuint plane_vbo;
GLuint cube_vbo;
GLuint plane_ebo;
GLuint cube_ebo;
GLuint plane_ebo_size;
GLuint cube_ebo_size;
GLuint sphere_vao;
GLuint sphere_vbo;
GLuint sphere_ebo;
GLuint sphere_ebo_size;
GLuint shader_vert;
GLuint shader_frag;
GLuint program;
string vertex_shader =
R"(
#version 430
layout (location = 0) uniform mat4 pvm;
layout (location = 1) uniform mat4 model;
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
layout (location = 2) in vec2 coord;
layout (location = 3) in vec4 color;
struct v2f{
vec3 normal;
vec2 coord;
vec4 color;
vec3 position;
};
out v2f vert_out;
void main(){
vec4 position_ = vec4(position,1);
vert_out.normal = mat3(transpose(inverse(model))) * normal;
vert_out.coord = coord;
vert_out.color = color;
vert_out.position = (model * position_).xyz;
gl_Position = pvm * position_;
}
)";
string fragment_shader =
R"(
#version 430
//layout (location = 1) uniform sampler2D sampler;
layout (location = 2) uniform vec4 light_position;
layout (location = 3) uniform vec4 light_ambient;
layout (location = 4) uniform vec4 light_diffuse;
layout (location = 5) uniform vec4 light_specular;
layout (location = 6) uniform vec3 eye;
float specular_intensity = 32.0;
out vec4 o;
struct v2f{
vec3 normal;
vec2 coord;
vec4 color;
vec3 position;
};
in v2f vert_out;
void main() {
vec3 normal = normalize(vert_out.normal);
vec3 ambient = light_ambient.xyz;
vec3 light_direction = normalize(light_position.xyz - vert_out.position);
float diffuse_factor = dot(normal,light_direction);
vec3 diffuse = vec3(0,0,0);
vec3 specular = vec3(0,0,0);
if (diffuse_factor > 0)
{
diffuse = light_diffuse.xyz * diffuse_factor ;
vec3 vertex_eye = normalize(eye -vert_out.position );
vec3 light_reflect = normalize(reflect(-light_direction, normal));
float specular_factor = dot(vertex_eye,light_reflect);
if (specular_factor > 0)
{
specular_factor = pow(specular_factor, specular_intensity);
specular = light_specular.xyz * specular_factor;
}
}
float distance = length(light_position.xyz - vert_out.position);
float attenuation = 10.0 / ( 1 + (distance*distance));
o = vert_out.color * vec4(ambient + (diffuse + specular) *attenuation,1);
}
)";
void resource_init() // 纹理初始化
{
glEnable(GL_DEPTH_TEST);
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
glClearColor(0.f, 0.f, .3f, 1.f);
glViewport(0, 0, 800, 600);
vector<vertex> vertices =
{
{{-10,-10,0},{0,0,1},{0,0},{0.5,0.5,0.5,1}},
{{10,-10,0},{0,0,1},{1,0},{0.5,0.5,0.5,1}},
{ {10,10,0},{0,0,1},{1,1},{0.5,0.5,0.5,1}},
{{-10,10,0},{0,0,1},{0,1},{0.5,0.5,0.5,1}},
};
vector<GLuint> indices =
{
0,1,2,0,2,3,
};
glGenVertexArrays(1, &plane_vao);
glGenBuffers(1, &plane_vbo);
glGenBuffers(1, &plane_ebo);
glBindVertexArray(plane_vao);
glBindBuffer(GL_ARRAY_BUFFER, plane_vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex)*vertices.size(), vertices.data(), GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), (const void*)(0));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), (const void*)(sizeof(float[3])));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(vertex), (const void*)(sizeof(float[6])));
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, sizeof(vertex), (const void*)(sizeof(float[8])));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, plane_ebo);
plane_ebo_size = indices.size();
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)*plane_ebo_size, indices.data(), GL_STATIC_DRAW);
vertices =
{
{{-0.5,-0.5,0.5},{0,0,1},{0,0},{1,1,1,1}},
{{0.5,-0.5,0.5},{0,0,1},{1,0},{1,1,1,1}},
{{0.5,0.5,0.5},{0,0,1},{1,1},{1,1,1,1}},
{{-0.5,0.5,0.5},{0,0,1},{0,1},{1,1,1,1}},
{{-0.5,-0.5,-0.5},{0,0,-1},{0,0},{1,1,1,1}},
{{-0.5,0.5,-0.5},{0,0,-1},{0,1},{1,1,1,1}},
{{0.5,0.5,-0.5},{0,0,-1},{1,1},{1,1,1,1}},
{{0.5,-0.5,-0.5},{0,0,-1},{1,0},{1,1,1,1}},
{{-0.5,-0.5,0.5},{0,-1,0},{0,0},{1,1,1,1}},
{{-0.5,-0.5,-0.5},{0,-1,0},{1,0},{1,1,1,1}},
{{0.5,-0.5,-0.5},{0,-1,0},{1,1},{1,1,1,1}},
{{0.5,-0.5,0.5},{0,-1,0},{0,1},{1,1,1,1}},
{{0.5,-0.5,0.5},{1,0,0},{0,0},{1,1,1,1}},
{{0.5,-0.5,-0.5},{1,0,0},{1,0},{1,1,1,1}},
{{0.5,0.5,-0.5},{1,0,0},{1,1},{1,1,1,1}},
{{0.5,0.5,0.5},{1,0,0},{0,1},{1,1,1,1}},
{{0.5,0.5,0.5},{0,1,0},{0,0},{1,1,1,1}},
{{0.5,0.5,-0.5},{0,1,0},{1,0},{1,1,1,1}},
{{-0.5,0.5,-0.5},{0,1,0},{1,1},{1,1,1,1}},
{{-0.5,0.5,0.5},{0,1,0},{0,1},{1,1,1,1}},
{{-0.5,0.5,0.5},{-1,0,0},{0,0},{1,1,1,1}},
{{-0.5,0.5,-0.5},{-1,0,0},{1,0},{1,1,1,1}},
{{-0.5,-0.5,-0.5},{-1,0,0},{1,1},{1,1,1,1}},
{{-0.5,-0.5,0.5},{-1,0,0},{0,1},{1,1,1,1}},
};
indices =
{
0,1,2,0,2,3,
4,5,6,4,6,7,
8,9,10,8,10,11,
12,13,14,12,14,15,
16,17,18,16,18,19,
20,21,22,20,22,23,
};
glGenVertexArrays(1, &cube_vao);
glGenBuffers(1, &cube_vbo);
glGenBuffers(1, &cube_ebo);
glBindVertexArray(cube_vao);
glBindBuffer(GL_ARRAY_BUFFER, cube_vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex)*vertices.size(), vertices.data(), GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), (const void*)(0));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), (const void*)(sizeof(float[3])));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(vertex), (const void*)(sizeof(float[6])));
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, sizeof(vertex), (const void*)(sizeof(float[8])));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cube_ebo);
cube_ebo_size = indices.size();
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)*cube_ebo_size, indices.data(), GL_STATIC_DRAW);
glBindVertexArray(0);
GLint compiled = GL_FALSE;
shader_vert = glCreateShader(GL_VERTEX_SHADER);
const GLchar* src = reinterpret_cast<const GLchar*>(vertex_shader.data());
glShaderSource(shader_vert, 1, &src, NULL);
glCompileShader(shader_vert);
shader_frag = glCreateShader(GL_FRAGMENT_SHADER);
src = reinterpret_cast<const GLchar*>(fragment_shader.data());
glShaderSource(shader_frag, 1, &src, NULL);
glCompileShader(shader_frag);
program = glCreateProgram();
glAttachShader(program , shader_vert);
glAttachShader(program , shader_frag);
glLinkProgram(program );
GLint size;
glGetProgramiv(program , GL_INFO_LOG_LENGTH, &size);
if (size > 0) {
xgc::list<char> str(size);
GLint len;
glGetProgramInfoLog(program , size, &len, str.data());
cout << str.data() << endl;
}
}
float rotate_ = 0.0;
void _Render()
{
//---------------------------------------第1次绘制,生成深度纹理--------
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// 将摄像机放置在光源位置,投影矩阵和视图矩阵
rotate_ += 0.01f;
//vec4 light_position = (-vec4(cos(rotate_), sin(rotate_), 1, 0)) .normalize();
auto R = mat4::rotate(vec3(1, 0, 0), rotate_);
glUseProgram(program );
glUniform4fv(2, 1, light_position.data());
glUniform4fv(3, 1, light_ambient.data());
glUniform4fv(4, 1, light_diffuse.data());
glUniform4fv(5, 1, light_specular.data());
glUniform3fv(6, 1, eye.data());
auto pvm = persp * view * model_1;
glUniformMatrix4fv(0, 1, GL_FALSE, pvm.data());
glUniformMatrix4fv(1, 1, GL_FALSE, model_1.data());
glBindVertexArray(plane_vao);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, plane_ebo);
glDrawElements(GL_TRIANGLES, plane_ebo_size, GL_UNSIGNED_INT, NULL);
auto _model = model_2 * R;
pvm = persp * view * _model;
glUniformMatrix4fv(0, 1, GL_FALSE, pvm.data());
glUniformMatrix4fv(1, 1, GL_FALSE, _model.data());
glBindVertexArray(cube_vao);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cube_ebo);
glDrawElements(GL_TRIANGLES, cube_ebo_size, GL_UNSIGNED_INT, NULL);
}
int main(int argc, char** argv, char** envp)
{
auto hr = glfwInit();
glfwSetErrorCallback(error_callback);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); // OpenGL主版本号
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // OpenGL副版本号
glfwWindowHint(GLFW_RESIZABLE, GL_TRUE); //可改变大小
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
hwnd = glfwCreateWindow(800, 600, "GLFW Window", NULL, NULL);
glfwSetInputMode(hwnd, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE);
glfwMakeContextCurrent(hwnd);
glfwSwapInterval(1);
glfwSetFramebufferSizeCallback(hwnd, (GLFWframebuffersizefun)size_changed);
glfwSetKeyCallback(hwnd, (GLFWkeyfun)key_board);
glfwSetMouseButtonCallback(hwnd, MouseEvent);
glfwSetScrollCallback(hwnd, MouseScrollEvent);
auto err = glewInit();
if (GLEW_OK != err) {
std::cerr << "GLEW Error : " << glewGetErrorString(err) << std::endl;
return err;
}
resource_init();
while (!glfwWindowShouldClose(hwnd)) {
_Render();
glfwSwapBuffers(hwnd);
glfwPollEvents();
}
glfwDestroyWindow(hwnd);
glfwTerminate();
return 0;
}