Modern OpenGL :光照shader

11 篇文章 1 订阅
9 篇文章 0 订阅

Modern OpenGL :光照shader

1. 前言

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

2. 数学背景

老生长谈了。

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

环境光通常是一个常量
a m b i e n t = C a ambient= C_{a} ambient=Ca

漫反射与面的法向量N和光线向量L有关
d i f f u s e = C d ∗ m a x ( d o t ( N , L ) , 0 ) diffuse = C_{d} * max (dot (N , L),0) diffuse=Cdmax(dot(N,L),0)

镜面反射与面的法向量N和光线向量L以及视线向量V有关
s p e c u l a r = C s ∗ m a x ( d o t ( V , r e f l e c t ( − L , N ) ) , 0 ) s h i n i n e s s specular = C_{s} * max (dot (V , reflect(-L,N)),0)^{shininess} specular=Csmax(dot(V,reflect(L,N)),0)shininess

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

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()
{
	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;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值