123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493 |
- // using System;
- using System.Collections.Generic;
- using UnityEditor.ShaderGraph.Internal;
-
- namespace UnityEditor.ShaderGraph
- {
- enum ConversionType
- {
- Position,
- Direction,
- Normal
- }
-
- internal struct SpaceTransform
- {
- public CoordinateSpace from;
- public CoordinateSpace to;
- public ConversionType type;
- public bool normalize;
- public int version;
-
- public const int kLatestVersion = 2;
-
- public SpaceTransform(CoordinateSpace from, CoordinateSpace to, ConversionType type, bool normalize = false, int version = kLatestVersion)
- {
- this.from = from;
- this.to = to;
- this.type = type;
- this.normalize = normalize;
- this.version = version;
- }
-
- internal string NormalizeString()
- {
- return normalize ? "true" : "false";
- }
-
- // non-identity transforms involving tangent space require the full tangent frame
- public NeededCoordinateSpace RequiresNormal =>
- (((from == CoordinateSpace.Tangent) || (to == CoordinateSpace.Tangent)) && (from != to)) ?
- NeededCoordinateSpace.World : NeededCoordinateSpace.None;
- public NeededCoordinateSpace RequiresTangent =>
- (((from == CoordinateSpace.Tangent) || (to == CoordinateSpace.Tangent)) && (from != to)) ?
- NeededCoordinateSpace.World : NeededCoordinateSpace.None;
- public NeededCoordinateSpace RequiresBitangent =>
- (((from == CoordinateSpace.Tangent) || (to == CoordinateSpace.Tangent)) && (from != to)) ?
- NeededCoordinateSpace.World : NeededCoordinateSpace.None;
-
- // non-identity position transforms involving tangent space require the world position
- public NeededCoordinateSpace RequiresPosition =>
- ((type == ConversionType.Position) && ((from == CoordinateSpace.Tangent) || (to == CoordinateSpace.Tangent)) && (from != to)) ?
- NeededCoordinateSpace.World : NeededCoordinateSpace.None;
-
- public IEnumerable<NeededTransform> RequiresTransform =>
- SpaceTransformUtil.ComputeTransformRequirement(this);
- };
-
- static class SpaceTransformUtil
- {
- delegate void TransformFunction(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb);
-
- public static string GenerateTangentTransform(ShaderStringBuilder sb, CoordinateSpace tangentTransformSpace)
- {
- sb.AddLine("$precision3x3 tangentTransform = $precision3x3(IN.",
- tangentTransformSpace.ToString(), "SpaceTangent, IN.",
- tangentTransformSpace.ToString(), "SpaceBiTangent, IN.",
- tangentTransformSpace.ToString(), "SpaceNormal);");
- return "tangentTransform";
- }
-
- public static void Identity(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb)
- {
- // identity didn't normalize before version 2
- if ((xform.version > 1) && xform.normalize && (xform.type != ConversionType.Position))
- sb.AddLine(outputVariable, " = SafeNormalize(", inputValue, ");");
- else
- sb.AddLine(outputVariable, " = ", inputValue, ";");
- }
-
- private static void ViaWorld(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb)
- {
- // should never be calling this if one of the spaces is already world space (silly, and could lead to infinite recursions)
- if ((xform.from == CoordinateSpace.World) || (xform.to == CoordinateSpace.World))
- return;
-
- // this breaks the transform into two parts: (from->world) and (world->to)
- var toWorld = new SpaceTransform()
- {
- from = xform.from,
- to = CoordinateSpace.World,
- type = xform.type,
- normalize = false,
- version = xform.version
- };
-
- var fromWorld = new SpaceTransform()
- {
- from = CoordinateSpace.World,
- to = xform.to,
- type = xform.type,
- normalize = xform.normalize,
- version = xform.version
- };
-
- // Apply Versioning Hacks to match old (incorrect) versions
- if (xform.version <= 1)
- {
- if (xform.type == ConversionType.Direction)
- {
- switch (xform.from)
- {
- case CoordinateSpace.AbsoluteWorld:
- if ((xform.to == CoordinateSpace.Object) || (xform.to == CoordinateSpace.View))
- {
- // these transforms were wrong in v0, but correct in v1, so here we
- // pretend it is a later version to disable the v1 versioning in the AbsWorldToWorld transform
- if (xform.version == 1)
- toWorld.version = 2;
- }
- break;
- case CoordinateSpace.View:
- if ((xform.to == CoordinateSpace.Tangent) || (xform.to == CoordinateSpace.AbsoluteWorld))
- {
- // these transforms erroneously used the position view-to-world transform
- toWorld.type = ConversionType.Position;
- }
- break;
- case CoordinateSpace.Tangent:
- if ((xform.to == CoordinateSpace.Object) || (xform.to == CoordinateSpace.View) || (xform.to == CoordinateSpace.AbsoluteWorld))
- {
- // manually version to 2, to remove normalization (while keeping Normal type)
- toWorld.type = ConversionType.Normal;
- toWorld.version = 2;
- }
- break;
- }
- }
- }
-
- using (sb.BlockScope())
- {
- sb.AddLine("// Converting ", xform.type.ToString(), " from ", xform.from.ToString(), " to ", xform.to.ToString(), " via world space");
- sb.AddLine("float3 world;");
- GenerateTransformCodeStatement(toWorld, inputValue, "world", sb);
- GenerateTransformCodeStatement(fromWorld, "world", outputVariable, sb);
- }
- }
-
- public static void WorldToObject(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb)
- {
- switch (xform.type)
- {
- case ConversionType.Position:
- sb.AddLine(outputVariable, " = TransformWorldToObject(", inputValue, ");");
- break;
- case ConversionType.Direction:
- if (xform.version <= 1)
- xform.normalize = true;
- sb.AddLine(outputVariable, " = TransformWorldToObjectDir(", inputValue, ", ", xform.NormalizeString(), ");");
- break;
- case ConversionType.Normal:
- sb.AddLine(outputVariable, " = TransformWorldToObjectNormal(", inputValue, ", ", xform.NormalizeString(), ");");
- break;
- }
- }
-
- public static void WorldToTangent(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb)
- {
- if (xform.version <= 1)
- {
- // prior to version 2, all transform were normalized, and all transforms were Normal transforms
- xform.normalize = true;
- xform.type = ConversionType.Normal;
- }
-
- using (sb.BlockScope())
- {
- string tangentTransform = GenerateTangentTransform(sb, xform.from);
-
- switch (xform.type)
- {
- case ConversionType.Position:
- sb.AddLine(outputVariable, " = TransformWorldToTangentDir(", inputValue, " - IN.WorldSpacePosition, ", tangentTransform, ", false);");
- break;
- case ConversionType.Direction:
- sb.AddLine(outputVariable, " = TransformWorldToTangentDir(", inputValue, ", ", tangentTransform, ", ", xform.NormalizeString(), ");");
- break;
- case ConversionType.Normal:
- sb.AddLine(outputVariable, " = TransformWorldToTangent(", inputValue, ", ", tangentTransform, ", ", xform.NormalizeString(), ");");
- break;
- }
- }
- }
-
- public static void WorldToView(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb)
- {
- switch (xform.type)
- {
- case ConversionType.Position:
- sb.AddLine(outputVariable, " = TransformWorldToView(", inputValue, ");");
- break;
- case ConversionType.Direction:
- if (xform.version <= 1)
- xform.normalize = false;
- sb.AddLine(outputVariable, " = TransformWorldToViewDir(", inputValue, ", ", xform.NormalizeString(), ");");
- break;
- case ConversionType.Normal:
- sb.AddLine(outputVariable, " = TransformWorldToViewNormal(", inputValue, ", ", xform.NormalizeString(), ");");
- break;
- }
- }
-
- public static void WorldToAbsoluteWorld(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb)
- {
- // prior to version 2 always used Position transform
- if (xform.version <= 1)
- xform.type = ConversionType.Position;
-
- switch (xform.type)
- {
- case ConversionType.Position:
- sb.AddLine(outputVariable, " = GetAbsolutePositionWS(", inputValue, ");");
- break;
- case ConversionType.Direction:
- case ConversionType.Normal:
- // both normal and direction are unchanged
- if (xform.normalize)
- sb.AddLine(outputVariable, " = SafeNormalize(", inputValue, ");");
- else
- sb.AddLine(outputVariable, " = ", inputValue, ";");
- break;
- }
- }
-
- public static void ObjectToWorld(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb)
- {
- switch (xform.type)
- {
- case ConversionType.Position:
- sb.AddLine(outputVariable, " = TransformObjectToWorld(", inputValue, ");");
- break;
- case ConversionType.Direction:
- if (xform.version <= 1)
- xform.normalize = true;
- sb.AddLine(outputVariable, " = TransformObjectToWorldDir(", inputValue, ", ", xform.NormalizeString(), ");");
- break;
- case ConversionType.Normal:
- sb.AddLine(outputVariable, " = TransformObjectToWorldNormal(", inputValue, ", ", xform.NormalizeString(), ");");
- break;
- }
- }
-
- public static void ObjectToAbsoluteWorld(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb)
- {
- switch (xform.type)
- {
- case ConversionType.Position:
- ViaWorld(xform, inputValue, outputVariable, sb);
- break;
- case ConversionType.Direction:
- if (xform.version <= 1)
- xform.normalize = true;
- sb.AddLine(outputVariable, " = TransformObjectToWorldDir(", inputValue, ", ", xform.NormalizeString(), ");");
- break;
- case ConversionType.Normal:
- sb.AddLine(outputVariable, " = TransformObjectToWorldNormal(", inputValue, ", ", xform.NormalizeString(), ");");
- break;
- }
- }
-
- public static void TangentToWorld(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb)
- {
- // prior to version 2 all transforms were Normal, and directional transforms were normalized
- if (xform.version <= 1)
- {
- if (xform.type != ConversionType.Position)
- xform.normalize = true;
- xform.type = ConversionType.Normal;
- }
-
- using (sb.BlockScope())
- {
- string tangentTransform = GenerateTangentTransform(sb, CoordinateSpace.World);
- switch (xform.type)
- {
- case ConversionType.Position:
- sb.AddLine(outputVariable, " = TransformTangentToWorldDir(", inputValue, ", ", tangentTransform, ", false).xyz + IN.WorldSpacePosition;");
- break;
- case ConversionType.Direction:
- sb.AddLine(outputVariable, " = TransformTangentToWorldDir(", inputValue, ", ", tangentTransform, ", ", xform.NormalizeString(), ").xyz;");
- break;
- case ConversionType.Normal:
- sb.AddLine(outputVariable, " = TransformTangentToWorld(", inputValue, ", ", tangentTransform, ", ", xform.NormalizeString(), ");");
- break;
- }
- }
- }
-
- public static void ViewToWorld(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb)
- {
- switch (xform.type)
- {
- case ConversionType.Position:
- sb.AddLine(outputVariable, " = TransformViewToWorld(", inputValue, ");");
- break;
- case ConversionType.Direction:
- if (xform.version <= 1)
- xform.normalize = false;
- sb.AddLine(outputVariable, " = TransformViewToWorldDir(", inputValue, ", ", xform.NormalizeString(), ");");
- break;
- case ConversionType.Normal:
- sb.AddLine(outputVariable, " = TransformViewToWorldNormal(", inputValue, ", ", xform.NormalizeString(), ");");
- break;
- }
- }
-
- public static void AbsoluteWorldToWorld(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb)
- {
- // prior to version 2, always used position transform
- if (xform.version <= 1)
- xform.type = ConversionType.Position;
-
- switch (xform.type)
- {
- case ConversionType.Position:
- sb.AddLine(outputVariable, " = GetCameraRelativePositionWS(", inputValue, ");");
- break;
- case ConversionType.Direction:
- case ConversionType.Normal:
- // both normal and direction are unchanged
- if (xform.normalize)
- sb.AddLine(outputVariable, " = SafeNormalize(", inputValue, ");");
- else
- sb.AddLine(outputVariable, " = ", inputValue, ";");
- break;
- }
- }
-
- public static void ObjectToHScreen(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb)
- {
- switch (xform.type)
- {
- case ConversionType.Position:
- using (sb.BlockScope())
- {
- sb.AddLine("$precision4 ", outputVariable, "_value = TransformObjectToHClip(", inputValue, ");");
- sb.AddLine("$precision3 ", outputVariable, "_uv = ", outputVariable, "_value.xyz / ", outputVariable, "_value.w;");
- sb.AddLine("#if UNITY_UV_STARTS_AT_TOP");
- sb.AddLine(outputVariable, "_uv.y = -", outputVariable, "_uv.y;");
- sb.AddLine("#endif");
- sb.AddLine(outputVariable, "_uv.xy = ", outputVariable, "_uv.xy * 0.5 + 0.5;");
- sb.AddLine(outputVariable, " = ", outputVariable, "_uv;");
- }
- break;
- case ConversionType.Direction:
- case ConversionType.Normal:
- ViaWorld(xform, inputValue, outputVariable, sb);
- break;
- }
- }
-
- public static void ViewToHScreen(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb)
- {
- switch (xform.type)
- {
- case ConversionType.Position:
- sb.AddLine("$precision4 ", outputVariable, "_value = TransformWViewToHClip(", inputValue, ");");
- sb.AddLine("$precision3 ", outputVariable, "_uv = ", outputVariable, "_value.xyz / ", outputVariable, "_value.w;");
- sb.AddLine("#if UNITY_UV_STARTS_AT_TOP");
- sb.AddLine(outputVariable, "_uv.y = -", outputVariable, "_uv.y;");
- sb.AddLine("#endif");
- sb.AddLine(outputVariable, "_uv.xy = ", outputVariable, "_uv.xy * 0.5 + 0.5;");
- sb.AddLine(outputVariable, " = ", outputVariable, "_uv;");
- break;
- case ConversionType.Direction:
- case ConversionType.Normal:
- ViaWorld(xform, inputValue, outputVariable, sb);
- break;
- }
- }
-
- public static void WorldToHScreen(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb)
- {
- switch (xform.type)
- {
- case ConversionType.Position:
- sb.AddLine("$precision4 ", outputVariable, "_value = TransformWorldToHClip(", inputValue, ");");
- break;
- case ConversionType.Direction:
- if (xform.version <= 1)
- xform.normalize = true;
- sb.AddLine("$precision4 ", outputVariable, "_value = $precision4(TransformWorldToHClipDir(", inputValue, ", ", xform.NormalizeString(), "), 1.0f);");
- break;
- case ConversionType.Normal:
- sb.AddLine("$precision4 ", outputVariable, "_value = $precision4(TransformWorldToHClipDir(", inputValue, ", ", xform.NormalizeString(), "), 1.0f);");
- break;
- }
- sb.AddLine("$precision3 ", outputVariable, "_uv = ", outputVariable, "_value.xyz / ", outputVariable, "_value.w;");
- sb.AddLine("#if UNITY_UV_STARTS_AT_TOP");
- sb.AddLine(outputVariable, "_uv.y = -", outputVariable, "_uv.y;");
- sb.AddLine("#endif");
- sb.AddLine(outputVariable, "_uv.xy = ", outputVariable, "_uv.xy * 0.5 + 0.5;");
- sb.AddLine(outputVariable, " = ", outputVariable, "_uv;");
- }
-
- public static void HScreenToWorld(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb)
- {
- switch (xform.type)
- {
- case ConversionType.Position:
- sb.AddLine(outputVariable, " = ComputeWorldSpacePosition(", inputValue, ".xy, ", inputValue, ".z, UNITY_MATRIX_I_VP);");
- break;
- case ConversionType.Direction:
- case ConversionType.Normal:
- sb.AddLine("$precision4 ", outputVariable, "_CS = ComputeClipSpacePosition(", inputValue, ".xy, ", inputValue, ".z);");
- sb.AddLine(outputVariable, " = mul(UNITY_MATRIX_I_VP, $precision4(", outputVariable, "_CS.xyz, 0.0f)).xyz;");
- break;
- }
- }
-
- static readonly TransformFunction[,] k_TransformFunctions = new TransformFunction[6, 6] // [from, to]
- {
- { // from CoordinateSpace.Object
- Identity, // to CoordinateSpace.Object
- ViaWorld, // to CoordinateSpace.View
- ObjectToWorld, // to CoordinateSpace.World
- ViaWorld, // to CoordinateSpace.Tangent
- ObjectToAbsoluteWorld, // to CoordinateSpace.AbsoluteWorld
- ObjectToHScreen // to CoordinateSpace.Screen
- },
- { // from CoordinateSpace.View
- ViaWorld, // to CoordinateSpace.Object
- Identity, // to CoordinateSpace.View
- ViewToWorld, // to CoordinateSpace.World
- ViaWorld, // to CoordinateSpace.Tangent
- ViaWorld, // to CoordinateSpace.AbsoluteWorld
- ViewToHScreen // to CoordinateSpace.Screen
- },
- { // from CoordinateSpace.World
- WorldToObject, // to CoordinateSpace.Object
- WorldToView, // to CoordinateSpace.View
- Identity, // to CoordinateSpace.World
- WorldToTangent, // to CoordinateSpace.Tangent
- WorldToAbsoluteWorld, // to CoordinateSpace.AbsoluteWorld
- WorldToHScreen // to CoordinateSpace.Screen
- },
- { // from CoordinateSpace.Tangent
- ViaWorld, // to CoordinateSpace.Object
- ViaWorld, // to CoordinateSpace.View
- TangentToWorld, // to CoordinateSpace.World
- Identity, // to CoordinateSpace.Tangent
- ViaWorld, // to CoordinateSpace.AbsoluteWorld
- ViaWorld // to CoordinateSpace.Screen
- },
- { // from CoordinateSpace.AbsoluteWorld
- ViaWorld, // to CoordinateSpace.Object
- ViaWorld, // to CoordinateSpace.View
- AbsoluteWorldToWorld, // to CoordinateSpace.World
- ViaWorld, // to CoordinateSpace.Tangent
- Identity, // to CoordinateSpace.AbsoluteWorld
- ViaWorld // to CoordinateSpace.Screen
- },
- { // from CoordinateSpace.Screen
- ViaWorld, // to CoordinateSpace.Object
- ViaWorld, // to CoordinateSpace.View
- HScreenToWorld, // to CoordinateSpace.World
- ViaWorld, // to CoordinateSpace.Tangent
- ViaWorld, // to CoordinateSpace.AbsoluteWorld
- Identity, // to CoordinateSpace.Screen
- }
- };
-
- internal static IEnumerable<NeededTransform> ComputeTransformRequirement(SpaceTransform xform)
- {
- var func = k_TransformFunctions[(int)xform.from, (int)xform.to];
- if (func == ViaWorld || func == ObjectToAbsoluteWorld)
- {
- yield return new NeededTransform(xform.from.ToNeededCoordinateSpace(), NeededCoordinateSpace.World);
- yield return new NeededTransform(NeededCoordinateSpace.World, xform.to.ToNeededCoordinateSpace());
- }
- else
- {
- yield return new NeededTransform(xform.from.ToNeededCoordinateSpace(), xform.to.ToNeededCoordinateSpace());
- }
- }
-
- public static void GenerateTransformCodeStatement(SpaceTransform xform, string inputValue, string outputVariable, ShaderStringBuilder sb)
- {
- var func = k_TransformFunctions[(int)xform.from, (int)xform.to];
- func(xform, inputValue, outputVariable, sb);
- }
- }
- }
|