从0开始的OpenGL学习(十二)-材质

本文主要解决一个问题:

如何使用材质控制光照效果?

引言

真实世界里,每个物体对光的反射属性都不同。铁轮子永远都比木轮子要闪亮。物体对于镜面高光的反应也不同。有些物体没有太多散射,就呈现出一个集中的亮斑;有些物体的散射多,就不会有那么小那么亮的亮斑了。如何描述物体的这些特性,我们就需要一个新的概念,那就是:材质!

材质

之前的章节中,我们指定了物体和光源的颜色,用环境光强度和散射光强度来物体的反射属性。使用材质属性的时候,我们依旧需要指定描述环境光、漫反射光和镜面高光的分量。除此之外,我们还需要一个光泽度(shininess)参数(还记得前一篇文章中的32吗?)用来表示镜面高光的发散范围。

我们的材质结构也就成型了:

#version 330 core
struct Material {
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
    float shininess;
}; 
  
uniform Material material;

在片元着色器中,我们创建了一个材质结构来保存物体的材质属性。有了这四个分量之后,我们就能模拟一些真实世界中的物体了(之后会模拟一个宝石绿的颜色)。

要得到物体的精确材质是一件非常费时又费力的事情,而用一个不正确的材质毁掉物体本来该有的视觉效果确实非常容易的事。

让我们在着色器中来实现这样一个材质系统。

使用材质

既然我们已经在片元着色器中创建了一个材质结构,接下来要做的就是使用材质属性来计算光照效果。GLSL中引用结构体中的成员和C语言中一样,采用material.ambient的形式就可以:

void main()
{
    //环境光
    vec3 ambient = lightColor * material.ambient;

    //漫反射光
    vec3 norm = normalize(Normal);
    vec3 lightDir = normalize(LightPos - FragPos);  

    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = lightColor * (diff * material.diffuse);

    //镜面高光
    vec3 viewDir = normalize( - FragPos);
    vec3 reflectDir = reflect(-lightDir, norm);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
    vec3 specular = lightColor * (spec * material.specular) ;

    vec3 result = ambient + diffuse + specular;
    FragColor = vec4(result, 1.0f);
}

就如代码中写的那样,我们用材质的属性乘上光照颜色作为光照的效果。要设置材质的属性,只能设置材质结构中的某个属性,而不能直接设置整个材质结构。所以,设置的代码就只能是下面这个样子:

lightingShader.setVec3("material.ambient",  1.0f, 0.5f, 0.31f);
lightingShader.setVec3("material.diffuse",  1.0f, 0.5f, 0.31f);
lightingShader.setVec3("material.specular", 0.5f, 0.5f, 0.5f);
lightingShader.setFloat("material.shininess", 32.0f);

设置完之后,编译运行应该能看到这样的效果:

运行效果

是不是感觉有点奇怪?

光照属性

对比一下前一章的代码,我们发现,我们的material.ambient数值并不是0.1这样小的数值,而是几乎把所有光都反射回去了。从另一个角度来讲,一个光源对环境光、漫反射光和镜面高光的贡献应该也是不同的。对环境光的贡献应该很小,漫反射光应该次之,镜面高光最大。所以,这次我们不改material.ambient的数值,而是为光源也设置光源属性。

struct Light{
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
};
uniform Light light;

添加了光源的属性之后,我们也需要更新一下光照计算的代码。

vec3 ambient = lightColor * material.ambient * light.ambient;
vec3 diffuse = lightColor * (diff * material.diffuse) * light.diffuse;
vec3 specular = lightColor * (spec * material.specular) * light.specular;

然后,在主函数中设置光照属性:

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);

编译运行之后,效果应该是这样子:

运行效果

如果你显示的不对,可以参考这里的代码。

实现一个绿宝石的颜色

正如之前所说的,要得到一个正确的材质并不容易,我们可以一个个数据去试验,但这太浪费时间了。下面一张表是有人整理出来的,我们照方抓药就行。

材质表

设置材质的属性,并且将光源的属性为1.0f,表中的光泽度需要乘上128才能使用,如下所示:

lightingShader.setVec3("material.ambient", 0.0215f, 0.1745f, 0.0215f);
lightingShader.setVec3("material.diffuse", 0.07568f, 0.61424f, 0.07568f);
lightingShader.setVec3("material.specular", 0.633f, 0.727811f, 0.633f);
lightingShader.setFloat("material.shininess", 128 * 0.6f);
lightingShader.setVec3("light.ambient", 1.0f, 1.0f, 1.0f);
lightingShader.setVec3("light.diffuse", 1.0f, 1.0f, 1.0f);
lightingShader.setVec3("light.specular", 1.0f, 1.0f, 1.0f);
运行效果

总结

本章我们学习了使用材质来整理物体对光照的反射程度,并且实现了一个绿宝石的材质,非常简单,只是需要实践。

下一篇
目录
上一篇

参考资料

https://www.learningopengl.com(非常好的网站,建议学习)
http://devernay.free.fr/cours/opengl/materials.html(材质表)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容