最近沉迷做后处理效果,无法自拔~真的太有趣了,我基本上一天能做一个,哈哈哈。

今天想跟大家分享的效果,应用范围非常广,而且很有趣呀。

基于该系列第一篇文章的内容,我们先创建 RampImageEffect.shader 和 RampImageEffect.cs 两个文件。如果大家眼尖的话,看文件命名就能马上猜到“哇!是不是要放ramp纹理?”“Bingo!" 其实在做角色的时候,我们经常会把halfLambert放入UV中,但今天我会把它放入后处理里面。

什么是Ramp纹理呢?

把模型的明暗梯度当成uv,采样横向长的纹理(Ramp纹理,其实横纵的数据都可用,但今天我暂且只用横向数据...)。看上去好像是纹理一一对应包裹了模型,这个技术叫Diffuse Warp,这里使用的纹理是Ramp texture。

这个技术可用于卡通渲染,fake BRDF,特效等等...应用范围非常广,我先来做一个基本形。

在shader中,添加两个属性 _ RampAmount和 _ RampTexture来控制_Ramp的强度。

按之前的方法,在脚本中生成RampImageEffect,并连接OnRenderImage。重复写几次代码之后,码代码的速度也越来越快,也越来越熟练了...(译者:笑hhhh)

现在重新回到shader里,写一下处理核心计算的frag函数。

因为在后处理过程中,我们用ndotl求halfLambert,不能放Ramp纹理,所以我把在第1篇文章中做的 luminance拿过来,把它当做uv的x坐标来用。如果使用_RampAmount插值的话,就可在源图像和Ramp图像之间插值。

组件如上图所示,我临时做了一张ramp纹理,导入。

Ramp texture放大后的效果如上。

此外,如果我们换一张ramp纹理的话,可得到不同的效果。对比效果如下。

每张图像都的风格都不一样。可是假如我想要不同的效果,就需要去Photoshop中一次次反复修改和确认ramp纹理,想想就觉得很麻烦。

所以啊,如果可以边看效果边改画面的颜色和明暗值,岂不是美滋滋,对吧?:)))

嗯,以下就是我今天要分享的核心内容啦,如何动态生成、使用Ramp纹理!

如上图所示,蓝色框是注释,红色框是我添加的代码。

为了替换之前的ramp纹理,我想用新的动态纹理来设置shader的 _RampTex,所以我注释掉了一些代码。因为明暗和色调是分开实现的,所以AnimationCurve类型的rampCurve处理明暗,Gradient类型的rampColor处理色调,把它们都放进dynamicTex里面。

酱紫,就能添加曲线和颜色渐变了。接下来的内容非常关键!在Update函数中添加生成纹理的逻辑。

由于这个功能只用在编辑器中执行,所以用 #if UNITY_EDITOR封装比较好。如果没有封装的话,build好运行时,这个计算会一直执行,很耗性能。在没有dynamicTex的时候,我们生成一张水平为256,垂直为1的临时纹理(压缩选无压缩)。然后创建一个数组来储存颜色,并命名为ColorBuffer。为了获取我们刚做好的纹理的全部像素,我用了GetPixels函数,所以Color的数组计数就是256。

现在,让这些数组执行for语句,就可以从rampColor和 rampCurve中得到各个通道值。如果把0~1范围的值作为因子(x坐标)放入Evaluate的话,就能返回至对应的结果值。即,如果渐变的中间部分是黄色的话,输入0.5就会返回为黄色。这样获得各个通道值之后,使用SetPixel绘制dynamicTex。因为我们用的是Ramp,所以Warp模式选择Clamp之后,把dynamic纹理作为SetTexture添加至shader的_RampTex中。

在shader中可以根据我们的实际需求,分离rgb和a,然后对两者的乘积进行插值计算。这样,就可以动态地控制曲线和梯度了(如下图所示)。

现在我们就可以不用每次都去Photoshop手动修改了,直接在引擎里边看图像边实时调效果就行,非常方便!!

我挺喜欢这个风格的。

以上就是我今日的分享,谢谢大家~

本文仅限于学习参考交流,请勿做商业用途和随意转载。

译者话:大家对于译文有看不明白的地方,欢迎赐教呀~

译 Qinfei

2020/06/12