-
Notifications
You must be signed in to change notification settings - Fork 131
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
365 additions
and
0 deletions.
There are no files selected for viewing
146 changes: 146 additions & 0 deletions
146
Packages/com.alelievr.mixture/Editor/Views/SubgraphNodeView.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
using GraphProcessor; | ||
using System.Linq; | ||
using UnityEditor.UIElements; | ||
using UnityEngine; | ||
using UnityEngine.UIElements; | ||
|
||
namespace Mixture | ||
{ | ||
[NodeCustomEditor(typeof(SubgraphNode))] | ||
public class SubgraphNodeView : MixtureNodeView | ||
{ | ||
SubgraphNode _node; | ||
|
||
DropdownField _previewOutputField; | ||
|
||
public override void Enable(bool fromInspector) | ||
{ | ||
base.Enable(fromInspector); | ||
|
||
_node = nodeTarget as SubgraphNode; | ||
|
||
_previewOutputField = new DropdownField( | ||
"Preview Output", | ||
_node.subgraph?.outputNode?.outputTextureSettings?.Select(setting => setting.name)?.ToList(), | ||
_node.previewOutputIndex | ||
) | ||
{ visible = _node.previewOutputIndex > -1 }; | ||
_previewOutputField.RegisterValueChangedCallback(e => | ||
{ | ||
_node.previewOutputIndex = _previewOutputField.index; | ||
NotifyNodeChanged(); | ||
}); | ||
|
||
var subgraphTextureField = new ObjectField("Subgraph Texture") | ||
{ | ||
value = _node.subgraphTexture, | ||
objectType = typeof(CustomRenderTexture) | ||
}; | ||
subgraphTextureField.RegisterValueChangedCallback(e => | ||
{ | ||
_node.subgraphTexture = e.newValue as CustomRenderTexture; | ||
UpdateSubgraph(); | ||
title = _node.name; | ||
}); | ||
|
||
controlsContainer.Add(_previewOutputField); | ||
controlsContainer.Add(subgraphTextureField); | ||
|
||
_node.onAfterEdgeDisconnected += UpdateSubgraph; | ||
|
||
UpdateSubgraph(); | ||
} | ||
|
||
public override void Disable() | ||
{ | ||
base.Disable(); | ||
|
||
if (_node != null) _node.onAfterEdgeDisconnected -= UpdateSubgraph; | ||
} | ||
|
||
void UpdateSubgraph(SerializableEdge _) => UpdateSubgraph(); | ||
|
||
void UpdateSubgraph() | ||
{ | ||
if (_node.subgraph != null) | ||
{ | ||
_node.subgraph.onExposedParameterModified -= UpdateSubgraphInputs; | ||
_node.subgraph.onExposedParameterListChanged -= UpdateSubgraphInputs; | ||
_node.subgraph.outputNode.onPortsUpdated -= UpdateSubgraphOutputs; | ||
} | ||
|
||
_node.subgraph = MixtureDatabase.GetGraphFromTexture(_node.subgraphTexture); | ||
|
||
if (ValidateSubgraph()) | ||
{ | ||
_node.subgraph.onExposedParameterModified += UpdateSubgraphInputs; | ||
_node.subgraph.onExposedParameterListChanged += UpdateSubgraphInputs; | ||
_node.subgraph.outputNode.onPortsUpdated += UpdateSubgraphOutputs; | ||
|
||
_node.UpdateOutputTextures(); | ||
UpdatePreviewUI(); | ||
} | ||
else | ||
{ | ||
_node.ReleaseOutputTextures(); | ||
_node.previewOutputIndex = -1; | ||
} | ||
|
||
_previewOutputField.visible = _node.previewOutputIndex > -1; | ||
|
||
ForceUpdatePorts(); | ||
NotifyNodeChanged(); | ||
} | ||
|
||
void UpdateSubgraphInputs() | ||
{ | ||
ForceUpdatePorts(); | ||
NotifyNodeChanged(); | ||
} | ||
|
||
void UpdateSubgraphInputs(ExposedParameter _) => UpdateSubgraphInputs(); | ||
|
||
void UpdateSubgraphOutputs() | ||
{ | ||
_node.UpdateOutputTextures(); | ||
UpdatePreviewUI(); | ||
ForceUpdatePorts(); | ||
NotifyNodeChanged(); | ||
} | ||
|
||
void UpdateSubgraphOutputs(string _) => UpdateSubgraphOutputs(); | ||
|
||
void UpdatePreviewUI() | ||
{ | ||
var settings = _node.subgraph.outputNode.outputTextureSettings; | ||
|
||
_previewOutputField.choices = settings.Select(setting => setting.name).ToList(); | ||
_node.previewOutputIndex = Mathf.Clamp(_node.previewOutputIndex, 0, settings.Count - 1); | ||
_previewOutputField.index = _node.previewOutputIndex; | ||
} | ||
|
||
bool ValidateSubgraph() | ||
{ | ||
_node.ClearMessages(); | ||
|
||
if (_node.subgraphTexture == null) | ||
{ | ||
return false; | ||
} | ||
|
||
if (_node.subgraph == null) | ||
{ | ||
_node.AddMessage($"Cannot find Mixture graph for texture: {_node.subgraphTexture.name}", NodeMessageType.Error); | ||
return false; | ||
} | ||
|
||
if (_node.subgraph == _node.graph) | ||
{ | ||
_node.AddMessage($"Cannot execute graph recursively!", NodeMessageType.Error); | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
Packages/com.alelievr.mixture/Editor/Views/SubgraphNodeView.cs.meta
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
197 changes: 197 additions & 0 deletions
197
Packages/com.alelievr.mixture/Runtime/Nodes/SubgraphNode.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,197 @@ | ||
using GraphProcessor; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using UnityEngine; | ||
using UnityEngine.Rendering; | ||
|
||
namespace Mixture | ||
{ | ||
[System.Serializable, NodeMenuItem("Subgraph")] | ||
public class SubgraphNode : MixtureNode, ICreateNodeFrom<CustomRenderTexture> | ||
{ | ||
// Placeholders for custom port behaviours | ||
[Input, System.NonSerialized] public int subgraphInputs; | ||
[Output, System.NonSerialized] public int subgraphOutputs; | ||
|
||
public MixtureGraph subgraph; | ||
public CustomRenderTexture subgraphTexture; | ||
public int previewOutputIndex = -1; | ||
|
||
List<CustomRenderTexture> _outputTextures = new List<CustomRenderTexture>(); | ||
|
||
public override string name => subgraph?.name ?? "Subgraph"; | ||
public override bool isRenamable => true; | ||
public override bool hasPreview => -1 < previewOutputIndex && previewOutputIndex < _outputTextures.Count; | ||
public override Texture previewTexture => hasPreview ? _outputTextures[previewOutputIndex] : null; | ||
|
||
public bool InitializeNodeFromObject(CustomRenderTexture texture) | ||
{ | ||
subgraph = MixtureDatabase.GetGraphFromTexture(texture); | ||
|
||
if (subgraph == null) return false; | ||
|
||
subgraphTexture = texture; | ||
previewOutputIndex = Mathf.Clamp(previewOutputIndex, 0, subgraph.outputNode.outputTextureSettings.Count - 1); | ||
|
||
return true; | ||
} | ||
|
||
[CustomPortBehavior(nameof(subgraphInputs))] | ||
public IEnumerable<PortData> ListGraphInputs(List<SerializableEdge> edges) | ||
{ | ||
if (subgraph == null || subgraph == graph) yield break; | ||
|
||
for (var i = 0; i < subgraph.exposedParameters.Count; i++) | ||
{ | ||
var parameter = subgraph.exposedParameters[i]; | ||
|
||
yield return new PortData | ||
{ | ||
identifier = System.Convert.ToString(i), | ||
displayName = parameter.name, | ||
displayType = parameter.GetValueType(), | ||
acceptMultipleEdges = false, | ||
}; | ||
} | ||
} | ||
|
||
[CustomPortBehavior(nameof(subgraphOutputs))] | ||
public IEnumerable<PortData> ListGraphOutputs(List<SerializableEdge> edges) | ||
{ | ||
if (subgraph == null || subgraph == graph) yield break; | ||
|
||
var settings = subgraph.outputNode.outputTextureSettings; | ||
var textureType = GetSubgraphTextureType(); | ||
|
||
for (var i = 0; i < settings.Count; i++) | ||
{ | ||
yield return new PortData | ||
{ | ||
identifier = System.Convert.ToString(i), | ||
displayName = settings[i].name, | ||
displayType = textureType, | ||
acceptMultipleEdges = true, | ||
}; | ||
} | ||
} | ||
|
||
[CustomPortInput(nameof(subgraphInputs), typeof(object))] | ||
public void AssignGraphInputs(List<SerializableEdge> edges) | ||
{ | ||
foreach (var edge in edges) | ||
{ | ||
var index = System.Convert.ToInt32(edge.inputPortIdentifier); | ||
var parameter = subgraph.exposedParameters[index]; | ||
|
||
switch (edge.passThroughBuffer) | ||
{ | ||
case float v: parameter.value = CoerceVectorValue(parameter, new Vector4(v, v, v, v)); break; | ||
case Vector2 v: parameter.value = CoerceVectorValue(parameter, v); break; | ||
case Vector3 v: parameter.value = CoerceVectorValue(parameter, v); break; | ||
case Vector4 v: parameter.value = CoerceVectorValue(parameter, v); break; | ||
default: parameter.value = edge.passThroughBuffer; break; | ||
} | ||
} | ||
} | ||
|
||
[CustomPortOutput(nameof(subgraphOutputs), typeof(object))] | ||
public void AssignGraphOutputs(List<SerializableEdge> edges) | ||
{ | ||
foreach (var edge in edges) | ||
{ | ||
var index = System.Convert.ToInt32(edge.outputPortIdentifier); | ||
edge.passThroughBuffer = _outputTextures[index]; | ||
} | ||
} | ||
|
||
public void UpdateOutputTextures() | ||
{ | ||
ReleaseOutputTextures(); | ||
|
||
if (subgraph != null && subgraph != graph) GenerateOutputTextures(); | ||
} | ||
|
||
public void GenerateOutputTextures() | ||
{ | ||
var settings = subgraph.outputNode.outputTextureSettings; | ||
|
||
_outputTextures.Capacity = Mathf.Max(_outputTextures.Capacity, settings.Count); | ||
|
||
foreach (var setting in settings) | ||
{ | ||
CustomRenderTexture outputTexture = null; | ||
UpdateTempRenderTexture(ref outputTexture); | ||
_outputTextures.Add(outputTexture); | ||
} | ||
} | ||
|
||
public void ReleaseOutputTextures() | ||
{ | ||
foreach (var texture in _outputTextures) texture?.Release(); | ||
|
||
_outputTextures.Clear(); | ||
} | ||
|
||
protected override void Enable() | ||
{ | ||
base.Enable(); | ||
|
||
UpdateOutputTextures(); | ||
} | ||
|
||
protected override void Disable() | ||
{ | ||
base.Disable(); | ||
|
||
ReleaseOutputTextures(); | ||
} | ||
|
||
public override bool canProcess => base.canProcess && subgraph != null && subgraph != graph; | ||
|
||
protected override bool ProcessNode(CommandBuffer cmd) | ||
{ | ||
if (!base.ProcessNode(cmd)) return false; | ||
|
||
MixtureGraphProcessor.RunOnce(subgraph); | ||
|
||
using (var copyCmd = new CommandBuffer { name = $"{graph.name}/{subgraph.name}" }) | ||
{ | ||
for (int i = 0; i < _outputTextures.Count; i++) | ||
{ | ||
var outputTexture = _outputTextures[i]; | ||
UpdateTempRenderTexture(ref outputTexture); | ||
copyCmd.Blit(subgraph.outputNode.outputTextureSettings[i].finalCopyRT, outputTexture); | ||
} | ||
|
||
Graphics.ExecuteCommandBuffer(copyCmd); | ||
} | ||
|
||
return true; | ||
} | ||
|
||
System.Type GetSubgraphTextureType() | ||
{ | ||
var textureDimension = subgraph.settings.GetResolvedTextureDimension(subgraph); | ||
|
||
switch (textureDimension) | ||
{ | ||
case UnityEngine.Rendering.TextureDimension.Tex2D: return typeof(Texture2D); | ||
case UnityEngine.Rendering.TextureDimension.Tex3D: return typeof(Texture3D); | ||
case UnityEngine.Rendering.TextureDimension.Cube: return typeof(Cubemap); | ||
default: throw new System.Exception($"Texture dimension not supported: {textureDimension}"); | ||
} | ||
} | ||
|
||
object CoerceVectorValue(ExposedParameter parameter, Vector4 vector) | ||
{ | ||
switch (parameter.value) | ||
{ | ||
case float: return vector.x; | ||
case Vector2: return (Vector2)vector; | ||
case Vector3: return (Vector3)vector; | ||
case Vector4: return vector; | ||
default: throw new System.Exception($"Cannot cast vector to {parameter.GetValueType()}"); | ||
} | ||
} | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
Packages/com.alelievr.mixture/Runtime/Nodes/SubgraphNode.cs.meta
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.