【Unity Shader】还原CSGO全息贴纸效果(hologram sticker)

小伙伴提供的素材:

【Unity Shader】还原CSGO全息贴纸效果(hologram sticker)【Unity Shader】还原CSGO全息贴纸效果(hologram sticker)【Unity Shader】还原CSGO全息贴纸效果(hologram sticker)

hologram sticker效果,简称holo:

【Unity Shader】还原CSGO全息贴纸效果(hologram sticker)

成果:

基于URP的shader graph实现,以及基于built-in管线的实现


1. 效果分析

在这里可以看到csgo的贴纸效果:StatTrak™ AWP | Man-o'-war (Minimal Wear) | 3D Skin Viewer

根据观察,发现:

a. 全息颜色是根据视角变化的,所以会利用到view direction dot normal direction(视线方向点乘法线方向,即VdotN),即下图的V和N。两个单位向量点乘得到它们夹角的cos值,值越大,夹角越小(想象一下cos曲线)。

       【Unity Shader】还原CSGO全息贴纸效果(hologram sticker)

b. 全息是多层叠加的,每层的颜色以及颜色的变化速度都是不一样的,所以我们会将全息效果写成一个函数,然后调用若干次


2. 实现

基于Unity 2019.4.23

【Unity Shader】还原CSGO全息贴纸效果(hologram sticker)

 大致流程是,我们将上图作为色板,将VdotN作为横坐标,纵坐标取固定值。随着视角的变化,shader会在图中横着采样从左到右的彩虹色。我们给贴纸的背景部分使用小的y值,主体使用高的y值,这样背景的颜色发灰,主体颜色很亮。

【Unity Shader】还原CSGO全息贴纸效果(hologram sticker)【Unity Shader】还原CSGO全息贴纸效果(hologram sticker)

 ↑这两张图作为mask。根据观察,认为是三层holo叠加,对应mask的rgb通道。

 2.1 全息效果

我们给全息效果制作了一个sub graph:

【Unity Shader】还原CSGO全息贴纸效果(hologram sticker)

 讲解下参数:

  • Mask:哪里有全息效果(1),哪里没有效果(0),会把mask图的某个通道传进来
  • Scale:采样色板的快慢,即holo颜色变化快慢
  • Offset:颜色偏移
  • Y Sample Value:色板取色的y值
  • Color Multiplier:取到的颜色的乘数
  • LUT:look up table,色板

 如下图所示,比起通常用uv采样贴图的做法,我们会在uv上叠加VdotN去采样色板,这样视角变化会影响取色。add节点的输入是VdotN和uv。VdotN注意要在object space,如果在world space变化会很鬼畜,可能是数值太大导致的精度问题。uv这里有两个操作。第一个操作是因为色板直接采样,颜色的变化方向是左右,我们需要上下变化,所以把uv split掉后取的是y。第二个操作是scale & offset。我这里控制的是原始uv,读者也可以把它放在别的地方。

【Unity Shader】还原CSGO全息贴纸效果(hologram sticker)

 如下图所示,采样LUT后,乘以mask和色彩乘数得到最终结果。 

【Unity Shader】还原CSGO全息贴纸效果(hologram sticker)

2.2 多层holo叠加

接下来读取两张mask的三个通道。

【Unity Shader】还原CSGO全息贴纸效果(hologram sticker)【Unity Shader】还原CSGO全息贴纸效果(hologram sticker)【Unity Shader】还原CSGO全息贴纸效果(hologram sticker)【Unity Shader】还原CSGO全息贴纸效果(hologram sticker)

【Unity Shader】还原CSGO全息贴纸效果(hologram sticker)【Unity Shader】还原CSGO全息贴纸效果(hologram sticker)【Unity Shader】还原CSGO全息贴纸效果(hologram sticker)【Unity Shader】还原CSGO全息贴纸效果(hologram sticker)

这两张图怎么使用读者可以*决定,我的做法是这样的,并不是所有图都用上了:

【Unity Shader】还原CSGO全息贴纸效果(hologram sticker)

 参数:

  • R Scale Offset Y Mult:对应holo节点的四个参数

 【Unity Shader】还原CSGO全息贴纸效果(hologram sticker)

 【Unity Shader】还原CSGO全息贴纸效果(hologram sticker)【Unity Shader】还原CSGO全息贴纸效果(hologram sticker)【Unity Shader】还原CSGO全息贴纸效果(hologram sticker)

单层

【Unity Shader】还原CSGO全息贴纸效果(hologram sticker)

叠加

 2.3 转为built-in管线shader

Shader "Unlit/UnlitShader card"
{
    Properties
    {
        _MaskA ("mask a", 2D) = "white" {}
        _MaskB ("mask b", 2D) = "white" {}
        _LUT ("LUT", 2D) = "white" {}
        RParam("R param", Vector) = (1, 0, 0, 1)
        GParam("G param", Vector) = (1, 0, 0, 1)
        BParam("B param", Vector) = (1, 0, 0, 1)
        _ClipValue("AlphaClipThreshold", Float) = 0
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
                float3 normal : TEXCOORD1;
            };

            sampler2D _MaskA;
            sampler2D _MaskB;
            sampler2D _LUT;
            float4 RParam;
            float4 GParam;
            float4 BParam;
            float _ClipValue;
                      

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;//TRANSFORM_TEX(v.uv, _MaskA);
                o.normal = v.normal;
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            fixed4 Holo(half2 uv, float3 normal, half mask, half4 param)
            {
                half viewAngle=dot(_WorldSpaceCameraPos.xyz, normal);
                float2 calc_uv = float2(uv.y*param.x + param.y+viewAngle, param.z);
                return tex2D(_LUT, calc_uv) * mask * param.w;
            }
            fixed4 frag (v2f i) : SV_Target
            {
                half4 maskB = tex2D(_MaskB, i.uv);
                clip(maskB.a - _ClipValue);
                
                half4 maskA = tex2D(_MaskA, i.uv);
                
                half4 holoR = Holo(i.uv, i.normal, maskA.r * maskB.r, RParam);
                half4 holoG = Holo(i.uv, i.normal, maskA.g, GParam);
                half4 holoB = Holo(i.uv, i.normal, maskA.b, BParam);
                
                fixed4 col = half4((holoR+holoG+holoB).rgb, maskB.a);
                return col;
            }
            ENDCG
        }
    }
}

4. 总结与回顾

视角的计算:用sin值也可以表示视角变化,但是点乘用起来很方便,所以用cos

GitHub - MidoriMeng/URP-Hologram-Sticker-Effect

上一篇:php smarty 缓存和配置文件的基本使用方法


下一篇:php redis模糊查询匹配key