您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

533 行
23 KiB

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using UnityEngine.Graphing;
namespace UnityEngine.MaterialGraph
{
public static class ShaderGeneratorNames
{
private static string[] UV = {"uv0", "uv1", "uv2", "uv3"};
public static int UVCount = 4;
public const string ObjectSpaceNormal = "objectSpaceNormal";
public const string ViewSpaceNormal = "viewSpaceNormal";
public const string WorldSpaceNormal = "worldSpaceNormal";
public const string TangentSpaceNormal = "tangentSpaceNormal";
public const string ObjectSpaceBiTangent = "objectSpaceBiTangent";
public const string ViewSpaceBiTangent = "viewSpaceBiTangent";
public const string WorldSpaceBiTangent = "worldSpaceBiTangent";
public const string TangentSpaceBiTangent = "TangentSpaceBitangent";
public const string ObjectSpaceTangent = "objectSpaceTangent";
public const string ViewSpaceTangent = "viewSpaceTangent";
public const string WorldSpaceTangent = "worldSpaceTangent";
public const string TangentSpaceTangent = "tangentSpaceTangent";
public const string ObjectSpaceViewDirection = "objectSpaceViewDirection";
public const string ViewSpaceViewDirection = "viewSpaceViewDirection";
public const string WorldSpaceViewDirection = "worldSpaceViewDirection";
public const string TangentSpaceViewDirection = "tangentSpaceViewDirection";
public const string ObjectSpacePosition = "objectSpacePosition";
public const string ViewSpacePosition = "viewSpaceVPosition";
public const string WorldSpacePosition = "worldSpacePosition";
public const string TangentSpacePosition = "tangentSpacePosition";
public const string ScreenPosition = "screenPosition";
public const string VertexColor = "vertexColor";
public static string GetUVName(this UVChannel channel)
{
return UV[(int) channel];
}
}
public enum UVChannel
{
uv0 = 0,
uv1 = 1,
uv2 = 2,
uv3 = 3,
}
public 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 AddShaderChunk(string s, bool unique)
{
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 Indent()
{
m_IndentLevel++;
}
public void Deindent()
{
m_IndentLevel = Math.Max(0, m_IndentLevel - 1);
}
public string GetShaderString(int baseIndentLevel)
{
var sb = new StringBuilder();
foreach (var shaderChunk in m_ShaderChunks)
{
var lines = shaderChunk.chunkString.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
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.AppendLine(line);
}
}
return sb.ToString();
}
internal static string GetTemplatePath(string templateName)
{
var path = new List<string>
{
Application.dataPath,
"UnityShaderEditor",
"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);
return result;
}
private const string kErrorString = @"ERROR!";
public static string AdaptNodeOutput(AbstractMaterialNode node, int outputSlotId, ConcreteSlotValueType convertToType, bool textureSampleUVHack = false)
{
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}{1})", rawOutput, ".xx");
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}{1})", rawOutput, ".xxx");
case ConcreteSlotValueType.Vector4:
return string.Format("({0}.xyz)", rawOutput);
default:
return kErrorString;
}
case ConcreteSlotValueType.Vector4:
switch (convertFromType)
{
case ConcreteSlotValueType.Vector1:
return string.Format("({0}{1})", rawOutput, ".xxxx");
default:
return kErrorString;
}
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, and we always ignore alpha
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);
default:
return kErrorString;
}
}
public int numberOfChunks
{
get { return m_ShaderChunks.Count; }
}
public static void GenerateStandardTransforms(
int interpolatorStartIndex,
ShaderGenerator interpolators,
ShaderGenerator vertexShader,
ShaderGenerator pixelShader,
ShaderGenerator surfaceInputs,
ShaderGraphRequirements externalGraphRequiements,
ShaderGraphRequirements modelRequiements)
{
// step 1:
// *generate needed interpolators
// *generate output from the vertex shader that writes into these interpolators
// *generate the pixel shader code that declares needed variables in the local scope
var combinedRequierments = externalGraphRequiements.Union(modelRequiements);
// bitangent needs normal for x product
if (combinedRequierments.requiresNormal > 0 || combinedRequierments.requiresBitangent > 0)
{
interpolators.AddShaderChunk(string.Format("float3 {0} : NORMAL;", ShaderGeneratorNames.ObjectSpaceNormal), false);
vertexShader.AddShaderChunk(string.Format("o.{0} = v.normal;", ShaderGeneratorNames.ObjectSpaceNormal), false);
pixelShader.AddShaderChunk(string.Format("float3 {0} = normalize(IN.{0});", ShaderGeneratorNames.ObjectSpaceNormal), false);
}
if (combinedRequierments.requiresTangent > 0 || combinedRequierments.requiresBitangent > 0)
{
interpolators.AddShaderChunk(string.Format("float4 {0} : TANGENT;", ShaderGeneratorNames.ObjectSpaceTangent), false);
vertexShader.AddShaderChunk(string.Format("o.{0} = v.tangent;", ShaderGeneratorNames.ObjectSpaceTangent), false);
pixelShader.AddShaderChunk(string.Format("float4 {0} = IN.{0};", ShaderGeneratorNames.ObjectSpaceTangent), false);
pixelShader.AddShaderChunk(string.Format("float3 {0} = normalize(cross(normalize(IN.{1}), normalize(IN.{2}.xyz)) * IN.{2}.w);",
ShaderGeneratorNames.ObjectSpaceBiTangent,
ShaderGeneratorNames.ObjectSpaceNormal,
ShaderGeneratorNames.ObjectSpaceTangent), false);
}
int interpolatorIndex = interpolatorStartIndex;
if (combinedRequierments.requiresViewDir > 0)
{
interpolators.AddShaderChunk(string.Format("float3 {0} : TEXCOORD{1};", ShaderGeneratorNames.ObjectSpaceViewDirection, interpolatorIndex), false);
vertexShader.AddShaderChunk(string.Format("o.{0} = ObjSpaceViewDir(v.vertex);", ShaderGeneratorNames.ObjectSpaceViewDirection), false);
pixelShader.AddShaderChunk(string.Format("float3 {0} = normalize(IN.{0});", ShaderGeneratorNames.ObjectSpaceViewDirection), false);
interpolatorIndex++;
}
if (combinedRequierments.requiresPosition > 0)
{
interpolators.AddShaderChunk(string.Format("float4 {0} : TEXCOORD{1};", ShaderGeneratorNames.ObjectSpacePosition, interpolatorIndex), false);
vertexShader.AddShaderChunk(string.Format("o.{0} = v.vertex;", ShaderGeneratorNames.ObjectSpacePosition), false);
pixelShader.AddShaderChunk(string.Format("float4 {0} = IN.{0};", ShaderGeneratorNames.ObjectSpacePosition), false);
interpolatorIndex++;
}
if (combinedRequierments.NeedsTangentSpace())
{
pixelShader.AddShaderChunk(string.Format("float3x3 tangentSpaceTransform = float3x3({0},{1},{2});",
ShaderGeneratorNames.ObjectSpaceTangent, ShaderGeneratorNames.ObjectSpaceBiTangent, ShaderGeneratorNames.ObjectSpaceNormal), false);
}
ShaderGenerator.GenerateSpaceTranslationPixelShader(combinedRequierments.requiresNormal, pixelShader,
ShaderGeneratorNames.ObjectSpaceNormal, ShaderGeneratorNames.ViewSpaceNormal,
ShaderGeneratorNames.WorldSpaceNormal, ShaderGeneratorNames.TangentSpaceNormal, Dimension.Three, true);
ShaderGenerator.GenerateSpaceTranslationPixelShader(combinedRequierments.requiresTangent, pixelShader,
ShaderGeneratorNames.ObjectSpaceTangent, ShaderGeneratorNames.ViewSpaceTangent,
ShaderGeneratorNames.WorldSpaceTangent, ShaderGeneratorNames.TangentSpaceTangent, Dimension.Three);
ShaderGenerator.GenerateSpaceTranslationPixelShader(combinedRequierments.requiresBitangent, pixelShader,
ShaderGeneratorNames.ObjectSpaceBiTangent, ShaderGeneratorNames.ViewSpaceBiTangent,
ShaderGeneratorNames.WorldSpaceBiTangent, ShaderGeneratorNames.TangentSpaceBiTangent, Dimension.Three);
ShaderGenerator.GenerateSpaceTranslationPixelShader(combinedRequierments.requiresViewDir, pixelShader,
ShaderGeneratorNames.ObjectSpaceViewDirection, ShaderGeneratorNames.ViewSpaceViewDirection,
ShaderGeneratorNames.WorldSpaceViewDirection, ShaderGeneratorNames.TangentSpaceViewDirection, Dimension.Three);
ShaderGenerator.GenerateSpaceTranslationPixelShader(combinedRequierments.requiresPosition, pixelShader,
ShaderGeneratorNames.ObjectSpacePosition, ShaderGeneratorNames.ViewSpacePosition,
ShaderGeneratorNames.WorldSpacePosition, ShaderGeneratorNames.TangentSpacePosition, Dimension.Three);
if (combinedRequierments.requiresVertexColor)
{
interpolators.AddShaderChunk(string.Format("float4 {0} : COLOR;", ShaderGeneratorNames.VertexColor), false);
vertexShader.AddShaderChunk(string.Format("o.{0} = color", ShaderGeneratorNames.VertexColor), false);
pixelShader.AddShaderChunk(string.Format("float4 {0} = IN.{0};", ShaderGeneratorNames.VertexColor), false);
}
if (combinedRequierments.requiresScreenPosition)
{
interpolators.AddShaderChunk(string.Format("float4 {0} : TEXCOORD{1};", ShaderGeneratorNames.ScreenPosition, interpolatorIndex), false);
vertexShader.AddShaderChunk(string.Format("o.{0} = ComputeScreenPos(UnityObjectToClipPos(v.vertex));", ShaderGeneratorNames.ScreenPosition), false);
pixelShader.AddShaderChunk(string.Format("float4 {0} = IN.{0};", ShaderGeneratorNames.ScreenPosition), false);
interpolatorIndex++;
}
foreach (var channel in combinedRequierments.requiresMeshUVs.Distinct())
{
interpolators.AddShaderChunk(string.Format("half4 {0} : TEXCOORD{1};", channel.GetUVName(), interpolatorIndex == 0 ? "" : interpolatorIndex.ToString()), false);
vertexShader.AddShaderChunk(string.Format("o.{0} = v.texcoord{1};", channel.GetUVName(), (int)channel), false);
pixelShader.AddShaderChunk(string.Format("float4 {0} = IN.{0};", channel.GetUVName()), false);
interpolatorIndex++;
}
// step 2
// copy the locally defined values into the surface description
// structure using the requirements for ONLY the shader graph
// additional requirements have come from the lighting model
// and are not needed in the shader graph
ShaderGenerator.GenerateCopyToSurfaceInputs(externalGraphRequiements.requiresNormal, surfaceInputs,
ShaderGeneratorNames.ObjectSpaceNormal, ShaderGeneratorNames.ViewSpaceNormal,
ShaderGeneratorNames.WorldSpaceNormal, ShaderGeneratorNames.TangentSpaceNormal);
ShaderGenerator.GenerateCopyToSurfaceInputs(externalGraphRequiements.requiresTangent, surfaceInputs,
ShaderGeneratorNames.ObjectSpaceTangent, ShaderGeneratorNames.ViewSpaceTangent,
ShaderGeneratorNames.WorldSpaceTangent, ShaderGeneratorNames.TangentSpaceTangent);
ShaderGenerator.GenerateCopyToSurfaceInputs(externalGraphRequiements.requiresBitangent, surfaceInputs,
ShaderGeneratorNames.ObjectSpaceBiTangent, ShaderGeneratorNames.ViewSpaceBiTangent,
ShaderGeneratorNames.WorldSpaceBiTangent, ShaderGeneratorNames.TangentSpaceBiTangent);
ShaderGenerator.GenerateCopyToSurfaceInputs(externalGraphRequiements.requiresViewDir, surfaceInputs,
ShaderGeneratorNames.ObjectSpaceViewDirection, ShaderGeneratorNames.ViewSpaceViewDirection,
ShaderGeneratorNames.WorldSpaceViewDirection, ShaderGeneratorNames.TangentSpaceViewDirection);
ShaderGenerator.GenerateCopyToSurfaceInputs(externalGraphRequiements.requiresPosition, surfaceInputs,
ShaderGeneratorNames.ObjectSpacePosition, ShaderGeneratorNames.ViewSpacePosition,
ShaderGeneratorNames.WorldSpacePosition, ShaderGeneratorNames.TangentSpacePosition);
if (externalGraphRequiements.requiresVertexColor)
surfaceInputs.AddShaderChunk(string.Format("surfaceInput.{0} = {0};", ShaderGeneratorNames.VertexColor), false);
if (externalGraphRequiements.requiresScreenPosition)
surfaceInputs.AddShaderChunk(string.Format("surfaceInput.{0} = {0};", ShaderGeneratorNames.ScreenPosition), false);
foreach (var channel in combinedRequierments.requiresMeshUVs.Distinct())
surfaceInputs.AddShaderChunk(string.Format("surfaceInput.{0} ={0};", channel.GetUVName()), false);
}
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";
}
public static void GenerateSpaceTranslationPixelShader(
NeededCoordinateSpace neededSpaces,
ShaderGenerator pixelShader,
string objectSpaceName,
string viewSpaceName,
string worldSpaceName,
string tangentSpaceName,
Dimension dimension,
bool isNormal = false)
{
if ((neededSpaces & NeededCoordinateSpace.World) > 0)
{
if (isNormal)
pixelShader.AddShaderChunk(string.Format("float{0} {1} = UnityObjectToWorldNormal({2});", DimensionToString(dimension), worldSpaceName, objectSpaceName), false);
else
pixelShader.AddShaderChunk(string.Format("float{0} {1} = UnityObjectToWorldDir({2});", DimensionToString(dimension), worldSpaceName, objectSpaceName), false);
}
if ((neededSpaces & NeededCoordinateSpace.View) > 0)
{
pixelShader.AddShaderChunk(string.Format("float{0} {1} = UnityObjectToViewPos({2});", DimensionToString(dimension), viewSpaceName, objectSpaceName), false);
}
if ((neededSpaces & NeededCoordinateSpace.Tangent) > 0)
{
pixelShader.AddShaderChunk(string.Format("float{0} {1} = mul(tangentSpaceTransform, {2})", DimensionToString(dimension), tangentSpaceName, objectSpaceName), false);
}
}
public static void GenerateCopyToSurfaceInputs(
NeededCoordinateSpace neededSpaces,
ShaderGenerator pixelShader,
string objectSpaceName,
string viewSpaceName,
string worldSpaceName,
string tangentSpaceName)
{
if ((neededSpaces & NeededCoordinateSpace.Object) > 0)
pixelShader.AddShaderChunk(string.Format("surfaceInput.{0} = {0};", objectSpaceName), false);
if ((neededSpaces & NeededCoordinateSpace.World) > 0)
pixelShader.AddShaderChunk(string.Format("surfaceInput.{0} = {0};", worldSpaceName), false);
if ((neededSpaces & NeededCoordinateSpace.View) > 0)
pixelShader.AddShaderChunk(string.Format("surfaceInput.{0} = {0};", viewSpaceName), false);
if ((neededSpaces & NeededCoordinateSpace.Tangent) > 0)
pixelShader.AddShaderChunk(string.Format("surfaceInput.{0} = {0}", tangentSpaceName), false);
}
public static string GetPreviewSubShader(AbstractMaterialNode node, ShaderGraphRequirements shaderGraphRequirements)
{
var activeNodeList = ListPool<INode>.Get();
NodeUtils.DepthFirstCollectNodesFromNode(activeNodeList, node);
var interpolators = new ShaderGenerator();
var vertexShader = new ShaderGenerator();
var pixelShader = new ShaderGenerator();
var surfaceInputs = new ShaderGenerator();
ShaderGenerator.GenerateStandardTransforms(
0,
interpolators,
vertexShader,
pixelShader,
surfaceInputs,
shaderGraphRequirements,
ShaderGraphRequirements.none);
var outputs = new ShaderGenerator();
var outputSlot = node.GetOutputSlots<MaterialSlot>().FirstOrDefault();
if (outputSlot != null)
{
var result = string.Format("surf.{0}", node.GetVariableNameForSlot(outputSlot.id));
outputs.AddShaderChunk(string.Format("return {0};", AdaptNodeOutputForPreview(node, outputSlot.id, result)), true);
}
else
outputs.AddShaderChunk("return 0;", true);
var res = subShaderTemplate.Replace("${Interpolators}", interpolators.GetShaderString(0));
res = res.Replace("${VertexShader}", vertexShader.GetShaderString(0));
res = res.Replace("${LocalPixelShader}", pixelShader.GetShaderString(0));
res = res.Replace("${SurfaceInputs}", surfaceInputs.GetShaderString(0));
res = res.Replace("${SurfaceOutputRemap}", outputs.GetShaderString(0));
return res;
}
private const string subShaderTemplate = @"
SubShader
{
Tags { ""RenderType""=""Opaque"" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include ""UnityCG.cginc""
struct GraphVertexOutput
{
float4 position : POSITION;
${Interpolators}
};
GraphVertexOutput vert (GraphVertexInput v)
{
v = PopulateVertexData(v);
GraphVertexOutput o;
o.position = UnityObjectToClipPos(v.vertex);
${VertexShader}
return o;
}
fixed4 frag (GraphVertexOutput IN) : SV_Target
{
${LocalPixelShader}
SurfaceInputs surfaceInput = (SurfaceInputs)0;;
${SurfaceInputs}
SurfaceDescription surf = PopulateSurfaceData(surfaceInput);
${SurfaceOutputRemap}
}
ENDCG
}
}";
}
}