Stipple Transparency – 点阵像素剔除半透明

Last modified date

基于屏幕像素点阵以像素剔除的方式做半透明效果,比传统alpha blend方式更节约性能开销的半透明做法。

Stipple Transparency也叫做:Screen-door transparency,screen space stipple,stipple patterns,dissolve,fizzle,等等。中文可能叫做“点阵像素剔除半透明”吧。原理是将普通的非透明渲染对象,通过以网点方式剔除像素,获得近似半透明的效果。有点像漫画网点纸。

这个半透明实现方式已经是蛮有年头的老办法了。因为3D引擎中实现半透明效果一直是很麻烦的事,而且挺消耗性能的,因为一般半透明对象会把半透明的内容连同背景每一层都渲染一遍,可能会增加Draw Call,还牵扯到深度测试和排序问题。所以很早就有人想出了网点剔除的方式来实现半透明效果,因为这个方式性能开销很低。

早期的电脑屏幕像素低,这种半透明的显示效果其实很low。但是现在都是高清屏了,这种网点的方式反而变的又好看又实用。现在很多主机3A游戏还都在用,例如《马里奥-奥德赛》《神秘海域》。

具体做法就是在渲染的最后阶段,通过屏幕坐标计算出点阵的位置和透明度,透明度低于0的像素就剔除掉。

代码参考

Surface shader:

Shader "WalkingFat/StippleTransparency"
{
    Properties 
    {
        _MainTex ("Base (RGB)", 2D) = "white" {}
        _Alpha ("Alpha", Range(0,1)) = 1.0
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 150

        CGPROGRAM
        #pragma surface surf Lambert noforwardadd

        sampler2D _MainTex;

        struct Input {
            float2 uv_MainTex;
            float4 screenPos;
        };

        half _Alpha;

        void surf (Input IN, inout SurfaceOutput o) {
            fixed4 c = tex2D(_MainTex, IN.uv_MainTex);
            o.Albedo = c.rgb;
            o.Alpha = c.a;
            // Screen-door transparency: Discard pixel if below threshold.
            float4x4 thresholdMatrix =
            {  1.0 / 17.0,  9.0 / 17.0,  3.0 / 17.0, 11.0 / 17.0,
              13.0 / 17.0,  5.0 / 17.0, 15.0 / 17.0,  7.0 / 17.0,
               4.0 / 17.0, 12.0 / 17.0,  2.0 / 17.0, 10.0 / 17.0,
              16.0 / 17.0,  8.0 / 17.0, 14.0 / 17.0,  6.0 / 17.0
            };
            float4x4 _RowAccess = { 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 };
            float2 pos = IN.screenPos.xy / IN.screenPos.w;
            pos *= _ScreenParams.xy; // pixel position
            clip(_Alpha - thresholdMatrix[fmod(pos.x, 4)] * _RowAccess[fmod(pos.y, 4)]);
        }
        ENDCG
    }
    Fallback "Mobile/VertexLit"
}

Vertex and fragment shader:

Shader "WalkingFat/StippleTransparency"
{
    Properties
    {
        _MainTex ("Base (RGB)", 2D) = "white" {}
        _Alpha ("Alpha", Range(0,1)) = 1.0
    }

    SubShader
    {
        Tags
        { 
            "RenderType"="Opaque"
            "Queue" = "Geometry"
        }

        LOD 100

        Pass
        {
            Tags
            {
                "LightMode" = "ForwardBase"
            }

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

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

            struct v2f
            {
                float4 pos : SV_POSITION;
                float2 uv : TEXCOORD0;
                float4 screenPos : TEXCOORD1;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            half _Alpha;

            v2f vert (appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                o.screenPos = ComputeScreenPos (o.pos);

                return o;
            }

            float4 frag (v2f i) : COLOR {
                fixed4 c = tex2D(_MainTex, i.uv);

                // get pixel matrix and caculate screen position
                float4x4 thresholdMatrix =
                {  1.0 / 17.0,  9.0 / 17.0,  3.0 / 17.0, 11.0 / 17.0,
                  13.0 / 17.0,  5.0 / 17.0, 15.0 / 17.0,  7.0 / 17.0,
                   4.0 / 17.0, 12.0 / 17.0,  2.0 / 17.0, 10.0 / 17.0,
                  16.0 / 17.0,  8.0 / 17.0, 14.0 / 17.0,  6.0 / 17.0
                };

                float4x4 _RowAccess = { 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 };
                float2 pos = i.screenPos.xy / i.screenPos.w;
                pos *= _ScreenParams.xy; // pixel position

                // Discard pixel if below threshold.
                clip(_Alpha - thresholdMatrix[fmod(pos.x, 4)] * _RowAccess[fmod(pos.y, 4)]);

                return c;
            }
            ENDCG
        }
    }
    Fallback "Mobile/VertexLit"
}

Share

This site is protected by wp-copyrightpro.com