unity 全息和xRay shader

Posted xiaogeformax

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了unity 全息和xRay shader相关的知识,希望对你有一定的参考价值。

unity 全息和xRay shader

这个是网上的效果,科幻的感觉是不是很强烈。

下面是我们去实现的效果。
先看下效果图,左边的是Xray的效果,右边是全息的效果。都有着异曲同工的妙处。

全息的效果

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

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
        
    

另一种全息

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

在顶点函数里面,我们使用了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
        
    

以上是关于unity 全息和xRay shader的主要内容,如果未能解决你的问题,请参考以下文章

小功能⭐️Unity2018 Shader Graph——全息影像物体消融

小功能⭐️Unity2018 Shader Graph——全息影像物体消融

小功能⭐️Unity2018 Shader Graph——全息影像物体消融

Unity 之 ShaderGraph 实现全息效果入门级教程

unity中场景和游戏的画质不一样

Hololens开发笔记之使用Unity开发一个简单的应用