欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Modern OpenGL :光照shader

程序员文章站 2023-12-27 10:29:33
...

Modern OpenGL :光照shader

1. 前言

  采用shader实现了标准? 冯氏光照模型。

2. 数学背景

老生长谈了。

  • 光照模型:冯氏光照模型(环境光+漫反射+镜面反射)
  • 光源类型:点光源

环境光通常是一个常量
ambient=Caambient= C_{a}

漫反射与面的法向量N和光线向量L有关
diffuse=Cdmax(dot(N,L),0)diffuse = C_{d} * max (dot (N , L),0)

镜面反射与面的法向量N和光线向量L以及视线向量V有关
specular=Csmax(dot(V,reflect(L,N)),0)shininessspecular = C_{s} * max (dot (V , reflect(-L,N)),0)^{shininess}

不同于平行光,点光源还有一个属性。其光照强度随距离D缩减
attenuation=1D2attenuation = \frac{1}{D^2}
但是此公式在物体及其接近光源的时候亮度会及其高,因此一般采用如下变种
attenuation=1C+AD+BD2attenuation = \frac{1}{C + A*D + B* D^2}

3. 实现

Modern OpenGL :光照shader
Modern OpenGL :光照shader
矩阵库是我自己的渣渣实现这里就不献丑放出来了,读者用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;
}

相关标签: 图形 OpenGL c++

上一篇:

下一篇: