基于兰伯特漫反射的色散(Dispersion)效果解析

12 篇文章 7 订阅
4 篇文章 1 订阅

本文分享基于兰伯特漫反射的色散(Dispersion)效果解析

我们知道, 兰伯特漫反射可以表现渐变的明暗效果, 而这种明暗效果可以结合一些手段来实现很多有意思的效果, 今天就给大家介绍其中一种.

先看看最终效果:

1

效果解析

可以看到, 颜色分布由暗到明, 分别是: 黑色->蓝色->天蓝->白色.

我们使用兰伯特漫反射表现明暗变化, 为了比较清晰的观察变化, 这里使用球的模型:

Shader "Custom/Dispersion" {
    Properties {
        _RangeColor ("RangeColor", Color) = (0.5,0.8,0.2,1)
        _node_6044 ("node_6044", Color) = (0.5,0.5,0.5,1)
    }
    SubShader {
        Tags {
            "RenderType"="Opaque"
        }
        Pass {
            Name "FORWARD"
            Tags {
                "LightMode"="ForwardBase"
            }
            
            
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #pragma multi_compile_fwdbase_fullshadows
            #pragma target 3.0
            struct VertexInput {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };
            struct VertexOutput {
                float4 pos : SV_POSITION;
                float4 posWorld : TEXCOORD0;
                float3 normalDir : TEXCOORD1;
            };
            VertexOutput vert (VertexInput v) {
                VertexOutput o = (VertexOutput)0;
                o.normalDir = UnityObjectToWorldNormal(v.normal);
                o.posWorld = mul(unity_ObjectToWorld, v.vertex);
                o.pos = UnityObjectToClipPos( v.vertex );
                return o;
            }
            float4 frag(VertexOutput i) : COLOR {
                i.normalDir = normalize(i.normalDir);
                float3 normalDirection = i.normalDir;
                float3 lightDirection = normalize(_WorldSpaceLightPos0.xyz);

                // 着色代码--begin
                float nDotl = saturate(dot(i.normalDir,lightDirection));
                float3 finalColor = nDotl;
                // 着色代码--end
                return fixed4(finalColor,1);
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

效果如下:

2

可以看到, 大概从一半的位置往右上角渐变, 越来越白.

一次分割

接下来使用step函数来分散明暗色:

// 着色代码--begin
float nDotl = max(0,dot(i.normalDir,lightDirection));
float color = step(0.6,nDotl);
float3 finalColor = float3(color,color,color);
return fixed4(finalColor,1);
// 着色代码--end

step(a, b)是一个内置函数, 其作用为a <= b时返回1, a > b时返回0.

如果其中的参数是向量, 则每个分量分别处理, 如:

step(float2(0.5, 0.8), 0.6)
// 则得到二维向量 => (1, 0)
// 0.5 <= 0.6 => 1
// 0.8 > 0.6 => 0

漫反射值超过0.6的部分将显示为纯白, 其它部分为纯黑, 当前阶段效果如下:

3

二次分割

使用二维向量来分散明暗色:

// 着色代码--begin
float nDotl = max(0,dot(i.normalDir,lightDirection));
float2 color = step(float2(0.6, 0.2),nDotl);
float3 finalColor = float3(color,0);
return fixed4(finalColor,1);
// 着色代码--end

漫反射值超过0.6的部分将显示为纯黄, 0.2到0.6之间的部分将显示为纯绿, 当前阶段效果如下:

4

这是最容易让人迷惑的部分, 为什么是黄色和绿色呢?

首先我们要明白一点: step函数的第一个参数的维度数代表要对球进行"分割"的次数, 比如本阶段的第一个参数为二维向量, 表示要将球"分割"两次, 变成三个部分.

然后我们分别分析其颜色构成:

明暗值大于0.6的部分, 肯定也是大于0.2的, 所以大于0.6的部分, 经过step后会输出(1, 1, 0)也就是纯黄色.

也就是说:

step(float2(0.6, 0.2), 0.8)
// => float2(1, 1)

而0.2到0.6的部分, 经过step后会输出(0, 1, 0)也就是纯绿色.

同理可得:

step(float2(0.6, 0.2), 0.5)
// => float2(0, 1)

最后小于0.2的部分将输出(0, 0, 0), 即纯黑色:

step(float2(0.6, 0.2), 0.1)
// => float2(0, 0)
三次分割

然后使用三维向量进行分割:

// 着色代码--begin
float nDotl = max(0,dot(i.normalDir,lightDirection));
float3 color = step(float3(0.8, 0.5, 0.2),nDotl);
float3 finalColor = float3(color);
return fixed4(finalColor,1);
// 着色代码--end

效果如下:

5

超过0.8的部分显示为白色:

step(float2(0.8, 0.5, 0.2), 0.9)
// => float2(1, 1, 1)

0.5到0.8的部分显示为天蓝色:

step(float2(0.8, 0.5, 0.2), 0.6)
// => float2(0, 1, 1)

0.2到0.5的部分显示为纯蓝色:

step(float2(0.8, 0.5, 0.2), 0.6)
// => float2(0, 0, 1)

小于0.2的部分为纯黑色:

step(float2(0.8, 0.5, 0.2), 0.6)
// => float2(0, 0, 0)

切换模型后就可得到图1的效果.

总结

今天分享在兰伯特漫反射的基础上进行色散的效果, 利用漫反射的明暗过度, 使用step来分区颜色达到想要的效果.

因为step函数的输出只有0和1, 所以该效果的颜色是有限的, 当然, 我们也可以在这个基础上进一步做更多的效果.

step的分割次数和最后输出颜色的关系:

  • 一次分割: 只能得到纯黑(0, 0, 0)和纯白(1, 1, 1)
  • 二次分割: 能得到纯黑(0, 0, 0), 纯红(1, 0, 0), 纯绿(0, 1, 0), 纯黄(1, 1, 0)
  • 三次分割: 能得到纯蓝(0, 0, 1), 天蓝(0, 1, 1), 纯白(1, 1, 1), 粉红(1, 0, 1)

可以将step的结果理解为分割颜色后得到某个颜色遮罩, 然后按照区间计算颜色.

好了, 今天分享就这么多, 希望对大家有所帮助.

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

拂面清风三点水

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值