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

432 行
18 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 GenerateSpaceTranslationPixelShader(
NeededCoordinateSpace neededSpaces,
ShaderGenerator pixelShader,
string objectSpaceName,
string viewSpaceName,
string worldSpaceName,
string tangentSpaceName,
bool isNormal = false)
{
if ((neededSpaces & NeededCoordinateSpace.Object) > 0)
{
pixelShader.AddShaderChunk(string.Format("surfaceInput.{0} = {0};", objectSpaceName), false);
}
if ((neededSpaces & NeededCoordinateSpace.World) > 0)
{
if (isNormal)
pixelShader.AddShaderChunk(string.Format("surfaceInput.{0} = UnityObjectToWorldNormal({1});", worldSpaceName, objectSpaceName), false);
else
pixelShader.AddShaderChunk(string.Format("surfaceInput.{0} = UnityObjectToWorldDir({1});", worldSpaceName, objectSpaceName), false);
}
if ((neededSpaces & NeededCoordinateSpace.View) > 0)
{
pixelShader.AddShaderChunk(string.Format("surfaceInput.{0} = UnityObjectToViewPos({1});", viewSpaceName, objectSpaceName), false);
}
if ((neededSpaces & NeededCoordinateSpace.Tangent) > 0)
{
pixelShader.AddShaderChunk(string.Format("surfaceInput.{0} = mul(tangentSpaceTransform, {1})", tangentSpaceName, objectSpaceName), 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();
// bitangent needs normal for x product
if (shaderGraphRequirements.requiresNormal > 0 || shaderGraphRequirements.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 (shaderGraphRequirements.requiresTangent > 0 || shaderGraphRequirements.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("float4 {0} = normalize(cross(normalize(IN.{1}), normalize(IN.{2}.xyz)) * IN.{2}.w);",
ShaderGeneratorNames.ObjectSpaceBiTangent,
ShaderGeneratorNames.ObjectSpaceTangent,
ShaderGeneratorNames.ObjectSpaceNormal), false);
}
int interpolatorIndex = 0;
if (shaderGraphRequirements.requiresViewDir > 0)
{
interpolators.AddShaderChunk(string.Format("float4 {0} : TEXCOORD{1};", ShaderGeneratorNames.ObjectSpaceViewDirection, interpolatorIndex), false);
vertexShader.AddShaderChunk(string.Format("o.{0} = ObjSpaceViewDir(v.vertex);", ShaderGeneratorNames.ObjectSpaceViewDirection), false);
pixelShader.AddShaderChunk(string.Format("float4 {0} = normalize(IN.{0});", ShaderGeneratorNames.ObjectSpaceViewDirection), false);
interpolatorIndex++;
}
if (shaderGraphRequirements.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 (shaderGraphRequirements.NeedsTangentSpace())
{
pixelShader.AddShaderChunk(string.Format("float3x3 tangentSpaceTransform = float3x3({0},{1},{2});",
ShaderGeneratorNames.ObjectSpaceTangent, ShaderGeneratorNames.ObjectSpaceBiTangent, ShaderGeneratorNames.ObjectSpaceNormal), false);
}
GenerateSpaceTranslationPixelShader(shaderGraphRequirements.requiresNormal, pixelShader,
ShaderGeneratorNames.ObjectSpaceNormal, ShaderGeneratorNames.ViewSpaceNormal,
ShaderGeneratorNames.WorldSpaceNormal, ShaderGeneratorNames.TangentSpaceNormal);
GenerateSpaceTranslationPixelShader(shaderGraphRequirements.requiresTangent, pixelShader,
ShaderGeneratorNames.ObjectSpaceTangent, ShaderGeneratorNames.ViewSpaceTangent,
ShaderGeneratorNames.WorldSpaceTangent, ShaderGeneratorNames.TangentSpaceTangent);
GenerateSpaceTranslationPixelShader(shaderGraphRequirements.requiresBitangent, pixelShader,
ShaderGeneratorNames.ObjectSpaceBiTangent, ShaderGeneratorNames.ViewSpaceBiTangent,
ShaderGeneratorNames.WorldSpaceBiTangent, ShaderGeneratorNames.TangentSpaceBiTangent);
GenerateSpaceTranslationPixelShader(shaderGraphRequirements.requiresViewDir, pixelShader,
ShaderGeneratorNames.ObjectSpaceViewDirection, ShaderGeneratorNames.ViewSpaceViewDirection,
ShaderGeneratorNames.WorldSpaceViewDirection, ShaderGeneratorNames.TangentSpaceViewDirection);
GenerateSpaceTranslationPixelShader(shaderGraphRequirements.requiresPosition, pixelShader,
ShaderGeneratorNames.ObjectSpacePosition, ShaderGeneratorNames.ViewSpacePosition,
ShaderGeneratorNames.WorldSpacePosition, ShaderGeneratorNames.TangentSpacePosition);
if (shaderGraphRequirements.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("surfaceInput.{0} = IN.{0};", ShaderGeneratorNames.VertexColor), false);
}
if (shaderGraphRequirements.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("surfaceInput.{0} = IN.{0};", ShaderGeneratorNames.ScreenPosition), false);
interpolatorIndex++;
}
for (int uvIndex = 0; uvIndex < ShaderGeneratorNames.UVCount; ++uvIndex)
{
var channel = (UVChannel) uvIndex;
if (activeNodeList.OfType<IMayRequireMeshUV>().Any(x => x.RequiresMeshUV(channel)))
{
interpolators.AddShaderChunk(string.Format("half4 meshUV{0} : TEXCOORD{1};", uvIndex, interpolatorIndex), false);
vertexShader.AddShaderChunk(string.Format("o.meshUV{0} = v.texcoord{1};", uvIndex, uvIndex), false);
pixelShader.AddShaderChunk(string.Format("surfaceInput.{0} = IN.meshUV{1};", channel.GetUVName(), uvIndex), false);
interpolatorIndex++;
}
}
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("{0}", interpolators.GetShaderString(0));
res = res.Replace("{1}", vertexShader.GetShaderString(0));
res = res.Replace("{2}", pixelShader.GetShaderString(0));
res = res.Replace("{3}", 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;
{0}
};
GraphVertexOutput vert (GraphVertexInput v)
{
v = PopulateVertexData(v);
GraphVertexOutput o;
o.position = UnityObjectToClipPos(v.vertex);
{1}
return o;
}
fixed4 frag (GraphVertexOutput IN) : SV_Target
{
SurfaceInputs surfaceInput;
{2}
SurfaceDescription surf = PopulateSurfaceData(surfaceInput);
{3}
}
ENDCG
}
}";
}
}