Keine Beschreibung
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

ParallaxOcclusionMappingNode.cs 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. using UnityEngine;
  2. using UnityEditor.Graphing;
  3. using System.Linq;
  4. using UnityEditor.ShaderGraph.Internal;
  5. using UnityEditor.ShaderGraph.Drawing.Controls;
  6. namespace UnityEditor.ShaderGraph
  7. {
  8. [Title("UV", "Parallax Occlusion Mapping")]
  9. [FormerName("UnityEditor.Experimental.Rendering.HDPipeline.ParallaxOcclusionMappingNode")]
  10. [FormerName("UnityEditor.Rendering.HighDefinition.ParallaxOcclusionMappingNode")]
  11. class ParallaxOcclusionMappingNode : AbstractMaterialNode, IGeneratesBodyCode, IGeneratesFunction, IMayRequireViewDirection, IMayRequireMeshUV
  12. {
  13. public ParallaxOcclusionMappingNode()
  14. {
  15. name = "Parallax Occlusion Mapping";
  16. synonyms = new string[] { "pom" };
  17. UpdateNodeAfterDeserialization();
  18. }
  19. // Input slots
  20. private const int kHeightmapSlotId = 2;
  21. private const string kHeightmapSlotName = "Heightmap";
  22. private const int kHeightmapSamplerSlotId = 3;
  23. private const string kHeightmapSamplerSlotName = "HeightmapSampler";
  24. private const int kAmplitudeSlotId = 4;
  25. private const string kAmplitudeSlotName = "Amplitude";
  26. private const int kStepsSlotId = 5;
  27. private const string kStepsSlotName = "Steps";
  28. private const int kUVsSlotId = 6;
  29. private const string kUVsSlotName = "UVs";
  30. private const int kLodSlotId = 7;
  31. private const string kLodSlotName = "LOD";
  32. private const int kLodThresholdSlotId = 8;
  33. private const string kLodThresholdSlotName = "LODThreshold";
  34. private const int kTilingSlotId = 10;
  35. private const string kTilingSlotName = "Tiling";
  36. private const int kOffsetSlotId = 11;
  37. private const string kOffsetSlotName = "Offset";
  38. private const int kPrimitiveSizeSlotId = 12;
  39. private const string kPrimitiveSizeSlotName = "PrimitiveSize";
  40. // Output slots
  41. private const int kPixelDepthOffsetOutputSlotId = 0;
  42. private const string kPixelDepthOffsetOutputSlotName = "PixelDepthOffset";
  43. private const int kParallaxUVsOutputSlotId = 1;
  44. private const string kParallaxUVsOutputSlotName = "ParallaxUVs";
  45. public override bool hasPreview { get { return false; } }
  46. [SerializeField]
  47. private Channel m_Channel = Channel.Red;
  48. [EnumControl("Heightmap Sample Channel")]
  49. public Channel channel
  50. {
  51. get { return m_Channel; }
  52. set
  53. {
  54. if (m_Channel == value)
  55. return;
  56. m_Channel = value;
  57. Dirty(ModificationScope.Graph);
  58. }
  59. }
  60. public sealed override void UpdateNodeAfterDeserialization()
  61. {
  62. AddSlot(new Texture2DInputMaterialSlot(kHeightmapSlotId, kHeightmapSlotName, kHeightmapSlotName, ShaderStageCapability.Fragment));
  63. AddSlot(new SamplerStateMaterialSlot(kHeightmapSamplerSlotId, kHeightmapSamplerSlotName, kHeightmapSamplerSlotName, SlotType.Input));
  64. AddSlot(new Vector1MaterialSlot(kAmplitudeSlotId, kAmplitudeSlotName, kAmplitudeSlotName, SlotType.Input, 1.0f, ShaderStageCapability.Fragment));
  65. AddSlot(new Vector1MaterialSlot(kStepsSlotId, kStepsSlotName, kStepsSlotName, SlotType.Input, 5.0f, ShaderStageCapability.Fragment));
  66. AddSlot(new UVMaterialSlot(kUVsSlotId, kUVsSlotName, kUVsSlotName, UVChannel.UV0, ShaderStageCapability.Fragment));
  67. AddSlot(new Vector2MaterialSlot(kTilingSlotId, kTilingSlotName, kTilingSlotName, SlotType.Input, Vector2.one, ShaderStageCapability.Fragment));
  68. AddSlot(new Vector2MaterialSlot(kOffsetSlotId, kOffsetSlotName, kOffsetSlotName, SlotType.Input, Vector2.zero, ShaderStageCapability.Fragment));
  69. AddSlot(new Vector2MaterialSlot(kPrimitiveSizeSlotId, kPrimitiveSizeSlotName, kPrimitiveSizeSlotName, SlotType.Input, Vector2.one, ShaderStageCapability.Fragment));
  70. AddSlot(new Vector1MaterialSlot(kLodSlotId, kLodSlotName, kLodSlotName, SlotType.Input, 0.0f, ShaderStageCapability.Fragment));
  71. AddSlot(new Vector1MaterialSlot(kLodThresholdSlotId, kLodThresholdSlotName, kLodThresholdSlotName, SlotType.Input, 0.0f, ShaderStageCapability.Fragment));
  72. AddSlot(new Vector1MaterialSlot(kPixelDepthOffsetOutputSlotId, kPixelDepthOffsetOutputSlotName, kPixelDepthOffsetOutputSlotName, SlotType.Output, 0.0f, ShaderStageCapability.Fragment));
  73. AddSlot(new Vector2MaterialSlot(kParallaxUVsOutputSlotId, kParallaxUVsOutputSlotName, kParallaxUVsOutputSlotName, SlotType.Output, Vector2.zero, ShaderStageCapability.Fragment));
  74. RemoveSlotsNameNotMatching(new[]
  75. {
  76. kPixelDepthOffsetOutputSlotId,
  77. kParallaxUVsOutputSlotId,
  78. kHeightmapSlotId,
  79. kHeightmapSamplerSlotId,
  80. kAmplitudeSlotId,
  81. kStepsSlotId,
  82. kUVsSlotId,
  83. kLodSlotId,
  84. kLodThresholdSlotId,
  85. kTilingSlotId,
  86. kOffsetSlotId,
  87. kPrimitiveSizeSlotId
  88. });
  89. }
  90. string GetFunctionName() => GetVariableNameForNode() + "_$precision";
  91. public override void Setup()
  92. {
  93. base.Setup();
  94. var textureSlot = FindInputSlot<Texture2DInputMaterialSlot>(kHeightmapSlotId);
  95. textureSlot.defaultType = Texture2DShaderProperty.DefaultType.Black;
  96. }
  97. public void GenerateNodeFunction(FunctionRegistry registry, GenerationMode generationMode)
  98. {
  99. // we don't declare this include via the registry include path
  100. // because it uses macro magic, and can be included more than once, generating different functions
  101. string perPixelDisplacementInclude = @"#include ""Packages/com.unity.render-pipelines.core/ShaderLibrary/PerPixelDisplacement.hlsl""";
  102. // Texture sample inputs
  103. var samplerSlot = FindInputSlot<MaterialSlot>(kHeightmapSamplerSlotId);
  104. var edgesSampler = owner.GetEdges(samplerSlot.slotReference);
  105. var heightmap = GetSlotValue(kHeightmapSlotId, generationMode);
  106. // We first generate components that can be used by multiple POM node
  107. registry.ProvideFunction("PerPixelHeightDisplacementParam", s =>
  108. {
  109. s.AppendLine("struct PerPixelHeightDisplacementParam");
  110. using (s.BlockSemicolonScope())
  111. {
  112. s.AppendLine("float2 uv;");
  113. }
  114. s.AppendNewLine();
  115. });
  116. registry.ProvideFunction("GetDisplacementObjectScale_$precision", s =>
  117. {
  118. s.AppendLine($"$precision3 GetDisplacementObjectScale_$precision()");
  119. using (s.BlockScope())
  120. {
  121. s.AppendLines(@"
  122. float3 objectScale = float3(1.0, 1.0, 1.0);
  123. float4x4 worldTransform = GetWorldToObjectMatrix();
  124. objectScale.x = length(float3(worldTransform._m00, worldTransform._m01, worldTransform._m02));
  125. objectScale.z = length(float3(worldTransform._m20, worldTransform._m21, worldTransform._m22));
  126. return objectScale;");
  127. }
  128. });
  129. // Then we add the functions that are specific to this node
  130. registry.ProvideFunction(GetFunctionName(), s =>
  131. {
  132. s.AppendLine("// Required struct and function for the ParallaxOcclusionMapping function:");
  133. s.AppendLine($"$precision ComputePerPixelHeightDisplacement_{GetVariableNameForNode()}($precision2 texOffsetCurrent, $precision lod, PerPixelHeightDisplacementParam param, TEXTURE2D_PARAM(heightTexture, heightSampler))");
  134. using (s.BlockScope())
  135. {
  136. s.AppendLine("return SAMPLE_TEXTURE2D_LOD(heightTexture, heightSampler, param.uv + texOffsetCurrent, lod)[{0}];", (int)channel);
  137. }
  138. // heightmap,
  139. // edgesSampler.Any() ? GetSlotValue(kHeightmapSamplerSlotId, generationMode) : "sampler" + heightmap);
  140. s.AppendLine($"#define ComputePerPixelHeightDisplacement ComputePerPixelHeightDisplacement_{GetVariableNameForNode()}");
  141. s.AppendLine($"#define POM_NAME_ID {GetFunctionName()}");
  142. s.AppendLine($"#define POM_USER_DATA_PARAMETERS , TEXTURE2D_PARAM(heightTexture, samplerState)");
  143. s.AppendLine($"#define POM_USER_DATA_ARGUMENTS , TEXTURE2D_ARGS(heightTexture, samplerState)");
  144. s.AppendLine(perPixelDisplacementInclude);
  145. s.AppendLine($"#undef ComputePerPixelHeightDisplacement");
  146. s.AppendLine($"#undef POM_NAME_ID");
  147. s.AppendLine($"#undef POM_USER_DATA_PARAMETERS");
  148. s.AppendLine($"#undef POM_USER_DATA_ARGUMENTS");
  149. });
  150. }
  151. public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode)
  152. {
  153. string amplitude = GetSlotValue(kAmplitudeSlotId, generationMode);
  154. string steps = GetSlotValue(kStepsSlotId, generationMode);
  155. string uvs = GetSlotValue(kUVsSlotId, generationMode);
  156. string tiling = GetSlotValue(kTilingSlotId, generationMode);
  157. string offset = GetSlotValue(kOffsetSlotId, generationMode);
  158. string primitiveSize = GetSlotValue(kPrimitiveSizeSlotId, generationMode);
  159. string lod = GetSlotValue(kLodSlotId, generationMode);
  160. string lodThreshold = GetSlotValue(kLodThresholdSlotId, generationMode);
  161. string heightmap = GetSlotValue(kHeightmapSlotId, generationMode);
  162. string sampler = GetSlotValue(kHeightmapSamplerSlotId, generationMode);
  163. string tmpPOMParam = GetVariableNameForNode() + "_POM";
  164. string tmpViewDir = GetVariableNameForNode() + "_ViewDir";
  165. string tmpNdotV = GetVariableNameForNode() + "_NdotV";
  166. string tmpMaxHeight = GetVariableNameForNode() + "_MaxHeight";
  167. string tmpViewDirUV = GetVariableNameForNode() + "_ViewDirUV";
  168. string tmpOutHeight = GetVariableNameForNode() + "_OutHeight";
  169. string tmpUVs = GetVariableNameForNode() + "_UVs";
  170. string tmpUVSpaceScale = GetVariableNameForNode() + "_UVSpaceScale";
  171. sb.AppendLines($@"
  172. $precision3 {tmpViewDir} = IN.{CoordinateSpace.Tangent.ToVariableName(InterpolatorType.ViewDirection)} * GetDisplacementObjectScale_$precision().xzy;
  173. $precision {tmpNdotV} = {tmpViewDir}.z;
  174. $precision {tmpMaxHeight} = {amplitude} * 0.01; // cm in the interface so we multiply by 0.01 in the shader to convert in meter
  175. {tmpMaxHeight} *= 2.0 / ( abs({tiling}.x) + abs({tiling}.y) ); // reduce height based on the tiling values
  176. $precision2 {tmpUVSpaceScale} = {tmpMaxHeight} * {tiling} / {primitiveSize};
  177. // Transform the view vector into the UV space.
  178. $precision3 {tmpViewDirUV} = normalize($precision3({tmpViewDir}.xy * {tmpUVSpaceScale}, {tmpViewDir}.z)); // TODO: skip normalize
  179. PerPixelHeightDisplacementParam {tmpPOMParam};
  180. $precision2 {tmpUVs} = {uvs} * {tiling} + {offset};
  181. {tmpPOMParam}.uv = {heightmap}.GetTransformedUV({tmpUVs});");
  182. // to avoid crashes when steps gets too big, and
  183. // to avoid divide by zero, we clamp it to the range [1, 256]
  184. // This should compile out when steps is a static value.
  185. steps = "max(min(" + steps + ", 256), 1)";
  186. sb.AppendLines($@"
  187. $precision {tmpOutHeight};
  188. $precision2 {GetVariableNameForSlot(kParallaxUVsOutputSlotId)} = {heightmap}.GetTransformedUV({tmpUVs}) + ParallaxOcclusionMapping{GetFunctionName()}({lod}, {lodThreshold}, {steps}, {tmpViewDirUV}, {tmpPOMParam}, {tmpOutHeight}, TEXTURE2D_ARGS({heightmap}.tex, {sampler}.samplerstate));
  189. $precision {GetVariableNameForSlot(kPixelDepthOffsetOutputSlotId)} = ({tmpMaxHeight} - {tmpOutHeight} * {tmpMaxHeight}) / max({tmpNdotV}, 0.0001);
  190. ");
  191. }
  192. public NeededCoordinateSpace RequiresViewDirection(ShaderStageCapability stageCapability = ShaderStageCapability.All)
  193. {
  194. return NeededCoordinateSpace.Tangent;
  195. }
  196. public bool RequiresMeshUV(UVChannel channel, ShaderStageCapability stageCapability)
  197. {
  198. using (var tempSlots = PooledList<MaterialSlot>.Get())
  199. {
  200. GetInputSlots(tempSlots);
  201. var result = false;
  202. foreach (var slot in tempSlots)
  203. {
  204. if (slot.RequiresMeshUV(channel))
  205. {
  206. result = true;
  207. break;
  208. }
  209. }
  210. tempSlots.Clear();
  211. return result;
  212. }
  213. }
  214. }
  215. }