123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930 |
- /**
- \author Michael Mara and Morgan McGuire, Casual Effects. 2015.
- */
- Shader "Hidden/Post FX/Screen Space Reflection"
- {
- Properties
- {
- _MainTex ("Base (RGB)", 2D) = "white" {}
- }
- CGINCLUDE
- #pragma target 3.0
- #include "UnityCG.cginc"
- #include "UnityPBSLighting.cginc"
- #include "UnityStandardBRDF.cginc"
- #include "UnityStandardUtils.cginc"
- #include "Common.cginc"
- #include "ScreenSpaceRaytrace.cginc"
- float4 _ProjInfo;
- float4x4 _WorldToCameraMatrix;
- float4x4 _CameraToWorldMatrix;
- float4x4 _ProjectToPixelMatrix;
- float2 _ScreenSize;
- float2 _ReflectionBufferSize;
- float2 _InvScreenSize;
- float3 _CameraClipInfo;
- sampler2D _CameraGBufferTexture0;
- sampler2D _CameraGBufferTexture1;
- sampler2D _CameraGBufferTexture2;
- sampler2D _CameraGBufferTexture3;
- sampler2D _CameraReflectionsTexture;
- float _CurrentMipLevel;
- float _RayStepSize;
- float _MaxRayTraceDistance;
- float _LayerThickness;
- float _FresnelFade;
- float _FresnelFadePower;
- float _ReflectionBlur;
- int _HalfResolution;
- int _TreatBackfaceHitAsMiss;
- int _AllowBackwardsRays;
- // RG: SS Hitpoint of ray
- // B: distance ray travelled, used for mip-selection in the final resolve
- // A: confidence value
- sampler2D _HitPointTexture;
- sampler2D _FinalReflectionTexture;
- // RGB: camera-space normal (encoded in [0-1])
- // A: Roughness
- sampler2D _NormalAndRoughnessTexture;
- int _EnableRefine;
- int _AdditiveReflection;
- float _ScreenEdgeFading;
- int _MaxSteps;
- int _BilateralUpsampling;
- float _MaxRoughness;
- float _RoughnessFalloffRange;
- float _SSRMultiplier;
- float _FadeDistance;
- int _TraceBehindObjects;
- int _UseEdgeDetector;
- int _HighlightSuppression;
- /** The height in pixels of a 1m object if viewed from 1m away. */
- float _PixelsPerMeterAtOneMeter;
- // For temporal filtering:
- float4x4 _CurrentCameraToPreviousCamera;
- sampler2D _PreviousReflectionTexture;
- sampler2D _PreviousCSZBuffer;
- float _TemporalAlpha;
- int _UseTemporalConfidence;
- struct v2f
- {
- float4 pos : SV_POSITION;
- float2 uv : TEXCOORD0;
- float2 uv2 : TEXCOORD1;
- };
- v2f vert( appdata_img v )
- {
- v2f o;
- o.pos = UnityObjectToClipPos(v.vertex);
- o.uv = v.texcoord.xy;
- o.uv2 = v.texcoord.xy;
- #if UNITY_UV_STARTS_AT_TOP
- if (_MainTex_TexelSize.y < 0)
- o.uv2.y = 1.0 - o.uv2.y;
- #endif
- return o;
- }
- float2 mipToSize(int mip)
- {
- return floor(_ReflectionBufferSize * exp2(-mip));
- }
- float3 ReconstructCSPosition(float2 S, float z)
- {
- float linEyeZ = -LinearEyeDepth(z);
- return float3((((S.xy * _MainTex_TexelSize.zw)) * _ProjInfo.xy + _ProjInfo.zw) * linEyeZ, linEyeZ);
- }
- /** Read the camera-space position of the point at screen-space pixel ssP */
- float3 GetPosition(float2 ssP)
- {
- float3 P;
- P.z = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, ssP.xy);
- // Offset to pixel center
- P = ReconstructCSPosition(float2(ssP) /*+ float2(0.5, 0.5)*/, P.z);
- return P;
- }
- float applyEdgeFade(float2 tsP, float fadeStrength)
- {
- float maxFade = 0.1;
- float2 itsP = float2(1.0, 1.0) - tsP;
- float dist = min(min(itsP.x, itsP.y), min(tsP.x, tsP.x));
- float fade = dist / (maxFade*fadeStrength + 0.001);
- fade = max(min(fade, 1.0), 0.0);
- fade = pow(fade, 0.2);
- return fade;
- }
- float3 csMirrorVector(float3 csPosition, float3 csN)
- {
- float3 csE = -normalize(csPosition.xyz);
- float cos_o = dot(csN, csE);
- float3 c_mi = normalize((csN * (2.0 * cos_o)) - csE);
- return c_mi;
- }
- float4 fragRaytrace(v2f i, int stepRate)
- {
- float2 ssP = i.uv2.xy;
- float3 csPosition = GetPosition(ssP);
- float smoothness = tex2D(_CameraGBufferTexture1, ssP).a;
- if (csPosition.z < -100.0 || smoothness == 0.0)
- {
- return float4(0.0,0.0,0.0,0.0);
- }
- float3 wsNormal = tex2D(_CameraGBufferTexture2, ssP).rgb * 2.0 - 1.0;
- int2 ssC = int2(ssP * _ScreenSize);
- float3 csN = mul((float3x3)(_WorldToCameraMatrix), wsNormal);
- float3 csRayDirection = csMirrorVector(csPosition, csN);
- if (_AllowBackwardsRays == 0 && csRayDirection.z > 0.0)
- {
- return float4(0.0, 0.0, 0.0, 0.0);
- }
- float maxRayTraceDistance = _MaxRayTraceDistance;
- float jitterFraction = 0.0f;
- float layerThickness = _LayerThickness;
- int maxSteps = _MaxSteps;
- // Bump the ray more in world space as it gets farther away (and so each pixel covers more WS distance)
- float rayBump = max(-0.01*csPosition.z, 0.001);
- float2 hitPixel;
- float3 csHitPoint;
- float stepCount;
- bool wasHit = castDenseScreenSpaceRay
- (csPosition + (csN) * rayBump,
- csRayDirection,
- _ProjectToPixelMatrix,
- _ScreenSize,
- _CameraClipInfo,
- jitterFraction,
- maxSteps,
- layerThickness,
- maxRayTraceDistance,
- hitPixel,
- stepRate,
- _TraceBehindObjects == 1,
- csHitPoint,
- stepCount);
- float2 tsPResult = hitPixel / _ScreenSize;
- float rayDist = dot(csHitPoint - csPosition, csRayDirection);
- float confidence = 0.0;
- if (wasHit)
- {
- confidence = Pow2(1.0 - max(2.0*float(stepCount) / float(maxSteps) - 1.0, 0.0));
- confidence *= clamp(((_MaxRayTraceDistance - rayDist) / _FadeDistance), 0.0, 1.0);
- // Fake fresnel fade
- float3 csE = -normalize(csPosition.xyz);
- confidence *= max(0.0, lerp(pow(abs(dot(csRayDirection, -csE)), _FresnelFadePower), 1, 1.0 - _FresnelFade));
- if (_TreatBackfaceHitAsMiss > 0)
- {
- float3 wsHitNormal = tex2Dlod(_CameraGBufferTexture2, float4(tsPResult, 0, 0)).rgb * 2.0 - 1.0;
- float3 wsRayDirection = mul(_CameraToWorldMatrix, float4(csRayDirection, 0)).xyz;
- if (dot(wsHitNormal, wsRayDirection) > 0)
- {
- confidence = 0.0;
- }
- }
- }
- // Fade out reflections that hit near edge of screen, to prevent abrupt appearance/disappearance when object go off screen
- // Fade out reflections that hit near edge of screen,
- // to prevent abrupt appearance/disappearance when object go off screen
- float vignette = applyEdgeFade(tsPResult, _ScreenEdgeFading);
- confidence *= vignette;
- confidence *= vignette;
- return float4(tsPResult, rayDist, confidence);
- }
- float4 fragComposite(v2f i) : SV_Target
- {
- // Pixel being shaded
- float2 tsP = i.uv2.xy;
- // View space point being shaded
- float3 C = GetPosition(tsP);
- // Final image before this pass
- float4 gbuffer3 = tex2D(_MainTex, i.uv);
- float4 specEmission = float4(0.0,0.0,0.0,0.0);
- float3 specColor = tex2D(_CameraGBufferTexture1, tsP).rgb;
- float roughness = tex2D(_CameraGBufferTexture1, tsP).a;
- float4 reflectionTexel = tex2D(_FinalReflectionTexture, tsP);
- float4 gbuffer0 = tex2D(_CameraGBufferTexture0, tsP);
- // Let core Unity functions do the dirty work of applying the BRDF
- float3 baseColor = gbuffer0.rgb;
- float occlusion = gbuffer0.a;
- float oneMinusReflectivity;
- baseColor = EnergyConservationBetweenDiffuseAndSpecular(baseColor, specColor, oneMinusReflectivity);
- float3 wsNormal = tex2D(_CameraGBufferTexture2, tsP).rgb * 2.0 - 1.0;
- float3 csEyeVec = normalize(C);
- float3 eyeVec = mul(_CameraToWorldMatrix, float4(csEyeVec, 0)).xyz;
- float3 worldPos = mul(_CameraToWorldMatrix, float4(C, 1)).xyz;
- float cos_o = dot(wsNormal, eyeVec);
- float3 w_mi = -normalize((wsNormal * (2.0 * cos_o)) - eyeVec);
- float3 incomingRadiance = reflectionTexel.rgb;
- UnityLight light;
- light.color = 0;
- light.dir = 0;
- #if UNITY_VERSION < 550
- light.ndotl = 0;
- #endif
- UnityIndirect ind;
- ind.diffuse = 0;
- ind.specular = incomingRadiance;
- float3 ssrResult = UNITY_BRDF_PBS (0, specColor, oneMinusReflectivity, roughness, wsNormal, -eyeVec, light, ind).rgb * _SSRMultiplier;
- float confidence = reflectionTexel.a;
- specEmission.rgb = tex2D(_CameraReflectionsTexture, tsP).rgb;
- float3 finalGlossyTerm;
- // Subtract out Unity's glossy result: (we're just applying the delta)
- if (_AdditiveReflection == 0)
- {
- gbuffer3 -= specEmission;
- // We may have blown out our dynamic range by adding then subtracting the reflection probes.
- // As a half-measure to fix this, simply clamp to zero
- gbuffer3 = max(gbuffer3, 0);
- finalGlossyTerm = lerp(specEmission.rgb, ssrResult, saturate(confidence));
- }
- else
- {
- finalGlossyTerm = ssrResult*saturate(confidence);
- }
- finalGlossyTerm *= occlusion;
- // Additively blend the glossy GI result with the output buffer
- return gbuffer3 + float4(finalGlossyTerm, 0);
- }
- float roughnessWeight(float midpointRoughness, float tapRoughness)
- {
- return (1.0 - sqrt(sqrt(abs(midpointRoughness-tapRoughness))));
- }
- float normalWeight(float3 midpointNormal, float3 tapNormal)
- {
- return clamp(dot(midpointNormal, tapNormal), 0, 1);
- }
- float highlightDecompression(float x)
- {
- return x / (1.0 - x);
- }
- float3 highlightDecompression(float3 x)
- {
- return float3(
- highlightDecompression(x.x),
- highlightDecompression(x.y),
- highlightDecompression(x.z)
- );
- }
- float highlightCompression(float x)
- {
- return x / (1.0 + x);
- }
- float3 highlightCompression(float3 x)
- {
- return float3(
- highlightCompression(x.x),
- highlightCompression(x.y),
- highlightCompression(x.z)
- );
- }
- float4 _Axis;
- float4 fragGBlur(v2f i) : SV_Target
- {
- int radius = 4;
- // Pixel being shaded
- float2 tsP = i.uv2.xy;
- float weightSum = 0.0;
- float gaussWeights[5] = { 0.225, 0.150, 0.110, 0.075, 0.0525 };//{0.225, 0.150, 0.110, 0.075, 0.0525};
- float4 resultSum = float4(0.0, 0.0, 0.0, 0.0);
- float4 unweightedResultSum = float4(0.0, 0.0, 0.0, 0.0);
- float4 nAndRough = tex2D(_NormalAndRoughnessTexture, tsP);
- float midpointRoughness = nAndRough.a;
- float3 midpointNormal = nAndRough.rgb * 2 - 1;
- for (int i = -radius; i <= radius; ++i)
- {
- float4 temp;
- float tapRoughness;
- float3 tapNormal;
- float2 tsTap = tsP + (_Axis.xy * _MainTex_TexelSize.xy * float2(i,i)*2.0);
- temp = tex2D(_MainTex, tsTap);
- float weight = temp.a * gaussWeights[abs(i)];
- // Bilateral filtering
- // if (_ImproveCorners)
- // {
- nAndRough = tex2D(_NormalAndRoughnessTexture, tsTap);
- tapRoughness = nAndRough.a;
- tapNormal = nAndRough.rgb * 2 - 1;
- weight *= normalWeight(midpointNormal, tapNormal);
- // }
- weightSum += weight;
- if (_HighlightSuppression)
- {
- temp.rgb = highlightCompression(temp.rgb);
- }
- unweightedResultSum += temp;
- resultSum += temp*weight;
- }
- if (weightSum > 0.01)
- {
- float invWeightSum = (1.0/weightSum);
- // Adding the sqrt seems to decrease temporal flickering at the expense
- // of having larger "halos" of fallback on rough surfaces
- // Subject to change with testing. Sqrt around only half the expression is *intentional*.
- float confidence = min(resultSum.a * sqrt(max(invWeightSum, 2.0)), 1.0);
- float3 finalColor = resultSum.rgb * invWeightSum;
- if (_HighlightSuppression)
- {
- finalColor = highlightDecompression(finalColor);
- }
- return float4(finalColor, confidence);
- }
- else
- {
- float3 finalColor = unweightedResultSum.rgb / (2 * radius + 1);
- if (_HighlightSuppression)
- {
- finalColor = highlightDecompression(finalColor);
- }
- return float4(finalColor, 0.0);
- }
- }
- sampler2D _ReflectionTexture0;
- sampler2D _ReflectionTexture1;
- sampler2D _ReflectionTexture2;
- sampler2D _ReflectionTexture3;
- sampler2D _ReflectionTexture4;
- // Simulate mip maps, since we don't have NPOT mip-chains
- float4 getReflectionValue(float2 tsP, int mip)
- {
- float4 coord = float4(tsP,0,0);
- if (mip == 0)
- {
- return tex2Dlod(_ReflectionTexture0, coord);
- }
- else if (mip == 1)
- {
- return tex2Dlod(_ReflectionTexture1, coord);
- }
- else if (mip == 2)
- {
- return tex2Dlod(_ReflectionTexture2, coord);
- }
- else if (mip == 3)
- {
- return tex2Dlod(_ReflectionTexture3, coord);
- }
- else
- {
- return tex2Dlod(_ReflectionTexture4, coord);
- }
- }
- sampler2D _EdgeTexture0;
- sampler2D _EdgeTexture1;
- sampler2D _EdgeTexture2;
- sampler2D _EdgeTexture3;
- sampler2D _EdgeTexture4;
- // Simulate mip maps, since we don't have NPOT mip-chains
- float4 getEdgeValue(float2 tsP, int mip)
- {
- float4 coord = float4(tsP + float2(1.0/(2 * mipToSize(mip))),0,0);
- if (mip == 0)
- {
- return tex2Dlod(_EdgeTexture0, coord);
- }
- else if (mip == 1)
- {
- return tex2Dlod(_EdgeTexture1, coord);
- }
- else if (mip == 2)
- {
- return tex2Dlod(_EdgeTexture2, coord);
- }
- else if (mip == 3)
- {
- return tex2Dlod(_EdgeTexture3, coord);
- }
- else
- {
- return tex2Dlod(_EdgeTexture4, coord);
- }
- }
- float2 centerPixel(float2 inputP)
- {
- return floor(inputP - float2(0.5,0.5)) + float2(0.5,0.5);
- }
- float2 snapToTexelCenter(float2 inputP, float2 texSize, float2 texSizeInv)
- {
- return centerPixel(inputP * texSize) * texSizeInv;
- }
- float4 bilateralUpsampleReflection(float2 tsP, int mip)
- {
- float2 smallTexSize = mipToSize(mip);
- float2 smallPixelPos = tsP * smallTexSize;
- float2 smallPixelPosi = centerPixel(smallPixelPos);
- float2 smallTexSizeInv = 1.0 / smallTexSize;
- float2 p0 = smallPixelPosi * smallTexSizeInv;
- float2 p3 = (smallPixelPosi + float2(1.0, 1.0)) * smallTexSizeInv;
- float2 p1 = float2(p3.x, p0.y);
- float2 p2 = float2(p0.x, p3.y);
- float4 V0 = getReflectionValue(p0.xy, mip);
- float4 V1 = getReflectionValue(p1.xy, mip);
- float4 V2 = getReflectionValue(p2.xy, mip);
- float4 V3 = getReflectionValue(p3.xy, mip);
- // Bilateral weights:
- // Bilinear interpolation (filter distance)
- float2 smallPixelPosf = smallPixelPos - smallPixelPosi;
- float a0 = (1.0 - smallPixelPosf.x) * (1.0 - smallPixelPosf.y);
- float a1 = smallPixelPosf.x * (1.0 - smallPixelPosf.y);
- float a2 = (1.0 - smallPixelPosf.x) * smallPixelPosf.y;
- float a3 = smallPixelPosf.x * smallPixelPosf.y;
- float2 fullTexSize = _ReflectionBufferSize;
- float2 fullTexSizeInv = 1.0 / fullTexSize;
- float4 hiP0 = float4(snapToTexelCenter(p0, fullTexSize, fullTexSizeInv), 0,0);
- float4 hiP3 = float4(snapToTexelCenter(p3, fullTexSize, fullTexSizeInv), 0,0);
- float4 hiP1 = float4(snapToTexelCenter(p1, fullTexSize, fullTexSizeInv), 0,0);
- float4 hiP2 = float4(snapToTexelCenter(p2, fullTexSize, fullTexSizeInv), 0,0);
- float4 tempCenter = tex2Dlod(_NormalAndRoughnessTexture, float4(tsP, 0, 0));
- float3 n = tempCenter.xyz * 2 - 1;
- float4 temp0 = tex2Dlod(_NormalAndRoughnessTexture, hiP0);
- float4 temp1 = tex2Dlod(_NormalAndRoughnessTexture, hiP1);
- float4 temp2 = tex2Dlod(_NormalAndRoughnessTexture, hiP2);
- float4 temp3 = tex2Dlod(_NormalAndRoughnessTexture, hiP3);
- float3 n0 = temp0.xyz * 2 - 1;
- float3 n1 = temp1.xyz * 2 - 1;
- float3 n2 = temp2.xyz * 2 - 1;
- float3 n3 = temp3.xyz * 2 - 1;
- a0 *= normalWeight(n, n0);
- a1 *= normalWeight(n, n1);
- a2 *= normalWeight(n, n2);
- a3 *= normalWeight(n, n3);
- float r = tempCenter.a;
- float r0 = temp0.a;
- float r1 = temp1.a;
- float r2 = temp2.a;
- float r3 = temp3.a;
- a0 *= roughnessWeight(r, r0);
- a1 *= roughnessWeight(r, r1);
- a2 *= roughnessWeight(r, r2);
- a3 *= roughnessWeight(r, r3);
- // Slightly offset from zero
- a0 = max(a0, 0.001);
- a1 = max(a1, 0.001);
- a2 = max(a2, 0.001);
- a3 = max(a3, 0.001);
- // Nearest neighbor
- // a0 = a1 = a2 = a3 = 1.0;
- // Normalize the blending weights (weights were chosen so that
- // the denominator can never be zero)
- float norm = 1.0 / (a0 + a1 + a2 + a3);
- // Blend
- float4 value = (V0 * a0 + V1 * a1 + V2 * a2 + V3 * a3) * norm;
- //return V0;
- return value;
- }
- /** Explicit bilinear fetches; must be used if the reflection buffer is bound using point sampling */
- float4 bilinearUpsampleReflection(float2 tsP, int mip)
- {
- float2 smallTexSize = mipToSize(mip);
- float2 smallPixelPos = tsP * smallTexSize;
- float2 smallPixelPosi = centerPixel(smallPixelPos);
- float2 smallTexSizeInv = 1.0 / smallTexSize;
- float2 p0 = smallPixelPosi * smallTexSizeInv;
- float2 p3 = (smallPixelPosi + float2(1.0, 1.0)) * smallTexSizeInv;
- float2 p1 = float2(p3.x, p0.y);
- float2 p2 = float2(p0.x, p3.y);
- float4 V0 = getReflectionValue(p0.xy, mip);
- float4 V1 = getReflectionValue(p1.xy, mip);
- float4 V2 = getReflectionValue(p2.xy, mip);
- float4 V3 = getReflectionValue(p3.xy, mip);
- float a0 = 1.0;
- float a1 = 1.0;
- float a2 = 1.0;
- float a3 = 1.0;
- // Bilateral weights:
- // Bilinear interpolation (filter distance)
- float2 smallPixelPosf = smallPixelPos - smallPixelPosi;
- a0 = (1.0 - smallPixelPosf.x) * (1.0 - smallPixelPosf.y);
- a1 = smallPixelPosf.x * (1.0 - smallPixelPosf.y);
- a2 = (1.0 - smallPixelPosf.x) * smallPixelPosf.y;
- a3 = smallPixelPosf.x * smallPixelPosf.y;
- // Blend
- float4 value = (V0 * a0 + V1 * a1 + V2 * a2 + V3 * a3);
- return value;
- }
- // Unity's roughness is GGX roughness squared
- float roughnessToBlinnPhongExponent(float roughness)
- {
- float r2 = roughness*roughness;
- return 2.0f / r2*r2 - 2.0f;
- }
- float glossyLobeSlope(float roughness)
- {
- return pow(roughness, 4.0/3.0);
- }
- // Empirically based on our filter:
- // Mip | Pixels
- // --------------
- // 0 | 1 no filter, so single pixel
- // 1 | 17 2r + 1 filter applied once, grabbing from pixels r away in either direction (r=8, four samples times stride of 2)
- // 2 | 50 2r + 1 filter applied on double size pixels, and each of those pixels had reached another r out to the side 2(2r + 1) + m_1
- // 3 | 118 4(2r + 1) + m_2
- // 4 | 254 8(2r + 1) + m_3
- //
- // Approximated by pixels = 16*2^mip-15
- // rearranging we get mip = log_2((pixels + 15) / 16)
- //
- float filterFootprintInPixelsToMip(float footprint)
- {
- return log2((footprint + 15) / 16);
- }
- float3 ansiGradient(float t)
- {
- //return float3(t, t, t);
- return fmod(floor(t * float3(8.0, 4.0, 2.0)), 2.0);
- }
- float4 fragCompositeSSR(v2f i) : SV_Target
- {
- // Pixel being shaded
- float2 tsP = i.uv2.xy;
- float roughness = 1.0-tex2D(_CameraGBufferTexture1, tsP).a;
- float rayDistance = tex2D(_HitPointTexture, tsP).z;
- // Get the camera space position of the reflection hit
- float3 csPosition = GetPosition(tsP);
- float3 wsNormal = tex2D(_CameraGBufferTexture2, tsP).rgb * 2.0 - 1.0;
- float3 csN = mul((float3x3)(_WorldToCameraMatrix), wsNormal);
- float3 c_mi = csMirrorVector(csPosition, csN);
- float3 csHitpoint = c_mi * rayDistance + csPosition;
- float gatherFootprintInMeters = glossyLobeSlope(roughness) * rayDistance;
- // We could add a term that incorporates the normal
- // This approximation assumes reflections happen at a glancing angle
- float filterFootprintInPixels = gatherFootprintInMeters * _PixelsPerMeterAtOneMeter / csHitpoint.z;
- if (_HalfResolution == 1)
- {
- filterFootprintInPixels *= 0.5;
- }
- float mip = filterFootprintInPixelsToMip(filterFootprintInPixels);
- float nonPhysicalMip = pow(roughness, 3.0 / 4.0) * UNITY_SPECCUBE_LOD_STEPS;
- if (_HalfResolution == 1)
- {
- nonPhysicalMip = nonPhysicalMip * 0.7;
- }
- mip = max(0, min(4, mip));
- float4 result = 0.;
- {
- int mipMin = int(mip);
- int mipMax = min(mipMin + 1, 4);
- float mipLerp = mip-mipMin;
- if (_BilateralUpsampling == 1)
- {
- result = lerp(bilateralUpsampleReflection(tsP, mipMin), bilateralUpsampleReflection(tsP, mipMax), mipLerp);
- }
- else
- {
- float4 minResult = getReflectionValue(tsP, mipMin);
- float4 maxResult = getReflectionValue(tsP, mipMax);
- result = lerp(minResult, maxResult, mipLerp);
- result.a = min(minResult.a, maxResult.a);
- }
- }
- result.a = min(result.a, 1.0);
- float vignette = applyEdgeFade(tsP, _ScreenEdgeFading);
- result.a *= vignette;
- // THIS MIGHT BE SLIGHTLY WRONG, TRY STEP()
- float alphaModifier = 1.0 - clamp(roughness * .3, 0., 1.);
- result.a *= alphaModifier;
- return result;
- }
- int _LastMip;
- float4 fragMin(v2f i) : SV_Target
- {
- float2 tsP = i.uv2.xy;
- float2 lastTexSize = mipToSize(_LastMip);
- float2 lastTexSizeInv = 1.0 / lastTexSize;
- float2 p00 = snapToTexelCenter(tsP, lastTexSize, lastTexSizeInv);
- float2 p11 = p00 + lastTexSizeInv;
- return min(
- min(tex2D(_MainTex, p00), tex2D(_MainTex, p11)),
- min(tex2D(_MainTex, float2(p00.x, p11.y)), tex2D(_MainTex, float2(p11.x, p00.y)))
- );
- }
- float4 fragResolveHitPoints(v2f i) : SV_Target
- {
- float2 tsP = i.uv2.xy;
- float4 temp = tex2D(_HitPointTexture, tsP);
- float2 hitPoint = temp.xy;
- float confidence = temp.w;
- float3 colorResult = confidence > 0.0 ? tex2D(_MainTex, hitPoint).rgb : tex2D(_CameraReflectionsTexture, tsP).rgb;
- #ifdef UNITY_COMPILER_HLSL
- /*if (any(isnan(colorResult)))
- colorResult = float3(0.0, 0.0, 0.0);
- // As of 11/29/2015, on Unity 5.3 on a Windows 8.1 computer with a NVIDIA GeForce 980,
- // with driver 347.62, the above check does not actually work to get rid of NaNs!
- // So we add this "redundant" check.
- if (!all(isfinite(colorResult)))
- colorResult = float3(0.0, 0.0, 0.0);*/
- #endif
- return float4(colorResult, confidence);
- }
- float4 fragBilatKeyPack(v2f i) : SV_Target
- {
- float2 tsP = i.uv2.xy;
- float3 csN = tex2D(_CameraGBufferTexture2, tsP).xyz;
- float roughness = tex2D(_CameraGBufferTexture1, tsP).a;
- return float4(csN, roughness);
- }
- float4 fragDepthToCSZ(v2f i) : SV_Target
- {
- float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv2.xy);
- return float4(-LinearEyeDepth(depth), 0.0, 0.0, 0.0);
- }
- static const int NUM_POISSON_TAPS = 12;
- // Same as used in CameraMotionBlur.shader
- static const float2 poissonSamples[NUM_POISSON_TAPS] =
- {
- float2(-0.326212,-0.40581),
- float2(-0.840144,-0.07358),
- float2(-0.695914,0.457137),
- float2(-0.203345,0.620716),
- float2(0.96234,-0.194983),
- float2(0.473434,-0.480026),
- float2(0.519456,0.767022),
- float2(0.185461,-0.893124),
- float2(0.507431,0.064425),
- float2(0.89642,0.412458),
- float2(-0.32194,-0.932615),
- float2(-0.791559,-0.59771)
- };
- float4 fragFilterSharpReflections(v2f i) : SV_Target
- {
- // Could improve perf by not computing blur when we won't be sampling the highest level anyways
- float2 tsP = i.uv2.xy;
- float4 sum = 0.0;
- float sampleRadius = _MainTex_TexelSize.xy * _ReflectionBlur;
- for (int i = 0; i < NUM_POISSON_TAPS; i++)
- {
- float2 p = tsP + poissonSamples[i] * sampleRadius;
- float4 tap = tex2D(_MainTex, p);
- if (_HighlightSuppression)
- {
- tap.rgb = highlightCompression(tap.rgb);
- }
- sum += tap;
- }
- float4 result = sum / float(NUM_POISSON_TAPS);
- if (_HighlightSuppression)
- {
- result.rgb = highlightDecompression(result.rgb);
- }
- return result;
- }
- ENDCG
- SubShader
- {
- ZTest Always Cull Off ZWrite Off
- // 0: Raytrace
- Pass
- {
- CGPROGRAM
- #pragma exclude_renderers gles xbox360 ps3
- #pragma vertex vert
- #pragma fragment fragRaytrace1
- float4 fragRaytrace1(v2f i) : SV_Target
- {
- return fragRaytrace(i, _RayStepSize);
- }
- ENDCG
- }
- // 1: Composite
- Pass
- {
- CGPROGRAM
- #pragma exclude_renderers gles xbox360 ps3
- #pragma vertex vert
- #pragma fragment fragComposite
- ENDCG
- }
- // 2: GBlur
- Pass
- {
- CGPROGRAM
- #pragma exclude_renderers gles xbox360 ps3
- #pragma vertex vert
- #pragma fragment fragGBlur
- ENDCG
- }
- // 3: CompositeSSR
- Pass
- {
- CGPROGRAM
- #pragma exclude_renderers gles xbox360 ps3
- #pragma vertex vert
- #pragma fragment fragCompositeSSR
- ENDCG
- }
- // 4: Min mip generation
- Pass
- {
- CGPROGRAM
- #pragma exclude_renderers gles xbox360 ps3
- #pragma vertex vert
- #pragma fragment fragMin
- ENDCG
- }
- // 5: Hit point texture to reflection buffer
- Pass
- {
- CGPROGRAM
- #pragma exclude_renderers gles xbox360 ps3
- #pragma vertex vert
- #pragma fragment fragResolveHitPoints
- ENDCG
- }
- // 6: Pack Bilateral Filter Keys in single buffer
- Pass
- {
- CGPROGRAM
- #pragma exclude_renderers gles xbox360 ps3
- #pragma vertex vert
- #pragma fragment fragBilatKeyPack
- ENDCG
- }
- // 7: Blit depth information as camera space Z
- Pass
- {
- CGPROGRAM
- #pragma exclude_renderers gles xbox360 ps3
- #pragma vertex vert
- #pragma fragment fragDepthToCSZ
- ENDCG
- }
- // 8: Filter the highest quality reflection buffer
- Pass
- {
- CGPROGRAM
- #pragma exclude_renderers gles xbox360 ps3
- #pragma vertex vert
- #pragma fragment fragFilterSharpReflections
- ENDCG
- }
- }
- Fallback "Diffuse"
- }
|