Страница 1 из 1

Проблема с самопальным SSAO шейдером

СообщениеДобавлено: 05 янв 2017, 01:34
marggob
Пишу шейдер SSAO для общего развития. В ходе экспериментов и разбирательства с принципом работы SSAO пришёл вот к такому коду.
Синтаксис:
Используется glsl
Shader "Hidden/TestRenderEffect"
{
        Properties
        {
                _MainTex ("Base (RGB)", 2D) = "white" {}
        }

        SubShader
        {
                Cull Off ZWrite Off ZTest Always

                Pass
                {
                        CGPROGRAM
                        #pragma vertex vert
                        #pragma fragment frag
                        #pragma target 3.0
                        #include "UnityCG.cginc"
                        #define MIN_SAMPLE_SIZE 1
                        #define MAX_SAMPLE_SIZE 128

                        sampler2D _MainTex;
                        fixed _Samples, _Radius;
                        sampler2D _CameraDepthNormalsTexture;

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

                        struct v2f     
                        {
                                float2 uv : TEXCOORD0;
                                float4 vertex : SV_POSITION;
                        };

                        v2f vert (appdata v)   
                        {
                                v2f o;
                                o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                                o.uv = v.uv;
                                return o;
                        }

                        fixed4 frag (v2f i) : SV_Target
                        {

                                fixed4 c = tex2D(_MainTex, i.uv);

                                //ScreenUV
                                float2 screenUV = i.uv;

                                //Normal and Depth
                                float3 nrm;
                                float depth;
                                DecodeDepthNormal(tex2D(_CameraDepthNormalsTexture, screenUV), depth, nrm);

                                //Linear Depth
                                float linDepth = Linear01Depth(depth);

                                //Position
                                float2 p11_22 = (unity_CameraProjection._11, unity_CameraProjection._22);
                                float2 p13_31 = (unity_CameraProjection._13, unity_CameraProjection._23);
                                float3 position = float3((screenUV * 2 - 1 - p13_31) / p11_22 * lerp(depth, 1, unity_OrthoParams.w), depth);

                                //Ambient Occlusion
                                float3 ao;
                                float samples = _Samples * 127 + 1;

                                for(int i = 0; i < samples; i++){

                                        //RandomVector
                                        float2 skew = screenUV + i;
                                        float2 skewSin = sin(489.123*(skew));
                                        float onePlusSkew = (1 + skew.x);
                                        //
                                        float2 rndX = 4.789 * skewSin;
                                        float2 rndY = 3.526 * skewSin;
                                        //
                                        float rndFX = rndX.x * rndX.y * onePlusSkew;
                                        float rndFY = rndY.x * rndY.y * onePlusSkew;
                                        float rndFZ = rndX.x * rndY.y * onePlusSkew;

                                        float4 rndTable = normalize(frac(float4(rndFX, rndFY, rndFZ + 0.5, rndFZ)) - 0.5);
                                        rndTable.xyz *= (i + 1)/samples;
                                        rndTable.xyz *= sign(dot(rndTable, nrm));
                                        rndTable.xyz *= linDepth * _Radius;

                                        //Random Position
                                        float3 newPos = position + rndTable.xyz * (MIN_SAMPLE_SIZE + rndTable.w * MAX_SAMPLE_SIZE) / _ScreenParams.x;

                                        //New UV
                                        float4 newUV = mul(unity_CameraProjection, float4(newPos, 1));
                                        newUV.xy /=newUV.w;
                                        newUV.x *= (_ScreenParams.x / _ScreenParams.y);
                                        newUV.xy = 1 - (newUV.xy * 0.5 + 0.5);

                                        //Sampled Position
                                        float newDepth;
                                        float3 newNrm;
                                        DecodeDepthNormal(tex2D(_CameraDepthNormalsTexture, newUV.xy), newDepth, newNrm);

                                        //AO calculate
                                        float distanceCheck = smoothstep(0.0, 1.0, _Radius / abs(position.z - newDepth));
                                        ao += 1 - step(newDepth, newPos.z) * distanceCheck;                                            
                                }

                                c.rgb = lerp( 1, (ao / samples),  1 - depth); //Здесь обрезаю небо, что бы было белым. Потом пиксели дальше заданного расстояния вообще уберу из просчёта.
                                return c;
                        }
                        ENDCG
                }
        }
}

На количество семплов не обращаем внимание, это исключительно для удобства просмотра. Потом порежу до удобоваримого количества.

Суть проблемы. АО считается по сфере, а не по полусфере. И я ни как не могу понять в каком месте я накосячил. Укажите мне неразумному где я чего ни так написал.
На сколько я сам могу понять - у меня где-то косяк то ли в генерирования псевдослучайных векторов, либо в следующем блоке, в котором уже происходит смещение в новую точку.
Изображение

Re: Проблема с самопальным SSAO шейдером

СообщениеДобавлено: 26 янв 2017, 01:09
marggob
Вернулся к расколупыванию своего SSAO. Оказывается что бы корректно считалось SSAO нужно z-составляющую экранных нормалей домножить на -1. Однако здравствуйте.
После небольших дополнений в шейдере он стал куда симпатичней. Как только будет немного свободного времени - займусь отсечением ореолов и подавлением шума. Да и вообще надо переписать весь алгоритм по новой.
Изображение