浏览代码

Added a quick & dirty post-processing stack for artists until the big one is ready

/main
Chman 8 年前
当前提交
9e250d76
共有 22 个文件被更改,包括 1748 次插入151 次删除
  1. 8
      Assets/ScriptableRenderLoop/HDRenderPipeline/Editor/HDRenderPipelineInspector.cs
  2. 16
      Assets/ScriptableRenderLoop/HDRenderPipeline/Editor/HDRenderPipelineMenuItems.cs
  3. 52
      Assets/ScriptableRenderLoop/HDRenderPipeline/HDRenderPipeline.cs
  4. 207
      Assets/ScriptableRenderLoop/HDRenderPipeline/PostProcess/Resources/FinalPass.shader
  5. 9
      Assets/ScriptableRenderLoop/HDRenderPipeline/PostProcess/Editor.meta
  6. 257
      Assets/ScriptableRenderLoop/HDRenderPipeline/PostProcess/PostProcessing.cs
  7. 12
      Assets/ScriptableRenderLoop/HDRenderPipeline/PostProcess/PostProcessing.cs.meta
  8. 77
      Assets/ScriptableRenderLoop/HDRenderPipeline/PostProcess/Resources/ColorGrading.hlsl
  9. 9
      Assets/ScriptableRenderLoop/HDRenderPipeline/PostProcess/Resources/ColorGrading.hlsl.meta
  10. 22
      Assets/ScriptableRenderLoop/HDRenderPipeline/PostProcess/Resources/EyeAdaptation.hlsl
  11. 9
      Assets/ScriptableRenderLoop/HDRenderPipeline/PostProcess/Resources/EyeAdaptation.hlsl.meta
  12. 236
      Assets/ScriptableRenderLoop/HDRenderPipeline/PostProcess/Resources/EyeAdaptation.shader
  13. 9
      Assets/ScriptableRenderLoop/HDRenderPipeline/PostProcess/Resources/EyeAdaptation.shader.meta
  14. 59
      Assets/ScriptableRenderLoop/HDRenderPipeline/PostProcess/Resources/EyeHistogram.compute
  15. 9
      Assets/ScriptableRenderLoop/HDRenderPipeline/PostProcess/Resources/EyeHistogram.compute.meta
  16. 68
      Assets/ScriptableRenderLoop/HDRenderPipeline/PostProcess/Resources/LutGen.shader
  17. 9
      Assets/ScriptableRenderLoop/HDRenderPipeline/PostProcess/Resources/LutGen.shader.meta
  18. 422
      Assets/Textures/CoolingFilterLUT.exr
  19. 108
      Assets/Textures/CoolingFilterLUT.exr.meta
  20. 289
      Assets/ScriptableRenderLoop/HDRenderPipeline/PostProcess/Editor/PostProcessingEditor.cs
  21. 12
      Assets/ScriptableRenderLoop/HDRenderPipeline/PostProcess/Editor/PostProcessingEditor.cs.meta

8
Assets/ScriptableRenderLoop/HDRenderPipeline/Editor/HDRenderPipelineInspector.cs


public readonly GUIContent displayOpaqueObjects = new GUIContent("Display Opaque Objects", "Toggle opaque objects rendering on and off.");
public readonly GUIContent displayTransparentObjects = new GUIContent("Display Transparent Objects", "Toggle transparent objects rendering on and off.");
public readonly GUIContent enableTonemap = new GUIContent("Enable Tonemap");
public readonly GUIContent exposure = new GUIContent("Exposure");
public readonly GUIContent useForwardRenderingOnly = new GUIContent("Use Forward Rendering Only");
public readonly GUIContent useDepthPrepass = new GUIContent("Use Depth Prepass");

debugParameters.debugViewMaterial = EditorGUILayout.IntPopup(styles.debugViewMaterial, (int)debugParameters.debugViewMaterial, styles.debugViewMaterialStrings, styles.debugViewMaterialValues);
EditorGUILayout.Space();
debugParameters.enableTonemap = EditorGUILayout.Toggle(styles.enableTonemap, debugParameters.enableTonemap);
debugParameters.exposure = Mathf.Max(Mathf.Min(EditorGUILayout.FloatField(styles.exposure, debugParameters.exposure), k_MaxExposure), -k_MaxExposure);
EditorGUILayout.Space();
if (EditorGUI.EndChangeCheck())
{
EditorUtility.SetDirty(renderContext); // Repaint

16
Assets/ScriptableRenderLoop/HDRenderPipeline/Editor/HDRenderPipelineMenuItems.cs


using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine.Experimental.Rendering.HDPipeline;
namespace UnityEditor.Experimental.Rendering.HDPipeline

[UnityEditor.MenuItem("HDRenderPipeline/Create Scene Settings")]
[MenuItem("HDRenderPipeline/Create Scene Settings")]
CommonSettings[] settings = Object.FindObjectsOfType(typeof(CommonSettings)) as CommonSettings[];
CommonSettings[] settings = Object.FindObjectsOfType<CommonSettings>();
GameObject go = new GameObject();
go.name = "SceneSettings";
go.AddComponent(typeof(CommonSettings));
GameObject go = new GameObject { name = "SceneSettings" };
go.AddComponent<CommonSettings>();
go.AddComponent<PostProcessing>();
}
else
{

[UnityEditor.MenuItem("HDRenderPipeline/Synchronize all Layered materials")]
[MenuItem("HDRenderPipeline/Synchronize all Layered materials")]
static void SynchronizeAllLayeredMaterial()
{
Object[] materials = Resources.FindObjectsOfTypeAll<Material>();

52
Assets/ScriptableRenderLoop/HDRenderPipeline/HDRenderPipeline.cs


public bool useForwardRenderingOnly = false; // TODO: Currently there is no way to strip the extra forward shaders generated by the shaders compiler, so we can switch dynamically.
public bool useDepthPrepass = false;
public bool useDistortion = true;
public bool enableTonemap = true;
public float exposure = 0;
}
DebugParameters m_DebugParameters = new DebugParameters();

}
// Various set of material use in render loop
Material m_FinalPassMaterial;
Material m_DebugViewMaterialGBuffer;
// Various buffer

m_SkyManager.Build();
m_FinalPassMaterial = Utilities.CreateEngineMaterial("Hidden/HDRenderPipeline/FinalPass");
m_DebugViewMaterialGBuffer = Utilities.CreateEngineMaterial("Hidden/HDRenderPipeline/DebugViewMaterialGBuffer");
m_ShadowPass = new ShadowRenderPass(m_ShadowSettings);

m_lightLoop.Cleanup();
m_LitRenderLoop.Cleanup();
Utilities.Destroy(m_FinalPassMaterial);
Utilities.Destroy(m_DebugViewMaterialGBuffer);
m_SkyManager.Cleanup();

}
}
void FinalPass(ScriptableRenderContext renderContext)
void FinalPass(Camera camera, ScriptableRenderContext renderContext)
// Those could be tweakable for the neutral tonemapper, but in the case of the LookDev we don't need that
const float blackIn = 0.02f;
const float whiteIn = 10.0f;
const float blackOut = 0.0f;
const float whiteOut = 10.0f;
const float whiteLevel = 5.3f;
const float whiteClip = 10.0f;
const float dialUnits = 20.0f;
const float halfDialUnits = dialUnits * 0.5f;
// converting from artist dial units to easy shader-lerps (0-1)
var tonemapCoeff1 = new Vector4((blackIn * dialUnits) + 1.0f, (blackOut * halfDialUnits) + 1.0f, (whiteIn / dialUnits), (1.0f - (whiteOut / dialUnits)));
var tonemapCoeff2 = new Vector4(0.0f, 0.0f, whiteLevel, whiteClip / halfDialUnits);
// All of this is temporary, sub-optimal and quickly hacked together but is necessary
// for artists to do lighting work until the fully-featured framework is ready
m_FinalPassMaterial.SetVector("_ToneMapCoeffs1", tonemapCoeff1);
m_FinalPassMaterial.SetVector("_ToneMapCoeffs2", tonemapCoeff2);
var localPostProcess = camera.GetComponent<PostProcessing>();
var globalPostProcess = commonSettings == null
? null
: commonSettings.GetComponent<PostProcessing>();
m_FinalPassMaterial.SetFloat("_EnableToneMap", debugParameters.enableTonemap ? 1.0f : 0.0f);
m_FinalPassMaterial.SetFloat("_Exposure", debugParameters.exposure);
bool localActive = localPostProcess != null && localPostProcess.enabled;
bool globalActive = globalPostProcess != null && globalPostProcess.enabled;
var cmd = new CommandBuffer { name = "" };
if (!localActive && !globalActive)
{
var cmd = new CommandBuffer { name = "" };
cmd.Blit(m_CameraColorBufferRT, BuiltinRenderTextureType.CameraTarget);
renderContext.ExecuteCommandBuffer(cmd);
cmd.Dispose();
return;
}
// Resolve our HDR texture to CameraTarget.
cmd.Blit(m_CameraColorBufferRT, BuiltinRenderTextureType.CameraTarget, m_FinalPassMaterial, 0);
renderContext.ExecuteCommandBuffer(cmd);
cmd.Dispose();
var target = localActive ? localPostProcess : globalPostProcess;
target.Render(camera, renderContext, m_CameraColorBufferRT, BuiltinRenderTextureType.CameraTarget);
}
}

// Instead we chose to apply distortion at the end after we cumulate distortion vector and desired blurriness. This
RenderDistortion(cullResults, camera, renderContext);
FinalPass(renderContext);
FinalPass(camera, renderContext);
}
// bind depth surface for editor grid/gizmo/selection rendering

renderContext.Submit();
}
// Post effects
}
}
}

207
Assets/ScriptableRenderLoop/HDRenderPipeline/PostProcess/Resources/FinalPass.shader


// Final compositing pass, just does gamma correction for now.
_ToneMapCoeffs1("Parameters for neutral tonemap", Vector) = (0.0, 0.0, 0.0, 0.0)
_ToneMapCoeffs2("Parameters for neutral tonemap", Vector) = (0.0, 0.0, 0.0, 0.0)
_Exposure("Exposure", Range(-32.0, 32.0)) = 0
[ToggleOff] _EnableToneMap("Enable Tone Map", Float) = 0
SubShader {
Pass {
ZTest Always Cull Off ZWrite Off
HLSLINCLUDE
HLSLPROGRAM
#pragma vertex Vert
#pragma fragment Frag
#pragma target 5.0
#pragma target 5.0
#include "Common.hlsl"
#include "Assets/ScriptableRenderLoop/HDRenderPipeline/ShaderVariables.hlsl"
#include "ColorGrading.hlsl"
#include "Common.hlsl"
#include "Color.hlsl"
#include "Assets/ScriptableRenderLoop/HDRenderPipeline/ShaderVariables.hlsl"
TEXTURE2D(_MainTex);
SAMPLER2D(sampler_MainTex);
TEXTURE2D(_MainTex);
SAMPLER2D(sampler_MainTex);
TEXTURE2D(_AutoExposure);
SAMPLER2D(sampler_AutoExposure);
float4 _ToneMapCoeffs1;
float4 _ToneMapCoeffs2;
TEXTURE2D(_LogLut);
SAMPLER2D(sampler_LogLut);
#define InBlack _ToneMapCoeffs1.x
#define OutBlack _ToneMapCoeffs1.y
#define InWhite _ToneMapCoeffs1.z
#define OutWhite _ToneMapCoeffs1.w
#define WhiteLevel _ToneMapCoeffs2.z
#define WhiteClip _ToneMapCoeffs2.w
float4 _LogLut_Params;
float _Exposure;
float _EnableToneMap;
float _Exposure;
struct Attributes
{
float3 vertex : POSITION;
float2 texcoord : TEXCOORD0;
};
float4 _NeutralTonemapperParams1;
float4 _NeutralTonemapperParams2;
struct Varyings
{
float4 vertex : SV_POSITION;
float2 texcoord : TEXCOORD0;
};
struct Attributes
{
float3 vertex : POSITION;
float2 texcoord : TEXCOORD0;
};
Varyings Vert(Attributes input)
{
Varyings output;
output.vertex = TransformWorldToHClip(input.vertex);
output.texcoord = input.texcoord.xy;
return output;
}
struct Varyings
{
float4 vertex : SV_POSITION;
float2 texcoord : TEXCOORD0;
};
float3 evalCurve(float3 x, float A, float B, float C, float D, float E, float F)
{
return ((x*(A*x + C*B) + D*E) / (x*(A*x + B) + D*F)) - E / F;
}
Varyings Vert(Attributes input)
{
Varyings output;
output.vertex = TransformWorldToHClip(input.vertex);
output.texcoord = input.texcoord.xy;
return output;
}
float3 applyTonemapFilmicAD(float3 linearColor)
{
float blackRatio = InBlack / OutBlack;
float whiteRatio = InWhite / OutWhite;
// Neutral tonemapping (Hable/Hejl/Frostbite)
// Input is linear RGB
float3 NeutralCurve(float3 x, float a, float b, float c, float d, float e, float f)
{
return ((x * (a * x + c * b) + d * e) / (x * (a * x + b) + d * f)) - e / f;
}
float3 NeutralTonemap(float3 x, float4 params1, float4 params2)
{
// ACES supports negative color values and WILL output negative values when coming from ACES or ACEScg
// Make sure negative channels are clamped to 0.0 as this neutral tonemapper can't deal with them properly
x = max((0.0).xxx, x);
// Tonemap
float a = params1.x;
float b = params1.y;
float c = params1.z;
float d = params1.w;
float e = params2.x;
float f = params2.y;
float whiteLevel = params2.z;
float whiteClip = params2.w;
// blend tunable coefficients
float B = lerp(0.57, 0.37, blackRatio);
float C = lerp(0.01, 0.24, whiteRatio);
float D = lerp(0.02, 0.20, blackRatio);
float3 whiteScale = (1.0).xxx / NeutralCurve(whiteLevel, a, b, c, d, e, f);
x = NeutralCurve(x * whiteScale, a, b, c, d, e, f);
x *= whiteScale;
// constants
float A = 0.2;
float E = 0.02;
float F = 0.30;
// Post-curve white point adjustment
x /= whiteClip.xxx;
// eval and correct for white point
float3 whiteScale = 1.0f / evalCurve(WhiteLevel, A, B, C, D, E, F);
float3 curr = evalCurve(linearColor * whiteScale, A, B, C, D, E, F);
return x;
}
return curr * whiteScale;
}
float4 Frag(Varyings input) : SV_Target
{
float4 color = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, input.texcoord);
float3 remapWhite(float3 inPixel, float whitePt)
#if EYE_ADAPTATION
// var breakout for readability
const float inBlack = 0;
const float outBlack = 0;
float inWhite = whitePt;
const float outWhite = 1;
// remap input range to output range
float3 outPixel = ((inPixel.rgb) - inBlack.xxx) / (inWhite.xxx - inBlack.xxx) * (outWhite.xxx - outBlack.xxx) + outBlack.xxx;
return (outPixel.rgb);
float autoExposure = SAMPLE_TEXTURE2D(_AutoExposure, sampler_AutoExposure, input.texcoord).r;
color *= autoExposure;
#endif
float3 NeutralTonemap(float3 x)
color.rgb *= _Exposure; // Exposure is in ev units (or 'stops'), precomputed CPU-side
#if NEUTRAL_GRADING
float3 finalColor = applyTonemapFilmicAD(x); // curve (dynamic coeffs differ per level)
finalColor = remapWhite(finalColor, WhiteClip); // post-curve white point adjustment
finalColor = saturate(finalColor);
return finalColor;
color.rgb = NeutralTonemap(color.rgb, _NeutralTonemapperParams1, _NeutralTonemapperParams2);
#elif CUSTOM_GRADING
{
float3 uvw = saturate(LinearToLogC(color));
float3 ApplyToneMap(float3 color)
// Strip lut format where `height = sqrt(width)`
uvw.z *= _LogLut_Params.z;
half shift = floor(uvw.z);
uvw.xy = uvw.xy * _LogLut_Params.z * _LogLut_Params.xy + _LogLut_Params.xy * 0.5;
uvw.x += shift * _LogLut_Params.y;
uvw.xyz = lerp(
SAMPLE_TEXTURE2D(_LogLut, sampler_LogLut, uvw.xy).rgb,
SAMPLE_TEXTURE2D(_LogLut, sampler_LogLut, uvw.xy + half2(_LogLut_Params.y, 0)).rgb,
uvw.z - shift
);
color.rgb = uvw;
}
#else
if (_EnableToneMap > 0.0)
{
return NeutralTonemap(color);
}
else
{
return saturate(color);
}
color = saturate(color);
#endif
float4 Frag(Varyings input) : SV_Target
{
float4 c = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, input.texcoord);
// Gamma correction
return color;
}
// TODO: Currenlt in the editor there a an additional pass were the result is copyed in a render target RGBA8_sRGB.
// So we must not correct the sRGB here else it will be done two time.
// To fix!
ENDHLSL
c.rgb = ApplyToneMap(c.rgb * exp2(_Exposure));
SubShader
{
Cull Off ZWrite Off ZTest Always
// return LinearToSRGB(c);
return c;
Pass
{
HLSLPROGRAM
#pragma vertex Vert
#pragma fragment Frag
#pragma multi_compile __ NEUTRAL_GRADING CUSTOM_GRADING
#pragma multi_compile __ EYE_ADAPTATION
}
Fallback Off
}

9
Assets/ScriptableRenderLoop/HDRenderPipeline/PostProcess/Editor.meta


fileFormatVersion: 2
guid: 5d4f8c766010cda4b97dbd7bb0905215
folderAsset: yes
timeCreated: 1483612561
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

257
Assets/ScriptableRenderLoop/HDRenderPipeline/PostProcess/PostProcessing.cs


using System;
using UnityEngine.Rendering;
// TEMPORARY, minimalist post-processing stack until the fully-featured framework is ready
namespace UnityEngine.Experimental.Rendering.HDPipeline
{
using GradingType = PostProcessing.ColorGradingSettings.GradingType;
using EyeAdaptationType = PostProcessing.EyeAdaptationSettings.EyeAdaptationType;
[ExecuteInEditMode]
public sealed class PostProcessing : MonoBehaviour
{
[Serializable]
public sealed class ColorGradingSettings
{
public enum GradingType
{
None,
Neutral,
Custom
}
public GradingType type = GradingType.None;
public float exposure = 0f;
public Texture logLut = null;
[Range(-0.10f, 0.1f)] public float neutralBlackIn = 0.02f;
[Range( 1.00f, 20.0f)] public float neutralWhiteIn = 10f;
[Range(-0.09f, 0.1f)] public float neutralBlackOut = 0f;
[Range( 1.00f, 19.0f)] public float neutralWhiteOut = 10f;
[Range( 0.10f, 20.0f)] public float neutralWhiteLevel = 5.3f;
[Range( 1.00f, 10.0f)] public float neutralWhiteClip = 10f;
}
[Serializable]
public sealed class EyeAdaptationSettings
{
public enum EyeAdaptationType
{
Progressive,
Fixed
}
public bool enabled = false;
public bool showDebugHistogramInGameView = true;
[Range(1f, 99f)] public float lowPercent = 65f;
[Range(1f, 99f)] public float highPercent = 95f;
public float minLuminance = 0.03f;
public float maxLuminance = 2f;
public float exposureCompensation = 0.5f;
public EyeAdaptationType adaptationType = EyeAdaptationType.Progressive;
public float speedUp = 2f;
public float speedDown = 1f;
[Range(-16, -1)] public int logMin = -8;
[Range( 1, 16)] public int logMax = 4;
}
public EyeAdaptationSettings eyeAdaptation = new EyeAdaptationSettings();
public ColorGradingSettings colorGrading = new ColorGradingSettings();
Material m_EyeAdaptationMaterial;
Material m_FinalPassMaterial;
ComputeShader m_EyeCompute;
ComputeBuffer m_HistogramBuffer;
readonly RenderTexture[] m_AutoExposurePool = new RenderTexture[2];
int m_AutoExposurePingPing;
RenderTexture m_CurrentAutoExposure;
RenderTexture m_DebugHistogram = null;
static uint[] s_EmptyHistogramBuffer = new uint[k_HistogramBins];
bool m_FirstFrame = true;
// Don't forget to update 'EyeAdaptation.cginc' if you change these values !
const int k_HistogramBins = 64;
const int k_HistogramThreadX = 16;
const int k_HistogramThreadY = 16;
void OnEnable()
{
m_FinalPassMaterial = Utilities.CreateEngineMaterial("Hidden/HDRenderPipeline/FinalPass");
m_EyeAdaptationMaterial = Utilities.CreateEngineMaterial("Hidden/HDRenderPipeline/EyeAdaptation");
m_EyeCompute = Resources.Load<ComputeShader>("EyeHistogram");
m_HistogramBuffer = new ComputeBuffer(k_HistogramBins, sizeof(uint));
m_AutoExposurePool[0] = new RenderTexture(1, 1, 0, RenderTextureFormat.RFloat);
m_AutoExposurePool[1] = new RenderTexture(1, 1, 0, RenderTextureFormat.RFloat);
m_FirstFrame = true;
}
void OnDisable()
{
Utilities.Destroy(m_EyeAdaptationMaterial);
Utilities.Destroy(m_FinalPassMaterial);
foreach (var rt in m_AutoExposurePool)
Utilities.Destroy(rt);
Utilities.Destroy(m_DebugHistogram);
Utilities.SafeRelease(m_HistogramBuffer);
}
public void Render(Camera camera, ScriptableRenderContext context, RenderTargetIdentifier source, RenderTargetIdentifier destination)
{
m_FinalPassMaterial.shaderKeywords = null;
var cmd = new CommandBuffer { name = "Final Pass" };
if (eyeAdaptation.enabled)
{
int tempRt = Shader.PropertyToID("_Source");
// Downscale the framebuffer, we don't need an absolute precision for auto exposure
// and it helps making it more stable - should be using a previously downscaled pass
var scaleOffsetRes = GetHistogramScaleOffsetRes(camera);
cmd.GetTemporaryRT(tempRt, (int)scaleOffsetRes.z, (int)scaleOffsetRes.w, 0, FilterMode.Bilinear, RenderTextureFormat.ARGBHalf);
cmd.Blit(source, tempRt);
// Clears the buffer on every frame as we use it to accumulate luminance values on each frame
m_HistogramBuffer.SetData(s_EmptyHistogramBuffer);
// Gets a log histogram
int kernel = m_EyeCompute.FindKernel("KEyeHistogram");
cmd.SetComputeBufferParam(m_EyeCompute, kernel, "_Histogram", m_HistogramBuffer);
cmd.SetComputeTextureParam(m_EyeCompute, kernel, "_Source", tempRt);
cmd.SetComputeVectorParam(m_EyeCompute, "_ScaleOffsetRes", scaleOffsetRes);
cmd.DispatchCompute(m_EyeCompute, kernel, Mathf.CeilToInt(scaleOffsetRes.z / (float)k_HistogramThreadX), Mathf.CeilToInt(scaleOffsetRes.w / (float)k_HistogramThreadY), 1);
// Cleanup
cmd.ReleaseTemporaryRT(tempRt);
// Make sure filtering values are correct to avoid apocalyptic consequences
const float kMinDelta = 1e-2f;
eyeAdaptation.highPercent = Mathf.Clamp(eyeAdaptation.highPercent, 1f + kMinDelta, 99f);
eyeAdaptation.lowPercent = Mathf.Clamp(eyeAdaptation.lowPercent, 1f, eyeAdaptation.highPercent - kMinDelta);
// Compute auto exposure
m_EyeAdaptationMaterial.SetBuffer("_Histogram", m_HistogramBuffer);
m_EyeAdaptationMaterial.SetVector("_Params", new Vector4(eyeAdaptation.lowPercent * 0.01f, eyeAdaptation.highPercent * 0.01f, eyeAdaptation.minLuminance, eyeAdaptation.maxLuminance));
m_EyeAdaptationMaterial.SetVector("_Speed", new Vector2(eyeAdaptation.speedDown, eyeAdaptation.speedUp));
m_EyeAdaptationMaterial.SetVector("_ScaleOffsetRes", scaleOffsetRes);
m_EyeAdaptationMaterial.SetFloat("_ExposureCompensation", eyeAdaptation.exposureCompensation);
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.Blit(null, m_CurrentAutoExposure, m_EyeAdaptationMaterial, (int)EyeAdaptationType.Fixed);
// Copy current exposure to the other pingpong target on first frame to avoid adapting from black
cmd.Blit(m_AutoExposurePool[0], m_AutoExposurePool[1]);
} else
{
int pp = m_AutoExposurePingPing;
var src = m_AutoExposurePool[++pp % 2];
var dst = m_AutoExposurePool[++pp % 2];
cmd.Blit(src, dst, m_EyeAdaptationMaterial, (int)eyeAdaptation.adaptationType);
m_AutoExposurePingPing = ++pp % 2;
m_CurrentAutoExposure = dst;
}
m_FinalPassMaterial.EnableKeyword("EYE_ADAPTATION");
m_FinalPassMaterial.SetTexture("_AutoExposure", m_CurrentAutoExposure);
// Debug histogram visualization
if (eyeAdaptation.showDebugHistogramInGameView)
{
if (m_DebugHistogram == null || !m_DebugHistogram.IsCreated())
{
m_DebugHistogram = new RenderTexture(256, 128, 0, RenderTextureFormat.ARGB32)
{
filterMode = FilterMode.Point,
wrapMode = TextureWrapMode.Clamp
};
}
m_EyeAdaptationMaterial.SetFloat("_DebugWidth", m_DebugHistogram.width);
cmd.Blit(null, m_DebugHistogram, m_EyeAdaptationMaterial, 2);
}
m_FirstFrame = false;
}
float ev = Mathf.Exp(colorGrading.exposure * 0.6931471805599453f);
m_FinalPassMaterial.SetFloat("_Exposure", ev);
if (colorGrading.type == GradingType.Neutral)
{
const float kScaleFactor = 20f;
const float kScaleFactorHalf = kScaleFactor * 0.5f;
float inBlack = colorGrading.neutralBlackIn * kScaleFactor + 1f;
float outBlack = colorGrading.neutralBlackOut * kScaleFactorHalf + 1f;
float inWhite = colorGrading.neutralWhiteIn / kScaleFactor;
float outWhite = 1f - colorGrading.neutralWhiteOut / kScaleFactor;
float blackRatio = inBlack / outBlack;
float whiteRatio = inWhite / outWhite;
const float a = 0.2f;
float b = Mathf.Max(0f, Mathf.LerpUnclamped(0.57f, 0.37f, blackRatio));
float c = Mathf.LerpUnclamped(0.01f, 0.24f, whiteRatio);
float d = Mathf.Max(0f, Mathf.LerpUnclamped(0.02f, 0.20f, blackRatio));
const float e = 0.02f;
const float f = 0.30f;
m_FinalPassMaterial.SetVector("_NeutralTonemapperParams1", new Vector4(a, b, c, d));
m_FinalPassMaterial.SetVector("_NeutralTonemapperParams2", new Vector4(e, f, colorGrading.neutralWhiteLevel, colorGrading.neutralWhiteClip / kScaleFactorHalf));
m_FinalPassMaterial.EnableKeyword("NEUTRAL_GRADING");
}
else if (colorGrading.type == GradingType.Custom)
{
if (colorGrading.logLut != null)
{
var lut = colorGrading.logLut;
m_FinalPassMaterial.SetTexture("_LogLut", lut);
m_FinalPassMaterial.SetVector("_LogLut_Params", new Vector3(1f / lut.width, 1f / lut.height, lut.height - 1f));
m_FinalPassMaterial.EnableKeyword("CUSTOM_GRADING");
}
}
cmd.Blit(source, destination, m_FinalPassMaterial, 0);
context.ExecuteCommandBuffer(cmd);
cmd.Dispose();
}
Vector4 GetHistogramScaleOffsetRes(Camera camera)
{
float diff = eyeAdaptation.logMax - eyeAdaptation.logMin;
float scale = 1f / diff;
float offset = -eyeAdaptation.logMin * scale;
return new Vector4(scale, offset, Mathf.Floor(camera.pixelWidth / 2f), Mathf.Floor(camera.pixelHeight / 2f));
}
void OnGUI()
{
if (!eyeAdaptation.enabled || !eyeAdaptation.showDebugHistogramInGameView || m_DebugHistogram == null || !m_DebugHistogram.IsCreated())
return;
var rect = new Rect(8f, 8f, m_DebugHistogram.width, m_DebugHistogram.height);
GUI.DrawTexture(rect, m_DebugHistogram);
}
}
}

12
Assets/ScriptableRenderLoop/HDRenderPipeline/PostProcess/PostProcessing.cs.meta


fileFormatVersion: 2
guid: aaa10d337b215d94dbc0ce5467cdc79a
timeCreated: 1483612023
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

77
Assets/ScriptableRenderLoop/HDRenderPipeline/PostProcess/Resources/ColorGrading.hlsl


#ifndef UNITY_COLOR_GRADING
#define UNITY_COLOR_GRADING
// Set to 1 to use more precise but more expensive log/linear conversions. I haven't found a proper
// use case for the high precision version yet so I'm leaving this to 0.
#define COLOR_GRADING_PRECISE_LOG 0
//
// Alexa LogC converters (El 1000)
// See http://www.vocas.nl/webfm_send/964
// It's a good fit to store HDR values in log as the range is pretty wide (1 maps to ~58.85666) and
// is quick enough to compute.
//
struct ParamsLogC
{
float cut;
float a, b, c, d, e, f;
};
static const ParamsLogC LogC =
{
0.011361, // cut
5.555556, // a
0.047996, // b
0.244161, // c
0.386036, // d
5.301883, // e
0.092819 // f
};
half LinearToLogC_Precise(half x)
{
float o;
if (x > LogC.cut)
o = LogC.c * log10(LogC.a * x + LogC.b) + LogC.d;
else
o = LogC.e * x + LogC.f;
return o;
}
float3 LinearToLogC(float3 x)
{
#if COLOR_GRADING_PRECISE_LOG
return float3(
LinearToLogC_Precise(x.x),
LinearToLogC_Precise(x.y),
LinearToLogC_Precise(x.z)
);
#else
return LogC.c * log10(LogC.a * x + LogC.b) + LogC.d;
#endif
}
float LogCToLinear_Precise(float x)
{
float o;
if (x > LogC.e * LogC.cut + LogC.f)
o = (pow(10.0, (x - LogC.d) / LogC.c) - LogC.b) / LogC.a;
else
o = (x - LogC.f) / LogC.e;
return o;
}
float3 LogCToLinear(float3 x)
{
#if COLOR_GRADING_PRECISE_LOG
return float3(
LogCToLinear_Precise(x.x),
LogCToLinear_Precise(x.y),
LogCToLinear_Precise(x.z)
);
#else
return (pow(10.0, (x - LogC.d) / LogC.c) - LogC.b) / LogC.a;
#endif
}
#endif // UNITY_COLOR_GRADING

9
Assets/ScriptableRenderLoop/HDRenderPipeline/PostProcess/Resources/ColorGrading.hlsl.meta


fileFormatVersion: 2
guid: d353f8a66edd94f4ab3f3c8e2ef7dd61
timeCreated: 1483709991
licenseType: Pro
ShaderImporter:
defaultTextures: []
userData:
assetBundleName:
assetBundleVariant:

22
Assets/ScriptableRenderLoop/HDRenderPipeline/PostProcess/Resources/EyeAdaptation.hlsl


#ifndef UNITY_EYE_ADAPTATION
#define UNITY_EYE_ADAPTATION
// Optimal values for PS4/GCN
// Using a group size of 32x32 seems to be a bit faster on Kepler/Maxwell
// Don't forget to update 'EyeAdaptationController.cs' if you change these values !
#define HISTOGRAM_BINS 64
#define HISTOGRAM_TEXELS HISTOGRAM_BINS / 4
#define HISTOGRAM_THREAD_X 16
#define HISTOGRAM_THREAD_Y 16
float GetHistogramBinFromLuminance(float value, float2 scaleOffset)
{
return saturate(log2(value) * scaleOffset.x + scaleOffset.y);
}
float GetLuminanceFromHistogramBin(float bin, float2 scaleOffset)
{
return exp2((bin - scaleOffset.y) / scaleOffset.x);
}
#endif // UNITY_EYE_ADAPTATION

9
Assets/ScriptableRenderLoop/HDRenderPipeline/PostProcess/Resources/EyeAdaptation.hlsl.meta


fileFormatVersion: 2
guid: a34d57fb96cd85e4db20d2b70a6f0b1d
timeCreated: 1483621596
licenseType: Pro
ShaderImporter:
defaultTextures: []
userData:
assetBundleName:
assetBundleVariant:

236
Assets/ScriptableRenderLoop/HDRenderPipeline/PostProcess/Resources/EyeAdaptation.shader


Shader "Hidden/HDRenderPipeline/EyeAdaptation"
{
Properties
{
_MainTex("Texture", any) = "" {}
}
HLSLINCLUDE
#pragma target 5.0
#include "Common.hlsl"
#include "Assets/ScriptableRenderLoop/HDRenderPipeline/ShaderVariables.hlsl"
#include "EyeAdaptation.hlsl"
TEXTURE2D(_MainTex);
SAMPLER2D(sampler_MainTex);
float4 _Params; // x: lowPercent, y: highPercent, z: minBrightness, w: maxBrightness
float2 _Speed; // x: down, y: up
float4 _ScaleOffsetRes; // x: scale, y: offset, w: histogram pass width, h: histogram pass height
float _ExposureCompensation;
StructuredBuffer<uint> _Histogram;
float GetBinValue(uint index, float maxHistogramValue)
{
return float(_Histogram[index]) * maxHistogramValue;
}
float FindMaxHistogramValue()
{
uint maxValue = 0u;
for (uint i = 0; i < HISTOGRAM_BINS; i++)
{
uint h = _Histogram[i];
maxValue = max(maxValue, h);
}
return float(maxValue);
}
void FilterLuminance(uint i, float maxHistogramValue, inout float4 filter)
{
float binValue = GetBinValue(i, maxHistogramValue);
// Filter dark areas
float offset = min(filter.z, binValue);
binValue -= offset;
filter.zw -= offset.xx;
// Filter highlights
binValue = min(filter.w, binValue);
filter.w -= binValue;
// Luminance at the bin
float luminance = GetLuminanceFromHistogramBin(float(i) / float(HISTOGRAM_BINS), _ScaleOffsetRes.xy);
filter.xy += float2(luminance * binValue, binValue);
}
float GetAverageLuminance(float maxHistogramValue)
{
// Sum of all bins
uint i;
float totalSum = 0.0;
[loop]
for (i = 0; i < HISTOGRAM_BINS; i++)
totalSum += GetBinValue(i, maxHistogramValue);
// Skip darker and lighter parts of the histogram to stabilize the auto exposure
// x: filtered sum
// y: accumulator
// zw: fractions
float4 filter = float4(0.0, 0.0, totalSum * _Params.xy);
[loop]
for (i = 0; i < HISTOGRAM_BINS; i++)
FilterLuminance(i, maxHistogramValue, filter);
// Clamp to user brightness range
return clamp(filter.x / max(filter.y, 1.0e-4), _Params.z, _Params.w);
}
float GetExposureMultiplier(float avgLuminance)
{
avgLuminance = max(1.0e-4, avgLuminance);
//half keyValue = 1.03 - (2.0 / (2.0 + log2(avgLuminance + 1.0)));
half keyValue = _ExposureCompensation;
half exposure = keyValue / avgLuminance;
return exposure;
}
float InterpolateExposure(float newExposure, float oldExposure)
{
float delta = newExposure - oldExposure;
float speed = delta > 0.0 ? _Speed.x : _Speed.y;
float exposure = oldExposure + delta * (1.0 - exp2(-unity_DeltaTime.x * speed));
//float exposure = oldExposure + delta * (unity_DeltaTime.x * speed);
return exposure;
}
struct Attributes
{
float4 vertex : POSITION;
float4 texcoord : TEXCOORD0;
};
struct Varyings
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
};
Varyings Vert(Attributes v)
{
Varyings o;
o.pos = TransformWorldToHClip(v.vertex.xyz);
o.uv = v.texcoord.xy;
return o;
}
float4 FragAdaptProgressive(Varyings i) : SV_Target
{
float maxValue = 1.0 / FindMaxHistogramValue();
float avgLuminance = GetAverageLuminance(maxValue);
float exposure = GetExposureMultiplier(avgLuminance);
float prevExposure = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, (0.5).xx).r;
exposure = InterpolateExposure(exposure, prevExposure);
return exposure.xxxx;
}
float4 FragAdaptFixed(Varyings i) : SV_Target
{
float maxValue = 1.0 / FindMaxHistogramValue();
float avgLuminance = GetAverageLuminance(maxValue);
float exposure = GetExposureMultiplier(avgLuminance);
return exposure.xxxx;
}
// Editor stuff (histogram debug visualization)
int _DebugWidth;
struct VaryingsEditorHisto
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float maxValue : TEXCOORD1;
float avgLuminance : TEXCOORD2;
};
VaryingsEditorHisto VertEditorHisto(Attributes v)
{
VaryingsEditorHisto o;
o.pos = TransformWorldToHClip(v.vertex.xyz);
o.uv = v.texcoord.xy;
o.maxValue = 1.0 / FindMaxHistogramValue();
o.avgLuminance = GetAverageLuminance(o.maxValue);
return o;
}
float4 FragEditorHisto(VaryingsEditorHisto i) : SV_Target
{
const float3 kRangeColor = float3(0.05, 0.4, 0.6);
const float3 kAvgColor = float3(0.8, 0.3, 0.05);
float4 color = float4(0.0, 0.0, 0.0, 0.7);
uint ix = (uint)(round(i.uv.x * HISTOGRAM_BINS));
float bin = saturate(float(_Histogram[ix]) * i.maxValue);
float fill = step(i.uv.y, bin);
// Min / max brightness markers
float luminanceMin = GetHistogramBinFromLuminance(_Params.z, _ScaleOffsetRes.xy);
float luminanceMax = GetHistogramBinFromLuminance(_Params.w, _ScaleOffsetRes.xy);
color.rgb += fill.rrr;
if (i.uv.x > luminanceMin && i.uv.x < luminanceMax)
{
color.rgb = fill.rrr * kRangeColor;
color.rgb += kRangeColor;
}
// Current average luminance marker
float luminanceAvg = GetHistogramBinFromLuminance(i.avgLuminance, _ScaleOffsetRes.xy);
float avgPx = luminanceAvg * _DebugWidth;
if (abs(i.pos.x - avgPx) < 2)
color.rgb = kAvgColor;
return color;
}
ENDHLSL
SubShader
{
Cull Off ZWrite Off ZTest Always
Pass
{
HLSLPROGRAM
#pragma vertex Vert
#pragma fragment FragAdaptProgressive
ENDHLSL
}
Pass
{
HLSLPROGRAM
#pragma vertex Vert
#pragma fragment FragAdaptFixed
ENDHLSL
}
Pass
{
HLSLPROGRAM
#pragma vertex VertEditorHisto
#pragma fragment FragEditorHisto
ENDHLSL
}
}
Fallback Off
}

9
Assets/ScriptableRenderLoop/HDRenderPipeline/PostProcess/Resources/EyeAdaptation.shader.meta


fileFormatVersion: 2
guid: aeefbc574fd1b81489d0c8f8dcd5f1b7
timeCreated: 1483625503
licenseType: Pro
ShaderImporter:
defaultTextures: []
userData:
assetBundleName:
assetBundleVariant:

59
Assets/ScriptableRenderLoop/HDRenderPipeline/PostProcess/Resources/EyeHistogram.compute


// Put the following line to 0 or comment it to disable vignette weighting
#define USE_VIGNETTE_WEIGHTING 1
#include "Common.hlsl"
#include "EyeAdaptation.hlsl"
RWStructuredBuffer<uint> _Histogram;
Texture2D<float4> _Source;
CBUFFER_START(Params)
float4 _ScaleOffsetRes; // x: scale, y: offset, z: width, w: height
CBUFFER_END
groupshared uint gs_histogram[HISTOGRAM_BINS];
#pragma kernel KEyeHistogram
[numthreads(HISTOGRAM_THREAD_X,HISTOGRAM_THREAD_Y,1)]
void KEyeHistogram(uint2 dispatchThreadId : SV_DispatchThreadID, uint2 groupThreadId : SV_GroupThreadID)
{
// Pretty straightforward implementation of histogram gathering using atomic ops.
// I tried a few methods (no atomic ops / heavy LDS leveraging) but this one turned out to be
// the fastest on desktop (Nvidia - Kepler/Maxwell) and PS4. Still need to try it on GCN/desktop
// but considering it runs very fast on PS4 we can expect it to run well (?).
const uint localThreadId = groupThreadId.y * HISTOGRAM_THREAD_X + groupThreadId.x;
// Clears the shared memory
if (localThreadId < HISTOGRAM_BINS)
gs_histogram[localThreadId] = 0u;
GroupMemoryBarrierWithGroupSync();
// Gather local group histogram
if (dispatchThreadId.x < (uint)_ScaleOffsetRes.z && dispatchThreadId.y < (uint)_ScaleOffsetRes.w)
{
#if USE_VIGNETTE_WEIGHTING
// Vignette weighting to put more focus on what's in the center of the screen
float2 uv01 = float2(dispatchThreadId) / float2(_ScaleOffsetRes.z, _ScaleOffsetRes.w);
float2 d = abs(uv01 - (0.5).xx);
float vfactor = saturate(1.0 - dot(d, d));
vfactor *= vfactor;
uint weight = (uint)(64.0 * vfactor);
#else
uint weight = 1u;
#endif
float3 color = _Source[dispatchThreadId].xyz;
float luminance = max(color.r, max(color.g, color.b)); // Looks more natural than using a Rec.709 luminance
float logLuminance = GetHistogramBinFromLuminance(luminance, _ScaleOffsetRes.xy);
uint idx = (uint)(logLuminance * (HISTOGRAM_BINS - 1u));
InterlockedAdd(gs_histogram[idx], weight);
}
GroupMemoryBarrierWithGroupSync();
// Merge everything
if (localThreadId < HISTOGRAM_BINS)
InterlockedAdd(_Histogram[localThreadId], gs_histogram[localThreadId]);
}

9
Assets/ScriptableRenderLoop/HDRenderPipeline/PostProcess/Resources/EyeHistogram.compute.meta


fileFormatVersion: 2
guid: 6ffb363cabef3ec459559197dbeda232
timeCreated: 1483621596
licenseType: Pro
ComputeShaderImporter:
currentAPIMask: 4
userData:
assetBundleName:
assetBundleVariant:

68
Assets/ScriptableRenderLoop/HDRenderPipeline/PostProcess/Resources/LutGen.shader


Shader "Hidden/HDRenderPipeline/LutGen"
{
HLSLINCLUDE
#pragma target 5.0
#include "Common.hlsl"
#include "Assets/ScriptableRenderLoop/HDRenderPipeline/ShaderVariables.hlsl"
#include "ColorGrading.hlsl"
float4 _LutParams;
struct Attributes
{
float3 vertex : POSITION;
float2 texcoord : TEXCOORD0;
};
struct Varyings
{
float4 vertex : SV_POSITION;
float2 texcoord : TEXCOORD0;
};
Varyings Vert(Attributes input)
{
Varyings output;
output.vertex = TransformWorldToHClip(input.vertex);
output.texcoord = input.texcoord.xy;
return output;
}
float4 Frag(Varyings input) : SV_Target
{
// 2D strip lut
float2 uv = input.texcoord - _LutParams.yz;
float3 color;
color.r = frac(uv.x * _LutParams.x);
color.b = uv.x - color.r / _LutParams.x;
color.g = uv.y;
// Lut is in LogC
float3 colorLogC = color * _LutParams.w;
// Switch back to unity linear
float3 colorLinear = LogCToLinear(colorLogC);
return float4(colorLinear, 1.0);
}
ENDHLSL
SubShader
{
Cull Off ZWrite Off ZTest Always
Pass
{
HLSLPROGRAM
#pragma vertex Vert
#pragma fragment Frag
ENDHLSL
}
}
Fallback Off
}

9
Assets/ScriptableRenderLoop/HDRenderPipeline/PostProcess/Resources/LutGen.shader.meta


fileFormatVersion: 2
guid: d5ac66d76294f88419a16132df665c37
timeCreated: 1483708495
licenseType: Pro
ShaderImporter:
defaultTextures: []
userData:
assetBundleName:
assetBundleVariant:

422
Assets/Textures/CoolingFilterLUT.exr
文件差异内容过多而无法显示
查看文件

108
Assets/Textures/CoolingFilterLUT.exr.meta


fileFormatVersion: 2
guid: 36ff124e89908864e932c5a3c7c6d366
timeCreated: 1483716363
licenseType: Pro
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 0
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
filterMode: 1
aniso: 0
mipBias: -1
wrapMode: -1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Standalone
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: iPhone
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: tvOS
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Windows Store Apps
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: WebGL
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

289
Assets/ScriptableRenderLoop/HDRenderPipeline/PostProcess/Editor/PostProcessingEditor.cs


using System.IO;
using UnityEngine;
using UnityEngine.Experimental.Rendering.HDPipeline;
namespace UnityEditor.Experimental.Rendering.HDPipeline
{
using GradingType = PostProcessing.ColorGradingSettings.GradingType;
using EyeAdaptationType = PostProcessing.EyeAdaptationSettings.EyeAdaptationType;
[CustomEditor(typeof(PostProcessing))]
public class PostProcessingEditor : Editor
{
public class ColorGradingSettings
{
public SerializedProperty type;
public SerializedProperty exposure;
public SerializedProperty logLut;
public SerializedProperty neutralBlackIn;
public SerializedProperty neutralWhiteIn;
public SerializedProperty neutralBlackOut;
public SerializedProperty neutralWhiteOut;
public SerializedProperty neutralWhiteLevel;
public SerializedProperty neutralWhiteClip;
}
public class EyeAdaptationSettings
{
public SerializedProperty enabled;
public SerializedProperty showDebugHistogramInGameView;
public SerializedProperty lowPercent;
public SerializedProperty highPercent;
public SerializedProperty minLuminance;
public SerializedProperty maxLuminance;
public SerializedProperty exposureCompensation;
public SerializedProperty adaptationType;
public SerializedProperty speedUp;
public SerializedProperty speedDown;
public SerializedProperty logMin;
public SerializedProperty logMax;
}
public ColorGradingSettings colorGrading;
public EyeAdaptationSettings eyeAdaptation;
void OnEnable()
{
colorGrading = new ColorGradingSettings()
{
type = serializedObject.FindProperty("colorGrading.type"),
exposure = serializedObject.FindProperty("colorGrading.exposure"),
logLut = serializedObject.FindProperty("colorGrading.logLut"),
neutralBlackIn = serializedObject.FindProperty("colorGrading.neutralBlackIn"),
neutralWhiteIn = serializedObject.FindProperty("colorGrading.neutralWhiteIn"),
neutralBlackOut = serializedObject.FindProperty("colorGrading.neutralBlackOut"),
neutralWhiteOut = serializedObject.FindProperty("colorGrading.neutralWhiteOut"),
neutralWhiteLevel = serializedObject.FindProperty("colorGrading.neutralWhiteLevel"),
neutralWhiteClip = serializedObject.FindProperty("colorGrading.neutralWhiteClip")
};
eyeAdaptation = new EyeAdaptationSettings()
{
enabled = serializedObject.FindProperty("eyeAdaptation.enabled"),
showDebugHistogramInGameView = serializedObject.FindProperty("eyeAdaptation.showDebugHistogramInGameView"),
lowPercent = serializedObject.FindProperty("eyeAdaptation.lowPercent"),
highPercent = serializedObject.FindProperty("eyeAdaptation.highPercent"),
minLuminance = serializedObject.FindProperty("eyeAdaptation.minLuminance"),
maxLuminance = serializedObject.FindProperty("eyeAdaptation.maxLuminance"),
exposureCompensation = serializedObject.FindProperty("eyeAdaptation.exposureCompensation"),
adaptationType = serializedObject.FindProperty("eyeAdaptation.adaptationType"),
speedUp = serializedObject.FindProperty("eyeAdaptation.speedUp"),
speedDown = serializedObject.FindProperty("eyeAdaptation.speedDown"),
logMin = serializedObject.FindProperty("eyeAdaptation.logMin"),
logMax = serializedObject.FindProperty("eyeAdaptation.logMax")
};
}
public override void OnInspectorGUI()
{
serializedObject.Update();
var camera = (target as PostProcessing).GetComponent<Camera>();
if (camera == null)
EditorGUILayout.HelpBox("Global post-processing settings will be overriden by local camera settings. Global settings are the only one visible in the scene view.", MessageType.Info);
EditorGUILayout.LabelField("Color Grading", EditorStyles.boldLabel);
EditorGUI.indentLevel++;
if (camera != null)
{
using (new EditorGUILayout.HorizontalScope())
{
GUILayout.Space(EditorGUI.indentLevel * 15f);
if (GUILayout.Button("Export frame to EXR", EditorStyles.miniButton))
{
string path = EditorUtility.SaveFilePanelInProject("Export frame as EXR...", "Frame.exr", "exr", "");
if (!string.IsNullOrEmpty(path))
SaveFrameToEXR(camera, path);
}
}
}
EditorGUILayout.PropertyField(colorGrading.exposure);
EditorGUILayout.PropertyField(colorGrading.type);
EditorGUI.indentLevel++;
var gradingType = (GradingType)colorGrading.type.intValue;
if (gradingType == GradingType.Custom)
{
EditorGUILayout.PropertyField(colorGrading.logLut);
if (!ValidateLutImportSettings())
{
EditorGUILayout.HelpBox("Invalid LUT import settings.", MessageType.Warning);
GUILayout.Space(-32);
using (new EditorGUILayout.HorizontalScope())
{
GUILayout.FlexibleSpace();
if (GUILayout.Button("Fix", GUILayout.Width(60)))
{
SetLUTImportSettings();
AssetDatabase.Refresh();
}
GUILayout.Space(8);
}
GUILayout.Space(11);
}
}
else if (gradingType == GradingType.Neutral)
{
EditorGUILayout.PropertyField(colorGrading.neutralBlackIn);
EditorGUILayout.PropertyField(colorGrading.neutralWhiteIn);
EditorGUILayout.PropertyField(colorGrading.neutralBlackOut);
EditorGUILayout.PropertyField(colorGrading.neutralWhiteOut);
EditorGUILayout.PropertyField(colorGrading.neutralWhiteLevel);
EditorGUILayout.PropertyField(colorGrading.neutralWhiteClip);
}
EditorGUI.indentLevel--;
EditorGUI.indentLevel--;
EditorGUILayout.LabelField("Eye Adaptation", EditorStyles.boldLabel);
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(eyeAdaptation.enabled);
if (eyeAdaptation.enabled.boolValue)
{
EditorGUILayout.PropertyField(eyeAdaptation.showDebugHistogramInGameView);
EditorGUILayout.PropertyField(eyeAdaptation.logMin, new GUIContent("Histogram Log Min"));
EditorGUILayout.PropertyField(eyeAdaptation.logMax, new GUIContent("Histogram Log Max"));
EditorGUILayout.Space();
float low = eyeAdaptation.lowPercent.floatValue;
float high = eyeAdaptation.highPercent.floatValue;
EditorGUILayout.MinMaxSlider(new GUIContent("Filter"), ref low, ref high, 1f, 99f);
eyeAdaptation.lowPercent.floatValue = low;
eyeAdaptation.highPercent.floatValue = high;
EditorGUILayout.PropertyField(eyeAdaptation.minLuminance);
EditorGUILayout.PropertyField(eyeAdaptation.maxLuminance);
EditorGUILayout.PropertyField(eyeAdaptation.exposureCompensation);
EditorGUILayout.PropertyField(eyeAdaptation.adaptationType);
if (eyeAdaptation.adaptationType.intValue == (int)EyeAdaptationType.Progressive)
{
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(eyeAdaptation.speedUp);
EditorGUILayout.PropertyField(eyeAdaptation.speedDown);
EditorGUI.indentLevel--;
}
}
EditorGUI.indentLevel--;
serializedObject.ApplyModifiedProperties();
}
void SetLUTImportSettings()
{
var lut = (target as PostProcessing).colorGrading.logLut;
var importer = (TextureImporter)AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(lut));
importer.textureType = TextureImporterType.Default;
importer.filterMode = FilterMode.Bilinear;
importer.mipmapEnabled = false;
importer.anisoLevel = 0;
importer.sRGBTexture = false;
importer.npotScale = TextureImporterNPOTScale.None;
importer.textureCompression = TextureImporterCompression.Uncompressed;
importer.SaveAndReimport();
AssetDatabase.Refresh();
}
bool ValidateLutImportSettings()
{
var lut = (target as PostProcessing).colorGrading.logLut;
if (lut == null)
return true;
var importer = (TextureImporter)AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(lut));
return importer.anisoLevel == 0
&& importer.mipmapEnabled == false
&& importer.sRGBTexture == false
&& (importer.textureCompression == TextureImporterCompression.Uncompressed)
&& importer.filterMode == FilterMode.Bilinear;
}
void SaveFrameToEXR(Camera camera, string path)
{
// We want a 1024x32 sized render at a minimum so that we have enough space to stamp the lut
var aspect = (float)camera.pixelHeight / (float)camera.pixelWidth;
var width = camera.pixelWidth >= 1024
? camera.pixelWidth
: 1024;
var height = Mathf.RoundToInt(width * aspect);
var texture = new Texture2D(width, height, TextureFormat.RGBAHalf, false, true);
var targetRt = RenderTexture.GetTemporary(width, height, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear);
// Render the current frame without post processing
var oldPPState = (target as PostProcessing).enabled;
(target as PostProcessing).enabled = false;
var oldTarget = camera.targetTexture;
var oldActive = RenderTexture.active;
camera.targetTexture = targetRt;
camera.Render();
// Stamp the log lut in the top left corner
const int k_InternalLogLutSize = 32;
var stampMaterial = Utilities.CreateEngineMaterial("Hidden/HDRenderPipeline/LutGen");
stampMaterial.SetVector("_LutParams", new Vector4(
k_InternalLogLutSize,
0.5f / (k_InternalLogLutSize * k_InternalLogLutSize),
0.5f / k_InternalLogLutSize,
k_InternalLogLutSize / (k_InternalLogLutSize - 1f))
);
var stampRt = RenderTexture.GetTemporary(1024, 32, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear);
Graphics.Blit(null, stampRt, stampMaterial, 0);
RenderTexture.active = targetRt;
GL.PushMatrix();
{
GL.LoadPixelMatrix(0, width, height, 0);
Graphics.DrawTexture(new Rect(0, 0, stampRt.width, stampRt.height), stampRt);
}
GL.PopMatrix();
// Read back
texture.ReadPixels(new Rect(0, 0, targetRt.width, targetRt.height), 0, 0);
camera.targetTexture = oldTarget;
RenderTexture.active = oldActive;
(target as PostProcessing).enabled = oldPPState;
// Cleanup
RenderTexture.ReleaseTemporary(stampRt);
RenderTexture.ReleaseTemporary(targetRt);
Utilities.Destroy(stampMaterial);
// Save
File.WriteAllBytes(path, texture.EncodeToEXR(Texture2D.EXRFlags.CompressPIZ));
AssetDatabase.Refresh();
}
}
}

12
Assets/ScriptableRenderLoop/HDRenderPipeline/PostProcess/Editor/PostProcessingEditor.cs.meta


fileFormatVersion: 2
guid: 5ddd90f68799818409996b6fd52790dc
timeCreated: 1483612569
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
正在加载...
取消
保存