unity 全息和xRay shader

unity 全息和xRay shader

这个是网上的效果,科幻的感觉是不是很强烈。
unity 全息和xRay shader_第1张图片

下面是我们去实现的效果。
先看下效果图,左边的是Xray的效果,右边是全息的效果。都有着异曲同工的妙处。
unity 全息和xRay shader_第2张图片

全息的效果

全息特效只显示物体的轮廓,必然会有用到类似于边缘光照的效果。

void surf(Input IN, inout SurfaceOutput o) {
            float4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
            o.Albedo = c.rgb;

            float border = 1 - (abs(dot(IN.viewDir, IN.worldNormal)));
            float alpha = (border * (1 - _DotProduct) + _DotProduct);
            o.Alpha = c.a * alpha;
        }

这个里面用了类似边缘光照的算法。

float rim = 1 - max(0, dot(worldViewDir, worldNormal));

这里把float border = 1 - (abs(dot(IN.viewDir, IN.worldNormal)));

在边缘光照里面,当worldViewDir和worldNormal大于90度的时候,就会将其置于1,就是说模型背面的部分全部置为1,所以不是透明的。但是在全息特效里面,用了abs函数,不管是正面还是背面都是给其减去了,所以,只会显示出边缘光照,中间就会呈现出镂空的效果。

同时,在后面的代码对其alpha值进行线性插值。
纹理中的初始alpha值与新的系数进行插值去完成的。

下面看下全部的shader代码:

Shader "CookbookShaders/Chapter02/Silhouette" {
    Properties{
        _Color("Color", Color) = (1,1,1,1)
        _MainTex("Albedo (RGB)", 2D) = "white" {}

        _DotProduct("Rim effect", Range(-1,1)) = 0.25
    }
    SubShader{
        Tags{
            "Queue" = "Transparent"
            "IgnoreProjector" = "True"
            "RenderType" = "Transparent"
        }
        LOD 200

        Cull Off

        CGPROGRAM
        //#pragma surface surf Lambert alpha:fade nolighting
        #pragma surface surf Lambert alpha

        sampler2D _MainTex;
        fixed4 _Color;

        float _DotProduct;

        struct Input {
            float2 uv_MainTex;
            float3 worldNormal;
            float3 viewDir;
        };

        //void surf(Input IN, inout SurfaceOutputStandard o) {
        void surf(Input IN, inout SurfaceOutput o) {
            float4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
            o.Albedo = c.rgb;

            float border = 1 - (abs(dot(IN.viewDir, IN.worldNormal)));
            float alpha = (border * (1 - _DotProduct) + _DotProduct);
            o.Alpha = c.a * alpha;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

XRay特效

我们看下xRay的代码,其实效果和全息的有着很大的相似度。

  v2f vert (appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(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;
            }

这里的最后的颜色用了_RimColor 和上面的val相乘,val和上面的全息特效相似,都是在边缘时较大,在模型的中间比较小。后面,又给乘了个强度。
下面给出全部代码:


Shader "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//打开混合模式
            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 = UnityObjectToClipPos(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
        }
    }
}

另一种全息

同样是上面的模型,下面来展示另一种全息,是把模型的全身变为很多的点,然后绕成一圈圈的。然后调制颜色为淡蓝色,成为下面的样子。
unity 全息和xRay shader_第3张图片

在顶点函数里面,我们使用了o.worldPos = mul(unity_ObjectToWorld, v.vertex);获得物体本身的坐标,之后,在片元着色器里面进行处理。
col = _Color * max(0, cos(i.worldPos.y * _ScanningFrequency + _Time.x * _ScanningSpeed) + _Bias);
col = 1 - max(0, cos(i.worldPos.x _ScanningFrequency + _Time.x * _ScanningSpeed) +0.9);
col = 1 - max(0, cos(i.worldPos.z _ScanningFrequency + _Time.x * _ScanningSpeed) +0.9);

这个是片元里面的代码,分别对其 X,Y,Z坐标进行处理。首先对Y坐标进行处理,就是高度,使用cos函数,对其进行处理,将cos函数小于0的部分全部置为0,后面进行乘上颜色,使之为透明。

同样的道理,对X,Z进行切割,使用1-max(**) 省略公式了,就是把cos的数值为1的部分进行透明。在X,Z坐标上很少的一部分为透明。

下面看下全部的shader代码吧
代码来源World of Zero,shader的第一行就有的,在此引用了。

Shader "World of Zero/Hologram"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Color ("Color", Color) = (1, 0, 0, 1)
        _Bias("Bias", range(-2,2)) = 0
        _ScanningFrequency ("Scanning Frequency", Float) = 100
        _ScanningSpeed ("Scanning Speed", Float) = 100
    }
    SubShader
    {
        Tags { "Queue" = "Transparent" "RenderType" = "Transparent" }
        LOD 100
        ZWrite Off
        Blend SrcAlpha One
        Cull Off

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

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

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(2)
                float4 vertex : SV_POSITION;
                float4 worldPos : TEXCOORD1;
            };

            fixed4 _Color;
            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _Bias;
            float _ScanningFrequency;
            float _ScanningSpeed;

            v2f vert (appdata v)
            {
                v2f o;
                o.worldPos = mul(unity_ObjectToWorld, v.vertex);
                o.vertex= UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                col = _Color * max(0, cos(i.worldPos.y * _ScanningFrequency + _Time.x * _ScanningSpeed) + _Bias);
                col *= 1 - max(0, cos(i.worldPos.x * _ScanningFrequency + _Time.x * _ScanningSpeed) +0.9);
                col *= 1 - max(0, cos(i.worldPos.z * _ScanningFrequency + _Time.x * _ScanningSpeed) +0.9);
                return col;
            }
            ENDCG
        }
    }
}

你可能感兴趣的:(shader,Untiy,unity3d)