You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

400 lines
25 KiB

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using UnityEditor.ShaderGraph;
using UnityEditor.ShaderGraph.Internal;
using UnityEngine;
namespace UnityEditor.VFX
{
static class VFXOldShaderGraphHelpers
{
public class PassInfo
{
public int[] vertexPorts;
public int[] pixelPorts;
}
public class RPInfo
{
public Dictionary<string, PassInfo> passInfos;
HashSet<int> m_AllPorts;
public IEnumerable<int> allPorts
{
get
{
if (m_AllPorts == null)
{
m_AllPorts = new HashSet<int>();
foreach (var pass in passInfos.Values)
{
foreach (var port in pass.vertexPorts)
m_AllPorts.Add(port);
foreach (var port in pass.pixelPorts)
m_AllPorts.Add(port);
}
}
return m_AllPorts;
}
}
}
public static readonly RPInfo hdrpInfo = new RPInfo
{
passInfos = new Dictionary<string, PassInfo>()
{
{ "Forward", new PassInfo() { vertexPorts = new int[] {}, pixelPorts = new int[] { ShaderGraphVfxAsset.ColorSlotId, ShaderGraphVfxAsset.EmissiveSlotId, ShaderGraphVfxAsset.AlphaSlotId, ShaderGraphVfxAsset.AlphaThresholdSlotId } } },
{ "DepthOnly", new PassInfo() { vertexPorts = new int[] {}, pixelPorts = new int[] { ShaderGraphVfxAsset.AlphaSlotId, ShaderGraphVfxAsset.AlphaThresholdSlotId } } },
{ "DepthNormals", new PassInfo() { vertexPorts = new int[] {}, pixelPorts = new int[] { ShaderGraphVfxAsset.AlphaSlotId, ShaderGraphVfxAsset.AlphaThresholdSlotId, ShaderGraphVfxAsset.NormalSlotId } } }
}
};
public static readonly RPInfo hdrpLitInfo = new RPInfo
{
passInfos = new Dictionary<string, PassInfo>()
{
{ "GBuffer", new PassInfo() { vertexPorts = new int[] {}, pixelPorts = new int[] { ShaderGraphVfxAsset.BaseColorSlotId, ShaderGraphVfxAsset.AlphaSlotId, ShaderGraphVfxAsset.MetallicSlotId, ShaderGraphVfxAsset.SmoothnessSlotId, ShaderGraphVfxAsset.EmissiveSlotId, ShaderGraphVfxAsset.NormalSlotId, ShaderGraphVfxAsset.AlphaThresholdSlotId } } },
{ "Forward", new PassInfo() { vertexPorts = new int[] {}, pixelPorts = new int[] { ShaderGraphVfxAsset.BaseColorSlotId, ShaderGraphVfxAsset.AlphaSlotId, ShaderGraphVfxAsset.MetallicSlotId, ShaderGraphVfxAsset.SmoothnessSlotId, ShaderGraphVfxAsset.EmissiveSlotId, ShaderGraphVfxAsset.NormalSlotId, ShaderGraphVfxAsset.AlphaThresholdSlotId } } },
{ "DepthOnly", new PassInfo() { vertexPorts = new int[] {}, pixelPorts = new int[] { ShaderGraphVfxAsset.AlphaSlotId, ShaderGraphVfxAsset.AlphaThresholdSlotId } } }
}
};
public static readonly RPInfo urpLitInfo = new RPInfo
{
passInfos = new Dictionary<string, PassInfo>()
{
{ "GBuffer", new PassInfo() { vertexPorts = new int[] {}, pixelPorts = new int[] { ShaderGraphVfxAsset.BaseColorSlotId, ShaderGraphVfxAsset.AlphaSlotId, ShaderGraphVfxAsset.MetallicSlotId, ShaderGraphVfxAsset.SmoothnessSlotId, ShaderGraphVfxAsset.EmissiveSlotId, ShaderGraphVfxAsset.NormalSlotId, ShaderGraphVfxAsset.AlphaThresholdSlotId } } },
{ "Forward", new PassInfo() { vertexPorts = new int[] {}, pixelPorts = new int[] { ShaderGraphVfxAsset.BaseColorSlotId, ShaderGraphVfxAsset.AlphaSlotId, ShaderGraphVfxAsset.MetallicSlotId, ShaderGraphVfxAsset.SmoothnessSlotId, ShaderGraphVfxAsset.EmissiveSlotId, ShaderGraphVfxAsset.NormalSlotId, ShaderGraphVfxAsset.AlphaThresholdSlotId } } },
{ "DepthOnly", new PassInfo() { vertexPorts = new int[] {}, pixelPorts = new int[] { ShaderGraphVfxAsset.AlphaSlotId, ShaderGraphVfxAsset.AlphaThresholdSlotId } } },
{ "DepthNormals", new PassInfo() { vertexPorts = new int[] {}, pixelPorts = new int[] { ShaderGraphVfxAsset.AlphaSlotId, ShaderGraphVfxAsset.AlphaThresholdSlotId, ShaderGraphVfxAsset.NormalSlotId } } }
}
};
private static bool NeedsPositionWorldInterpolator(GraphCode graphCode)
{
return graphCode.requirements.requiresPosition != NeededCoordinateSpace.None
|| graphCode.requirements.requiresViewDir != NeededCoordinateSpace.None
|| graphCode.requirements.requiresScreenPosition;
}
public static Dictionary<string, GraphCode> BuildGraphCode(ShaderGraphVfxAsset shaderGraph, RPInfo info, bool isLitShader)
{
if (!isLitShader && shaderGraph.lit)
{
Debug.LogError("You must use an unlit vfx master node with an unlit output");
return null;
}
if (isLitShader && !shaderGraph.lit)
{
Debug.LogError("You must use a lit vfx master node with a lit output");
return null;
}
var graphCodes = new Dictionary<string, GraphCode>();
var outputMetadata = new List<OutputMetadata>();
foreach (var passInfo in info.passInfos)
{
outputMetadata.Clear();
foreach (var pixelPort in passInfo.Value.pixelPorts)
{
var output = shaderGraph.GetOutput(pixelPort);
if (!string.IsNullOrEmpty(output.referenceName))
outputMetadata.Add(output);
}
var code = shaderGraph.GetCode(outputMetadata.ToArray());
graphCodes.Add(passInfo.Key, code);
}
return graphCodes;
}
public static IEnumerable<string> GetAdditionalDefinesGetAdditionalReplacement(ShaderGraphVfxAsset shaderGraph, RPInfo info, Dictionary<string, GraphCode> graphCodes)
{
yield return "VFX_SHADERGRAPH";
foreach (var port in info.allPorts)
{
var portInfo = shaderGraph.GetOutput(port);
if (!string.IsNullOrEmpty(portInfo.referenceName))
yield return $"HAS_SHADERGRAPH_PARAM_{portInfo.referenceName.ToUpper(CultureInfo.InvariantCulture)}";
}
bool needsPosWS = false;
// Per pass define
foreach (var kvPass in graphCodes)
{
GraphCode graphCode = kvPass.Value;
var pixelPorts = info.passInfos[kvPass.Key].pixelPorts;
bool readsNormal = (graphCode.requirements.requiresNormal & ~NeededCoordinateSpace.Tangent) != 0;
bool readsTangent = (graphCode.requirements.requiresTangent & ~NeededCoordinateSpace.Tangent) != 0 ||
(graphCode.requirements.requiresBitangent & ~NeededCoordinateSpace.Tangent) != 0 ||
(graphCode.requirements.requiresViewDir & NeededCoordinateSpace.Tangent) != 0;
bool hasNormalPort = Array.IndexOf(pixelPorts, ShaderGraphVfxAsset.NormalSlotId) != -1 && shaderGraph.HasOutput(ShaderGraphVfxAsset.NormalSlotId);
if (readsNormal || readsTangent || hasNormalPort) // needs normal
yield return $"SHADERGRAPH_NEEDS_NORMAL_{kvPass.Key.ToUpper(CultureInfo.InvariantCulture)}";
if (readsTangent || hasNormalPort) // needs tangent
yield return $"SHADERGRAPH_NEEDS_TANGENT_{kvPass.Key.ToUpper(CultureInfo.InvariantCulture)}";
needsPosWS |= NeedsPositionWorldInterpolator(graphCode);
}
// TODO Put that per pass ?
if (needsPosWS)
yield return "VFX_NEEDS_POSWS_INTERPOLATOR";
}
public static IEnumerable<KeyValuePair<string, VFXShaderWriter>> GetAdditionalReplacement(ShaderGraphVfxAsset shaderGraph, RPInfo info, Dictionary<string, GraphCode> graphCodes, bool isMesh)
{
foreach (var port in info.allPorts)
{
var portInfo = shaderGraph.GetOutput(port);
if (!string.IsNullOrEmpty(portInfo.referenceName))
yield return new KeyValuePair<string, VFXShaderWriter>($"${{SHADERGRAPH_PARAM_{portInfo.referenceName.ToUpper(CultureInfo.InvariantCulture)}}}", new VFXShaderWriter($"{portInfo.referenceName}_{portInfo.id}"));
}
foreach (var kvPass in graphCodes)
{
GraphCode graphCode = kvPass.Value;
var preProcess = new VFXShaderWriter();
if (graphCode.requirements.requiresCameraOpaqueTexture)
preProcess.WriteLine("#define REQUIRE_OPAQUE_TEXTURE");
if (graphCode.requirements.requiresDepthTexture)
preProcess.WriteLine("#define REQUIRE_DEPTH_TEXTURE");
preProcess.WriteLine("${VFXShaderGraphFunctionsInclude}\n");
yield return new KeyValuePair<string, VFXShaderWriter>("${SHADERGRAPH_PIXEL_CODE_" + kvPass.Key.ToUpper(CultureInfo.InvariantCulture) + "}", new VFXShaderWriter(preProcess.ToString() + graphCode.code));
var callSG = new VFXShaderWriter("//Call Shader Graph\n");
callSG.builder.AppendLine($"{shaderGraph.inputStructName} INSG = ({shaderGraph.inputStructName})0;");
if (graphCode.requirements.requiresNormal != NeededCoordinateSpace.None)
{
callSG.builder.AppendLine("float3 WorldSpaceNormal = normalize(normalWS.xyz);");
if ((graphCode.requirements.requiresNormal & NeededCoordinateSpace.World) != 0)
callSG.builder.AppendLine("INSG.WorldSpaceNormal = WorldSpaceNormal;");
if ((graphCode.requirements.requiresNormal & NeededCoordinateSpace.Object) != 0)
callSG.builder.AppendLine("INSG.ObjectSpaceNormal = mul(WorldSpaceNormal, (float3x3)UNITY_MATRIX_M);");
if ((graphCode.requirements.requiresNormal & NeededCoordinateSpace.View) != 0)
callSG.builder.AppendLine("INSG.ViewSpaceNormal = mul(WorldSpaceNormal, (float3x3)UNITY_MATRIX_I_V);");
if ((graphCode.requirements.requiresNormal & NeededCoordinateSpace.Tangent) != 0)
callSG.builder.AppendLine("INSG.TangentSpaceNormal = float3(0.0f, 0.0f, 1.0f);");
}
if (graphCode.requirements.requiresTangent != NeededCoordinateSpace.None)
{
callSG.builder.AppendLine("float3 WorldSpaceTangent = normalize(tangentWS.xyz);");
if ((graphCode.requirements.requiresTangent & NeededCoordinateSpace.World) != 0)
callSG.builder.AppendLine("INSG.WorldSpaceTangent = WorldSpaceTangent;");
if ((graphCode.requirements.requiresTangent & NeededCoordinateSpace.Object) != 0)
callSG.builder.AppendLine("INSG.ObjectSpaceTangent = TransformWorldToObjectDir(WorldSpaceTangent);");
if ((graphCode.requirements.requiresTangent & NeededCoordinateSpace.View) != 0)
callSG.builder.AppendLine("INSG.ViewSpaceTangent = TransformWorldToViewDir(WorldSpaceTangent);");
if ((graphCode.requirements.requiresTangent & NeededCoordinateSpace.Tangent) != 0)
callSG.builder.AppendLine("INSG.TangentSpaceTangent = float3(1.0f, 0.0f, 0.0f);");
}
if (graphCode.requirements.requiresBitangent != NeededCoordinateSpace.None)
{
callSG.builder.AppendLine("float3 WorldSpaceBiTangent = normalize(bitangentWS.xyz);");
if ((graphCode.requirements.requiresBitangent & NeededCoordinateSpace.World) != 0)
callSG.builder.AppendLine("INSG.WorldSpaceBiTangent = WorldSpaceBiTangent;");
if ((graphCode.requirements.requiresBitangent & NeededCoordinateSpace.Object) != 0)
callSG.builder.AppendLine("INSG.ObjectSpaceBiTangent = TransformWorldToObjectDir(WorldSpaceBiTangent);");
if ((graphCode.requirements.requiresBitangent & NeededCoordinateSpace.View) != 0)
callSG.builder.AppendLine("INSG.ViewSpaceBiTangent = TransformWorldToViewDir(WorldSpaceBiTangent);");
if ((graphCode.requirements.requiresBitangent & NeededCoordinateSpace.Tangent) != 0)
callSG.builder.AppendLine("INSG.TangentSpaceBiTangent = float3(0.0f, 1.0f, 0.0f);");
}
if (NeedsPositionWorldInterpolator(graphCode))
{
callSG.builder.AppendLine("float3 posRelativeWS = VFXGetPositionRWS(i.VFX_VARYING_POSWS);");
callSG.builder.AppendLine("float3 posAbsoluteWS = VFXGetPositionAWS(i.VFX_VARYING_POSWS);");
if ((graphCode.requirements.requiresPosition & NeededCoordinateSpace.World) != 0)
callSG.builder.AppendLine("INSG.WorldSpacePosition = posRelativeWS;");
if ((graphCode.requirements.requiresPosition & NeededCoordinateSpace.Object) != 0)
callSG.builder.AppendLine("INSG.ObjectSpacePosition = TransformWorldToObject(posRelativeWS);");
if ((graphCode.requirements.requiresPosition & NeededCoordinateSpace.View) != 0)
callSG.builder.AppendLine("INSG.ViewSpacePosition = VFXTransformPositionWorldToView(posRelativeWS);");
if ((graphCode.requirements.requiresPosition & NeededCoordinateSpace.Tangent) != 0)
callSG.builder.AppendLine("INSG.TangentSpacePosition = float3(0.0f, 0.0f, 0.0f);");
if ((graphCode.requirements.requiresPosition & NeededCoordinateSpace.AbsoluteWorld) != 0)
callSG.builder.AppendLine("INSG.AbsoluteWorldSpacePosition = posAbsoluteWS;");
if (graphCode.requirements.requiresPositionPredisplacement != NeededCoordinateSpace.None)
{
if ((graphCode.requirements.requiresPositionPredisplacement & NeededCoordinateSpace.World) != 0)
callSG.builder.AppendLine("INSG.WorldSpacePositionPredisplacement = posRelativeWS;");
if ((graphCode.requirements.requiresPositionPredisplacement & NeededCoordinateSpace.Object) != 0)
callSG.builder.AppendLine("INSG.ObjectSpacePositionPredisplacement = TransformWorldToObject(posRelativeWS);");
if ((graphCode.requirements.requiresPositionPredisplacement & NeededCoordinateSpace.View) != 0)
callSG.builder.AppendLine("INSG.ViewSpacePositionPredisplacement = VFXTransformPositionWorldToView(posRelativeWS);");
if ((graphCode.requirements.requiresPositionPredisplacement & NeededCoordinateSpace.Tangent) != 0)
callSG.builder.AppendLine("INSG.TangentSpacePositionPredisplacement = float3(0.0f, 0.0f, 0.0f);");
if ((graphCode.requirements.requiresPositionPredisplacement & NeededCoordinateSpace.AbsoluteWorld) != 0)
callSG.builder.AppendLine("INSG.AbsoluteWorldSpacePositionPredisplacement = posAbsoluteWS;");
}
if (graphCode.requirements.requiresViewDir != NeededCoordinateSpace.None)
{
callSG.builder.AppendLine("float3 V = GetWorldSpaceNormalizeViewDir(VFXGetPositionRWS(i.VFX_VARYING_POSWS));");
if ((graphCode.requirements.requiresViewDir & NeededCoordinateSpace.World) != 0)
callSG.builder.AppendLine("INSG.WorldSpaceViewDirection = V;");
if ((graphCode.requirements.requiresViewDir & NeededCoordinateSpace.Object) != 0)
callSG.builder.AppendLine("INSG.ObjectSpaceViewDirection = TransformWorldToObjectDir(V);");
if ((graphCode.requirements.requiresViewDir & NeededCoordinateSpace.View) != 0)
callSG.builder.AppendLine("INSG.ViewSpaceViewDirection = TransformWorldToViewDir(V);");
if ((graphCode.requirements.requiresViewDir & NeededCoordinateSpace.Tangent) != 0)
callSG.builder.AppendLine("INSG.TangentSpaceViewDirection = mul(tbn, V);");
}
if (graphCode.requirements.requiresScreenPosition)
{
//ScreenPosition is expected to be the raw screen pos (float4) before the w division in pixel (SharedCode.template.hlsl)
callSG.builder.AppendLine("INSG.ScreenPosition = ComputeScreenPos(VFXTransformPositionWorldToClip(i.VFX_VARYING_POSWS), _ProjectionParams.x);");
}
}
if (graphCode.requirements.requiresNDCPosition || graphCode.requirements.requiresPixelPosition)
{
callSG.builder.AppendLine("{");
if (graphCode.requirements.requiresPixelPosition || graphCode.requirements.requiresNDCPosition)
{
callSG.builder.AppendLine("#if UNITY_UV_STARTS_AT_TOP");
callSG.builder.AppendLine(" float2 PixelPosition = float2(i.VFX_VARYING_POSCS.x, (_ProjectionParams.x < 0) ? (_ScreenParams.y - i.VFX_VARYING_POSCS.y) : i.VFX_VARYING_POSCS.y);");
callSG.builder.AppendLine("#else");
callSG.builder.AppendLine(" float2 PixelPosition = float2(i.VFX_VARYING_POSCS.x, (_ProjectionParams.x > 0) ? (_ScreenParams.y - i.VFX_VARYING_POSCS.y) : i.VFX_VARYING_POSCS.y);");
callSG.builder.AppendLine("#endif");
}
if (graphCode.requirements.requiresPixelPosition)
{
callSG.builder.AppendLine("INSG.PixelPosition = PixelPosition;");
}
if (graphCode.requirements.requiresNDCPosition)
{
callSG.builder.AppendLine("INSG.NDCPosition = PixelPosition.xy / _ScreenParams.xy;");
callSG.builder.AppendLine("INSG.NDCPosition.y = 1.0f - INSG.NDCPosition.y;");
}
callSG.builder.AppendLine("}");
}
if (graphCode.requirements.requiresMeshUVs.Contains(UVChannel.UV0))
{
callSG.builder.AppendLine("INSG.uv0.xy = i.uv;");
}
if (graphCode.requirements.requiresTime)
{
callSG.builder.AppendLine("INSG.TimeParameters = _TimeParameters.xyz;");
}
if (graphCode.requirements.requiresFaceSign)
{
callSG.builder.AppendLine("INSG.FaceSign = frontFace ? 1.0f : -1.0f;");
}
if (isMesh)
{
for (UVChannel uv = UVChannel.UV1; uv <= UVChannel.UV3; ++uv)
{
if (graphCode.requirements.requiresMeshUVs.Contains(uv))
{
int uvi = (int)uv;
yield return new KeyValuePair<string, VFXShaderWriter>($"VFX_SHADERGRAPH_HAS_UV{uvi}", new VFXShaderWriter("1")); // TODO put that in additionalDefines
callSG.builder.AppendLine($"INSG.uv{uvi} = i.uv{uvi};");
}
}
if (graphCode.requirements.requiresVertexColor)
{
yield return new KeyValuePair<string, VFXShaderWriter>($"VFX_SHADERGRAPH_HAS_COLOR", new VFXShaderWriter("1")); // TODO put that in additionalDefines
callSG.builder.AppendLine($"INSG.VertexColor = i.vertexColor;");
}
}
callSG.builder.Append($"\n{shaderGraph.outputStructName} OUTSG = {shaderGraph.evaluationFunctionName}(INSG");
foreach (var property in graphCode.properties)
{
var variableName = property.GetHLSLVariableName(true, GenerationMode.ForReals);
callSG.builder.Append(", ");
callSG.builder.Append(variableName);
}
callSG.builder.AppendLine(");");
var pixelPorts = info.passInfos[kvPass.Key].pixelPorts;
if (Array.IndexOf(pixelPorts, ShaderGraphVfxAsset.AlphaThresholdSlotId) != -1 && shaderGraph.alphaClipping)
{
callSG.builder.AppendLine(
@"#if (USE_ALPHA_TEST || VFX_FEATURE_MOTION_VECTORS_FORWARD) && defined(VFX_VARYING_ALPHATHRESHOLD)
i.VFX_VARYING_ALPHATHRESHOLD = OUTSG.AlphaClipThreshold_7;
#endif");
}
yield return new KeyValuePair<string, VFXShaderWriter>("${SHADERGRAPH_PIXEL_CALL_" + kvPass.Key.ToUpper(CultureInfo.InvariantCulture) + "}", callSG);
}
}
public static void ReplaceShaderGraphTag(StringBuilder stringBuilder, VFXContext context, VFXNamedExpression[] namedExpressions, Dictionary<VFXExpression, string> expressionToName)
{
var shaderGraph = VFXShaderGraphHelpers.GetShaderGraph(context);
if (shaderGraph == null || shaderGraph.generatesWithShaderGraph)
return;
int normSemantic = 0;
var additionalInterpolantsGeneration = new VFXShaderWriter();
var additionalInterpolantsDeclaration = new VFXShaderWriter();
var additionalInterpolantsPreparation = new VFXShaderWriter();
foreach (var fragmentProperty in shaderGraph.fragmentProperties)
{
if (VFXShaderGraphHelpers.IsTexture(fragmentProperty.propertyType))
continue;
var fragmentParameter = fragmentProperty.referenceName;
var filteredNamedExpressionIndex = Array.FindIndex(namedExpressions, o => fragmentParameter == o.name &&
!(expressionToName.ContainsKey(o.exp) && expressionToName[o.exp] == o.name)); // if parameter already in the global scope, there's nothing to do
if (filteredNamedExpressionIndex != -1)
{
var filteredNamedExpression = namedExpressions[filteredNamedExpressionIndex];
if (!filteredNamedExpression.exp.Is(VFXExpression.Flags.Constant))
{
additionalInterpolantsDeclaration.WriteDeclaration(filteredNamedExpression.exp.valueType, filteredNamedExpression.name, $"NORMAL{normSemantic++}");
additionalInterpolantsGeneration.WriteVariable(filteredNamedExpression.exp.valueType, filteredNamedExpression.name + "__", "0");
var expressionToNameLocal = new Dictionary<VFXExpression, string>(expressionToName);
additionalInterpolantsGeneration.EnterScope();
{
if (!expressionToNameLocal.ContainsKey(filteredNamedExpression.exp))
{
additionalInterpolantsGeneration.WriteVariable(filteredNamedExpression.exp, expressionToNameLocal);
additionalInterpolantsGeneration.WriteLine();
}
additionalInterpolantsGeneration.WriteAssignement(filteredNamedExpression.exp.valueType, filteredNamedExpression.name + "__", expressionToNameLocal[filteredNamedExpression.exp]);
additionalInterpolantsGeneration.WriteLine();
}
additionalInterpolantsGeneration.ExitScope();
additionalInterpolantsGeneration.WriteAssignement(filteredNamedExpression.exp.valueType, "o." + filteredNamedExpression.name, filteredNamedExpression.name + "__");
additionalInterpolantsPreparation.WriteVariable(filteredNamedExpression.exp.valueType, filteredNamedExpression.name, "i." + filteredNamedExpression.name);
}
else
additionalInterpolantsPreparation.WriteVariable(filteredNamedExpression.exp.valueType, filteredNamedExpression.name, filteredNamedExpression.exp.GetCodeString(null));
}
}
VFXCodeGenerator.ReplaceMultiline(stringBuilder, "${VFXAdditionalInterpolantsGeneration}", additionalInterpolantsGeneration.builder);
VFXCodeGenerator.ReplaceMultiline(stringBuilder, "${VFXAdditionalInterpolantsDeclaration}", additionalInterpolantsDeclaration.builder);
VFXCodeGenerator.ReplaceMultiline(stringBuilder, "${VFXAdditionalInterpolantsPreparation}", additionalInterpolantsPreparation.builder);
}
}
}