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

380 行
14 KiB

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEditor.Graphing;
namespace UnityEditor.ShaderGraph
{
[Serializable]
public class LayeredShaderGraph : AbstractMaterialGraph, IShaderGraph
{
[Serializable]
public class Layer
{
[SerializeField]
private SerializableGuid m_Guid = new SerializableGuid();
[SerializeField]
private Shader m_Shader;
public Layer() { }
public Guid guid
{
get { return m_Guid.guid; }
}
public Shader shader
{
get { return m_Shader; }
set { m_Shader = value; }
}
}
[NonSerialized]
private List<Layer> m_Layers = new List<Layer>();
[NonSerialized]
List<Layer> m_AddedLayers = new List<Layer>();
[NonSerialized]
List<Guid> m_RemovedLayers = new List<Guid>();
[SerializeField]
List<SerializationHelper.JSONSerializedElement> m_SerializedLayers = new List<SerializationHelper.JSONSerializedElement>();
public IEnumerable<Layer> layers
{
get { return m_Layers; }
}
public List<Layer> addedLayers
{
get { return m_AddedLayers; }
}
public List<Guid> removedLayers
{
get { return m_RemovedLayers; }
}
[NonSerialized]
private LayerWeightsOutputNode m_OutputNode;
public LayerWeightsOutputNode outputNode
{
get
{
// find existing node
if (m_OutputNode == null)
m_OutputNode = GetNodes<LayerWeightsOutputNode>().FirstOrDefault();
return m_OutputNode;
}
}
public override void ClearChanges()
{
base.ClearChanges();
m_AddedLayers.Clear();
m_RemovedLayers.Clear();
}
public override void AddNode(INode node)
{
if (outputNode != null && node is LayerWeightsOutputNode)
{
Debug.LogWarning("Attempting to add second LayerWeightsOutputNode to LayeredShaderGraph. This is not allowed.");
return;
}
base.AddNode(node);
}
public void AddLayer()
{
var layer = new Layer();
m_Layers.Add(layer);
m_AddedLayers.Add(layer);
if (outputNode != null)
outputNode.onModified(outputNode, ModificationScope.Graph);
}
public bool SetLayer(Guid layerId, Shader newShader)
{
try
{
var path = AssetDatabase.GetAssetPath(newShader);
if (!path.EndsWith("shaderGraph", StringComparison.InvariantCultureIgnoreCase))
return false;
var textGraph = File.ReadAllText(path, Encoding.UTF8);
var graph = JsonUtility.FromJson<MaterialGraph>(textGraph);
if (graph == null)
return false;
var layer = layers.FirstOrDefault(x => x.guid == layerId);
if (layer == null)
return false;
layer.shader = newShader;
if (outputNode != null)
{
outputNode.OnEnable();
outputNode.onModified(outputNode, ModificationScope.Graph);
}
return true;
}
catch (Exception)
{
// ignored
}
return false;
}
public void RemoveLayer(Guid id)
{
var num = m_Layers.RemoveAll(x => x.guid == id);
if (num > 0)
{
m_RemovedLayers.Add(id);
if (outputNode != null)
outputNode.onModified(outputNode, ModificationScope.Graph);
}
}
public override void OnBeforeSerialize()
{
base.OnBeforeSerialize();
m_SerializedLayers = SerializationHelper.Serialize<Layer>(m_Layers);
}
public override void OnAfterDeserialize()
{
m_OutputNode = null;
m_Layers = SerializationHelper.Deserialize<Layer>(m_SerializedLayers, null);
m_SerializedLayers = null;
base.OnAfterDeserialize();
}
public static string LayerToFunctionName(Guid id)
{
return string.Format("Layer_{0}", GuidEncoder.Encode(id));
}
public string GetShader(string name, GenerationMode mode, out List<PropertyCollector.TextureInfo> configuredTextures)
{
if (outputNode == null)
throw new InvalidOperationException();
var layerMap = new Dictionary<Guid, MaterialGraph>();
foreach (var layer in layers)
{
var path = AssetDatabase.GetAssetPath(layer.shader);
if (!path.EndsWith("shaderGraph", StringComparison.InvariantCultureIgnoreCase))
continue;
var textGraph = File.ReadAllText(path, Encoding.UTF8);
var graph = JsonUtility.FromJson<MaterialGraph>(textGraph);
if (graph == null)
continue;
layerMap[layer.guid] = graph;
}
if (layerMap.Count == 0)
{
configuredTextures = new List<PropertyCollector.TextureInfo>();
return string.Empty;
}
var vertexShader = new ShaderGenerator();
var layerShaders = new ShaderGenerator();
var surfaceDescriptionFunction = new ShaderGenerator();
var surfaceDescriptionStruct = new ShaderGenerator();
var shaderFunctionVisitor = new ShaderGenerator();
var surfaceInputs = new ShaderGenerator();
var graphVertexInput = @"
struct GraphVertexInput
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 tangent : TANGENT;
float4 texcoord0 : TEXCOORD0;
float4 lightmapUV : TEXCOORD1;
UNITY_VERTEX_INPUT_INSTANCE_ID
};";
surfaceInputs.AddShaderChunk("struct SurfaceInputs{", false);
surfaceInputs.Indent();
using (var activeNodesDisposable = ListPool<INode>.GetDisposable())
{
var activeNodes = activeNodesDisposable.value;
foreach (var layer in layerMap)
{
NodeUtils.DepthFirstCollectNodesFromNode(activeNodes, layer.Value.masterNode as AbstractMaterialNode);
}
NodeUtils.DepthFirstCollectNodesFromNode(activeNodes, outputNode);
var requirements = GetRequirements(activeNodes);
ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresNormal, InterpolatorType.Normal, surfaceInputs);
ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresTangent, InterpolatorType.Tangent, surfaceInputs);
ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresBitangent, InterpolatorType.BiTangent, surfaceInputs);
ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresViewDir, InterpolatorType.ViewDirection, surfaceInputs);
ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(requirements.requiresPosition, InterpolatorType.Position, surfaceInputs);
if (requirements.requiresVertexColor)
surfaceInputs.AddShaderChunk(string.Format("float4 {0};", ShaderGeneratorNames.VertexColor), false);
if (requirements.requiresScreenPosition)
surfaceInputs.AddShaderChunk(string.Format("float4 {0};", ShaderGeneratorNames.ScreenPosition), false);
foreach (var channel in requirements.requiresMeshUVs.Distinct())
surfaceInputs.AddShaderChunk(string.Format("half4 {0};", channel.GetUVName()), false);
surfaceInputs.Deindent();
surfaceInputs.AddShaderChunk("};", false);
vertexShader.AddShaderChunk("GraphVertexInput PopulateVertexData(GraphVertexInput v){", false);
vertexShader.Indent();
vertexShader.AddShaderChunk("return v;", false);
vertexShader.Deindent();
vertexShader.AddShaderChunk("}", false);
var shaderProperties = new PropertyCollector();
var baseGraph = layerMap.Values.FirstOrDefault();
if (baseGraph == null)
{
configuredTextures = new List<PropertyCollector.TextureInfo>();
return string.Empty;
}
var masterNode = baseGraph.masterNode;
GenerateSurfaceDescriptionStruct(surfaceDescriptionStruct, ((AbstractMaterialNode) masterNode).GetInputSlots<MaterialSlot>().ToList(), true);
foreach (var layer in layerMap)
{
activeNodes.Clear();
NodeUtils.DepthFirstCollectNodesFromNode(activeNodes, layer.Value.masterNode as AbstractMaterialNode);
GenerateSurfaceDescription(
activeNodes,
layer.Value.masterNode as AbstractMaterialNode,
this,
surfaceDescriptionFunction,
shaderFunctionVisitor,
shaderProperties,
requirements,
mode,
LayerToFunctionName(layer.Key));
}
surfaceDescriptionStruct.AddShaderChunk("struct WeightsSurfaceDescription{", false);
surfaceDescriptionStruct.Indent();
foreach (var slot in outputNode.GetInputSlots<MaterialSlot>())
surfaceDescriptionStruct.AddShaderChunk(AbstractMaterialNode.ConvertConcreteSlotValueTypeToString(AbstractMaterialNode.OutputPrecision.@float, slot.concreteValueType) + " " + slot.shaderOutputName + ";", false);
surfaceDescriptionStruct.Deindent();
surfaceDescriptionStruct.AddShaderChunk("};", false);
activeNodes.Clear();
NodeUtils.DepthFirstCollectNodesFromNode(activeNodes, outputNode);
GenerateSurfaceDescription(
activeNodes,
outputNode,
this,
surfaceDescriptionFunction,
shaderFunctionVisitor,
shaderProperties,
requirements,
mode,
"PopulateWeightsGraph",
"WeightsSurfaceDescription");
string functionName = "PopulateSurfaceData";
string surfaceDescriptionName = "SurfaceDescription";
layerShaders.AddShaderChunk(string.Format("{0} {1}(SurfaceInputs IN) {{", surfaceDescriptionName, functionName), false);
layerShaders.Indent();
layerShaders.AddShaderChunk("WeightsSurfaceDescription weights = PopulateWeightsGraph(IN);", false);
layerShaders.AddShaderChunk("SurfaceDescription result = (SurfaceDescription)0;", false);
foreach (var layer in layerMap)
{
layerShaders.AddShaderChunk(
string.Format(
"{0} {1} = {2}({3});",
surfaceDescriptionName,
LayerToFunctionName(layer.Key) + "_surface",
LayerToFunctionName(layer.Key),
"IN"), false);
layerShaders.AddShaderChunk(
string.Format("ScaleSurfaceDescription({0}_surface, weights.{0});", LayerToFunctionName(layer.Key)), false);
layerShaders.AddShaderChunk(string.Format("AddSurfaceDescription(result, {0}_surface);", LayerToFunctionName(layer.Key)), false);
}
layerShaders.AddShaderChunk("return result;", false);
layerShaders.Deindent();
layerShaders.AddShaderChunk("}", false);
var finalShader = new ShaderGenerator();
finalShader.AddShaderChunk(string.Format(@"Shader ""{0}""", name), false);
finalShader.AddShaderChunk("{", false);
finalShader.Indent();
finalShader.AddShaderChunk("Properties", false);
finalShader.AddShaderChunk("{", false);
finalShader.Indent();
finalShader.AddShaderChunk(shaderProperties.GetPropertiesBlock(2), false);
finalShader.Deindent();
finalShader.AddShaderChunk("}", false);
finalShader.AddShaderChunk("CGINCLUDE", false);
finalShader.AddShaderChunk("#include \"UnityCG.cginc\"", false);
finalShader.AddShaderChunk(shaderFunctionVisitor.GetShaderString(2), false);
finalShader.AddShaderChunk(graphVertexInput, false);
finalShader.AddShaderChunk(surfaceInputs.GetShaderString(2), false);
finalShader.AddShaderChunk(surfaceDescriptionStruct.GetShaderString(2), false);
finalShader.AddShaderChunk(shaderProperties.GetPropertiesDeclaration(2), false);
finalShader.AddShaderChunk(vertexShader.GetShaderString(2), false);
finalShader.AddShaderChunk(surfaceDescriptionFunction.GetShaderString(2), false);
finalShader.AddShaderChunk(layerShaders.GetShaderString(2), false);
finalShader.AddShaderChunk("ENDCG", false);
if (masterNode != null)
{
var subShaders = masterNode.GetSubshader(requirements, null);
foreach (var ss in subShaders)
finalShader.AddShaderChunk(ss, false);
}
finalShader.Deindent();
finalShader.AddShaderChunk("}", false);
configuredTextures = shaderProperties.GetConfiguredTexutres();
return finalShader.GetShaderString(0);
}
}
public void LoadedFromDisk()
{
OnEnable();
ValidateGraph();
}
}
}