简单边缘光

 

贴图漫反射(MainTex)+高光反射+边缘光

Shader "My/Light/RimLight"
{
    Properties
    {
        _MainTex("Main Tex", 2D) = "white" {}
        _Color("Diffuse Color", Color) = (1, 1, 1, 1) //类似之前的Diffuse

        _Specular("Specular", Color) = (1, 1, 1, 1) //高光反射颜色
        _Gloss("Gloss", Range(8.0, 256)) = 20 //高光区域大小

        _RimColor("Rim Color", Color) = (1, 1, 1, 1) //边缘光颜色
        _RimPower("Rim Power", Range(0.7, 9)) = 4 //边缘光强度
    }

    SubShader
    {
        Pass
        {
            Tags { "LightMode" = "ForwardBase" }

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "Lighting.cginc"

            sampler2D _MainTex;
            float4 _MainTex_ST;
            fixed4 _Color;

            fixed4 _Specular;
            float _Gloss;

            fixed4 _RimColor;
            float _RimPower;

            struct appdata
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL; //顶点法线
                float2 texcoord : TEXCOORD0;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float2 uv : TEXCOORD0;
                float3 worldNormal : TEXCOORD1;
                float3 worldPos: TEXCOORD2;
            };

            v2f vert(appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;

                o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
                return o;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                fixed3 worldNormal = normalize(i.worldNormal);
                fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); //指向光源向量(世界空间)

                fixed3 albedo = tex2D(_MainTex, i.uv).rgb * _Color.rgb; //取贴图颜色作为漫反射颜色
                fixed3 ambientColor = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo; //环境光,这里需要*albedo吗?

                fixed lambert = max(0, dot(worldNormal, worldLightDir)); //表面法线和光线方向夹角的cos值成正比
                fixed3 diffuseColor = _LightColor0.rgb * albedo * lambert; //漫反射计算公式

                fixed3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos)); //视线方向(顶点到相机)

                //fixed3 reflectDir = normalize(reflect(-worldLightDir, worldNormal));
                //fixed3 specularColor = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir, worldViewDir)), _Gloss); //phong模型高光反射计算公式

                fixed3 halfDir = normalize(worldLightDir + worldViewDir); // blinn模型引入的h向量
                fixed3 specularColor = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss); // blinn模型高光反射计算公式(更亮, 高光区域更大)

                float rim = 1 - abs(dot(worldNormal, worldViewDir)); //正对视线时边缘光最弱(0), 垂直视线时最强(1)
                rim = pow(rim, _RimPower); //_RimPower>1时, 正对附近缓慢变大, 快到垂直了快速变大;
            
                fixed4 c = fixed4(ambientColor + diffuseColor + specularColor, 1);
                c.rgb = c.rgb * (1-rim) + _RimColor.rgb * rim;
                return c;
            }
            ENDCG
        }
    }

    Fallback "Specular"
}

对rim因子增加一个power是为了让其可以非线性变化

a) >1时

b) <1时

 

 

不足

a) 边缘存在锯齿

b) 背面也有边缘光,且和前面是一样的

 

参考

Shader学习——边缘光 - 简书 (jianshu.com)

【玉兔 | 图形学与游戏开发】游戏中的人物边缘发光效果是如何实现的?码农小姐姐手把手教你写Shader | 2022开工啦,快来学习!_哔哩哔哩_bilibili

posted @ 2023-02-16 00:17  yanghui01  阅读(12)  评论(0编辑  收藏  举报