Синтаксис:
Используется 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
}
}
}
{
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
}
}
}
На количество семплов не обращаем внимание, это исключительно для удобства просмотра. Потом порежу до удобоваримого количества.
Суть проблемы. АО считается по сфере, а не по полусфере. И я ни как не могу понять в каком месте я накосячил. Укажите мне неразумному где я чего ни так написал.
На сколько я сам могу понять - у меня где-то косяк то ли в генерирования псевдослучайных векторов, либо в следующем блоке, в котором уже происходит смещение в новую точку.