Unity3D-Shader-实现X光效果

【旧博客转移 - 2016年1月3日 16:40 

最近学习了一些Shader效果,打算把学到的知识总结一下,这篇讲一下这种轮廓发光的效果(如下图所示),也有一些地方管这个叫X光

 
 

 

 

1.原理

可以看到图上的蓝色人物,边缘颜色比较深,而中间的比较浅,这是利用法线跟视线向量的点乘值计算出颜色浓度来实现的
 

2.代码

Shader "lijia/Xray"
{
    Properties
    {
        _RimColor("RimColor", Color) = (0, 0, 1, 1)
        _RimIntensity("Intensity", Range(0, 2)) = 1
    }
    SubShader
    {
        Tags {"Queue"="Transparent" "RenderType"="Opaque" }

        LOD 200
        Pass
        {
            Blend SrcAlpha One//打开混合模式
            ZWrite off
            Lighting off

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float3 normal:Normal;
            };

            struct v2f
            {
                float4 pos : SV_POSITION;
                fixed4 color:COLOR;
            };

            fixed4 _RimColor;
            float _RimIntensity;

            v2f vert (appdata v)
            {
                v2f o;
                o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
                float3 viewDir = normalize(ObjSpaceViewDir(v.vertex));//计算出顶点到相机的向量
                float val = 1 - saturate(dot(v.normal, viewDir));//计算点乘值
                o.color = _RimColor * val * (1 + _RimIntensity);//计算强度
                return o;
            }

            fixed4 frag (v2f i) : COLOR
            {
                return i.color;
            }
            ENDCG
        }
    }
}

 

float3 viewDir = normalize(ObjSpaceViewDir(v.vertex));//计算出顶点到相机的向量
这一句是调用了UnityCG.cginc库中的ObjSpaceViewDir方法,获得viewDir

inline float3 ObjSpaceViewDir( in float4 v )
{
    float3 objSpaceCameraPos = mul(_World2Object, float4(_WorldSpaceCameraPos.xyz, 1)).xyz;
    return objSpaceCameraPos - v.xyz;
}

 

翻看UnityCG中ObjSpaceViewDir方法的源码,发现它是拿到_WorldSpaceCameraPos(世界坐标相机的位置),左乘World2Object矩阵,转成模型坐标系
最后objSpaceCameraPos - v.xyz (向量相减),得到viewDir向量

viewDir跟normal的点乘值,就表示两个向量的夹角大小

  1. 夹角 < 90°时,点乘>0
  2. 夹角 = 90°时,点乘=0
  3. 夹角 > 90°时,点乘<0

边缘的顶点,点乘值接近90度,也就是值接近0,所以这里用1减去点乘值( saturate函数:返回0-1之间的数 )

float val = 1 - saturate(dot(v.normal, viewDir));

计算出颜色强度后,把颜色传给fragment着色器去输出渲染,就可以看到效果了

 

posted @ 2017-05-16 15:03  李嘉的博客  阅读(7724)  评论(1编辑  收藏  举报