基于叠加密度投影算法的X光效果

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34980278/article/details/83588312

思路:利用平面的顶点和法线模拟一束平行光线,计算光线与物体(AABB)相交部分,以一定的步长采样相交部分,并且累加每一步采样得到的值,最后乘以相同的系数取平均值输出颜色。

Shader "Custom/XShader"
{
    Properties
    {
        _Volume("Texture3D", 3D) = "" {}
        lightScale("LightScale",Range(0,5)) = 1
        LightColor("LightColor",color) = (0,0,0,1)
        Zvalue("value",Range(0,1)) = 0
    }

        SubShader
    {
        Tags{ "RenderType" = "Opaque" "Queue" = "Geometry" }
        LOD 100
        Pass
    {
        CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
    sampler3D _Volume;
    float lightScale;

    float4x4 Direction;
    fixed4 LightColor;
    float Zvalue;

    bool cubeIntersection(float3 origin, float3 direction, float3 aabbMax, float3 aabbMin, out float tNear, out float tFar)
    {
        float3 t1 = direction * (aabbMax - origin);
        float3 t2 = direction * (aabbMin - origin);
        float3 tMin = min(t1, t2);
        float3 tMax = max(t1, t2);
        tNear = min(max(tMin.x, tMin.y), tMin.z);
        tFar = max(min(tMax.x, tMax.y), tMax.z);
        return tNear <= tFar;
    }
    struct appdata
    {
        float4 vertex : POSITION;
        float3 normal : NORMAL;
    };

    struct v2f
    {
        float4 vertex : SV_POSITION;
        float3 Pos : TEXCOORD0;
        float3 Normal : TEXCOORD1;
    };

    v2f vert(appdata v)
    {
        v2f o;
        o.vertex = UnityObjectToClipPos(v.vertex);
        o.Pos = v.vertex;
        o.Normal =normalize(v.normal);
        return o;
    }
    fixed4 frag(v2f i) : SV_Target
    {
        float4 col = float4(0, 0, 0, 0);
        float3 lpos = i.Pos;
        float3 ldir = i.Normal;
        float3 origin = lpos - ldir;//投影算法需要的参数
        float tNear, tFar;
        cubeIntersection(origin, ldir, float3(0.5, 0.5, 0.5), float3(-0.5, 0.5, -0.5), tNear, tFar);//AABB投影算法
        float CurrentRayLength = tNear;
        float maxSamples = 512;//我的Texture3d是512*512*176的
        float CurrentSample = 0;
        float Steplength = 1.732 / maxSamples; //box两点间最大距离/max
        int CurrentStep = 0;
        while (CurrentRayLength<tFar)
        {
            float3 pos = mul(Direction, origin + ldir*CurrentRayLength);
            pos += 0.5;      //-0.5-0.5=>0-1                                   
            float4 pcol = tex3Dlod(_Volume, float4(pos, 0));//将采样数据投影到面片
            if (pcol.a >= Zvalue)
            {
                CurrentStep += 1;
                float single = (pcol.a - Zvalue) / (1 - Zvalue) * (maxSamples - CurrentSample) / maxSamples;//关于pcol.a直线方程乘以采样衰减系数
                col.a += single;                //叠加
            }
            CurrentRayLength += Steplength;
            CurrentSample += 1;
        }
        if (CurrentStep>0) {
            col.a = col.a *0.08;//以相同的标准取平均值,毕竟加了那么多次
        }
        return float4(col.aaa,1)*LightColor*lightScale;//加上光的强度和颜色
    }
        ENDCG
    }
    }
}
 

猜你喜欢

转载自blog.csdn.net/qq_34980278/article/details/83588312