2021-09-09 20:42:29 -04:00

209 lines
8.6 KiB
C#

using System.IO;
using UnityEngine;
using UnityEngine.Rendering.HighDefinition;
using UnityEngine.Rendering;
namespace UnityEditor.Rendering.HighDefinition
{
// TODO: handle retina / EditorGUIUtility.pixelsPerPoint
[VolumeComponentEditor(typeof(Tonemapping))]
sealed class TonemappingEditor : VolumeComponentEditor
{
SerializedDataParameter m_Mode;
SerializedDataParameter m_ToeStrength;
SerializedDataParameter m_ToeLength;
SerializedDataParameter m_ShoulderStrength;
SerializedDataParameter m_ShoulderLength;
SerializedDataParameter m_ShoulderAngle;
SerializedDataParameter m_Gamma;
SerializedDataParameter m_LutTexture;
SerializedDataParameter m_LutContribution;
// Curve drawing utilities
readonly HableCurve m_HableCurve = new HableCurve();
Rect m_CurveRect;
Material m_Material;
RenderTexture m_CurveTex;
public override void OnEnable()
{
var o = new PropertyFetcher<Tonemapping>(serializedObject);
m_Mode = Unpack(o.Find(x => x.mode));
m_ToeStrength = Unpack(o.Find(x => x.toeStrength));
m_ToeLength = Unpack(o.Find(x => x.toeLength));
m_ShoulderStrength = Unpack(o.Find(x => x.shoulderStrength));
m_ShoulderLength = Unpack(o.Find(x => x.shoulderLength));
m_ShoulderAngle = Unpack(o.Find(x => x.shoulderAngle));
m_Gamma = Unpack(o.Find(x => x.gamma));
m_LutTexture = Unpack(o.Find(x => x.lutTexture));
m_LutContribution = Unpack(o.Find(x => x.lutContribution));
m_Material = new Material(Shader.Find("Hidden/HD PostProcessing/Editor/Custom Tonemapper Curve"));
}
public override void OnDisable()
{
CoreUtils.Destroy(m_Material);
m_Material = null;
CoreUtils.Destroy(m_CurveTex);
m_CurveTex = null;
}
public override void OnInspectorGUI()
{
PropertyField(m_Mode);
// Draw a curve for the custom tonemapping mode to make it easier to tweak visually
if (m_Mode.value.intValue == (int)TonemappingMode.Custom)
{
EditorGUILayout.Space();
// Reserve GUI space
using (new GUILayout.HorizontalScope())
{
GUILayout.Space(EditorGUI.indentLevel * 15f);
m_CurveRect = GUILayoutUtility.GetRect(128, 80);
}
if (Event.current.type == EventType.Repaint)
{
// Prepare curve data
float toeStrength = m_ToeStrength.value.floatValue;
float toeLength = m_ToeLength.value.floatValue;
float shoulderStrength = m_ShoulderStrength.value.floatValue;
float shoulderLength = m_ShoulderLength.value.floatValue;
float shoulderAngle = m_ShoulderAngle.value.floatValue;
float gamma = m_Gamma.value.floatValue;
m_HableCurve.Init(
toeStrength,
toeLength,
shoulderStrength,
shoulderLength,
shoulderAngle,
gamma
);
float alpha = GUI.enabled ? 1f : 0.5f;
m_Material.SetVector(HDShaderIDs._CustomToneCurve, m_HableCurve.uniforms.curve);
m_Material.SetVector(HDShaderIDs._ToeSegmentA, m_HableCurve.uniforms.toeSegmentA);
m_Material.SetVector(HDShaderIDs._ToeSegmentB, m_HableCurve.uniforms.toeSegmentB);
m_Material.SetVector(HDShaderIDs._MidSegmentA, m_HableCurve.uniforms.midSegmentA);
m_Material.SetVector(HDShaderIDs._MidSegmentB, m_HableCurve.uniforms.midSegmentB);
m_Material.SetVector(HDShaderIDs._ShoSegmentA, m_HableCurve.uniforms.shoSegmentA);
m_Material.SetVector(HDShaderIDs._ShoSegmentB, m_HableCurve.uniforms.shoSegmentB);
m_Material.SetVector(HDShaderIDs._Variants, new Vector4(alpha, m_HableCurve.whitePoint, 0f, 0f));
CheckCurveRT((int)m_CurveRect.width, (int)m_CurveRect.height);
var oldRt = RenderTexture.active;
Graphics.Blit(null, m_CurveTex, m_Material, EditorGUIUtility.isProSkin ? 0 : 1);
RenderTexture.active = oldRt;
GUI.DrawTexture(m_CurveRect, m_CurveTex);
Handles.DrawSolidRectangleWithOutline(m_CurveRect, Color.clear, Color.white * 0.4f);
}
PropertyField(m_ToeStrength);
PropertyField(m_ToeLength);
PropertyField(m_ShoulderStrength);
PropertyField(m_ShoulderLength);
PropertyField(m_ShoulderAngle);
PropertyField(m_Gamma);
}
else if (m_Mode.value.intValue == (int)TonemappingMode.External)
{
PropertyField(m_LutTexture, EditorGUIUtility.TrTextContent("Lookup Texture"));
var lut = m_LutTexture.value.objectReferenceValue;
if (lut != null && !((Tonemapping)target).ValidateLUT())
EditorGUILayout.HelpBox("Invalid lookup texture. It must be a 3D texture or render texture with the same size as set in the HDRP settings.", MessageType.Warning);
PropertyField(m_LutContribution, EditorGUIUtility.TrTextContent("Contribution"));
EditorGUILayout.HelpBox("Use \"Edit > Render Pipeline > HD Render Pipeline > Render Selected Camera to Log EXR\" to export a log-encoded frame for external grading.", MessageType.Info);
}
}
void CheckCurveRT(int width, int height)
{
if (m_CurveTex == null || !m_CurveTex.IsCreated() || m_CurveTex.width != width || m_CurveTex.height != height)
{
CoreUtils.Destroy(m_CurveTex);
m_CurveTex = new RenderTexture(width, height, 0, RenderTextureFormat.ARGB32);
m_CurveTex.hideFlags = HideFlags.HideAndDontSave;
}
}
}
sealed class ExrExportMenu
{
[MenuItem("Edit/Render Pipeline/HD Render Pipeline/Render Selected Camera to Log EXR %#&e")]
static void Export()
{
var camera = Selection.activeGameObject?.GetComponent<Camera>();
if (camera == null)
{
Debug.LogError("Please select a camera before trying to export an EXR.");
return;
}
var hdInstance = RenderPipelineManager.currentPipeline as HDRenderPipeline;
if (hdInstance == null)
{
Debug.LogError("No HDRenderPipeline set in GraphicsSettings.");
return;
}
string outPath = EditorUtility.SaveFilePanel("Export EXR...", "", "Frame", "exr");
if (string.IsNullOrEmpty(outPath))
return;
var w = camera.pixelWidth;
var h = camera.pixelHeight;
var texOut = new Texture2D(w, h, TextureFormat.RGBAFloat, false, true);
var target = RenderTexture.GetTemporary(w, h, 24, RenderTextureFormat.ARGBFloat, RenderTextureReadWrite.Linear);
var lastActive = RenderTexture.active;
var lastTargetSet = camera.targetTexture;
hdInstance.debugDisplaySettings.SetFullScreenDebugMode(FullScreenDebugMode.ColorLog);
EditorUtility.DisplayProgressBar("Export EXR", "Rendering...", 0f);
camera.targetTexture = target;
camera.Render();
camera.targetTexture = lastTargetSet;
EditorUtility.DisplayProgressBar("Export EXR", "Reading...", 0.25f);
hdInstance.debugDisplaySettings.SetFullScreenDebugMode(FullScreenDebugMode.None);
RenderTexture.active = target;
texOut.ReadPixels(new Rect(0, 0, w, h), 0, 0);
texOut.Apply();
RenderTexture.active = lastActive;
EditorUtility.DisplayProgressBar("Export EXR", "Encoding...", 0.5f);
var bytes = texOut.EncodeToEXR(Texture2D.EXRFlags.OutputAsFloat | Texture2D.EXRFlags.CompressZIP);
EditorUtility.DisplayProgressBar("Export EXR", "Saving...", 0.75f);
File.WriteAllBytes(outPath, bytes);
EditorUtility.ClearProgressBar();
AssetDatabase.Refresh();
RenderTexture.ReleaseTemporary(target);
UnityEngine.Object.DestroyImmediate(texOut);
}
}
}