Skip to content

Commit

Permalink
Beta version of light shafts. Should be working. Mostly(tm).
Browse files Browse the repository at this point in the history
  • Loading branch information
robertcupisz committed Jan 9, 2014
0 parents commit 0a3ab0d
Show file tree
Hide file tree
Showing 31 changed files with 3,622 additions and 0 deletions.
92 changes: 92 additions & 0 deletions Coord.shader
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
Shader "Hidden/Coord" {
Subshader {
ZTest Always Cull Off ZWrite Off Fog { Mode Off }

Pass {
CGPROGRAM
#pragma target 3.0
#pragma glsl
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile LIGHT_ON_SCREEN LIGHT_OFF_SCREEN
#pragma multi_compile DIRECTIONAL_SHAFTS SPOT_SHAFTS
#include "UnityCG.cginc"
#include "Shared.cginc"

float4 _CoordTexDim;
float4 _ScreenTexDim;
sampler2D _CameraDepthTexture;

posuv vert (appdata_img v)
{
posuv o;
o.pos = v.vertex;
#if !UNITY_UV_STARTS_AT_TOP
o.pos.y *= -1;
#endif
o.uv = v.texcoord;
return o;
}

void frag (posuv i, out float4 coord : COLOR0, out float4 depth : COLOR1)
{
float2 uv = i.uv;

float sampleOnEpipolarLine = uv.x - 0.5f/_CoordTexDim.x;
float epipolarLine = saturate(uv.y - 0.5f/_CoordTexDim.y);

// sampleOnEpipolarLine is now in the range [0, 1 - 1/_CoordTexDim.x]
// We need to rescale it to be in [0, 1]
sampleOnEpipolarLine *= _CoordTexDim.x / (_CoordTexDim.x-1);
sampleOnEpipolarLine = saturate(sampleOnEpipolarLine);

// epipolarLine is in the range [0, 1 - 1/_CoordTexDim.y]
int edge = clamp(floor( epipolarLine * 4 ), 0, 3);
float posOnEdge = frac( epipolarLine * 4 );

// Left, bottom, right, top
float edgeCoord = -1 + 2*posOnEdge;
float4 edgeX = float4(-1, edgeCoord, 1, -edgeCoord);
float4 edgeY = float4(-edgeCoord, -1, edgeCoord, 1);
bool4 edgeFlags = bool4(edge.xxxx == int4(0,1,2,3));

float2 exit = -float2(dot(edgeY, edgeFlags), dot(edgeX, edgeFlags));
float2 entry = GetEpipolarLineEntryPoint(exit);

float2 coordTemp = lerp(entry, exit, sampleOnEpipolarLine);
coordTemp = coordTemp*0.5 + 0.5;
coord = float4(coordTemp.x, coordTemp.y, 0, 0);

// Sample depth from the main buffer and store in epipolar space
coordTemp = (floor(coordTemp*_ScreenTexDim.xy) + 0.5)*_ScreenTexDim.zw;
depth = Linear01Depth(tex2D(_CameraDepthTexture, coordTemp).x).xxxx;

// Test against the volume if we've hit at all
float near, far, rayLength;
float3 rayN;
if(!IntersectVolume(coord.xy, near, far, rayN, rayLength) || (depth.x < near/rayLength))
{
// When detecting depth breaks, we'll skip this sample (no raymarching)
depth *= -1.0;
}
else
{
// Clamp depth to the far end of the volume, to avoid later generation of depth break
// samples for things behind the volume (wasted computation, artifacts).
// Requires the same clamp for depth sampled in the final interpolation step.
depth = min(depth, far/rayLength);
}

// TODO: instead of intersecting volume here and in final interpolation, consider
// rasterizing the light shape into a smaller res buffer.
// Even though intersection is quite expensive in the final interpolation for every
// rasterized screen pixel, still beats not doing it by about 10% and gets rid of the artifacts
// of depth breaks for stuff behind the volume.
}
ENDCG
}

}

Fallback off
}
5 changes: 5 additions & 0 deletions Coord.shader.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 34 additions & 0 deletions Depth.shader
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
Shader "Hidden/Depth" {
SubShader {
Tags { "RenderType"="Opaque" }
Pass {
Fog { Mode Off }
Cull Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"

struct v2f {
float4 pos : SV_POSITION;
float depth : TEXCOORD0;
};

v2f vert (appdata_base v) {
v2f o;
o.pos = mul (UNITY_MATRIX_MVP, v.vertex);

// We want [0,1] linear depth, so that 0.5 is half way between near and far.
COMPUTE_EYEDEPTH(o.depth);
o.depth = (o.depth - _ProjectionParams.y)/(_ProjectionParams.z - _ProjectionParams.y);

return o;
}

float4 frag(v2f i) : COLOR {
return i.depth;
}
ENDCG
}
}
}
5 changes: 5 additions & 0 deletions Depth.shader.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

116 changes: 116 additions & 0 deletions DepthBreaks.shader
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
Shader "Hidden/DepthBreaks" {
SubShader {
Pass {
ZWrite Off Fog { Mode Off }
Blend Off
Cull Back
Stencil
{
Ref 1
Comp always
Pass replace
}

CGPROGRAM
#include "UnityCG.cginc"
#include "Shared.cginc"
#pragma target 3.0
#pragma glsl
#pragma vertex vert_simple
#pragma fragment frag
#pragma exclude_renderers xbox360

sampler2D _DepthEpi;
float4 _DepthEpiTexDim;
float _DepthThreshold;

float SampleDepth(float x, float y)
{
// tex2Dlod, because tex2D requires calculating derivatives and we can't do that in a loop
return abs(tex2Dlod(_DepthEpi, float4(x*_DepthEpiTexDim.z, y, 0, 0))).x;
}

float4 frag(posuv i) : COLOR
{
// _DepthEpi was marked -1 if the ray missed the volume completely.
// Skip, but don't discard, so it won't be a raymarching sample.
if (tex2Dlod(_DepthEpi, float4(i.uv.x, i.uv.y, 0, 0)).x < 0.0)
return -1;

float y = i.uv.y;
int step = GetInterpolationStep(i.uv.x);
float stepRcp = 1.0/float(step);

int x = floor(i.uv.x*_DepthEpiTexDim.x);
int start = x*stepRcp;
start *= step;
x -= start;
int left = x;
int right = x;

while (left > 0)
{
if (abs(SampleDepth(start + left - 1, y) - SampleDepth(start + left, y)) > _DepthThreshold)
break;
left--;
}

// We're going all the way to STEP, because if there's no depth break, we don't want to have
// raymarching samples on both sides of whatever is our current step. So e.g. if STEP is 16,
// we don't want a sample on the 15th and 16th pixel (16th is the leftmost from the next step),
// because that's redundant and would actually show as discontinuity after interpolated along rays.
// But if there is a depth break between the 15th and 16th pixel, we want samples on both.
while (right < step)
{
if (abs(SampleDepth(start + right, y) - SampleDepth(start + right + 1, y)) > _DepthThreshold)
break;
right++;
}

// Because of going all the way to STEP, the very last sample is a pixel too far - clamp it.
right = min(start + right, _DepthEpiTexDim.x - 1) - start;

float l = (x - left)*stepRcp;
float r = (right - x)*stepRcp;

// If either l or r is 0, it's a raymarching sample. The texture has been cleared to black, so
// we don't have to write anything and since we're discarding, stencil for those pixels will stay at 0.
// Then we only have to run raymarching for pixels will stencil 0.
if (l*r == 0)
discard;
return float4(l, r, 0, 0);
}

ENDCG
}

// Temporary, to clear the stencil, as GL.Clear doesn't work.
// Edit: fixed in 4.5, so this hack can be removed
Pass {
ZWrite Off Fog { Mode Off }
Blend Off
Cull Front
Stencil
{
Ref 0
Comp always
Pass zero
}

CGPROGRAM
#include "UnityCG.cginc"
#include "Shared.cginc"
#pragma target 3.0
#pragma glsl
#pragma vertex vert_simple
#pragma fragment frag

float4 frag (posuv i) : COLOR
{
return 0;
}
ENDCG
}

}
}
5 changes: 5 additions & 0 deletions DepthBreaks.shader.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions Editor.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 0a3ab0d

Please sign in to comment.