08 - OpenGL ES学习之材质

在现实世界里,每个物体会对光产生不同的反应。比如说钻石看起来闪闪发光,塑料看起来就回暗一些。表面比较光滑的反射光的时候会产生亮点,表面比较粗糙一点的,反射光会形成一个光斑。

在上一篇文章中,我们指定了一个物体和光的颜色,以及结合环境光和镜面强度分量,来定义物体的视觉输出。当描述一个物体的时候,我们可以用这三个分量来定义一个材质颜色(Material Color):环境光照(Ambient Lighting)、漫反射光照(Diffuse Lighting)和镜面光照(Specular Lighting)。通过为每个分量指定一个颜色,我们就能够对物体的颜色输出有着精细的控制了。现在,我们再添加反光度(Shininess)这个分量到上述的三个颜色中,这就有我们需要的所有材质属性了:

我们创建一个结构体来表示材质:

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

ambient 表示在环境光照下这个物体反射的颜色,通常这个是和物体相同的颜色,diffuse定义了在漫反射光照下物体的颜色(和环境光照一样),specular设置的是镜面光照对物体的颜色影响,最后,shineness影响镜面高光的散射/半径(这里可以举个例子解释:比如光照到比较粗糙的表面,可能散射的光圈半径就大一些,照到类似玻璃,钢铁这类物体的表面,形成的光斑直径就很小)。
这四个元素定义了一个物体的材质,通过它们,我们能模拟出很多现实世界中的材质。但是要想模拟出很真实的效果,这些参数需要很多次实验才能得到较为准确的结果。
让我们接着上一篇的代码,用材质结构体代替物体颜色来模拟物体的效果
顶点着色器如下:

#version 300 es
precision mediump float;

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

uniform vec3 lightColor;
//光源位置
uniform vec3 lightPos;

//观察点的位置
uniform vec3 viewPos;

//物体材质
uniform Material material;

in vec3 Normal;
in vec3 fragPos;

out vec4 gColor;

void main() {
    //计算环境光照
    vec3 ambient =  lightColor * material.ambient;
    
    //计算漫反射
    vec3 norm = normalize(Normal);
    vec3 lightDirection = normalize(lightPos - fragPos);
    
    float diffu = dot(norm,lightDirection);
    vec3 diffuse = lightColor * (diffu * material.diffuse);
    
    //计算镜面光照
    
    //观察向量
    vec3 viewDirection = normalize(viewPos - fragPos);
    //反射向量
    vec3 reflectDirection = reflect(-lightDirection,norm);
    
    float spec = pow(max(dot(viewDirection,reflectDirection), 0.0) , material.shineness);
    
    vec3 specular =  lightColor * (spec * material.specular);

    //最终颜色(这里指定物体颜色为红色)
    vec3 result = ambient + diffuse + specular;

    gColor = vec4(result,1.0);
}

这里我们假定lightColor为(1.0,1.0,1.0),也就是白光

得到的效果如图:


IMG_6706.PNG

这里我们看到了效果,大致是对的,但是会不会很奇怪,为什么这么亮,在上一篇文章中,我们通过一个环境光照强度和镜面光照强度来控制这两个分量对最终颜色的影响,而这里我们去掉了这两个强度,所以相当于环境光照,漫反射光照和镜面光照对物体颜色的影响都是以1.0的强度处理的,所以这里特别亮。

这一步的代码对应的是Cube_material-01文件夹

那么接下来我们改进这一点,我们定义一个结构体Light:

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

我们通过改变Light的三个参数 ambient ,diffuse, specular来改变每种光照的强度,

修改后的顶点着色器:

precision mediump float;

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

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

uniform vec3 lightColor;
//光源位置
uniform vec3 lightPos;

//观察点的位置
uniform vec3 viewPos;

//物体材质
uniform Material material;

//光照的属性
uniform Light light;

in vec3 Normal;
in vec3 fragPos;

out vec4 gColor;

void main() {
    //计算环境光照
    vec3 ambient =  light.ambient * material.ambient;
    
    //计算漫反射
    vec3 norm = normalize(Normal);
    vec3 lightDirection = normalize(lightPos - fragPos);
    
    float diffu = dot(norm,lightDirection);
    vec3 diffuse = light.diffuse * (diffu * material.diffuse);
    
    //计算镜面光照
    
    //观察向量
    vec3 viewDirection = normalize(viewPos - fragPos);
    //反射向量
    vec3 reflectDirection = reflect(-lightDirection,norm);
    
    float spec = pow(max(dot(viewDirection,reflectDirection), 0.0) , material.shineness);
    
    vec3 specular =  light.specular * (spec * material.specular);

    //最终颜色(这里指定物体颜色为红色)
    vec3 result = ambient + diffuse + specular;

    gColor = vec4(result,1.0);

}

注意这几处的修改:


修改

这里我们设置的光的颜色还是白色光 vec3(1.0,1.0,1.0);

这里我们传入Light结构体,对这几种光照强度进行设置:


glUniform3f(glGetUniformLocation(_esContext.program, "material.ambient"), 1.0, 0.5, 0.31);
    glUniform3f(glGetUniformLocation(_esContext.program, "material.diffuse"), 1.0, 0.5, 0.31);
    glUniform3f(glGetUniformLocation(_esContext.program, "material.specular"), 0.5, 0.5, 0.5);
    glUniform1f(glGetUniformLocation(_esContext.program, "material.shineness"), 32.f);
    
    glUniform3f(glGetUniformLocation(_esContext.program, "light.ambient"), 0.2 ,0.2, 0.2);
    glUniform3f(glGetUniformLocation(_esContext.program, "light.diffuse"), 0.5, 0.5, 0.5);
    glUniform3f(glGetUniformLocation(_esContext.program, "light.specular"), 1.0, 1.0, 1.0);

效果如图:


最终效果

这样看上去是不是比较接近真实效果了。
这一步对的代码对应Cube_material-02这个文件夹

彩蛋

现实世界中,环境光可能不只是单一的颜色,现在我们做一个变动,根据时间来改变环境光的颜色,看看有什么不一样的效果。
代码如下:

 //构建一个随时间改变光照颜色
    float r = sin(self.elapsedTime * 1.2);
    float g = sin(self.elapsedTime * 1.3);
    float b = sin(self.elapsedTime * 1.7);
    
    GLKVector3  lightColor = GLKVector3Make(r, g, b);
    
    GLKVector3 lightAmbient = GLKVector3Make(0.2, 0.2, 0.2);
    GLKVector3 lightDiffuse = GLKVector3Make(0.5, 0.5, 0.5);
    
    lightAmbient = GLKVector3Multiply(lightColor, lightAmbient);
    lightDiffuse = GLKVector3Multiply(lightColor, lightDiffuse);
    
    glUniform3fv(glGetUniformLocation(_esContext.program, "light.ambient"), 1, lightAmbient.v);
    glUniform3fv(glGetUniformLocation(_esContext.program, "light.diffuse"), 1, lightDiffuse.v);
    glUniform3f(glGetUniformLocation(_esContext.program, "light.specular"), 1.0, 1.0, 1.0);

我们这里传入随时间改变的颜色进去,然后乘到环境光和漫射光的参数上。最终效果如下:


RPReplay_Final1638942312.gif

这里通过改变环境光,影响物体最终的颜色输出,是不是类似呼吸灯的效果?
这一步的代码对应文件夹Cube_material-03。

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

推荐阅读更多精彩内容