OpenGL着色器与Phong光照明模型

本篇博客主要讨论在OpenGL的着色器中实现光照明模型。在我们组的项目中,采用Phong模型来解决光线与材质相互作用的问题。

首先简单介绍下Phong照明模型。如下图所示

OpenGL着色器与Phong光照明模型_第1张图片

其中,向量n是表面在p点处的法向量。向量v是从p点指向观察者的向量。L是从点p指向点光源的向量(对于非点光源,向量L可以是点p指向拓展光源上任意一点的向量)向量r的方向是根据是向量l的方向按照反射定律计算出的出射光线的方向。换句话说,向量r的方向由向量L和向量n决定。对于模型中的任意一点来说,向量L,向量n和向量v都是已知的,需要我们计算的只有向量r。

Phong光照模型考虑了光线和材质间的三种作用:漫反射,镜面反射和环境光反射。

根据Phong光照模型,某一点的光线强度可以表示为


其中,La,Ld,Ls分别为环境光反射光强,漫反射光强和镜面反射光强。Ra,Rd,Rs分别环境光反射率,漫反射光反射率和镜面反射率。

这里省略推导过程,直接给出Phong模型的结论


其中,d代表从光源到p点的距离,a b c均为代表距离衰减的常数。α代表材质的高光系数(这个高光系数只与材质有关)


以上是标准的Phong反射模型,为了减少计算量,我们小组采用了改进的Phong模型。

OpenGL着色器与Phong光照明模型_第2张图片

半角向量h位于向量l和向量v正中间。改进后,我们可以用n·h代替r·v。这样,我们就避免了对于每个点都需要计算向量r。


下面贴出着色器的实现代码。

#version 330 core

// input variables from vertex shder.
in vec3 v_position;
in vec3 v_normal;

// Automatic parameters.
uniform vec3 g_camera_position;

// Automatic parameters for lighting.
struct LightProperties {
	vec3 ambient;
	vec3 color;
	vec3 direction;
};
const int MAX_LIGHTS = 1;
uniform LightProperties g_lights[MAX_LIGHTS];
uniform int g_light_count;

// Material parameters for phong shading.
uniform vec3 m_diffuse = vec3(0.5, 0.5, 0.5);
uniform vec3 m_specular = vec3(0.0, 0.0, 0.0);
uniform float m_shininess = 0;

// output variable about fragment color.
out vec4 frag_color;

void main() {
	vec3 ambient = vec3(0.0);
	vec3 diffuse = vec3(0.0);
	vec3 specular = vec3(0.0);

	for (int i = 0; i < g_light_count; i++) {
		// Get the i-th light.
		LightProperties light = g_lights[i];

		vec3 light_direction = -normalize(light.direction);
		vec3 normal = normalize(v_normal);

		// Calculate the ambient component.
		ambient += m_diffuse * light.ambient;
		// Calculate the diffuse component.
		diffuse += m_diffuse * light.color * max(0, dot(normal, light_direction));

		vec3 view_direction = normalize(g_camera_position - v_position);
		vec3 half_vector = normalize(light_direction + view_direction);

		// Calculate the speculat component.
		specular += m_specular * light.color * pow(max(0, dot(normal, half_vector)), m_shininess);
	}
	
	vec3 color = min(ambient + diffuse + specular, vec3(1.0f));
	frag_color = vec4(color, 1.0);
	// frag_color = vec4(1.0f, 1.0f, 1.0f, 1.0f);
}

着色器的输入是要计算的点的坐标v_position以及法向量v_normal

几个uniform变量,g_camera_position表示摄像机的坐标值(将用来计算phong模型中的向量v),m_diffuse,m_specular分别为漫反射反射率和镜面反射反射率。(在绝大多数情况下,漫反射反射率和环境光反射反射率都相同,本段代码中m_diffuse也代表环境光反射的反射率)

m_shinness代表了材质的高光系数

分别计算出该点的环境光分量,漫反射光分量和镜面反射光分量ambient,diffuse和specular。三者的和即为该点的光线值。

你可能感兴趣的:(OpenGL着色器与Phong光照明模型)