I just remembered seeing a new “Deferred Reflections” shader override in the graphics options, so I downloaded the shader source for 5.2 to see if their deferred reflections shader was in there, and it was. I was able to find and fix this issue pretty easily. I’m still not sure what the reasoning for this change was. The comments mention artifacts. I’ll see if I run into any issues. Perhaps I’m using these new reflection probes incorrectly? Until then, I’m attaching my slight modification to Internal-DeferredReflections here. The changes are at line 67.
Shader "Hidden/Internal-DeferredReflectionsAccurate" {
Properties {
_SrcBlend ("", Float) = 1
_DstBlend ("", Float) = 1
}
SubShader {
// Calculates reflection contribution from a single probe (rendered as cubes) or default reflection (rendered as full screen quad)
Pass {
ZWrite Off
ZTest LEqual
Blend [_SrcBlend] [_DstBlend]
CGPROGRAM
#pragma target 3.0
#pragma vertex vert_deferred
#pragma fragment frag
#include "UnityCG.cginc"
#include "UnityDeferredLibrary.cginc"
#include "UnityStandardUtils.cginc"
#include "UnityStandardBRDF.cginc"
#include "UnityPBSLighting.cginc"
sampler2D _CameraGBufferTexture0;
sampler2D _CameraGBufferTexture1;
sampler2D _CameraGBufferTexture2;
half3 distanceFromAABB(half3 p, half3 aabbMin, half3 aabbMax)
{
return max(max(p - aabbMax, aabbMin - p), half3(0.0, 0.0, 0.0));
}
half4 frag (unity_v2f_deferred i) : SV_Target
{
// Stripped from UnityDeferredCalculateLightParams, refactor into function ?
i.ray = i.ray * (_ProjectionParams.z / i.ray.z);
float2 uv = i.uv.xy / i.uv.w;
// read depth and reconstruct world position
float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv);
depth = Linear01Depth (depth);
float4 viewPos = float4(i.ray * depth,1);
float3 worldPos = mul (_CameraToWorld, viewPos).xyz;
half4 gbuffer0 = tex2D (_CameraGBufferTexture0, uv);
half4 gbuffer1 = tex2D (_CameraGBufferTexture1, uv);
half4 gbuffer2 = tex2D (_CameraGBufferTexture2, uv);
half3 specColor = gbuffer1.rgb;
half oneMinusRoughness = gbuffer1.a;
half3 worldNormal = gbuffer2.rgb * 2 - 1;
worldNormal = normalize(worldNormal);
float3 eyeVec = normalize(worldPos - _WorldSpaceCameraPos);
half oneMinusReflectivity = 1 - SpecularStrength(specColor.rgb);
half occlusion = gbuffer0.a;
half3 worldNormalRefl = reflect(eyeVec, worldNormal);
float blendDistance = unity_SpecCube1_ProbePosition.w; // will be set to blend distance for this probe
#if UNITY_SPECCUBE_BOX_PROJECTION
// For box projection, use expanded bounds as they are rendered; otherwise
// box projection artifacts when outside of the box.
//This is where the reflections were becoming inaccurate by adding the blend distance.
//float4 boxMin = unity_SpecCube0_BoxMin - float4(blendDistance,blendDistance,blendDistance,0);
//float4 boxMax = unity_SpecCube0_BoxMax + float4(blendDistance,blendDistance,blendDistance,0);
float4 boxMin = unity_SpecCube0_BoxMin;
float4 boxMax = unity_SpecCube0_BoxMax;
half3 worldNormal0 = BoxProjectedCubemapDirection (worldNormalRefl, worldPos, unity_SpecCube0_ProbePosition, boxMin, boxMax);
#else
half3 worldNormal0 = worldNormalRefl;
#endif
Unity_GlossyEnvironmentData g;
g.roughness = 1 - oneMinusRoughness;
g.reflUVW = worldNormal0;
half3 env0 = Unity_GlossyEnvironment (UNITY_PASS_TEXCUBE(unity_SpecCube0), unity_SpecCube0_HDR, g);
UnityLight light;
light.color = 0;
light.dir = 0;
light.ndotl = 0;
UnityIndirect ind;
ind.diffuse = 0;
ind.specular = env0 * occlusion;
half3 rgb = UNITY_BRDF_PBS (0, specColor, oneMinusReflectivity, oneMinusRoughness, worldNormal, -eyeVec, light, ind).rgb;
// Calculate falloff value, so reflections on the edges of the probe would gradually blend to previous reflection.
// Also this ensures that pixels not located in the reflection probe AABB won't
// accidentally pick up reflections from this probe.
half3 distance = distanceFromAABB(worldPos, unity_SpecCube0_BoxMin.xyz, unity_SpecCube0_BoxMax.xyz);
half falloff = saturate(1.0 - length(distance)/blendDistance);
return half4(rgb, falloff);
}
ENDCG
}
// Adds reflection buffer to the lighting buffer
Pass
{
ZWrite Off
ZTest Always
Blend [_SrcBlend] [_DstBlend]
CGPROGRAM
#pragma target 3.0
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile ___ UNITY_HDR_ON
#include "UnityCG.cginc"
sampler2D _CameraReflectionsTexture;
struct v2f {
float2 uv : TEXCOORD0;
float4 pos : SV_POSITION;
};
v2f vert (float4 vertex : POSITION)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, vertex);
o.uv = ComputeScreenPos (o.pos).xy;
return o;
}
half4 frag (v2f i) : SV_Target
{
half4 c = tex2D (_CameraReflectionsTexture, i.uv);
#ifdef UNITY_HDR_ON
return c;
#else
return exp2(-c);
#endif
}
ENDCG
}
}
Fallback Off
}
Edit: Yeah, there are definitely blending issues with this. I’ll keep messing with it, but I’m no shader expert. Is there any way to revert to the old way of doing reflections, if there is no foreseeable fix for this? Most of the objects in my game don’t need to blend nicely and were set to only use one cubemap anyway.