0 前言
本节笔记对应的内容为材质,部分内容参考自傅老師/OpenGL教學 第二章。
上一节光照02中,我们学习了Phong光照模型,这一节我们来封装材质类。
在现实世界里,每个物体会对光产生不同的反应。比如说,钢看起来通常会比陶瓷花瓶更闪闪发光,木头箱子也不会像钢制箱子那样对光产生很强的反射。每个物体对镜面高光也有不同的反应。有些物体反射光的时候不会有太多的散射(Scatter),因而产生一个较小的高光点,而有些物体则会散射很多,产生一个有着更大半径的高光点。如果我们想要在OpenGL中模拟多种类型的物体,我们必须为每个物体分别定义一个材质(Material)属性。
1 着色器
在片段着色器中,我们创建一个结构体(Struct)来储存物体的材质属性。我们也可以把它们储存为独立的uniform值,但是作为一个结构体来储存会更有条理一些。
#version 330 core
struct Material {
vec3 ambient;
vec3 diffuse;
vec3 specular;
float shininess;
};
uniform Material material;
我们为每个Phong Model的分量都定义一个颜色向量。ambient材质向量定义了在环境光照下这个物体反射得是什么颜色\(k_a\),通常这是和物体颜色相同的颜色。diffuse材质向量定义了在漫反射光照下物体的颜色\(k_d\)。(和环境光照一样)漫反射颜色也要设置为我们需要的物体颜色\(k_s\)。specular材质向量设置的是镜面光照对物体的颜色影响(或者甚至可能反射一个物体特定的镜面高光颜色)。最后,shininess影响镜面高光的半径,参数为\(p\)。
片元着色器完整代码为:
#version 330 core
in vec3 FragPos;
in vec3 Normal;
struct Material {
vec3 ambient;
vec3 diffuse;
vec3 specular;
float shininess;
};
uniform Material material;
uniform vec3 objColor;
uniform vec3 ambientColor;
uniform vec3 lightPos;
uniform vec3 lightColor;
uniform vec3 cameraPos;
out vec4 FragColor;
void main() {
vec3 lightDir = normalize(lightPos - FragPos);
vec3 reflectVec = reflect(-lightDir, Normal);
vec3 cameraVec = normalize(cameraPos - FragPos);
// specular
float specularAmount =
pow(max(dot(reflectVec, cameraVec), 0), material.shininess);
vec3 specular = material.specular * specularAmount * lightColor;
// diffuse
vec3 diffuse = material.diffuse * max(dot(lightDir, Normal), 0) * lightColor;
// ambient
vec3 ambient = material.ambient * ambientColor;
FragColor = vec4((diffuse + ambient + specular) * objColor, 1.0f);
}
并在loop中传入material结构体变量
glUniform3f(glGetUniformLocation(testShader->ID, "material.ambient"), 0.2f, 0.2f 0.2f);
glUniform3f(glGetUniformLocation(testShader->ID, "material.diffuse"), 0, 0, 1.0f);
glUniform3f(glGetUniformLocation(testShader->ID, "material.specular"), 1.0f, 1.0f, 1.0f);
glUniform1f(glGetUniformLocation(testShader->ID, "material.shininess"), 64.0f);
2 Material类封装
新增Material类:
Material.h
#ifndef _MATERIAL_H_
#define _MATERIAL_H_
#include "Shader.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
class Material
{
public:
Shader * shader;
glm::vec3 diffuse;
glm::vec3 specular;
glm::vec3 ambient;
float shininess;
Material(Shader* _shader, glm::vec3 _diffuse, glm::vec3 _specular, glm::vec3 _ambient, float _shininess);
~Material();
};
#endif
Material.cpp
#include "Material.h"
Material::Material(Shader * _shader, glm::vec3 _diffuse, glm::vec3 _specular, glm::vec3 _ambient, float _shininess):
shader(_shader),
diffuse(_diffuse),
specular(_specular),
ambient(_ambient),
shininess(_shininess)
{
}
Material::~Material()
{
}
我们接下来改uniform,为了方便起见,我们把改uniform封装到shader里 在shader.h加上
# include <glm/glm.hpp>
# include <glm/gtc/matrix_transform.hpp>
# include <glm/gtc/type_ptr.hpp>
...
void SetUniform3f(const char*paraNameString,glm::vec3 param);
void SetUniform1f(const char* paraNameString, float param);
在shader.cpp加上
void Shader::SetUniform3f(const char * paraNameString, glm::vec3 param)
{
glUniform3f(glGetUniformLocation(ID, paraNameString), param.x, param.y, param.z);
}
void Shader::SetUniform1f(const char * paraNameString, float param)
{
glUniform1f(glGetUniformLocation(ID, paraNameString), param);
}
然后main中原来设置material的uniform部分改成
myMaterial->shader->SetUniform3f("material.ambient", myMaterial->ambient);
myMaterial->shader->SetUniform3f("material.specular", myMaterial->specular);
myMaterial->shader->SetUniform3f("material.diffuse", myMaterial->diffuse);
myMaterial->shader->SetUniform1f("material.shininess", myMaterial->shininess);
最后在main中初始化material,传入材质的相关参数
# include "Material.h"
......
# pragma region Init Material
Material* myMaterial = new Material(myShader,
glm::vec3 (1.0f, 0.5f, 0.31f),
glm::vec3 (0.5f, 0.5f, 0.5f),
glm::vec3 (1.0f, 0.5f, 0.31f),
150.0f);
# pragma endregion
结果与上一节结果一致
「如果这篇文章对你有用,请随意打赏」
如果这篇文章对你有用,请随意打赏
使用微信扫描二维码完成支付
comments powered by Disqus