172 lines
6.9 KiB
C#
172 lines
6.9 KiB
C#
|
using System.Collections.Generic;
|
||
|
using System;
|
||
|
using UnityEngine;
|
||
|
using UnityEditor.Graphing;
|
||
|
using UnityEditor.ShaderGraph;
|
||
|
using UnityEditor.ShaderGraph.Drawing.Controls;
|
||
|
using UnityEditor.ShaderGraph.Internal;
|
||
|
using UnityEngine.Rendering.Universal;
|
||
|
using System.Reflection;
|
||
|
using System.Linq;
|
||
|
using UnityEngine.XR;
|
||
|
|
||
|
namespace UnityEditor.Rendering.Universal
|
||
|
{
|
||
|
[SRPFilter(typeof(UniversalRenderPipeline))]
|
||
|
[Title("Input", "Universal", "URP Sample Buffer")]
|
||
|
sealed class UniversalSampleBufferNode : AbstractMaterialNode, IGeneratesBodyCode, IGeneratesFunction, IMayRequireScreenPosition, IMayRequireNDCPosition
|
||
|
{
|
||
|
const string k_ScreenPositionSlotName = "UV";
|
||
|
const string k_OutputSlotName = "Output";
|
||
|
|
||
|
const int k_ScreenPositionSlotId = 0;
|
||
|
const int k_OutputSlotId = 2;
|
||
|
|
||
|
public enum BufferType
|
||
|
{
|
||
|
NormalWorldSpace,
|
||
|
MotionVectors,
|
||
|
BlitSource,
|
||
|
}
|
||
|
|
||
|
[SerializeField]
|
||
|
private BufferType m_BufferType = BufferType.NormalWorldSpace;
|
||
|
|
||
|
[EnumControl("Source Buffer")]
|
||
|
public BufferType bufferType
|
||
|
{
|
||
|
get { return m_BufferType; }
|
||
|
set
|
||
|
{
|
||
|
if (m_BufferType == value)
|
||
|
return;
|
||
|
|
||
|
m_BufferType = value;
|
||
|
UpdateNodeAfterDeserialization();
|
||
|
Dirty(ModificationScope.Graph);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override string documentationURL => Documentation.GetPageLink(Documentation.packageName, "SGNode-Universal-Sample-Buffer");
|
||
|
|
||
|
public UniversalSampleBufferNode()
|
||
|
{
|
||
|
name = "URP Sample Buffer";
|
||
|
synonyms = new string[] { "normal", "motion vector", "blit" };
|
||
|
UpdateNodeAfterDeserialization();
|
||
|
}
|
||
|
|
||
|
public override bool hasPreview { get { return true; } }
|
||
|
public override PreviewMode previewMode => PreviewMode.Preview2D;
|
||
|
|
||
|
int channelCount;
|
||
|
|
||
|
public sealed override void UpdateNodeAfterDeserialization()
|
||
|
{
|
||
|
AddSlot(new ScreenPositionMaterialSlot(k_ScreenPositionSlotId, k_ScreenPositionSlotName, k_ScreenPositionSlotName, ScreenSpaceType.Default));
|
||
|
|
||
|
switch (bufferType)
|
||
|
{
|
||
|
case BufferType.NormalWorldSpace:
|
||
|
AddSlot(new Vector3MaterialSlot(k_OutputSlotId, k_OutputSlotName, k_OutputSlotName, SlotType.Output, Vector3.zero, ShaderStageCapability.Fragment));
|
||
|
channelCount = 3;
|
||
|
break;
|
||
|
case BufferType.MotionVectors:
|
||
|
AddSlot(new Vector2MaterialSlot(k_OutputSlotId, k_OutputSlotName, k_OutputSlotName, SlotType.Output, Vector2.zero, ShaderStageCapability.Fragment));
|
||
|
channelCount = 2;
|
||
|
break;
|
||
|
case BufferType.BlitSource:
|
||
|
AddSlot(new ColorRGBAMaterialSlot(k_OutputSlotId, k_OutputSlotName, k_OutputSlotName, SlotType.Output, Color.black, ShaderStageCapability.Fragment));
|
||
|
channelCount = 4;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
RemoveSlotsNameNotMatching(new[]
|
||
|
{
|
||
|
k_ScreenPositionSlotId,
|
||
|
k_OutputSlotId,
|
||
|
});
|
||
|
}
|
||
|
|
||
|
public override void CollectShaderProperties(PropertyCollector properties, GenerationMode generationMode)
|
||
|
{
|
||
|
if (generationMode.IsPreview())
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
string GetFunctionName() => $"Unity_Universal_SampleBuffer_{bufferType}_$precision";
|
||
|
|
||
|
public void GenerateNodeFunction(FunctionRegistry registry, GenerationMode generationMode)
|
||
|
{
|
||
|
// Preview SG doesn't have access to render pipeline buffer
|
||
|
if (!generationMode.IsPreview())
|
||
|
{
|
||
|
registry.ProvideFunction(GetFunctionName(), s =>
|
||
|
{
|
||
|
if (bufferType == BufferType.MotionVectors)
|
||
|
s.AppendLine("TEXTURE2D_X(_MotionVectorTexture);");
|
||
|
|
||
|
if (bufferType == BufferType.BlitSource)
|
||
|
{
|
||
|
s.AppendLine("TEXTURE2D_X(_BlitTexture);");
|
||
|
}
|
||
|
|
||
|
s.AppendLine("$precision{1} {0}($precision2 uv)", GetFunctionName(), channelCount);
|
||
|
using (s.BlockScope())
|
||
|
{
|
||
|
switch (bufferType)
|
||
|
{
|
||
|
case BufferType.NormalWorldSpace:
|
||
|
s.AppendLine("return SHADERGRAPH_SAMPLE_SCENE_NORMAL(uv);");
|
||
|
break;
|
||
|
case BufferType.MotionVectors:
|
||
|
s.AppendLine("uint2 pixelCoords = uint2(uv * _ScreenSize.xy);");
|
||
|
s.AppendLine($"return LOAD_TEXTURE2D_X_LOD(_MotionVectorTexture, pixelCoords, 0).xy;");
|
||
|
break;
|
||
|
case BufferType.BlitSource:
|
||
|
s.AppendLine("uint2 pixelCoords = uint2(uv * _ScreenSize.xy);");
|
||
|
s.AppendLine($"return LOAD_TEXTURE2D_X_LOD(_BlitTexture, pixelCoords, 0);");
|
||
|
break;
|
||
|
default:
|
||
|
s.AppendLine("return 0.0;");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
registry.ProvideFunction(GetFunctionName(), s =>
|
||
|
{
|
||
|
s.AppendLine("$precision{1} {0}($precision2 uv)", GetFunctionName(), channelCount);
|
||
|
using (s.BlockScope())
|
||
|
{
|
||
|
switch (bufferType)
|
||
|
{
|
||
|
case BufferType.NormalWorldSpace:
|
||
|
s.AppendLine("return LatlongToDirectionCoordinate(uv);");
|
||
|
break;
|
||
|
case BufferType.MotionVectors:
|
||
|
s.AppendLine("return uv * 2 - 1;");
|
||
|
break;
|
||
|
case BufferType.BlitSource:
|
||
|
default:
|
||
|
s.AppendLine("return 0.0;");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode)
|
||
|
{
|
||
|
string uv = GetSlotValue(k_ScreenPositionSlotId, generationMode);
|
||
|
sb.AppendLine($"$precision{channelCount} {GetVariableNameForSlot(k_OutputSlotId)} = {GetFunctionName()}({uv}.xy);");
|
||
|
}
|
||
|
|
||
|
public bool RequiresNDCPosition(ShaderStageCapability stageCapability = ShaderStageCapability.All) => true;
|
||
|
public bool RequiresScreenPosition(ShaderStageCapability stageCapability = ShaderStageCapability.All) => true;
|
||
|
}
|
||
|
}
|