mathe/Library/PackageCache/com.unity.shadergraph@14.0.8/Editor/Data/Nodes/UV/ParallaxMappingNode.cs
2024-09-20 20:30:10 +02:00

136 lines
5.2 KiB
C#

using UnityEngine;
using UnityEditor.Graphing;
using System;
using System.Linq;
using UnityEditor.ShaderGraph.Internal;
using UnityEditor.ShaderGraph.Drawing.Controls;
namespace UnityEditor.ShaderGraph
{
enum Channel
{
Red = 0,
Green = 1,
Blue = 2,
Alpha = 3,
}
[Title("UV", "Parallax Mapping")]
class ParallaxMappingNode : AbstractMaterialNode, IGeneratesBodyCode, IGeneratesFunction, IMayRequireViewDirection, IMayRequireMeshUV
{
public ParallaxMappingNode()
{
name = "Parallax Mapping";
synonyms = new string[] { "offset mapping" };
UpdateNodeAfterDeserialization();
}
// Input slots
private const int kHeightmapSlotId = 1;
private const string kHeightmapSlotName = "Heightmap";
private const int kHeightmapSamplerSlotId = 2;
private const string kHeightmapSamplerSlotName = "HeightmapSampler";
private const int kAmplitudeSlotId = 3;
private const string kAmplitudeSlotName = "Amplitude";
private const int kUVsSlotId = 4;
private const string kUVsSlotName = "UVs";
// Output slots
private const int kParallaxUVsOutputSlotId = 0;
private const string kParallaxUVsOutputSlotName = "ParallaxUVs";
public override bool hasPreview { get { return false; } }
[SerializeField]
private Channel m_Channel = Channel.Green;
[EnumControl("Heightmap Sample Channel")]
public Channel channel
{
get { return m_Channel; }
set
{
if (m_Channel == value)
return;
m_Channel = value;
Dirty(ModificationScope.Graph);
}
}
public sealed override void UpdateNodeAfterDeserialization()
{
AddSlot(new Texture2DInputMaterialSlot(kHeightmapSlotId, kHeightmapSlotName, kHeightmapSlotName, ShaderStageCapability.Fragment));
AddSlot(new SamplerStateMaterialSlot(kHeightmapSamplerSlotId, kHeightmapSamplerSlotName, kHeightmapSamplerSlotName, SlotType.Input));
AddSlot(new Vector1MaterialSlot(kAmplitudeSlotId, kAmplitudeSlotName, kAmplitudeSlotName, SlotType.Input, 1, ShaderStageCapability.Fragment));
AddSlot(new UVMaterialSlot(kUVsSlotId, kUVsSlotName, kUVsSlotName, UVChannel.UV0, ShaderStageCapability.Fragment));
AddSlot(new Vector2MaterialSlot(kParallaxUVsOutputSlotId, kParallaxUVsOutputSlotName, kParallaxUVsOutputSlotName, SlotType.Output, Vector2.zero, ShaderStageCapability.Fragment));
RemoveSlotsNameNotMatching(new[]
{
kParallaxUVsOutputSlotId,
kHeightmapSlotId,
kHeightmapSamplerSlotId,
kAmplitudeSlotId,
kUVsSlotId,
});
}
public override void Setup()
{
base.Setup();
var textureSlot = FindInputSlot<Texture2DInputMaterialSlot>(kHeightmapSlotId);
textureSlot.defaultType = Texture2DShaderProperty.DefaultType.Black;
}
public void GenerateNodeFunction(FunctionRegistry registry, GenerationMode generationMode)
{
registry.RequiresIncludePath("Packages/com.unity.render-pipelines.core/ShaderLibrary/ParallaxMapping.hlsl");
}
public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode)
{
var heightmap = GetSlotValue(kHeightmapSlotId, generationMode);
var samplerSlot = FindInputSlot<MaterialSlot>(kHeightmapSamplerSlotId);
var edgesSampler = owner.GetEdges(samplerSlot.slotReference);
var amplitude = GetSlotValue(kAmplitudeSlotId, generationMode);
var uvs = GetSlotValue(kUVsSlotId, generationMode);
sb.AppendLines(String.Format(@"$precision2 {5} = {0}.GetTransformedUV({4}) + ParallaxMappingChannel(TEXTURE2D_ARGS({0}.tex, {1}.samplerstate), IN.{2}, {3} * 0.01, {0}.GetTransformedUV({4}), {6});",
heightmap,
edgesSampler.Any() ? GetSlotValue(kHeightmapSamplerSlotId, generationMode) : heightmap,
CoordinateSpace.Tangent.ToVariableName(InterpolatorType.ViewDirection),
amplitude, // cm in the interface so we multiply by 0.01 in the shader to convert in meter
uvs,
GetSlotValue(kParallaxUVsOutputSlotId, generationMode),
(int)channel
));
}
public NeededCoordinateSpace RequiresViewDirection(ShaderStageCapability stageCapability = ShaderStageCapability.All)
{
return NeededCoordinateSpace.Tangent;
}
public bool RequiresMeshUV(UVChannel channel, ShaderStageCapability stageCapability)
{
using (var tempSlots = PooledList<MaterialSlot>.Get())
{
GetInputSlots(tempSlots);
var result = false;
foreach (var slot in tempSlots)
{
if (slot.RequiresMeshUV(channel))
{
result = true;
break;
}
}
tempSlots.Clear();
return result;
}
}
}
}