[webGL] 小米炫彩后盖材质分析

未标题-2.gif

红米k40 webGL连接程序员

背景

在小米出mi 11的时候,就注意到小米商城app下有360全景体验手机的功能,第一次打开的时候给个人感受是很震撼,震撼的不是模型,而是看到它的炫彩后盖可以渲染的那么真,感受和真机是如出一辙的,而后我就本身下载了手机模型,本身去作材质,发现怎么都实现不了这种炫彩材质,兴趣一下就没了,心想,我一个程序员,关心材质干什么,直接让建模师给到不就得了。。。就这样通过了几个月web

发现

在最近时间,我在琢磨模型软件中的程序化着色器,在学习节点的过程当中,看到了有个属性是菲涅尔,以前也有了解菲涅尔是水等透射物体上的物理现象,当视线和法向量的夹角越小时,越不容易造成反射,而在角度接近90°时,反射愈来愈明显。以下图:markdown

00e93901213fb80e7becc013e798382eb9389a503e97.jpg

原本是对菲涅尔反射有点了解的,但基本都是透射物体上才能想到的物理知识点,彻底没有往炫彩材质上想,后来在单独对菲涅尔属性进行颜色输出时,忽然发现这个感受和炫彩后盖材质有点联系,效果以下:app

未标题-4.gif

可是又不太同样,我试着调整菲涅尔的方式,改成面朝向(其实也是菲涅尔,只是实现方式略有不一样),效果以下:oop

未标题-5.gif

在模型软件中,材质我作到这个效果的时候,我发现这个就是我想要的,感受和炫彩效果很是吻合,剩下的就是须要根据这个灰度改变颜色便可,因而我开始个人实践。学习

实现

下图是我作炫彩的所有流程,图片很大,能够放大查看:webgl

未标题-1.jpg

  1. 得出菲涅尔值

首先是最主要的,也是前半截文章说的菲涅尔值,这里就用到了向量的点乘概念,点乘的值简单来讲就是一个向量的长度乘以另外一个向量投影在第一个向量的长度,若是夹角为90°是,投影的长度为0,结果为0,若是夹角远离90°时,点乘的结果会愈来愈大。ui

有了上述知识,再来看下菲涅尔,菲涅尔的值就是根据视线和物体的表面向量去进行点乘计算得来的,而面向量很差求,相反,各个面的法向量咱们是知道的,因而就有了视线和法向量求点乘,获得的值,而后被1减去获得菲涅尔值(可是这里不须要被1减去,在混合颜色时,传入该值,颜色顺序对调便可)。spa

因而有了上图中左边的三个节点:3d

未标题-2.jpg

相关glsl代码以下(基于three):

//片元着色器
    float dot_6 = dot(normalize(vViewPosition), normalize(vNormal));
复制代码
  1. 根据菲涅尔值进行颜色混合

我在观察 mi11 蓝色款时,发现他其实又三个色调变化,从直视后盖到视线和后盖相切,依次变化是:

白/浅蓝交替变化 -> 深蓝 -> 白

以下图:

未标题-7.gif

其中第一个阶段到第二个阶段,以及第二个阶段到最后一个阶段很好理解,根据获得的菲涅尔值进行混合颜色处理,在深蓝到白的阶段时我对菲涅尔值微调,缘由是由于我不想让白色影响的范围太大,后盖和视线快相切的时候才会起做用,并作了一次平滑处理:

未标题-8.jpg

相关glsl代码以下(基于three):

//片元着色器
    ...
    vec4 mix_11 = mix( 
        vec4(150./256., 152./256., 161./256., 1.0), //深蓝
        mix_10, //白/浅蓝交替变化的混合颜色
        dot_6
    );
    vec4 mix_15 = mix(
        vec4(210./256., 214./256., 223./256., 1.0), //白
        mix_11, //前两个阶段的混合颜色
        smoothstep(0.0, 1.0, (dot_6 * 8.0))
    );
复制代码

接下来讲下第一个阶段(白/浅蓝交替变化),和以后的阶段有所不一样的是,这个阶段交替变化,而不是出现一次,个人作法一样是根据菲涅尔值去进行mix混合颜色的,可是会乘以一个倍数,使值大于PI,而后sin曲线和规格化(使值变为0~1), 这样就能够获得交替变化的灰度值,再根据这个值进行颜色混合,就完成全部步骤了,最后输出这个混合颜色便可:

未标题-9.jpg

相关glsl代码以下(基于three):

//片元着色器
    ...
    vec4 mix_10 = mix(
        vec4(194./256., 198./256., 212./256., 1.0), 
        vec4(220./256., 234./256., 243./256., 1.0), 
        ((sin((dot_6 * 20.0)) + 1.0) / 2.0)
    );
复制代码

示例:

我尝试吸收k40pro 白色款的三种颜色用上述着色器作demo,感受效果和预期一致。

999edc37231fdb2b55abbadd1f35608b.gif aa21e16fc5fceab595fa7fdb0b505934.gif

相关文章
相关标签/搜索