123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using UnityEngine;
- using UnityEditor.Graphing;
- using UnityEditor.ShaderGraph.Internal;
- namespace UnityEditor.ShaderGraph
- {
- [HasDependencies(typeof(MinimalSubGraphNode))]
- [Title("Utility", "Sub-graph")]
- class SubGraphNode : AbstractMaterialNode
- , IGeneratesBodyCode
- , IOnAssetEnabled
- , IGeneratesFunction
- , IMayRequireNormal
- , IMayRequireTangent
- , IMayRequireBitangent
- , IMayRequireMeshUV
- , IMayRequireScreenPosition
- , IMayRequireViewDirection
- , IMayRequirePosition
- , IMayRequireVertexColor
- , IMayRequireTime
- , IMayRequireFaceSign
- , IMayRequireCameraOpaqueTexture
- , IMayRequireDepthTexture
- {
- [Serializable]
- public class MinimalSubGraphNode : IHasDependencies
- {
- [SerializeField]
- string m_SerializedSubGraph = string.Empty;
- public void GetSourceAssetDependencies(List<string> paths)
- {
- var assetReference = JsonUtility.FromJson<SubGraphAssetReference>(m_SerializedSubGraph);
- var guid = assetReference?.subGraph?.guid;
- if (guid != null)
- {
- paths.Add(AssetDatabase.GUIDToAssetPath(guid));
- }
- }
- }
- [Serializable]
- class SubGraphHelper
- {
- public SubGraphAsset subGraph;
- }
- [Serializable]
- class SubGraphAssetReference
- {
- public AssetReference subGraph = default;
- public override string ToString()
- {
- return $"subGraph={subGraph}";
- }
- }
- [Serializable]
- class AssetReference
- {
- public long fileID = default;
- public string guid = default;
- public int type = default;
- public override string ToString()
- {
- return $"fileID={fileID}, guid={guid}, type={type}";
- }
- }
-
- [SerializeField]
- string m_SerializedSubGraph = string.Empty;
- [NonSerialized]
- SubGraphAsset m_SubGraph;
- [SerializeField]
- List<string> m_PropertyGuids = new List<string>();
- [SerializeField]
- List<int> m_PropertyIds = new List<int>();
- public string subGraphGuid
- {
- get
- {
- var assetReference = JsonUtility.FromJson<SubGraphAssetReference>(m_SerializedSubGraph);
- return assetReference?.subGraph?.guid;
- }
- }
- void LoadSubGraph()
- {
- if (m_SubGraph == null)
- {
- if (string.IsNullOrEmpty(m_SerializedSubGraph))
- {
- return;
- }
-
- var graphGuid = subGraphGuid;
- var assetPath = AssetDatabase.GUIDToAssetPath(graphGuid);
- m_SubGraph = AssetDatabase.LoadAssetAtPath<SubGraphAsset>(assetPath);
- if (m_SubGraph == null)
- {
- return;
- }
-
- name = m_SubGraph.name;
- concretePrecision = m_SubGraph.outputPrecision;
- }
- }
- public SubGraphAsset asset
- {
- get
- {
- LoadSubGraph();
- return m_SubGraph;
- }
- set
- {
- if (asset == value)
- return;
- var helper = new SubGraphHelper();
- helper.subGraph = value;
- m_SerializedSubGraph = EditorJsonUtility.ToJson(helper, true);
- m_SubGraph = null;
- UpdateSlots();
- Dirty(ModificationScope.Topological);
- }
- }
- public override bool hasPreview
- {
- get { return asset != null; }
- }
- public override PreviewMode previewMode
- {
- get
- {
- if (asset == null)
- return PreviewMode.Preview2D;
- return PreviewMode.Preview3D;
- }
- }
- public SubGraphNode()
- {
- name = "Sub Graph";
- }
- public override bool allowedInSubGraph
- {
- get { return true; }
- }
-
- public override bool canSetPrecision
- {
- get { return false; }
- }
- public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode)
- {
- if (asset == null || hasError)
- {
- var outputSlots = new List<MaterialSlot>();
- GetOutputSlots(outputSlots);
- var outputPrecision = asset != null ? asset.outputPrecision : ConcretePrecision.Float;
- foreach (var slot in outputSlots)
- {
- sb.AppendLine($"{slot.concreteValueType.ToShaderString(outputPrecision)} {GetVariableNameForSlot(slot.id)} = {slot.GetDefaultValue(GenerationMode.ForReals)};");
- }
-
- return;
- }
- var inputVariableName = $"_{GetVariableNameForNode()}";
-
- SubShaderGenerator.GenerateSurfaceInputTransferCode(sb, asset.requirements, asset.inputStructName, inputVariableName);
- foreach (var outSlot in asset.outputs)
- sb.AppendLine("{0} {1};", outSlot.concreteValueType.ToShaderString(asset.outputPrecision), GetVariableNameForSlot(outSlot.id));
- var arguments = new List<string>();
- foreach (var prop in asset.inputs)
- {
- prop.ValidateConcretePrecision(asset.graphPrecision);
- var inSlotId = m_PropertyIds[m_PropertyGuids.IndexOf(prop.guid.ToString())];
- switch(prop)
- {
- case Texture2DShaderProperty texture2DProp:
- arguments.Add(string.Format("TEXTURE2D_ARGS({0}, sampler{0}), {0}_TexelSize", GetSlotValue(inSlotId, generationMode, prop.concretePrecision)));
- break;
- case Texture2DArrayShaderProperty texture2DArrayProp:
- arguments.Add(string.Format("TEXTURE2D_ARRAY_ARGS({0}, sampler{0})", GetSlotValue(inSlotId, generationMode, prop.concretePrecision)));
- break;
- case Texture3DShaderProperty texture3DProp:
- arguments.Add(string.Format("TEXTURE3D_ARGS({0}, sampler{0})", GetSlotValue(inSlotId, generationMode, prop.concretePrecision)));
- break;
- case CubemapShaderProperty cubemapProp:
- arguments.Add(string.Format("TEXTURECUBE_ARGS({0}, sampler{0})", GetSlotValue(inSlotId, generationMode, prop.concretePrecision)));
- break;
- default:
- arguments.Add(string.Format("{0}", GetSlotValue(inSlotId, generationMode, prop.concretePrecision)));
- break;
- }
- }
- // pass surface inputs through
- arguments.Add(inputVariableName);
- foreach (var outSlot in asset.outputs)
- arguments.Add(GetVariableNameForSlot(outSlot.id));
- sb.AppendLine("{0}({1});", asset.functionName, arguments.Aggregate((current, next) => string.Format("{0}, {1}", current, next)));
- }
- public void OnEnable()
- {
- UpdateSlots();
- }
-
- public void Reload(HashSet<string> changedFileDependencies)
- {
- if (asset == null)
- {
- return;
- }
- if (changedFileDependencies.Contains(asset.assetGuid) || asset.descendents.Any(changedFileDependencies.Contains))
- {
- m_SubGraph = null;
- UpdateSlots();
- if (hasError)
- {
- return;
- }
- owner.ClearErrorsForNode(this);
- ValidateNode();
- Dirty(ModificationScope.Graph);
- }
- }
- public virtual void UpdateSlots()
- {
- var validNames = new List<int>();
- if (asset == null)
- {
- return;
- }
- var props = asset.inputs;
- foreach (var prop in props)
- {
- SlotValueType valueType = prop.concreteShaderValueType.ToSlotValueType();
- var propertyString = prop.guid.ToString();
- var propertyIndex = m_PropertyGuids.IndexOf(propertyString);
- if (propertyIndex < 0)
- {
- propertyIndex = m_PropertyGuids.Count;
- m_PropertyGuids.Add(propertyString);
- m_PropertyIds.Add(prop.guid.GetHashCode());
- }
- var id = m_PropertyIds[propertyIndex];
- MaterialSlot slot = MaterialSlot.CreateMaterialSlot(valueType, id, prop.displayName, prop.referenceName, SlotType.Input, Vector4.zero, ShaderStageCapability.All);
-
- // Copy defaults
- switch(prop.concreteShaderValueType)
- {
- case ConcreteSlotValueType.Matrix4:
- {
- var tSlot = slot as Matrix4MaterialSlot;
- var tProp = prop as Matrix4ShaderProperty;
- if (tSlot != null && tProp != null)
- tSlot.value = tProp.value;
- }
- break;
- case ConcreteSlotValueType.Matrix3:
- {
- var tSlot = slot as Matrix3MaterialSlot;
- var tProp = prop as Matrix3ShaderProperty;
- if (tSlot != null && tProp != null)
- tSlot.value = tProp.value;
- }
- break;
- case ConcreteSlotValueType.Matrix2:
- {
- var tSlot = slot as Matrix2MaterialSlot;
- var tProp = prop as Matrix2ShaderProperty;
- if (tSlot != null && tProp != null)
- tSlot.value = tProp.value;
- }
- break;
- case ConcreteSlotValueType.Texture2D:
- {
- var tSlot = slot as Texture2DInputMaterialSlot;
- var tProp = prop as Texture2DShaderProperty;
- if (tSlot != null && tProp != null)
- tSlot.texture = tProp.value.texture;
- }
- break;
- case ConcreteSlotValueType.Texture2DArray:
- {
- var tSlot = slot as Texture2DArrayInputMaterialSlot;
- var tProp = prop as Texture2DArrayShaderProperty;
- if (tSlot != null && tProp != null)
- tSlot.textureArray = tProp.value.textureArray;
- }
- break;
- case ConcreteSlotValueType.Texture3D:
- {
- var tSlot = slot as Texture3DInputMaterialSlot;
- var tProp = prop as Texture3DShaderProperty;
- if (tSlot != null && tProp != null)
- tSlot.texture = tProp.value.texture;
- }
- break;
- case ConcreteSlotValueType.Cubemap:
- {
- var tSlot = slot as CubemapInputMaterialSlot;
- var tProp = prop as CubemapShaderProperty;
- if (tSlot != null && tProp != null)
- tSlot.cubemap = tProp.value.cubemap;
- }
- break;
- case ConcreteSlotValueType.Gradient:
- {
- var tSlot = slot as GradientInputMaterialSlot;
- var tProp = prop as GradientShaderProperty;
- if (tSlot != null && tProp != null)
- tSlot.value = tProp.value;
- }
- break;
- case ConcreteSlotValueType.Vector4:
- {
- var tSlot = slot as Vector4MaterialSlot;
- var vector4Prop = prop as Vector4ShaderProperty;
- var colorProp = prop as ColorShaderProperty;
- if (tSlot != null && vector4Prop != null)
- tSlot.value = vector4Prop.value;
- else if (tSlot != null && colorProp != null)
- tSlot.value = colorProp.value;
- }
- break;
- case ConcreteSlotValueType.Vector3:
- {
- var tSlot = slot as Vector3MaterialSlot;
- var tProp = prop as Vector3ShaderProperty;
- if (tSlot != null && tProp != null)
- tSlot.value = tProp.value;
- }
- break;
- case ConcreteSlotValueType.Vector2:
- {
- var tSlot = slot as Vector2MaterialSlot;
- var tProp = prop as Vector2ShaderProperty;
- if (tSlot != null && tProp != null)
- tSlot.value = tProp.value;
- }
- break;
- case ConcreteSlotValueType.Vector1:
- {
- var tSlot = slot as Vector1MaterialSlot;
- var tProp = prop as Vector1ShaderProperty;
- if (tSlot != null && tProp != null)
- tSlot.value = tProp.value;
- }
- break;
- case ConcreteSlotValueType.Boolean:
- {
- var tSlot = slot as BooleanMaterialSlot;
- var tProp = prop as BooleanShaderProperty;
- if (tSlot != null && tProp != null)
- tSlot.value = tProp.value;
- }
- break;
- }
-
- AddSlot(slot);
- validNames.Add(id);
- }
- var outputStage = asset.effectiveShaderStage;
- foreach (var slot in asset.outputs)
- {
- AddSlot(MaterialSlot.CreateMaterialSlot(slot.valueType, slot.id, slot.RawDisplayName(),
- slot.shaderOutputName, SlotType.Output, Vector4.zero, outputStage));
- validNames.Add(slot.id);
- }
- RemoveSlotsNameNotMatching(validNames, true);
- }
- void ValidateShaderStage()
- {
- if (asset != null)
- {
- List<MaterialSlot> slots = new List<MaterialSlot>();
- GetInputSlots(slots);
- GetOutputSlots(slots);
- var outputStage = asset.effectiveShaderStage;
- foreach (MaterialSlot slot in slots)
- slot.stageCapability = outputStage;
- }
- }
- public override void ValidateNode()
- {
- base.ValidateNode();
-
- if (asset == null)
- {
- hasError = true;
- var assetGuid = subGraphGuid;
- var assetPath = string.IsNullOrEmpty(subGraphGuid) ? null : AssetDatabase.GUIDToAssetPath(assetGuid);
- if (string.IsNullOrEmpty(assetPath))
- {
- owner.AddValidationError(tempId, $"Could not find Sub Graph asset with GUID {assetGuid}.");
- }
- else
- {
- owner.AddValidationError(tempId, $"Could not load Sub Graph asset at \"{assetPath}\" with GUID {assetGuid}.");
- }
- return;
- }
-
- if (asset.isRecursive || owner.isSubGraph && (asset.descendents.Contains(owner.assetGuid) || asset.assetGuid == owner.assetGuid))
- {
- hasError = true;
- owner.AddValidationError(tempId, $"Detected a recursion in Sub Graph asset at \"{AssetDatabase.GUIDToAssetPath(subGraphGuid)}\" with GUID {subGraphGuid}.");
- }
- else if (!asset.isValid)
- {
- hasError = true;
- owner.AddValidationError(tempId, $"Invalid Sub Graph asset at \"{AssetDatabase.GUIDToAssetPath(subGraphGuid)}\" with GUID {subGraphGuid}.");
- }
- ValidateShaderStage();
- }
- public override void CollectShaderProperties(PropertyCollector visitor, GenerationMode generationMode)
- {
- base.CollectShaderProperties(visitor, generationMode);
- if (asset == null)
- return;
- foreach (var property in asset.nodeProperties)
- {
- visitor.AddShaderProperty(property);
- }
- }
- public void CollectShaderKeywords(KeywordCollector keywords, GenerationMode generationMode)
- {
- if (asset == null)
- return;
- foreach (var keyword in asset.keywords)
- {
- keywords.AddShaderKeyword(keyword as ShaderKeyword);
- }
- }
- public override void CollectPreviewMaterialProperties(List<PreviewProperty> properties)
- {
- base.CollectPreviewMaterialProperties(properties);
-
- if (asset == null)
- return;
- foreach (var property in asset.nodeProperties)
- {
- properties.Add(property.GetPreviewMaterialProperty());
- }
- }
- public virtual void GenerateNodeFunction(FunctionRegistry registry, GenerationMode generationMode)
- {
- if (asset == null || hasError)
- return;
-
- foreach (var function in asset.functions)
- {
- registry.ProvideFunction(function.key, s =>
- {
- s.AppendLines(function.value);
- });
- }
- }
- public NeededCoordinateSpace RequiresNormal(ShaderStageCapability stageCapability)
- {
- if (asset == null)
- return NeededCoordinateSpace.None;
- return asset.requirements.requiresNormal;
- }
- public bool RequiresMeshUV(UVChannel channel, ShaderStageCapability stageCapability)
- {
- if (asset == null)
- return false;
- return asset.requirements.requiresMeshUVs.Contains(channel);
- }
- public bool RequiresScreenPosition(ShaderStageCapability stageCapability)
- {
- if (asset == null)
- return false;
- return asset.requirements.requiresScreenPosition;
- }
- public NeededCoordinateSpace RequiresViewDirection(ShaderStageCapability stageCapability)
- {
- if (asset == null)
- return NeededCoordinateSpace.None;
- return asset.requirements.requiresViewDir;
- }
- public NeededCoordinateSpace RequiresPosition(ShaderStageCapability stageCapability)
- {
- if (asset == null)
- return NeededCoordinateSpace.None;
- return asset.requirements.requiresPosition;
- }
- public NeededCoordinateSpace RequiresTangent(ShaderStageCapability stageCapability)
- {
- if (asset == null)
- return NeededCoordinateSpace.None;
- return asset.requirements.requiresTangent;
- }
- public bool RequiresTime()
- {
- if (asset == null)
- return false;
- return asset.requirements.requiresTime;
- }
- public bool RequiresFaceSign(ShaderStageCapability stageCapability)
- {
- if (asset == null)
- return false;
- return asset.requirements.requiresFaceSign;
- }
- public NeededCoordinateSpace RequiresBitangent(ShaderStageCapability stageCapability)
- {
- if (asset == null)
- return NeededCoordinateSpace.None;
- return asset.requirements.requiresBitangent;
- }
- public bool RequiresVertexColor(ShaderStageCapability stageCapability)
- {
- if (asset == null)
- return false;
- return asset.requirements.requiresVertexColor;
- }
- public bool RequiresCameraOpaqueTexture(ShaderStageCapability stageCapability)
- {
- if (asset == null)
- return false;
- return asset.requirements.requiresCameraOpaqueTexture;
- }
- public bool RequiresDepthTexture(ShaderStageCapability stageCapability)
- {
- if (asset == null)
- return false;
- return asset.requirements.requiresDepthTexture;
- }
- }
- }
|