1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027 |
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using System.Text;
- using System.Text.RegularExpressions;
- using UnityEngine;
- using UnityEditor.Graphing;
- using UnityEditor.ShaderGraph.Internal;
- namespace UnityEditor.ShaderGraph
- {
- class ShaderGenerator
- {
- private struct ShaderChunk
- {
- public ShaderChunk(int indentLevel, string shaderChunkString)
- {
- m_IndentLevel = indentLevel;
- m_ShaderChunkString = shaderChunkString;
- }
- private readonly int m_IndentLevel;
- private readonly string m_ShaderChunkString;
- public int chunkIndentLevel
- {
- get { return m_IndentLevel; }
- }
- public string chunkString
- {
- get { return m_ShaderChunkString; }
- }
- }
- private readonly List<ShaderChunk> m_ShaderChunks = new List<ShaderChunk>();
- private int m_IndentLevel;
- private string m_Pragma = string.Empty;
- public void AddPragmaChunk(string s)
- {
- m_Pragma += s;
- }
- public string GetPragmaString()
- {
- return m_Pragma;
- }
- public void AddNewLine()
- {
- m_ShaderChunks.Add(new ShaderChunk(m_IndentLevel, ""));
- }
- public void AddShaderChunk(string s, bool unique = false)
- {
- if (string.IsNullOrEmpty(s))
- return;
- if (unique && m_ShaderChunks.Any(x => x.chunkString == s))
- return;
- m_ShaderChunks.Add(new ShaderChunk(m_IndentLevel, s));
- }
- public void AddGenerator(ShaderGenerator generator)
- {
- foreach (ShaderChunk chunk in generator.m_ShaderChunks)
- {
- m_ShaderChunks.Add(new ShaderChunk(m_IndentLevel + chunk.chunkIndentLevel, chunk.chunkString));
- }
- }
- public void Indent()
- {
- m_IndentLevel++;
- }
- public void Deindent()
- {
- m_IndentLevel = Math.Max(0, m_IndentLevel - 1);
- }
- public string GetShaderString(int baseIndentLevel, bool finalNewline = true)
- {
- bool appendedNewline = false;
- var sb = new StringBuilder();
- foreach (var shaderChunk in m_ShaderChunks)
- {
- // TODO: regex split is a slow way to handle this .. should build an iterator instead
- var lines = Regex.Split(shaderChunk.chunkString, Environment.NewLine);
- for (int index = 0; index < lines.Length; index++)
- {
- var line = lines[index];
- for (var i = 0; i < shaderChunk.chunkIndentLevel + baseIndentLevel; i++)
- {
- //sb.Append("\t");
- sb.Append(" "); // unity convention use space instead of tab...
- }
- sb.AppendLine(line);
- appendedNewline = true;
- }
- }
- if (appendedNewline && !finalNewline)
- {
- // remove last newline if we didn't want it
- sb.Length -= Environment.NewLine.Length;
- }
- return sb.ToString();
- }
- public static string GetTemplatePath(string templateName)
- {
- var path = new List<string>
- {
- DefaultShaderIncludes.GetAssetsPackagePath() ?? Path.GetFullPath("Packages/com.unity.shadergraph"),
- "Editor",
- "Templates"
- };
- string result = path[0];
- for (int i = 1; i < path.Count; i++)
- result = Path.Combine(result, path[i]);
- result = Path.Combine(result, templateName);
- if (File.Exists(result))
- return result;
- return string.Empty;
- }
- private const string kErrorString = @"ERROR!";
- public static string AdaptNodeOutput(AbstractMaterialNode node, int outputSlotId, ConcreteSlotValueType convertToType)
- {
- var outputSlot = node.FindOutputSlot<MaterialSlot>(outputSlotId);
- if (outputSlot == null)
- return kErrorString;
- var convertFromType = outputSlot.concreteValueType;
- var rawOutput = node.GetVariableNameForSlot(outputSlotId);
- if (convertFromType == convertToType)
- return rawOutput;
- switch (convertToType)
- {
- case ConcreteSlotValueType.Vector1:
- return string.Format("({0}).x", rawOutput);
- case ConcreteSlotValueType.Vector2:
- switch (convertFromType)
- {
- case ConcreteSlotValueType.Vector1:
- return string.Format("({0}.xx)", rawOutput);
- case ConcreteSlotValueType.Vector3:
- case ConcreteSlotValueType.Vector4:
- return string.Format("({0}.xy)", rawOutput);
- default:
- return kErrorString;
- }
- case ConcreteSlotValueType.Vector3:
- switch (convertFromType)
- {
- case ConcreteSlotValueType.Vector1:
- return string.Format("({0}.xxx)", rawOutput);
- case ConcreteSlotValueType.Vector2:
- return string.Format("($precision3({0}, 0.0))", rawOutput);
- case ConcreteSlotValueType.Vector4:
- return string.Format("({0}.xyz)", rawOutput);
- default:
- return kErrorString;
- }
- case ConcreteSlotValueType.Vector4:
- switch (convertFromType)
- {
- case ConcreteSlotValueType.Vector1:
- return string.Format("({0}.xxxx)", rawOutput);
- case ConcreteSlotValueType.Vector2:
- return string.Format("($precision4({0}, 0.0, 1.0))", rawOutput);
- case ConcreteSlotValueType.Vector3:
- return string.Format("($precision4({0}, 1.0))", rawOutput);
- default:
- return kErrorString;
- }
- case ConcreteSlotValueType.Matrix3:
- return rawOutput;
- case ConcreteSlotValueType.Matrix2:
- return rawOutput;
- default:
- return kErrorString;
- }
- }
- public static string AdaptNodeOutputForPreview(AbstractMaterialNode node, int outputSlotId)
- {
- var rawOutput = node.GetVariableNameForSlot(outputSlotId);
- return AdaptNodeOutputForPreview(node, outputSlotId, rawOutput);
- }
- public static string AdaptNodeOutputForPreview(AbstractMaterialNode node, int slotId, string variableName)
- {
- var slot = node.FindSlot<MaterialSlot>(slotId);
- if (slot == null)
- return kErrorString;
- var convertFromType = slot.concreteValueType;
- // preview is always dimension 4
- switch (convertFromType)
- {
- case ConcreteSlotValueType.Vector1:
- return string.Format("half4({0}, {0}, {0}, 1.0)", variableName);
- case ConcreteSlotValueType.Vector2:
- return string.Format("half4({0}.x, {0}.y, 0.0, 1.0)", variableName);
- case ConcreteSlotValueType.Vector3:
- return string.Format("half4({0}.x, {0}.y, {0}.z, 1.0)", variableName);
- case ConcreteSlotValueType.Vector4:
- return string.Format("half4({0}.x, {0}.y, {0}.z, 1.0)", variableName);
- case ConcreteSlotValueType.Boolean:
- return string.Format("half4({0}, {0}, {0}, 1.0)", variableName);
- default:
- return "half4(0, 0, 0, 0)";
- }
- }
- public int numberOfChunks
- {
- get { return m_ShaderChunks.Count; }
- }
- public enum InputType
- {
- Position,
- Vector,
- Normal
- }
- public struct TransformDesc
- {
- public TransformDesc(string name)
- {
- this.name = name;
- transpose = false;
- }
- public TransformDesc(string name, bool transpose)
- {
- this.name = name;
- this.transpose = transpose;
- }
- public string name;
- public bool transpose;
- }
- static TransformDesc[, ][] m_transforms = null;
- static TransformDesc[] GetTransformPath(CoordinateSpace from, CoordinateSpace to)
- {
- if (m_transforms[(int)from, (int)to] != null)
- {
- return m_transforms[(int)from, (int)to];
- }
- var distance = new int[5];
- var prev = new CoordinateSpace ? [5];
- var queue = new List<CoordinateSpace>();
- foreach (var space in Enum.GetValues(typeof(CoordinateSpace)))
- {
- distance[(int)space] = int.MaxValue;
- prev[(int)space] = null;
- queue.Add((CoordinateSpace)space);
- }
- distance[(int)from] = 0;
- List<CoordinateSpace> path = null;
- while (queue.Count != 0)
- {
- queue.Sort((x, y) => distance[(int)x] - distance[(int)y]);
- var min = queue[0];
- queue.Remove(min);
- if (min == to)
- {
- path = new List<CoordinateSpace>();
- while (prev[(int)min] != null)
- {
- path.Add(min);
- min = prev[(int)min].Value;
- }
- break;
- }
- if (distance[(int)min] == int.MaxValue)
- {
- break;
- }
- foreach (var space in Enum.GetValues(typeof(CoordinateSpace)))
- {
- int index = (int)space;
- if (m_transforms[(int)min, index] != null)
- {
- var alt = distance[(int)min] + m_transforms[(int)min, index].Length;
- if (alt < distance[index])
- {
- distance[index] = alt;
- prev[index] = min;
- }
- }
- }
- }
- path.Reverse();
- var matrixList = new List<TransformDesc>();
- foreach (var node in path)
- {
- matrixList.AddRange(m_transforms[(int)from, (int)node]);
- from = node;
- }
- return matrixList.ToArray();
- }
- static void InitTransforms()
- {
- if (m_transforms == null)
- {
- m_transforms = new TransformDesc[5, 5][];
- m_transforms[(int)CoordinateSpace.Object, (int)CoordinateSpace.Object] = new TransformDesc[] {};
- m_transforms[(int)CoordinateSpace.View, (int)CoordinateSpace.View] = new TransformDesc[] {};
- m_transforms[(int)CoordinateSpace.World, (int)CoordinateSpace.World] = new TransformDesc[] {};
- m_transforms[(int)CoordinateSpace.Tangent, (int)CoordinateSpace.Tangent] = new TransformDesc[] {};
- m_transforms[(int)CoordinateSpace.AbsoluteWorld, (int)CoordinateSpace.AbsoluteWorld] = new TransformDesc[] {};
- m_transforms[(int)CoordinateSpace.Object, (int)CoordinateSpace.World]
- = new TransformDesc[] {new TransformDesc(MatrixNames.Model)};
- m_transforms[(int)CoordinateSpace.View, (int)CoordinateSpace.World]
- = new TransformDesc[] {new TransformDesc(MatrixNames.ViewInverse) };
- m_transforms[(int)CoordinateSpace.World, (int)CoordinateSpace.Object]
- = new TransformDesc[] {new TransformDesc(MatrixNames.ModelInverse)};
- m_transforms[(int)CoordinateSpace.World, (int)CoordinateSpace.View]
- = new TransformDesc[] {new TransformDesc(MatrixNames.View)};
- for (var from = CoordinateSpace.Object; from != CoordinateSpace.Tangent; from++)
- {
- for (var to = CoordinateSpace.Object; to != CoordinateSpace.Tangent; to++)
- {
- if (m_transforms[(int)from, (int)to] == null)
- {
- m_transforms[(int)from, (int)to] = GetTransformPath(from, to);
- }
- }
- }
- }
- for (var k = CoordinateSpace.Object; k != CoordinateSpace.Tangent; k++)
- {
- m_transforms[(int)CoordinateSpace.Tangent, (int)k] = null;
- m_transforms[(int)k, (int)CoordinateSpace.Tangent] = null;
- }
- }
- public static string EmitTransform(TransformDesc[] matrices, TransformDesc[] invMatrices, string variable, bool isAffine, bool noMatrixCast, bool inverseTranspose)
- {
- // Use inverse transpose for situations where
- // scale needs to be considered (normals)
- if (inverseTranspose)
- matrices = invMatrices;
- if (isAffine)
- {
- variable = string.Format("float4({0},1.0)", variable);
- }
- foreach (var m in matrices)
- {
- var matrix = m.name;
- if (!isAffine && !noMatrixCast)
- {
- matrix = "(float3x3)" + matrix;
- }
- // if the matrix is NOT a transpose type
- // invert the order of multiplication
- // it is implicit transpose.
- if (m.transpose)
- inverseTranspose = !inverseTranspose;
- variable = inverseTranspose
- ? string.Format("mul({1},{0})", matrix, variable)
- : string.Format("mul({0},{1})", matrix, variable);
- }
- return variable;
- }
- public static string ConvertBetweenSpace(string variable, CoordinateSpace from, CoordinateSpace to,
- InputType inputType, CoordinateSpace tangentMatrixSpace = CoordinateSpace.Object)
- {
- if (from == to)
- {
- // nothing to do
- return variable;
- }
- // Ensure that the transform graph is initialized
- InitTransforms();
- bool isNormal = false;
- bool affine = (inputType == InputType.Position && to != CoordinateSpace.World);
- bool noMatrixCast = (inputType == InputType.Position && to == CoordinateSpace.World);
- if (inputType == InputType.Normal)
- {
- inputType = InputType.Vector;
- isNormal = true;
- }
- m_transforms[(int)CoordinateSpace.Tangent, (int)tangentMatrixSpace] =
- new[] {new TransformDesc("tangentSpaceTransform")};
- m_transforms[(int)tangentMatrixSpace, (int)CoordinateSpace.Tangent] = new[]
- {new TransformDesc("tangentSpaceTransform", true)};
- if (from == CoordinateSpace.Tangent)
- {
- // if converting from tangent space, reuse the underlying space
- from = tangentMatrixSpace;
- variable = EmitTransform(
- GetTransformPath(CoordinateSpace.Tangent, tangentMatrixSpace),
- GetTransformPath(tangentMatrixSpace, CoordinateSpace.Tangent),
- variable, affine, noMatrixCast, !isNormal);
- if (to == tangentMatrixSpace)
- {
- return variable;
- }
- }
- return EmitTransform(GetTransformPath(from, to), GetTransformPath(to, from), variable, affine, noMatrixCast, isNormal);
- }
- public static void GenerateSpaceTranslationSurfaceInputs(
- NeededCoordinateSpace neededSpaces,
- InterpolatorType interpolatorType,
- ShaderStringBuilder builder,
- string format = "float3 {0};")
- {
- if ((neededSpaces & NeededCoordinateSpace.Object) > 0)
- builder.AppendLine(format, CoordinateSpace.Object.ToVariableName(interpolatorType));
- if ((neededSpaces & NeededCoordinateSpace.World) > 0)
- builder.AppendLine(format, CoordinateSpace.World.ToVariableName(interpolatorType));
- if ((neededSpaces & NeededCoordinateSpace.View) > 0)
- builder.AppendLine(format, CoordinateSpace.View.ToVariableName(interpolatorType));
- if ((neededSpaces & NeededCoordinateSpace.Tangent) > 0)
- builder.AppendLine(format, CoordinateSpace.Tangent.ToVariableName(interpolatorType));
-
- if ((neededSpaces & NeededCoordinateSpace.AbsoluteWorld) > 0)
- builder.AppendLine(format, CoordinateSpace.AbsoluteWorld.ToVariableName(interpolatorType));
- }
- public static void GenerateStandardTransforms(
- int interpolatorStartIndex,
- int maxInterpolators,
- ShaderStringBuilder vertexOutputStruct,
- ShaderStringBuilder vertexShader,
- ShaderStringBuilder vertexShaderDescriptionInputs,
- ShaderStringBuilder vertexShaderOutputs,
- ShaderStringBuilder pixelShader,
- ShaderStringBuilder pixelShaderSurfaceInputs,
- ShaderGraphRequirements pixelRequirements,
- ShaderGraphRequirements surfaceRequirements,
- ShaderGraphRequirements modelRequiements,
- ShaderGraphRequirements vertexRequirements,
- CoordinateSpace preferredCoordinateSpace)
- {
- // ----------------------------------------------------- //
- // SETUP //
- // ----------------------------------------------------- //
- // -------------------------------------
- // Tangent space requires going via World space
- if (preferredCoordinateSpace == CoordinateSpace.Tangent)
- preferredCoordinateSpace = CoordinateSpace.World;
- // -------------------------------------
- // Generate combined graph requirements
- var graphModelRequirements = pixelRequirements.Union(modelRequiements);
- var combinedRequirements = vertexRequirements.Union(graphModelRequirements);
- int interpolatorIndex = interpolatorStartIndex;
- // ----------------------------------------------------- //
- // GENERATE VERTEX > PIXEL PIPELINE //
- // ----------------------------------------------------- //
- // -------------------------------------
- // If any stage requires component write into vertex stage
- // If model or pixel requires component write into interpolators and pixel stage
- // -------------------------------------
- // Position
- if (combinedRequirements.requiresPosition > 0)
- {
- var name = preferredCoordinateSpace.ToVariableName(InterpolatorType.Position);
- var preferredSpacePosition = ConvertBetweenSpace("v.vertex", CoordinateSpace.Object, preferredCoordinateSpace, InputType.Position);
- vertexShader.AppendLine("float3 {0} = {1}.xyz;", name, preferredSpacePosition);
- if (graphModelRequirements.requiresPosition > 0)
- {
- vertexOutputStruct.AppendLine("float3 {0} : TEXCOORD{1};", name, interpolatorIndex);
- vertexShaderOutputs.AppendLine("o.{0} = {0};", name);
- pixelShader.AppendLine("float3 {0} = IN.{0};", name);
- interpolatorIndex++;
- }
- }
- // -------------------------------------
- // Normal
- // Bitangent needs Normal for x product
- if (combinedRequirements.requiresNormal > 0 || combinedRequirements.requiresBitangent > 0)
- {
- var name = preferredCoordinateSpace.ToVariableName(InterpolatorType.Normal);
- vertexShader.AppendLine("float3 {0} = normalize({1});", name, ConvertBetweenSpace("v.normal", CoordinateSpace.Object, preferredCoordinateSpace, InputType.Normal));
- if (graphModelRequirements.requiresNormal > 0 || graphModelRequirements.requiresBitangent > 0)
- {
- vertexOutputStruct.AppendLine("float3 {0} : TEXCOORD{1};", name, interpolatorIndex);
- vertexShaderOutputs.AppendLine("o.{0} = {0};", name);
- pixelShader.AppendLine("float3 {0} = IN.{0};", name);
- interpolatorIndex++;
- }
- }
- // -------------------------------------
- // Tangent
- if (combinedRequirements.requiresTangent > 0 || combinedRequirements.requiresBitangent > 0)
- {
- var name = preferredCoordinateSpace.ToVariableName(InterpolatorType.Tangent);
- vertexShader.AppendLine("float3 {0} = normalize({1});", name, ConvertBetweenSpace("v.tangent.xyz", CoordinateSpace.Object, preferredCoordinateSpace, InputType.Vector));
- if (graphModelRequirements.requiresTangent > 0 || graphModelRequirements.requiresBitangent > 0)
- {
- vertexOutputStruct.AppendLine("float3 {0} : TEXCOORD{1};", name, interpolatorIndex);
- vertexShaderOutputs.AppendLine("o.{0} = {0};", name);
- pixelShader.AppendLine("float3 {0} = IN.{0};", name);
- interpolatorIndex++;
- }
- }
- // -------------------------------------
- // Bitangent
- if (combinedRequirements.requiresBitangent > 0)
- {
- var name = preferredCoordinateSpace.ToVariableName(InterpolatorType.BiTangent);
- vertexShader.AppendLine("float3 {0} = cross({1}, {2}.xyz) * {3};",
- name,
- preferredCoordinateSpace.ToVariableName(InterpolatorType.Normal),
- preferredCoordinateSpace.ToVariableName(InterpolatorType.Tangent),
- "v.tangent.w");
- if (graphModelRequirements.requiresBitangent > 0)
- {
- vertexOutputStruct.AppendLine("float3 {0} : TEXCOORD{1};", name, interpolatorIndex);
- vertexShaderOutputs.AppendLine("o.{0} = {0};", name);
- pixelShader.AppendLine("float3 {0} = IN.{0};", name);
- interpolatorIndex++;
- }
- }
- // -------------------------------------
- // View Direction
- if (combinedRequirements.requiresViewDir > 0)
- {
- var name = preferredCoordinateSpace.ToVariableName(InterpolatorType.ViewDirection);
- const string worldSpaceViewDir = "_WorldSpaceCameraPos.xyz - mul(GetObjectToWorldMatrix(), float4(v.vertex.xyz, 1.0)).xyz";
- var preferredSpaceViewDir = ConvertBetweenSpace(worldSpaceViewDir, CoordinateSpace.World, preferredCoordinateSpace, InputType.Vector);
- vertexShader.AppendLine("float3 {0} = {1};", name, preferredSpaceViewDir);
- if (graphModelRequirements.requiresViewDir > 0)
- {
- vertexOutputStruct.AppendLine("float3 {0} : TEXCOORD{1};", name, interpolatorIndex);
- vertexShaderOutputs.AppendLine("o.{0} = {0};", name);
- pixelShader.AppendLine("float3 {0} = IN.{0};", name);
- interpolatorIndex++;
- }
- }
- // -------------------------------------
- // Tangent space transform matrix
- if (combinedRequirements.NeedsTangentSpace())
- {
- var tangent = preferredCoordinateSpace.ToVariableName(InterpolatorType.Tangent);
- var bitangent = preferredCoordinateSpace.ToVariableName(InterpolatorType.BiTangent);
- var normal = preferredCoordinateSpace.ToVariableName(InterpolatorType.Normal);
- if (vertexRequirements.NeedsTangentSpace())
- vertexShader.AppendLine("float3x3 tangentSpaceTransform = float3x3({0},{1},{2});",
- tangent, bitangent, normal);
- if (graphModelRequirements.NeedsTangentSpace())
- pixelShader.AppendLine("float3x3 tangentSpaceTransform = float3x3({0},{1},{2});",
- tangent, bitangent, normal);
- }
- // -------------------------------------
- // Vertex Color
- if (combinedRequirements.requiresVertexColor)
- {
- var vertexColor = "v.color";
- vertexShader.AppendLine("float4 {0} = {1};", ShaderGeneratorNames.VertexColor, vertexColor);
- if (graphModelRequirements.requiresVertexColor)
- {
- vertexOutputStruct.AppendLine("float4 {0} : COLOR;", ShaderGeneratorNames.VertexColor);
- vertexShaderOutputs.AppendLine("o.{0} = {0};", ShaderGeneratorNames.VertexColor);
- pixelShader.AppendLine("float4 {0} = IN.{0};", ShaderGeneratorNames.VertexColor);
- }
- }
- // -------------------------------------
- // Screen Position
- if (combinedRequirements.requiresScreenPosition)
- {
- var screenPosition = "ComputeScreenPos(mul(GetWorldToHClipMatrix(), mul(GetObjectToWorldMatrix(), v.vertex)), _ProjectionParams.x)";
- vertexShader.AppendLine("float4 {0} = {1};", ShaderGeneratorNames.ScreenPosition, screenPosition);
- if (graphModelRequirements.requiresScreenPosition)
- {
- vertexOutputStruct.AppendLine("float4 {0} : TEXCOORD{1};", ShaderGeneratorNames.ScreenPosition, interpolatorIndex);
- vertexShaderOutputs.AppendLine("o.{0} = {0};", ShaderGeneratorNames.ScreenPosition);
- pixelShader.AppendLine("float4 {0} = IN.{0};", ShaderGeneratorNames.ScreenPosition);
- interpolatorIndex++;
- }
- }
- // -------------------------------------
- // UV
- foreach (var channel in combinedRequirements.requiresMeshUVs.Distinct())
- vertexShader.AppendLine("float4 {0} = v.texcoord{1};", channel.GetUVName(), (int)channel);
- foreach (var channel in graphModelRequirements.requiresMeshUVs.Distinct())
- {
- vertexOutputStruct.AppendLine("half4 {0} : TEXCOORD{1};", channel.GetUVName(), interpolatorIndex == 0 ? "" : interpolatorIndex.ToString());
- vertexShaderOutputs.AppendLine("o.{0} = {0};", channel.GetUVName());
- pixelShader.AppendLine("float4 {0} = IN.{0};", channel.GetUVName());
- interpolatorIndex++;
- }
- // ----------------------------------------------------- //
- // TRANSLATE NEEDED SPACES //
- // ----------------------------------------------------- //
- // -------------------------------------
- // Generate the space translations needed by the vertex description
- GenerateSpaceTranslations(vertexRequirements.requiresNormal, InterpolatorType.Normal, preferredCoordinateSpace,
- InputType.Normal, vertexShader, Dimension.Three);
- GenerateSpaceTranslations(vertexRequirements.requiresTangent, InterpolatorType.Tangent, preferredCoordinateSpace,
- InputType.Vector, vertexShader, Dimension.Three);
- GenerateSpaceTranslations(vertexRequirements.requiresBitangent, InterpolatorType.BiTangent, preferredCoordinateSpace,
- InputType.Vector, vertexShader, Dimension.Three);
- GenerateSpaceTranslations(vertexRequirements.requiresViewDir, InterpolatorType.ViewDirection, preferredCoordinateSpace,
- InputType.Vector, vertexShader, Dimension.Three);
- GenerateSpaceTranslations(vertexRequirements.requiresPosition, InterpolatorType.Position, preferredCoordinateSpace,
- InputType.Position, vertexShader, Dimension.Three);
- // -------------------------------------
- // Generate the space translations needed by the surface description and model
- GenerateSpaceTranslations(graphModelRequirements.requiresNormal, InterpolatorType.Normal, preferredCoordinateSpace,
- InputType.Normal, pixelShader, Dimension.Three);
- GenerateSpaceTranslations(graphModelRequirements.requiresTangent, InterpolatorType.Tangent, preferredCoordinateSpace,
- InputType.Vector, pixelShader, Dimension.Three);
- GenerateSpaceTranslations(graphModelRequirements.requiresBitangent, InterpolatorType.BiTangent, preferredCoordinateSpace,
- InputType.Vector, pixelShader, Dimension.Three);
- GenerateSpaceTranslations(graphModelRequirements.requiresViewDir, InterpolatorType.ViewDirection, preferredCoordinateSpace,
- InputType.Vector, pixelShader, Dimension.Three);
- GenerateSpaceTranslations(graphModelRequirements.requiresPosition, InterpolatorType.Position, preferredCoordinateSpace,
- InputType.Position, pixelShader, Dimension.Three);
- // ----------------------------------------------------- //
- // START SURFACE DESCRIPTION //
- // ----------------------------------------------------- //
- // -------------------------------------
- // Copy the locally defined values into the surface description
- // structure using the requirements for ONLY the shader graph pixel stage
- // additional requirements have come from the lighting model
- // and are not needed in the shader graph
- {
- var replaceString = "surfaceInput.{0} = {0};";
- GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresNormal, InterpolatorType.Normal, pixelShaderSurfaceInputs, replaceString);
- GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresTangent, InterpolatorType.Tangent, pixelShaderSurfaceInputs, replaceString);
- GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresBitangent, InterpolatorType.BiTangent, pixelShaderSurfaceInputs, replaceString);
- GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresViewDir, InterpolatorType.ViewDirection, pixelShaderSurfaceInputs, replaceString);
- GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresPosition, InterpolatorType.Position, pixelShaderSurfaceInputs, replaceString);
- }
- if (pixelRequirements.requiresVertexColor)
- pixelShaderSurfaceInputs.AppendLine("surfaceInput.{0} = {0};", ShaderGeneratorNames.VertexColor);
- if (pixelRequirements.requiresScreenPosition)
- pixelShaderSurfaceInputs.AppendLine("surfaceInput.{0} = {0};", ShaderGeneratorNames.ScreenPosition);
- if (pixelRequirements.requiresFaceSign)
- pixelShaderSurfaceInputs.AppendLine("surfaceInput.{0} = {0};", ShaderGeneratorNames.FaceSign);
- foreach (var channel in pixelRequirements.requiresMeshUVs.Distinct())
- pixelShaderSurfaceInputs.AppendLine("surfaceInput.{0} = {0};", ShaderGeneratorNames.GetUVName(channel));
- if (pixelRequirements.requiresTime)
- {
- pixelShaderSurfaceInputs.AppendLine("surfaceInput.{0} = _TimeParameters.xyz;", ShaderGeneratorNames.TimeParameters);
- }
- // ----------------------------------------------------- //
- // START VERTEX DESCRIPTION //
- // ----------------------------------------------------- //
- // -------------------------------------
- // Copy the locally defined values into the vertex description
- // structure using the requirements for ONLY the shader graph vertex stage
- // additional requirements have come from the lighting model
- // and are not needed in the shader graph
- {
- var replaceString = "vdi.{0} = {0};";
- GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresNormal, InterpolatorType.Normal, vertexShaderDescriptionInputs, replaceString);
- GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresTangent, InterpolatorType.Tangent, vertexShaderDescriptionInputs, replaceString);
- GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresBitangent, InterpolatorType.BiTangent, vertexShaderDescriptionInputs, replaceString);
- GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresViewDir, InterpolatorType.ViewDirection, vertexShaderDescriptionInputs, replaceString);
- GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresPosition, InterpolatorType.Position, vertexShaderDescriptionInputs, replaceString);
- }
- if (vertexRequirements.requiresVertexColor)
- vertexShaderDescriptionInputs.AppendLine("vdi.{0} = {0};", ShaderGeneratorNames.VertexColor);
- if (vertexRequirements.requiresScreenPosition)
- vertexShaderDescriptionInputs.AppendLine("vdi.{0} = {0};", ShaderGeneratorNames.ScreenPosition);
- foreach (var channel in vertexRequirements.requiresMeshUVs.Distinct())
- vertexShaderDescriptionInputs.AppendLine("vdi.{0} = {0};", channel.GetUVName(), (int)channel);
- if (vertexRequirements.requiresTime)
- {
- vertexShaderDescriptionInputs.AppendLine("vdi.{0} = _TimeParameters.xyz;", ShaderGeneratorNames.TimeParameters);
- }
- }
- public enum Dimension
- {
- One,
- Two,
- Three,
- Four
- }
- private static string DimensionToString(Dimension d)
- {
- switch (d)
- {
- case Dimension.One:
- return string.Empty;
- case Dimension.Two:
- return "2";
- case Dimension.Three:
- return "3";
- case Dimension.Four:
- return "4";
- }
- return "error";
- }
- private static string DimensionToSwizzle(Dimension d)
- {
- switch (d)
- {
- case Dimension.One:
- return "x";
- case Dimension.Two:
- return "xy";
- case Dimension.Three:
- return "xyz";
- case Dimension.Four:
- return "xyzw";
- }
- return "error";
- }
- public static void GenerateSpaceTranslations(
- NeededCoordinateSpace neededSpaces,
- InterpolatorType type,
- CoordinateSpace from,
- InputType inputType,
- ShaderStringBuilder pixelShader,
- Dimension dimension)
- {
- if ((neededSpaces & NeededCoordinateSpace.Object) > 0 && from != CoordinateSpace.Object)
- pixelShader.AppendLine("float{0} {1} = {2}.{3};", DimensionToString(dimension),
- CoordinateSpace.Object.ToVariableName(type), ConvertBetweenSpace(from.ToVariableName(type), from, CoordinateSpace.Object, inputType, from),
- DimensionToSwizzle(dimension));
- if ((neededSpaces & NeededCoordinateSpace.World) > 0 && from != CoordinateSpace.World)
- pixelShader.AppendLine("float{0} {1} = {2}.{3};", DimensionToString(dimension),
- CoordinateSpace.World.ToVariableName(type), ConvertBetweenSpace(from.ToVariableName(type), from, CoordinateSpace.World, inputType, from),
- DimensionToSwizzle(dimension));
- if ((neededSpaces & NeededCoordinateSpace.View) > 0 && from != CoordinateSpace.View)
- pixelShader.AppendLine("float{0} {1} = {2}.{3};", DimensionToString(dimension),
- CoordinateSpace.View.ToVariableName(type),
- ConvertBetweenSpace(from.ToVariableName(type), from, CoordinateSpace.View, inputType, from),
- DimensionToSwizzle(dimension));
- if ((neededSpaces & NeededCoordinateSpace.Tangent) > 0 && from != CoordinateSpace.Tangent)
- pixelShader.AppendLine("float{0} {1} = {2}.{3};", DimensionToString(dimension),
- CoordinateSpace.Tangent.ToVariableName(type),
- ConvertBetweenSpace(from.ToVariableName(type), from, CoordinateSpace.Tangent, inputType, from),
- DimensionToSwizzle(dimension));
- if ((neededSpaces & NeededCoordinateSpace.AbsoluteWorld) > 0 && from != CoordinateSpace.AbsoluteWorld)
- pixelShader.AppendLine("float{0} {1} = GetAbsolutePositionWS({2}).{3};", DimensionToString(dimension),
- CoordinateSpace.AbsoluteWorld.ToVariableName(type),
- CoordinateSpace.World.ToVariableName(type),
- DimensionToSwizzle(dimension));
- }
- public static string GetPreviewSubShader(AbstractMaterialNode node, ShaderGraphRequirements shaderGraphRequirements)
- {
- // Should never be called without a node
- Debug.Assert(node != null);
- var vertexOutputStruct = new ShaderStringBuilder(2);
- var vertexShader = new ShaderStringBuilder(2);
- var vertexShaderDescriptionInputs = new ShaderStringBuilder(2);
- var vertexShaderOutputs = new ShaderStringBuilder(1);
- var pixelShader = new ShaderStringBuilder(2);
- var pixelShaderSurfaceInputs = new ShaderStringBuilder(2);
- var pixelShaderSurfaceRemap = new ShaderStringBuilder(2);
- ShaderGenerator.GenerateStandardTransforms(
- 0,
- 16,
- vertexOutputStruct,
- vertexShader,
- vertexShaderDescriptionInputs,
- vertexShaderOutputs,
- pixelShader,
- pixelShaderSurfaceInputs,
- shaderGraphRequirements,
- shaderGraphRequirements,
- ShaderGraphRequirements.none,
- ShaderGraphRequirements.none,
- CoordinateSpace.World);
- vertexShader.AppendLines(vertexShaderDescriptionInputs.ToString());
- vertexShader.AppendLines(vertexShaderOutputs.ToString());
- var outputSlot = node.GetOutputSlots<MaterialSlot>().FirstOrDefault();
- // Sub Graph Output uses first input slot
- if (node is SubGraphOutputNode)
- {
- outputSlot = node.GetInputSlots<MaterialSlot>().FirstOrDefault();
- }
- if (outputSlot != null)
- {
- var result = $"surf.{NodeUtils.GetHLSLSafeName(outputSlot.shaderOutputName)}_{outputSlot.id}";
- pixelShaderSurfaceRemap.AppendLine("return all(isfinite({0})) ? {1} : {2};",
- result, AdaptNodeOutputForPreview(node, outputSlot.id, result), nanOutput);
- }
- else
- {
- // No valid slots to display, so just show black.
- // It's up to each node to error or warn as appropriate.
- pixelShaderSurfaceRemap.AppendLine("return 0;");
- }
- // -------------------------------------
- // Extra pixel shader work
- var faceSign = new ShaderStringBuilder();
- if (shaderGraphRequirements.requiresFaceSign)
- faceSign.AppendLine(", half FaceSign : VFACE");
- var res = subShaderTemplate.Replace("${Interpolators}", vertexOutputStruct.ToString());
- res = res.Replace("${VertexShader}", vertexShader.ToString());
- res = res.Replace("${FaceSign}", faceSign.ToString());
- res = res.Replace("${LocalPixelShader}", pixelShader.ToString());
- res = res.Replace("${SurfaceInputs}", pixelShaderSurfaceInputs.ToString());
- res = res.Replace("${SurfaceOutputRemap}", pixelShaderSurfaceRemap.ToString());
- return res;
- }
- public static SurfaceMaterialTags BuildMaterialTags(SurfaceType surfaceType)
- {
- SurfaceMaterialTags materialTags = new SurfaceMaterialTags();
- if (surfaceType == SurfaceType.Opaque)
- {
- materialTags.renderQueue = SurfaceMaterialTags.RenderQueue.Geometry;
- materialTags.renderType = SurfaceMaterialTags.RenderType.Opaque;
- }
- else
- {
- materialTags.renderQueue = SurfaceMaterialTags.RenderQueue.Transparent;
- materialTags.renderType = SurfaceMaterialTags.RenderType.Transparent;
- }
- return materialTags;
- }
- public static SurfaceMaterialOptions GetMaterialOptions(SurfaceType surfaceType, AlphaMode alphaMode, bool twoSided, bool offscreenTransparent = false)
- {
- var materialOptions = new SurfaceMaterialOptions();
- switch (surfaceType)
- {
- case SurfaceType.Opaque:
- materialOptions.srcBlend = SurfaceMaterialOptions.BlendMode.One;
- materialOptions.dstBlend = SurfaceMaterialOptions.BlendMode.Zero;
- materialOptions.cullMode = twoSided ? SurfaceMaterialOptions.CullMode.Off : SurfaceMaterialOptions.CullMode.Back;
- materialOptions.zTest = SurfaceMaterialOptions.ZTest.LEqual;
- materialOptions.zWrite = SurfaceMaterialOptions.ZWrite.On;
- break;
- case SurfaceType.Transparent:
- switch (alphaMode)
- {
- case AlphaMode.Alpha:
- materialOptions.srcBlend = SurfaceMaterialOptions.BlendMode.SrcAlpha;
- materialOptions.dstBlend = SurfaceMaterialOptions.BlendMode.OneMinusSrcAlpha;
- if(offscreenTransparent)
- {
- materialOptions.alphaSrcBlend = SurfaceMaterialOptions.BlendMode.Zero;
- }
- else
- {
- materialOptions.alphaSrcBlend = SurfaceMaterialOptions.BlendMode.One;
- }
- materialOptions.alphaDstBlend = SurfaceMaterialOptions.BlendMode.OneMinusSrcAlpha;
- materialOptions.cullMode = twoSided ? SurfaceMaterialOptions.CullMode.Off : SurfaceMaterialOptions.CullMode.Back;
- materialOptions.zTest = SurfaceMaterialOptions.ZTest.LEqual;
- materialOptions.zWrite = SurfaceMaterialOptions.ZWrite.Off;
- break;
- case AlphaMode.Premultiply:
- materialOptions.srcBlend = SurfaceMaterialOptions.BlendMode.One;
- materialOptions.dstBlend = SurfaceMaterialOptions.BlendMode.OneMinusSrcAlpha;
- if (offscreenTransparent)
- {
- materialOptions.alphaSrcBlend = SurfaceMaterialOptions.BlendMode.Zero;
- }
- else
- {
- materialOptions.alphaSrcBlend = SurfaceMaterialOptions.BlendMode.One;
- }
- materialOptions.alphaDstBlend = SurfaceMaterialOptions.BlendMode.OneMinusSrcAlpha;
- materialOptions.cullMode = twoSided ? SurfaceMaterialOptions.CullMode.Off : SurfaceMaterialOptions.CullMode.Back;
- materialOptions.zTest = SurfaceMaterialOptions.ZTest.LEqual;
- materialOptions.zWrite = SurfaceMaterialOptions.ZWrite.Off;
- break;
- case AlphaMode.Additive:
- materialOptions.srcBlend = SurfaceMaterialOptions.BlendMode.One;
- materialOptions.dstBlend = SurfaceMaterialOptions.BlendMode.One;
- if (offscreenTransparent)
- {
- materialOptions.alphaSrcBlend = SurfaceMaterialOptions.BlendMode.Zero;
- }
- else
- {
- materialOptions.alphaSrcBlend = SurfaceMaterialOptions.BlendMode.One;
- }
- materialOptions.alphaDstBlend = SurfaceMaterialOptions.BlendMode.One;
- materialOptions.cullMode = twoSided ? SurfaceMaterialOptions.CullMode.Off : SurfaceMaterialOptions.CullMode.Back;
- materialOptions.zTest = SurfaceMaterialOptions.ZTest.LEqual;
- materialOptions.zWrite = SurfaceMaterialOptions.ZWrite.Off;
- break;
- case AlphaMode.Multiply:
- materialOptions.srcBlend = SurfaceMaterialOptions.BlendMode.DstColor;
- materialOptions.dstBlend = SurfaceMaterialOptions.BlendMode.Zero;
- materialOptions.cullMode = twoSided ? SurfaceMaterialOptions.CullMode.Off : SurfaceMaterialOptions.CullMode.Back;
- materialOptions.zTest = SurfaceMaterialOptions.ZTest.LEqual;
- materialOptions.zWrite = SurfaceMaterialOptions.ZWrite.Off;
- break;
- }
- break;
- }
- return materialOptions;
- }
- const string nanOutput = "float4(1.0f, 0.0f, 1.0f, 1.0f)";
- const string subShaderTemplate = @"
- SubShader
- {
- Tags { ""RenderType""=""Opaque"" }
- LOD 100
- Pass
- {
- HLSLPROGRAM
- #pragma vertex vert
- #pragma fragment frag
- struct GraphVertexOutput
- {
- float4 position : POSITION;
- ${Interpolators}
- };
- GraphVertexOutput vert (GraphVertexInput v)
- {
- v = PopulateVertexData(v);
- GraphVertexOutput o;
- float3 positionWS = TransformObjectToWorld(v.vertex);
- o.position = TransformWorldToHClip(positionWS);
- ${VertexShader}
- return o;
- }
- float4 frag (GraphVertexOutput IN ${FaceSign}) : SV_Target
- {
- ${LocalPixelShader}
- SurfaceDescriptionInputs surfaceInput = (SurfaceDescriptionInputs)0;
- ${SurfaceInputs}
- SurfaceDescription surf = PopulateSurfaceData(surfaceInput);
- ${SurfaceOutputRemap}
- }
- ENDHLSL
- }
- }";
- }
- }
|