Unity shader Xray 效果

本文详细介绍了在Unity中实现XRay透视效果的方法,包括通过ZTest判断物体遮挡、关闭深度写入、开启透明混合及忽略阴影投射等步骤。核心算法涉及边缘光计算,通过调整XRayColor和XRayPower参数,实现不同强度的边缘高亮。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

XRay X光射线效果

实现原理:

通过ZTest(深度测试)判断该物体是否被遮挡,如果被遮挡则为物体被遮挡的片元画上一层 边缘光,加上 Blend透明混合模式,实现Xray效果。需通过两个Pass通道来一个画被遮挡住的效果,一个画正常的模型效果,

1.开启深度测试 判断是否被遮挡:

Ztest Greater 含义:深度大于当前缓存的值则开通过,否则舍弃该片源。

在深度测试中,深度值一般用Z表示,范围在0—1之间,深度值越小越靠近相机,深度值越大越靠后,由此我们可以通过深度测试来得知物体是否被遮挡,如果某一个片元满足了ZTest Greater 则说明在该片元的前面已经有物体被渲染且写入了深度。

ZTest的状态有下面几中:

Less深度小于当前缓存则通过
Greater深度大于当前缓存则通过
LEqual深度小于等于当前缓存则通过
GEqual深度大于等于当前缓存则通过
Equal深度等于当前缓存则通过
NotEqual深度不等于当前缓存则通过
ZTest Always不论如何都通过

由此的知,当前片元处于大于当前颜色缓冲区的深度时,说明该物体前面有其他的物体被渲染且已经进行深度写入。所以在这种状态下,我们就可以绘边缘光实现我们的Xray效果了。

2.关闭深度写入:

ZWrite Off

注意:我们只需要开启深度测试,检测是否被遮挡。不需要写入深度。如果写入深度,那么就与深度测试相冲突,ZTest Greater永远不满足,那么我们的XRay效果也不会被绘制出来。

3.开启透明混合,否则渲染出来的片元无法透明化,如下图:

Blend SrcAlpha One
在这里插入图片描述
4.忽略阴影投射:

Tags{ "ForceNoShadowCasting" = "true" }

原因:Xray效果不需要阴影。

核心算法:

float rim=1-saturate(dot(NormalDir,ViewDir));
float4 rimColor=_XRayColor*pow(rim,1/_XRayPower);
return rimColor;

其实就是边缘光的算法,博文开始已经有讲到,若对边缘光有所不解 点击 UnityShader边缘光实现

效果图:
在这里插入图片描述
下面附上完整UnityShader:

Shader "Unity/XRay"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Diffuse("Color",Color) =(1,1,1,1)
        _XRayColor("XRayColor",Color)=(1,1,1,1)
        _XRayPower("XRayPower",float) =0 
        
    }
    SubShader
    {
        Tags {"Queue"= "Geometry+1000" "RenderType"="Opaque" }
        LOD 100

        //Xray效果
        Pass
        {
            Name "Xray"
            //忽略阴影,半透明物体不需要阴影,可开启此功能
            Tags{ "ForceNoShadowCasting" = "true" }
            //开启混合
            Blend SrcAlpha One 
            //不进行任何颜色信息写入
            ZWrite Off 
            //大于深度缓冲池中的颜色深度的片元才进行处理 其他的全部舍弃
            ZTest Greater

            CGPROGRAM
            #pragma vertex vert 
            #pragma fragment frag 
            #include "UnityCG.cginc"
            #include "Lighting.cginc"

            float4 _XRayColor;
            float _XRayPower;

            struct v2f
            {
                float4 vertex:SV_POSITION;
                float3 normal:TEXCOORD0;
                float3 viewDir:TEXCOORD1;

            };

            v2f vert(appdata_base v)
            {
                v2f o;
                o.vertex=UnityObjectToClipPos(v.vertex);
                o.normal= v.normal;
                o.viewDir=ObjSpaceViewDir(v.vertex);
                return o;
            };

            fixed4 frag(v2f i):SV_TARGET
            {
                float3 NormalDir=normalize(i.normal);
                float3 ViewDir=normalize(i.viewDir);
                    
                float rim=1-saturate(dot(NormalDir,ViewDir));
                float4 rimColor=_XRayColor*pow(rim,1/_XRayPower);
                return rimColor;
            };
            ENDCG
        }

        //正常的漫反射渲染
        Pass
        {
        
            CGPROGRAM 
            #pragma vertex vert
            #pragma fragment frag 
            #include "UnityCG.cginc"
            #include "Lighting.cginc"

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

            v2f vert(appdata_base v)
            {
                v2f o;
                o.vertex=UnityObjectToClipPos(v.vertex);
                o.uv=TRANSFORM_TEX(v.texcoord,_MainTex);
                o.worldPos=mul(unity_ObjectToWorld,v.vertex);
                o.worldNormal=UnityObjectToWorldNormal(v.normal);
                return o;
            };

            fixed4 frag(v2f i):SV_TARGET
            {
                float3 worldNormalDir=normalize(i.worldNormal);
                float3 WorldLightDir=normalize(UnityWorldSpaceLightDir(i.worldNormal));

                float3 texColor=tex2D(_MainTex,i.uv);

                float3 ambient=UNITY_LIGHTMODEL_AMBIENT.rgb*texColor.rgb;

                float3 diffuse=_LightColor0.rgb*_Diffuse.rgb*texColor.rgb*(dot(worldNormalDir,WorldLightDir)*0.5+0.5);
                
                float3 color=diffuse+ambient;
                return fixed4(color,1);
            };
            ENDCG
       }

    }
    Fallback "Diffuse"
}

努力积才能,壹叶便成名!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

铸梦xy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值