310 lines
11 KiB
C#
310 lines
11 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
#if UNITY_EDITOR
|
|
using UnityEditor;
|
|
#endif
|
|
using UnityEngine;
|
|
using UnityEngine.Rendering;
|
|
using UnityEngine.Rendering.Universal;
|
|
using UnityEngine.XR;
|
|
|
|
namespace Golems
|
|
{
|
|
/// <summary>
|
|
/// Creates a bunch of named RenderTexture for the camera that can then be used by other
|
|
/// render passes.
|
|
/// The textures can be used, for example, as a temporary texture when operating on the
|
|
/// camera colour texture and then copying it back - saving the pass having to create
|
|
/// its own texture. Another example is that the textures can be used to pass result between
|
|
/// passes - since these temporary textures will be around from the time they are created to
|
|
/// the end of the render pipeline.
|
|
///
|
|
/// Other passes should access the textures via the static interface this class
|
|
/// provides.
|
|
///
|
|
/// NOTE: names are converted to integer hashes to save doing string operations every frame.
|
|
/// </summary>
|
|
public class TemporaryCameraCopyTextureRenderFeature : ScriptableRendererFeature
|
|
{
|
|
[SerializeField]
|
|
private RenderPassEvent m_WhenToAdd = RenderPassEvent.BeforeRendering;
|
|
|
|
[SerializeField]
|
|
private List<string> m_TextureNames;
|
|
|
|
private TemporaryCameraTextureRenderPass m_Pass;
|
|
|
|
private readonly Dictionary<int, RenderTargetIdentifier> m_NameHashToTargetIdentifierMap =
|
|
new Dictionary<int, RenderTargetIdentifier>();
|
|
|
|
private readonly List<NameHashShaderIdPair> m_NameHashesAndIds = new List<NameHashShaderIdPair>();
|
|
|
|
public struct NameHashShaderIdPair
|
|
{
|
|
public int m_NameHash;
|
|
public int m_ShaderId;
|
|
}
|
|
|
|
public override void Create()
|
|
{
|
|
if (s_HasInstance && s_Instance != null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
s_HasInstance = true;
|
|
s_Instance = this;
|
|
|
|
//
|
|
// Create the name hashes
|
|
//
|
|
m_NameHashesAndIds.Clear();
|
|
for (int i = 0; i < m_TextureNames.Count; i++)
|
|
{
|
|
m_NameHashesAndIds.Add( new NameHashShaderIdPair()
|
|
{
|
|
m_NameHash = GetNameHash(m_TextureNames[i]),
|
|
m_ShaderId = Shader.PropertyToID(m_TextureNames[i]),
|
|
});
|
|
}
|
|
|
|
m_Pass = new TemporaryCameraTextureRenderPass();
|
|
}
|
|
|
|
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
|
|
{
|
|
if (m_Pass == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
#if ENABLE_VR
|
|
var isXR = XRSettings.enabled;
|
|
m_Pass.Setup(m_WhenToAdd, isXR, m_NameHashesAndIds, SetupTempTargetIdentifier, ClearTempTargetIdentifiers);
|
|
#else
|
|
m_Pass.Setup(m_WhenToAdd, false, m_NameHashesAndIds, SetupTempTargetIdentifier, ClearTempTargetIdentifiers);
|
|
#endif
|
|
renderer.EnqueuePass(m_Pass);
|
|
|
|
|
|
}
|
|
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
if (s_Instance == this)
|
|
{
|
|
s_HasInstance = false;
|
|
s_Instance = null;
|
|
}
|
|
base.Dispose(disposing);
|
|
}
|
|
|
|
|
|
private bool InternalTryGetTempTextureIdentifier(int nameHash, out RenderTargetIdentifier outTargetIdentifier)
|
|
{
|
|
return m_NameHashToTargetIdentifierMap.TryGetValue(nameHash, out outTargetIdentifier);
|
|
}
|
|
|
|
private void InternalClearTempTargetIdentifiers()
|
|
{
|
|
m_NameHashToTargetIdentifierMap.Clear();
|
|
}
|
|
|
|
private void InternalSetupTempTargetIdentifier(int nameHash, RenderTargetIdentifier identifier)
|
|
{
|
|
m_NameHashToTargetIdentifierMap[nameHash] = identifier;
|
|
}
|
|
|
|
//
|
|
//
|
|
// Static interface
|
|
//
|
|
//
|
|
public const int k_InvalidNameHash = -1;
|
|
private static bool s_HasInstance;
|
|
private static TemporaryCameraCopyTextureRenderFeature s_Instance;
|
|
|
|
/// <summary>
|
|
/// Used by passes to ask for a named texture by its name hash.
|
|
/// NOTE: hashes are used to avoid having a dictionary keyed by strings.
|
|
/// </summary>
|
|
/// <param name="nameHash"></param>
|
|
/// <param name="outTargetIdentifier"></param>
|
|
/// <returns>true if the texture is available, false otherwise</returns>
|
|
public static bool TryGetTempTextureIdentifier(int nameHash, out RenderTargetIdentifier outTargetIdentifier)
|
|
{
|
|
if (!s_HasInstance)
|
|
{
|
|
outTargetIdentifier = default;
|
|
return false;
|
|
}
|
|
|
|
return s_Instance.InternalTryGetTempTextureIdentifier(nameHash, out outTargetIdentifier);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Given a name, this returns the hash of that name.
|
|
/// </summary>
|
|
public static int GetNameHash(string name)
|
|
{
|
|
if (string.IsNullOrEmpty(name))
|
|
{
|
|
return k_InvalidNameHash;
|
|
}
|
|
|
|
return name.GetHashCode();
|
|
}
|
|
|
|
private static void SetupTempTargetIdentifier(int nameHash, RenderTargetIdentifier identifier)
|
|
{
|
|
if (!s_HasInstance)
|
|
{
|
|
return;
|
|
}
|
|
|
|
s_Instance.InternalSetupTempTargetIdentifier(nameHash, identifier);
|
|
}
|
|
|
|
private static void ClearTempTargetIdentifiers()
|
|
{
|
|
if (!s_HasInstance)
|
|
{
|
|
return;
|
|
}
|
|
|
|
s_Instance.InternalClearTempTargetIdentifiers();
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
private bool m_EditorNameHashToTargetIdentifierMapFoldout;
|
|
private bool m_EditorNameHashesAndIdsFoldout;
|
|
protected virtual void EditorOnInspectorGUIAfterBase()
|
|
{
|
|
EditorGUILayout.LabelField("Info", EditorStyles.boldLabel);
|
|
|
|
var origIndent = EditorGUI.indentLevel;
|
|
EditorGUI.indentLevel += 1;
|
|
#if false
|
|
//
|
|
// NOTE:
|
|
// m_NameHashToTargetIdentifierMap gets cleared every frame so no useful info
|
|
//
|
|
m_EditorNameHashToTargetIdentifierMapFoldout = EditorGUILayout.Foldout(m_EditorNameHashToTargetIdentifierMapFoldout, "Name hash to identifier map");
|
|
if (m_EditorNameHashToTargetIdentifierMapFoldout)
|
|
{
|
|
|
|
foreach (var nameHashIdentifier in m_NameHashToTargetIdentifierMap)
|
|
{
|
|
EditorGUILayout.LabelField(
|
|
$"Name hash: {nameHashIdentifier.Key}, identifier {nameHashIdentifier.Value}");
|
|
}
|
|
}
|
|
#endif
|
|
m_EditorNameHashesAndIdsFoldout = EditorGUILayout.Foldout(m_EditorNameHashesAndIdsFoldout, "Name hash to shader id map");
|
|
if (m_EditorNameHashesAndIdsFoldout)
|
|
{
|
|
foreach (var nameHashIds in m_NameHashesAndIds)
|
|
{
|
|
EditorGUILayout.LabelField(
|
|
$"Name hash: {nameHashIds.m_NameHash}, identifier {nameHashIds.m_ShaderId}");
|
|
}
|
|
}
|
|
|
|
EditorGUI.BeginDisabledGroup(true);
|
|
EditorGUILayout.ObjectField("Instance", s_Instance, typeof(TemporaryCameraCopyTextureRenderFeature), false);
|
|
EditorGUI.EndDisabledGroup();
|
|
|
|
EditorGUI.indentLevel = origIndent;
|
|
|
|
EditorGUILayout.LabelField("Controls", EditorStyles.boldLabel);
|
|
}
|
|
|
|
private static void EditorTextureNameAndHash(string label, string namedTemporaryName, int namedTemporaryNameHash)
|
|
{
|
|
EditorGUILayout.TextField(label);
|
|
EditorGUI.indentLevel += 1;
|
|
if (!string.IsNullOrEmpty(namedTemporaryName))
|
|
{
|
|
EditorGUILayout.IntField(namedTemporaryName, namedTemporaryNameHash);
|
|
}
|
|
else
|
|
{
|
|
EditorGUILayout.IntField("null name", namedTemporaryNameHash);
|
|
}
|
|
EditorGUI.indentLevel -= 1;
|
|
}
|
|
|
|
[CustomEditor(typeof(TemporaryCameraCopyTextureRenderFeature))]
|
|
private class TemporaryCameraCopyTextureRenderFeatureEditor : Editor
|
|
{
|
|
public override void OnInspectorGUI()
|
|
{
|
|
base.OnInspectorGUI();
|
|
|
|
var me = target as TemporaryCameraCopyTextureRenderFeature;
|
|
if (me != null)
|
|
{
|
|
me.EditorOnInspectorGUIAfterBase();
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// This is the pass that creates the named textures.
|
|
/// </summary>
|
|
public class TemporaryCameraTextureRenderPass : ScriptableRenderPass
|
|
{
|
|
private bool m_IsXR;
|
|
private List<TemporaryCameraCopyTextureRenderFeature.NameHashShaderIdPair> m_NameHashesAndIds;
|
|
private Action<int, RenderTargetIdentifier> m_SetIdentifierAction;
|
|
private Action m_ClearIdentifiersAction;
|
|
|
|
public void Setup(RenderPassEvent whenToRender, bool isXR,
|
|
List<TemporaryCameraCopyTextureRenderFeature.NameHashShaderIdPair> nameHashesAndIds, Action<int, RenderTargetIdentifier> setIdentifierAction,
|
|
Action clearIdentifiersAction)
|
|
{
|
|
renderPassEvent = whenToRender;
|
|
m_IsXR = isXR;
|
|
m_NameHashesAndIds = nameHashesAndIds;
|
|
m_SetIdentifierAction = setIdentifierAction;
|
|
m_ClearIdentifiersAction = clearIdentifiersAction;
|
|
}
|
|
|
|
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
|
|
{
|
|
//
|
|
// Create the temporary textures
|
|
//
|
|
#if UNITY_SWITCH
|
|
var renderTextureDescriptor = renderingData.cameraData.cameraTargetDescriptor;
|
|
var width = 1280;
|
|
var height = 720;
|
|
#elif ENABLE_VR
|
|
var renderTextureDescriptor = m_IsXR ? XRSettings.eyeTextureDesc : renderingData.cameraData.cameraTargetDescriptor;
|
|
#else
|
|
var renderTextureDescriptor = renderingData.cameraData.cameraTargetDescriptor;
|
|
#endif
|
|
for (int i = 0; i < m_NameHashesAndIds.Count; i++)
|
|
{
|
|
#if UNITY_SWITCH
|
|
cmd.GetTemporaryRT(m_NameHashesAndIds[i].m_ShaderId, width,height,renderTextureDescriptor.depthBufferBits,FilterMode.Bilinear,renderTextureDescriptor.colorFormat);
|
|
#else
|
|
cmd.GetTemporaryRT(m_NameHashesAndIds[i].m_ShaderId, renderTextureDescriptor);
|
|
#endif
|
|
m_SetIdentifierAction?.Invoke(m_NameHashesAndIds[i].m_NameHash, new RenderTargetIdentifier(m_NameHashesAndIds[i].m_ShaderId));
|
|
}
|
|
}
|
|
|
|
public override void OnCameraCleanup(CommandBuffer cmd)
|
|
{
|
|
m_ClearIdentifiersAction?.Invoke();
|
|
}
|
|
|
|
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
|
|
{
|
|
}
|
|
}
|
|
} |