天天看點

【OpenGL學習】材質材質

材質

在圖形學中,材質表示了光線如何和物體進行互動,有了解過 BRDF 的話,實際上 Material == BRDF,有關材質的講述,可以在這篇文章中了解:計算機圖形學(六)——材質 - 知乎 (zhihu.com)。

針對不同的物體,我們可以定義不同的材質屬性來進行區分,以此來獲得更加真實的效果。

一、添加材質屬性

當描述一個表面時,我們可以分别為三個光照分量定義一個材質顔色(Material Color):環境光照(Ambient Lighting)、漫反射光照(Diffuse Lighting)和鏡面光照(Specular Lighting)。另外再添加一個反光度(shininess)來控制物體的高光半徑,一般來說金屬具有更高的反光度。

struct Material
{
	vec3 ambient;
	vec3 diffuse;
	vec3 specular;
	float shininess;
};

uniform Material u_material;
           

ambient材質向量定義了在環境光照下這個表面反射的是什麼顔色,通常與表面的顔色相同。diffuse材質向量定義了在漫反射光照下表面的顔色。漫反射顔色(和環境光照一樣)也被設定為我們期望的物體顔色。specular材質向量設定的是表面上鏡面高光的顔色(或者甚至可能反映一個特定表面的顔色)。最後,shininess影響鏡面高光的散射/半徑。

二、設定材質

在片元着色器中建立了材質結構體并且建立了全局變量material 之後,需要對其屬性進行指定:

box_shader.set_vec3("material.ambient", glm::vec3(1.0f, 0.5f, 0.31f));
		box_shader.set_vec3("material.diffuse", glm::vec3(1.0f, 0.5f, 0.31f));
		box_shader.set_vec3("material.specular", glm::vec3(0.5f, 0.5f, 0.5f));
		box_shader.set_float("material.shininess", 35.0f);
           

然後在 shader 中進行計算:

vec3 ambient = light_color * material.ambient;

	vec3 normal = normalize(v_normal);
	vec3 light_dir = normalize(light_pos - v_world_pos);
	vec3 diffuse_color = light_color * max(0.0, dot(normal, light_dir)) * material.diffuse;
	
	vec3 view_dir = normalize(view_pos - v_world_pos);
	vec3 reflect_dir = reflect(-light_dir, normal);
	vec3 specular_color = light_color * pow(max(dot(view_dir, reflect_dir), 0.0), material.shininess) * material.specular;
	
	

	vec3 color = ambient + diffuse_color + specular_color;
           

運作檢視結果:

【OpenGL學習】材質材質

可以看到得到的立方體的亮度太亮了,這是因為環境光、漫反射和鏡面光這三個顔色都設定為 vec3(1.0f),顯然是有問題的,正确的做法是為每個光照分量分别指定一個強度向量。

三、添加光源屬性

和物體的材質一樣,我們同樣在shader中建立一個 Light 結構體來指定光源的屬性:

struct Light
{
	vec3 position;

	vec3 ambient;
	vec3 diffuse;
	vec3 specular;
};
           

一個光源對它的ambient、diffuse和specular光照分量有着不同的強度。環境光照通常被設定為一個比較低的強度,因為我們不希望環境光顔色太過主導。光源的漫反射分量通常被設定為我們希望光所具有的那個顔色,通常是一個比較明亮的白色。鏡面光分量通常會保持為

vec3(1.0)

,以最大強度發光。

在循環中進行 uniform 變量指定:

box_shader.set_vec3("light.position", light_pos);
		box_shader.set_vec3("light.ambient", ambient_color);
		box_shader.set_vec3("light.diffuse", diffuse_color);
		box_shader.set_vec3("light.specular", glm::vec3(1.0f, 1.0f, 1.0f));
           

之後重新進行計算:

vec3 ambient = light.ambient * material.ambient;

	vec3 normal = normalize(v_normal);
	vec3 light_dir = normalize(light.position - v_world_pos);
	vec3 diffuse_color = light.diffuse * max(0.0, dot(normal, light_dir)) * material.diffuse;
	
	vec3 view_dir = normalize(view_pos - v_world_pos);
	vec3 reflect_dir = reflect(-light_dir, normal);
	vec3 specular_color = light.specular * pow(max(dot(view_dir, reflect_dir), 0.0), material.shininess) * material.specular;
	
	

	vec3 color = ambient + diffuse_color + specular_color;
           

得到如下結果:

【OpenGL學習】材質材質

如果需要查閱代碼, GitHub 位址:OpenGL

繼續閱讀