public override void Render(PostProcessRenderContext context) { var cmd = context.command; cmd.BeginSample("AutoExposureLookup"); var sheet = context.propertySheets.Get(context.resources.shaders.autoExposure); sheet.ClearKeywords(); // Prepare autoExpo texture pool CheckTexture(0); CheckTexture(1); // Make sure filtering values are correct to avoid apocalyptic consequences float lowPercent = settings.filtering.value.x; float highPercent = settings.filtering.value.y; const float kMinDelta = 1e-2f; highPercent = Mathf.Clamp(highPercent, 1f + kMinDelta, 99f); lowPercent = Mathf.Clamp(lowPercent, 1f, highPercent - kMinDelta); // Compute auto exposure sheet.properties.SetBuffer(ShaderIDs.HistogramBuffer, context.logHistogram.data); sheet.properties.SetVector(ShaderIDs.Params, new Vector4(lowPercent * 0.01f, highPercent * 0.01f, RuntimeUtilities.Exp2(settings.minLuminance.value), RuntimeUtilities.Exp2(settings.maxLuminance.value))); sheet.properties.SetVector(ShaderIDs.Speed, new Vector2(settings.speedDown.value, settings.speedUp.value)); sheet.properties.SetVector(ShaderIDs.ScaleOffsetRes, context.logHistogram.GetHistogramScaleOffsetRes(context)); sheet.properties.SetFloat(ShaderIDs.ExposureCompensation, settings.keyValue.value); if (m_FirstFrame || !Application.isPlaying) { // We don't want eye adaptation when not in play mode because the GameView isn't // animated, thus making it harder to tweak. Just use the final audo exposure value. m_CurrentAutoExposure = m_AutoExposurePool[0]; cmd.BlitFullscreenTriangle(BuiltinRenderTextureType.None, m_CurrentAutoExposure, sheet, (int)EyeAdaptation.Fixed); // Copy current exposure to the other pingpong target to avoid adapting from black RuntimeUtilities.CopyTexture(cmd, m_AutoExposurePool[0], m_AutoExposurePool[1]); } else { int pp = m_AutoExposurePingPong; var src = m_AutoExposurePool[++pp % 2]; var dst = m_AutoExposurePool[++pp % 2]; cmd.BlitFullscreenTriangle(src, dst, sheet, (int)settings.eyeAdaptation.value); m_AutoExposurePingPong = ++pp % 2; m_CurrentAutoExposure = dst; } cmd.EndSample("AutoExposureLookup"); context.autoExposureTexture = m_CurrentAutoExposure; context.autoExposure = settings; m_FirstFrame = false; }
public override void Render(PostProcessRenderContext context) { var cmd = context.command; cmd.BeginSample("AutoExposureLookup"); // Prepare autoExpo texture pool CheckTexture(context.xrActiveEye, 0); CheckTexture(context.xrActiveEye, 1); // Make sure filtering values are correct to avoid apocalyptic consequences float lowPercent = settings.filtering.value.x; float highPercent = settings.filtering.value.y; const float kMinDelta = 1e-2f; highPercent = Mathf.Clamp(highPercent, 1f + kMinDelta, 99f); lowPercent = Mathf.Clamp(lowPercent, 1f, highPercent - kMinDelta); // Clamp min/max adaptation values as well float minLum = settings.minLuminance.value; float maxLum = settings.maxLuminance.value; settings.minLuminance.value = Mathf.Min(minLum, maxLum); settings.maxLuminance.value = Mathf.Max(minLum, maxLum); // Compute average luminance & auto exposure bool firstFrame = m_ResetHistory || !Application.isPlaying; string adaptation = null; if (firstFrame || settings.eyeAdaptation.value == EyeAdaptation.Fixed) { adaptation = "KAutoExposureAvgLuminance_fixed"; } else { adaptation = "KAutoExposureAvgLuminance_progressive"; } var compute = context.resources.computeShaders.autoExposure; int kernel = compute.FindKernel(adaptation); cmd.SetComputeBufferParam(compute, kernel, "_HistogramBuffer", context.logHistogram.data); cmd.SetComputeVectorParam(compute, "_Params1", new Vector4(lowPercent * 0.01f, highPercent * 0.01f, RuntimeUtilities.Exp2(settings.minLuminance.value), RuntimeUtilities.Exp2(settings.maxLuminance.value))); cmd.SetComputeVectorParam(compute, "_Params2", new Vector4(settings.speedDown.value, settings.speedUp.value, settings.keyValue.value, Time.deltaTime)); cmd.SetComputeVectorParam(compute, "_ScaleOffsetRes", context.logHistogram.GetHistogramScaleOffsetRes(context)); if (firstFrame) { // We don't want eye adaptation when not in play mode because the GameView isn't // animated, thus making it harder to tweak. Just use the final audo exposure value. m_CurrentAutoExposure = m_AutoExposurePool[context.xrActiveEye][0]; cmd.SetComputeTextureParam(compute, kernel, "_Destination", m_CurrentAutoExposure); cmd.DispatchCompute(compute, kernel, 1, 1, 1); // Copy current exposure to the other pingpong target to avoid adapting from black RuntimeUtilities.CopyTexture(cmd, m_AutoExposurePool[context.xrActiveEye][0], m_AutoExposurePool[context.xrActiveEye][1]); m_ResetHistory = false; } else { int pp = m_AutoExposurePingPong[context.xrActiveEye]; var src = m_AutoExposurePool[context.xrActiveEye][++pp % 2]; var dst = m_AutoExposurePool[context.xrActiveEye][++pp % 2]; cmd.SetComputeTextureParam(compute, kernel, "_Source", src); cmd.SetComputeTextureParam(compute, kernel, "_Destination", dst); cmd.DispatchCompute(compute, kernel, 1, 1, 1); m_AutoExposurePingPong[context.xrActiveEye] = ++pp % 2; m_CurrentAutoExposure = dst; } cmd.EndSample("AutoExposureLookup"); context.autoExposureTexture = m_CurrentAutoExposure; context.autoExposure = settings; }