LearnOpenGL note - Lighting:Materials

OpenGL光照系列3

Posted by Tao on Thursday, March 3, 2022

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

结果与上一节结果一致 result

「如果这篇文章对你有用,请随意打赏」

Heisenberg Blog

如果这篇文章对你有用,请随意打赏

使用微信扫描二维码完成支付


comments powered by Disqus