Shader "Custom/SSGIShader"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_AlbedoTex ("Texture", 2D) = "white" {}
_PrevTex ("Texture", 2D) = "white" {}
}
SubShader
{
Cull Off ZWrite Off ZTest Always
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#define PI 3.14159
struct appdata {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f {
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
v2f vert (appdata v) {
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
UNITY_DECLARE_DEPTH_TEXTURE( _CameraDepthTexture );
sampler2D_half _CameraMotionVectorsTexture;
sampler2D _MainTex;
sampler2D _CameraDepthNormalsTexture;
sampler2D _AlbedoTex;
sampler2D _PrevTex;
uniform float4 _MainTex_TexelSize;
uniform int FramesSinceStart;
float4x4 camtoworld;
float4x4 caminvproj;
float4x4 camproj;
float4x4 worldtocam;
float3 campos;
void CreateCameraRay(float2 uv, inout float3 origin, inout float3 direction) {
// Transform the camera origin to world space
origin = mul(camtoworld, float4(0.0f, 0.0f, 0.0f, 1.0f)).xyz;
// Invert the perspective projection of the view-space position
direction = mul(caminvproj, float4(uv, 0.0f, 1.0f)).xyz;
// Transform the direction from camera to world space and normalize
direction = mul(camtoworld, float4(direction, 0.0f)).xyz;
direction = normalize(direction);
}
float2 sample_disc(float u1, float u2) {
float a = 2.0f * u1 - 1.0f;
float b = 2.0f * u2 - 1.0f;
if (a == 0.0f) a = 0.00001;
if (b == 0.0f) b = 0.00001;
float phi, r;
if (a * a > b * b) {
r = a;
phi = (0.25f * PI) * (b / a);
}
else {
r = b;
phi = (0.25f * PI) * (a / b) + (0.5f * PI);
}
float sin_phi, cos_phi;
sincos(phi, sin_phi, cos_phi);
return float2(r * cos_phi, r * sin_phi);
}
float3 sample_cosine_weighted_direction(float u1, float u2) {
float2 d = sample_disc(u1, u2);
return float3(d.x, d.y, sqrt(abs(1.0f - dot(d, d))));
}
float3 GetWorldPos(float2 uv) {
float depth = LinearEyeDepth( SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, uv) );
float3 origin;
float3 direction;
CreateCameraRay(uv * 2.0f - 1.0f, origin, direction);
return direction * depth + origin;
}
float3x3 GetTangentSpace(float3 normal) {
// Choose a helper floattor for the cross product
float3 helper = float3(1, 0, 0);
if (abs(normal.x) > 0.99f)
helper = float3(0, 0, 1);
// Generate floattors
float3 tangent = normalize(cross(normal, helper));
float3 binormal = cross(normal, tangent);
return float3x3(tangent, binormal, normal);
}
uint hash_with(uint seed, uint hash) {
// Wang hash
seed = (seed ^ 61) ^ hash;
seed += seed << 3;
seed ^= seed >> 4;
seed *= 0x27d4eb2d;
return seed;
}
uint pcg_hash(uint seed) {
uint state = seed * 747796405u + 2891336453u;
uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;
return (word >> 22u) ^ word;
}
float2 random(uint samdim, uint pixel_index) {
uint hash = pcg_hash((pixel_index * (uint)204 + samdim));
const static float one_over_max_unsigned = asfloat(0x2f7fffff);
float x = hash_with(FramesSinceStart, hash) * one_over_max_unsigned;
float y = hash_with(FramesSinceStart + 0xdeadbeef, hash) * one_over_max_unsigned;
return float2(x, y);
}
float2 viewSpaceToScreenSpace(float3 position) {
position = normalize(position - campos)*(_ProjectionParams.y + (_ProjectionParams.z - _ProjectionParams.y))+campos;
fixed3 toCam = mul(worldtocam, position);
fixed camPosZ = toCam.z;
fixed height = 2 * camPosZ / camproj._m11;
fixed width = _ScreenParams.x / _ScreenParams.y * height;
float2 uv;
uv.x = (toCam.x + width / 2)/width;
uv.y = (toCam.y + height / 2)/height;
return 1.0f - uv;
}
float4 frag (v2f i) : SV_Target {
float2 uv = i.uv;
float3 throughput = tex2D(_AlbedoTex,uv).xyz;
int steps = 200;
float3 Lum = 0;//max(tex2D(_MainTex, uv).xyz - tex2D(_AlbedoTex,uv).xyz,0);
float2 motionvectors = tex2D(_CameraMotionVectorsTexture, uv);
float3 PrevCol = tex2D(_PrevTex, uv - motionvectors).xyz;
float3 origin;
float3 direction;
CreateCameraRay(uv * 2.0f - 1.0f, origin, direction);
for(int i2 = 0; i2 < 1; i2++) {
float3 CenterPos = GetWorldPos(uv);
float depth = LinearEyeDepth( SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, uv));
// float3 XOffPos =
float3 normal = normalize(mul((float3x3)camtoworld, DecodeViewNormalStereo(tex2D(_CameraDepthNormalsTexture, uv))));
float2 rand = random(53 + i2, (i.uv.x * 1920) + (i.uv.y * 1080) * 1920);
direction = reflect(direction, normal);//normalize(mul(sample_cosine_weighted_direction(rand.x,rand.y), GetTangentSpace(normal)));
// direction *= 3 / float(steps);
// CenterPos += normal * 0.1f;
CenterPos += normal * 0.01f;
for(int i = 1; i < steps; i++) {
float m = exp(pow(float(i) / 4.0, 0.05)) - 2.0;
CenterPos += direction * min(m, 1.);
float2 uv2 = viewSpaceToScreenSpace(CenterPos);
float2 newDepth = LinearEyeDepth( SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, uv2));
float depthdiff = newDepth - length(CenterPos - origin);
if(any(uv2 < 0 || uv2 > 1)) break;
if(depthdiff >= 0 && depthdiff < 0.2f) {
throughput *= tex2D(_AlbedoTex, uv2).xyz;
Lum = max(tex2D(_MainTex, uv2).xyz,0);
uv = uv2;
break;
}
}
}
return float4(lerp(Lum, PrevCol, 0.64f) , 1);
}
ENDCG
}
}
}