本篇blog讲一下关于材质的知识。
在前面中,我们通过设定几个光照分量以及物体本身的颜色,实现了物体的视觉输出(就是人眼看到的啦)。
设置材质:我们可以通过进一步地整合数据,来对物体的颜色进行更加严格的控制,既环境光照,漫反射光照,镜面光照三个分量,再加上反光度(为了方便理解,我们把这几个分量看成是物体本身的属性,也就是材质,同各个光照分量对应)。共四个分量,我们可以通过结构体来整合数据:
struct Material { vec3 ambient; vec3 diffuse; vec3 specular; float shininess; }; uniform Material material;
在主程序,我们可以传入数据:
//in the main.cpp void main() { ... somethingShader.setVec3("material.ambient", 1.0f, 0.5f, 0.31f); somethingShader.setVec3("material.diffuse", 1,0f, 0.5f, 0.31f); somethingShader.setVec3("material.specular", 0.5f, 0.5f, 0.5f); somethingShader.setFloat("material.shininess", 32.0f); ... }
这里将物体的ambient和diffuse分量都设置为物体本来的颜色,而将specular设置为0.5是因为高光程度过高。接着,我们可以在片段着色器里面这么做:
//fragment shader void main() { vec3 ambient = light * material.ambient; ...... ...... vec3 result = ambient + diffuse + specular; FragColor = vec4(result, 1.0f); }
这里和上一篇blog其实没有本质区别,上一篇blog我们是这么写的:
//fragment shader void main() { float ambientStrength = 0.1f; float ambient = light * ambientStrength; glm::vec3 result = ambient * coral; FragColor = vec4(result, 1.0f); }
注:只看ambient部分,coral是物体的颜色,而material.ambient也是物体的颜色,两者都是将光源乘以物体本身颜色,要说有区别的话,就是原来的ambient实际上是光强度罢了(下面我们会将这个光强度也补齐)。
既然没有本质区别,那么我们为什么要这样做呢?答案是处于结构化的思维,并且我们可以直接在main.cpp函数中更改数据(而不用在fragment shader中去更改)
光的属性:在前面的blog中,我们还加入了强度这个东西,而引入它是因为光照强度的问题,不经过处理的话,物体的ambient, diffuse, specular会全力反射光,造成很亮眼的结果。因此这里,我们尝试创建单独的光照属性来影响每个单独的光照向量(请记住,本质上这和前面的strength没有任何区别,只是出于结构化的思维,以及可以直接在main.cpp函数中更改它。
这里我们创建一个和材质差不多的结构体:
struct Light { vec3 position; vec3 ambient; vec3 diffuse; vec3 specular; }; uniform Light light;
传入数据:
lightingShader.setVec3("light.ambient", 0.2f, 0.2f, 0.2f); lightingShader.setVec3("light.diffuse", 0.5f, 0.5f, 0.5f); // 将光照调暗了一些以搭配场景 lightingShader.setVec3("light.specular", 1.0f, 1.0f, 1.0f);
然后更新着色器对应的代码:
vec3 ambient = light.ambient * material.ambient; vec3 diffuse = light.diffuse * (diff * material.diffuse); vec3 specular = light.specular * (spec * material.specular);
result = ambient + diffuse + specular;
这样子就完成了。
请记住,这种写法和前面的blog没有本质上的区别,只是出于结构化的思维,以及我们可以在main.cpp函数中*地操纵数据。