I am currently only able to render once every second, but not blend between the old and new cubemap. It instantly swaps to the new one. I found the ReflectionProbe.BlendCubemap function but have had no success with it. Most attempts I make crash Unity, and since there are a grand total of zero examples of it being used online I have a hard time even figuring out if it is the way to go.
I am hoping not to have to rely on blending the cubemaps inside the shader since I want this to work on all objects with all kinds of materials, not just certain ones which are blend-approved…
Here’s some of the code I’ve tried, which in my mind should probably work. All it does is render a new reflection every second with no blending. But as I said there isn’t really that much information available about this stuff so I have a hard time to figure out what I am doing wrong.
public class PlayerReflectionProbe : MonoBehaviour
{
private float timer;
public float updateTime = 1f;
private ReflectionProbe thisProbe;
public Texture oldCubemap;
public Texture newCubemap;
private RenderTexture finalCubemap;
public float blend = 0.5f;
public RenderTexture render;
void Awake()
{
// Set up reflection probe component.
if (thisProbe == null)
{
thisProbe = GetComponent<ReflectionProbe>();
}
// Set up final texture diplayed by render probe.
render = new RenderTexture(128, 128, 0);
render.dimension = UnityEngine.Rendering.TextureDimension.Cube;
render.useMipMap = true;
thisProbe.customBakedTexture = render;
}
// Update is called once per frame
void Update()
{
// Blend between old and new.
ReflectionProbe.BlendCubemap(oldCubemap, newCubemap, blend, render);
// Assign final render to probe ???
thisProbe.customBakedTexture = render;
// Update blend
blend -= Time.deltaTime;
if (blend <= 0f)
blend = 1f;
// Render new once every second, and save old render.
timer += Time.deltaTime;
if (timer >= updateTime)
{
oldCubemap = thisProbe.texture;
thisProbe.RenderProbe();
newCubemap = thisProbe.texture;
timer = 0f;
}
}
}
Here is some code I made a while ago that I forgot about that basically does what you asked, and also has a bunch of features. I forget how exactly you use it, but I tested it and it works fine for me. When set to medium, it updates the cubemap every n seconds, and interpolates to it smoothly. At high, it just updates every frame. At low, I think it just uses the skybox.
public class ReflectionProbeBlender : MonoBehaviour {
public ReflectionProbe outputProbe;
public ReflectionProbe samplerProbe;
public ReflectionProbe previousProbe;
public LayerMask cullingMask;
public ReflectionRes lowReflectionResolution;
public ReflectionRes mediumReflectionResolution;
public ReflectionRes highReflectionResolution;
private ReflectionRes currentReflectionRes;
public float updateReflectionEveryNSeconds = 1f;
public WaterReflectionQuality reflectionQuality;
private float updateTimer;
private RenderTexture blendedTexture;
public enum ReflectionRes
{
_16,
_32,
_64,
_128,
_256,
_512,
_1024,
_2048
};
public enum WaterReflectionQuality
{
Low,
Medium,
High
};
private int resolution;
private int GetReflectionRes(ReflectionRes res)
{
switch (res)
{
case ReflectionRes._16:
return 16;
case ReflectionRes._32:
return 32;
case ReflectionRes._64:
return 64;
case ReflectionRes._128:
return 128;
case ReflectionRes._256:
return 256;
case ReflectionRes._512:
return 512;
case ReflectionRes._1024:
return 1024;
case ReflectionRes._2048:
return 2048;
default:
return 16;
}
}
private void Start()
{
if (!UnityEngine.QualitySettings.realtimeReflectionProbes)
{
reflectionQuality = WaterReflectionQuality.Low;
}
samplerProbe.mode = UnityEngine.Rendering.ReflectionProbeMode.Realtime;
previousProbe.mode = UnityEngine.Rendering.ReflectionProbeMode.Realtime;
switch (reflectionQuality)
{
case WaterReflectionQuality.Low:
currentReflectionRes = lowReflectionResolution;
samplerProbe.cullingMask = 0;
previousProbe.cullingMask = 0;
outputProbe.mode = UnityEngine.Rendering.ReflectionProbeMode.Custom;
samplerProbe.mode = UnityEngine.Rendering.ReflectionProbeMode.Realtime;
previousProbe.mode = UnityEngine.Rendering.ReflectionProbeMode.Realtime;
samplerProbe.refreshMode = UnityEngine.Rendering.ReflectionProbeRefreshMode.OnAwake;
previousProbe.refreshMode = UnityEngine.Rendering.ReflectionProbeRefreshMode.OnAwake;
outputProbe.customBakedTexture = samplerProbe.texture;
break;
case WaterReflectionQuality.Medium:
currentReflectionRes = mediumReflectionResolution;
samplerProbe.cullingMask = cullingMask;
previousProbe.cullingMask = cullingMask;
outputProbe.mode = UnityEngine.Rendering.ReflectionProbeMode.Custom;
samplerProbe.mode = UnityEngine.Rendering.ReflectionProbeMode.Realtime;
previousProbe.mode = UnityEngine.Rendering.ReflectionProbeMode.Realtime;
samplerProbe.refreshMode = UnityEngine.Rendering.ReflectionProbeRefreshMode.ViaScripting;
previousProbe.refreshMode = UnityEngine.Rendering.ReflectionProbeRefreshMode.ViaScripting;
break;
case WaterReflectionQuality.High:
currentReflectionRes = highReflectionResolution;
samplerProbe.enabled = false;
previousProbe.enabled = false;
outputProbe.mode = UnityEngine.Rendering.ReflectionProbeMode.Realtime;
outputProbe.refreshMode = UnityEngine.Rendering.ReflectionProbeRefreshMode.EveryFrame;
break;
}
resolution = GetReflectionRes(currentReflectionRes);
blendedTexture = new RenderTexture(resolution, resolution, 0, RenderTextureFormat.ARGBHalf);
blendedTexture.isCubemap = true;
blendedTexture.useMipMap = true;
outputProbe.resolution = resolution;
samplerProbe.resolution = resolution;
previousProbe.resolution = resolution;
}
private void LateUpdate()
{
if(reflectionQuality == WaterReflectionQuality.Medium)
{
updateReflections();
}
}
private void updateReflections()
{
updateTimer += Time.deltaTime;
if (updateTimer >= updateReflectionEveryNSeconds)
{
updateTimer -= updateReflectionEveryNSeconds;
//samplerProbe.RenderProbe();
ReflectionProbe temp = previousProbe;
previousProbe = samplerProbe;
samplerProbe = temp;
samplerProbe.RenderProbe();
}
//Debug.Log
ReflectionProbe.BlendCubemap(previousProbe.texture, samplerProbe.texture, updateTimer / updateReflectionEveryNSeconds, blendedTexture);
outputProbe.customBakedTexture = blendedTexture;
}
}