First commit - witness me 🚀

This commit is contained in:
Chromium 2025-04-26 19:40:12 +01:00
commit e8e1978af4
77 changed files with 3214 additions and 0 deletions

75
.gitignore vendored Normal file
View File

@ -0,0 +1,75 @@
# User-specific files
.idea/
.vscode/
*.suo
*.user
*.userosscache
*.sln.docstates
# Windows image file thumbs
Thumbs.db
Desktop.ini
# Windows Installer files
*.cab
*.msi
*.msm
*.msp
# Build directories
[Ll]ibrary/
[Ll]ogs/
[Tt]emp/
[Tt]arget/
# User-generated files
*.booproj
*.pidb
*.userprefs
# Unity-generated file types
*.csproj
*.unityproj
*.sln
*.tmp
# Unity's Auto-generated Visual Studio files
.vs/
# Memory Captures and crash dumps
*.stackdump
*.dmp
*.bak
# Build Results
*.apk
*.unitypackage
*.app
*.exe
*.xcodeproj
*.log
*.tlog
# External tools / packages (can be useful to keep if necessary)
Packages/
# .NET configuration files
project.settings/
# Logs and statistics
*.log
*.bak
*.swp
# JetBrains Rider files
.idea/
# Mac OS files
.DS_Store
# Linux files
*~
# Package and Unity Asset files
AssetBundles/
Build/

12
GraphView.uss Normal file
View File

@ -0,0 +1,12 @@
ImageProcessingGraphViewWindow
{
flex-grow: 1;
}
#Grid
{
--thick-lines: 0;
--spacing: 15;
--grid-background-color: rgb(25,25,25);
--line-color: rgb(32,32,32);
}

11
GraphView.uss.meta Normal file
View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0432b5222a07aad498018736ca300a6f
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
disableValidation: 0

8
Graphs.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f6fe8f57402cf44e8bb5f1dffb3be6d8
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

232
Graphs/URP-MAS.asset Normal file
View File

@ -0,0 +1,232 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1da462fd3f736d04e80556b4ac8b470f, type: 3}
m_Name: URP-MAS
m_EditorClassIdentifier:
nodes:
- rid: 6869590814762467406
- rid: 6869590814762467407
- rid: 6869590814762467408
- rid: 6869590814762467409
- rid: 6869590814762467410
- rid: 6869590814762467411
- rid: 6869590814762467412
connections:
- inputPort:
nodeID: c72eea15-501d-41b1-add3-4f0816ef3373
nodeType: StringAppend
portID: 0
outputPort:
nodeID: c21a6722-828f-4372-a718-298a0fe7b79b
nodeType: StringAppend
portID: 0
- inputPort:
nodeID: 9ccc58ba-79a7-4a7f-8057-3bdfbf8fb5c3
nodeType: Texture2DOutput
portID: 1
outputPort:
nodeID: c72eea15-501d-41b1-add3-4f0816ef3373
nodeType: StringAppend
portID: 0
- inputPort:
nodeID: 87c7a966-55ec-42aa-a537-73ebe906412b
nodeType: RGBASplit
portID: 0
outputPort:
nodeID: ac4be66e-d3b8-4633-a692-60cb30579f97
nodeType: Texture2DImport
portID: 0
- inputPort:
nodeID: 1c21d8e6-5b93-4a6f-a7ff-7322be2d20be
nodeType: RGBASplit
portID: 0
outputPort:
nodeID: 9b32fc10-fda3-4faa-82ac-efcff95a5138
nodeType: Texture2DImport
portID: 0
- inputPort:
nodeID: 3abef457-f0ec-456e-baa8-e8ae657b49e4
nodeType: RGBASCombine
portID: 1
outputPort:
nodeID: 87c7a966-55ec-42aa-a537-73ebe906412b
nodeType: RGBASplit
portID: 0
- inputPort:
nodeID: 3abef457-f0ec-456e-baa8-e8ae657b49e4
nodeType: RGBASCombine
portID: 0
outputPort:
nodeID: 1c21d8e6-5b93-4a6f-a7ff-7322be2d20be
nodeType: RGBASplit
portID: 0
- inputPort:
nodeID: 3abef457-f0ec-456e-baa8-e8ae657b49e4
nodeType: RGBASCombine
portID: 3
outputPort:
nodeID: 1c21d8e6-5b93-4a6f-a7ff-7322be2d20be
nodeType: RGBASplit
portID: 3
- inputPort:
nodeID: b882f7b7-9f8b-43ef-a79a-33d4e874edd0
nodeType: Texture2DOutput
portID: 0
outputPort:
nodeID: 3abef457-f0ec-456e-baa8-e8ae657b49e4
nodeType: RGBASCombine
portID: 0
- inputPort:
nodeID: b882f7b7-9f8b-43ef-a79a-33d4e874edd0
nodeType: Texture2DOutput
portID: 2
outputPort:
nodeID: 9b32fc10-fda3-4faa-82ac-efcff95a5138
nodeType: Texture2DImport
portID: 2
- inputPort:
nodeID: 97953833-bdf9-47b5-b1d2-b4cbfa19f57a
nodeType: StringAppend
portID: 0
outputPort:
nodeID: 9b32fc10-fda3-4faa-82ac-efcff95a5138
nodeType: Texture2DImport
portID: 1
- inputPort:
nodeID: b882f7b7-9f8b-43ef-a79a-33d4e874edd0
nodeType: Texture2DOutput
portID: 1
outputPort:
nodeID: 97953833-bdf9-47b5-b1d2-b4cbfa19f57a
nodeType: StringAppend
portID: 0
- inputPort:
nodeID: 3abef457-f0ec-456e-baa8-e8ae657b49e4
nodeType: RGBASCombine
portID: 2
outputPort:
nodeID: 1c21d8e6-5b93-4a6f-a7ff-7322be2d20be
nodeType: RGBASplit
portID: 3
- inputPort:
nodeID: 3abef457-f0ec-456e-baa8-e8ae657b49e4
nodeType: RGBASCombine
portID: 3
outputPort:
nodeID: 1c21d8e6-5b93-4a6f-a7ff-7322be2d20be
nodeType: RGBASplit
portID: 2
references:
version: 2
RefIds:
- rid: 6869590814762467406
type: {class: Texture2DImport, ns: ImageProcessingGraph.Editor.Nodes.Import_Nodes, asm: ImageProcessingGraphEditor}
data:
guid: ac4be66e-d3b8-4633-a692-60cb30579f97
position:
serializedVersion: 2
x: -285.5
y: 18
width: 311
height: 125
typeName: ImageProcessingGraph.Editor.Nodes.Import_Nodes.Texture2DImport,
ImageProcessingGraphEditor, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
asset: {fileID: 11400000}
textureImport: {fileID: 2800000, guid: 44da9e368ce69454aa6ccc40919a7f50, type: 3}
fileName:
filePath:
- rid: 6869590814762467407
type: {class: Texture2DImport, ns: ImageProcessingGraph.Editor.Nodes.Import_Nodes, asm: ImageProcessingGraphEditor}
data:
guid: 9b32fc10-fda3-4faa-82ac-efcff95a5138
position:
serializedVersion: 2
x: -287
y: 292
width: 288
height: 125
typeName: ImageProcessingGraph.Editor.Nodes.Import_Nodes.Texture2DImport,
ImageProcessingGraphEditor, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
asset: {fileID: 11400000}
textureImport: {fileID: 2800000, guid: 1640d081a2287448cb2a75fba48b9dcf, type: 3}
fileName:
filePath:
- rid: 6869590814762467408
type: {class: RGBASplit, ns: ImageProcessingGraph.Editor.Nodes.Fun_Nodes.Texture, asm: ImageProcessingGraphEditor}
data:
guid: 87c7a966-55ec-42aa-a537-73ebe906412b
position:
serializedVersion: 2
x: 124
y: 18
width: 138
height: 149
typeName: ImageProcessingGraph.Editor.Nodes.Fun_Nodes.Texture.RGBASplit,
ImageProcessingGraphEditor, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
asset: {fileID: 11400000}
- rid: 6869590814762467409
type: {class: RGBASplit, ns: ImageProcessingGraph.Editor.Nodes.Fun_Nodes.Texture, asm: ImageProcessingGraphEditor}
data:
guid: 1c21d8e6-5b93-4a6f-a7ff-7322be2d20be
position:
serializedVersion: 2
x: 124
y: 167
width: 138
height: 149
typeName: ImageProcessingGraph.Editor.Nodes.Fun_Nodes.Texture.RGBASplit,
ImageProcessingGraphEditor, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
asset: {fileID: 11400000}
- rid: 6869590814762467410
type: {class: RGBASCombine, ns: ImageProcessingGraph.Editor.Nodes.Fun_Nodes.Texture, asm: ImageProcessingGraphEditor}
data:
guid: 3abef457-f0ec-456e-baa8-e8ae657b49e4
position:
serializedVersion: 2
x: 315.5
y: 92.5
width: 138
height: 149
typeName: ImageProcessingGraph.Editor.Nodes.Fun_Nodes.Texture.RGBASCombine,
ImageProcessingGraphEditor, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
asset: {fileID: 11400000}
- rid: 6869590814762467411
type: {class: Texture2DOutput, ns: ImageProcessingGraph.Editor.Nodes.Output, asm: ImageProcessingGraphEditor}
data:
guid: b882f7b7-9f8b-43ef-a79a-33d4e874edd0
position:
serializedVersion: 2
x: 559.5
y: 143
width: 129.5
height: 125
typeName: ImageProcessingGraph.Editor.Nodes.Output.Texture2DOutput, ImageProcessingGraphEditor,
Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
asset: {fileID: 11400000}
fileName:
fileDirectory:
- rid: 6869590814762467412
type: {class: StringAppend, ns: ImageProcessingGraph.Editor.Nodes.String_Nodes, asm: ImageProcessingGraphEditor}
data:
guid: 97953833-bdf9-47b5-b1d2-b4cbfa19f57a
position:
serializedVersion: 2
x: 124
y: 450.5
width: 248
height: 101
typeName: ImageProcessingGraph.Editor.Nodes.String_Nodes.StringAppend, ImageProcessingGraphEditor,
Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
asset: {fileID: 11400000}
baseString:
appendString: _MAS
output:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d04964bb165ef4820be34fe3f050be61
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

8
Icons.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2d724fe0ba9ad8949bac2c328d3d8288
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1,117 @@
fileFormatVersion: 2
guid: 91cfc70686fca0145b2b37b8b1db5dff
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 0
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 0
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 2
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 4
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
customData:
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:

8
Scripts.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d50733debc2a73c43b07c45bcac43761
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
Scripts/Editor.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7dab1883baf68bf47b782e97d8b6aa42
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 92c5327ff293bff4392ca3d8d16245cc
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,25 @@
using System;
using UnityEditor.Experimental.GraphView;
using UnityEngine.UIElements;
namespace ImageProcessingGraph.Editor
{
public class IPTPort : Port
{
protected IPTPort(Orientation portOrientation, Direction portDirection, Capacity portCapacity, Type type) : base(portOrientation, portDirection, portCapacity, type)
{
}
public static IPTPort Create(IEdgeConnectorListener connectorListener, bool isInput, Type type)
{
var port = new IPTPort(Orientation.Horizontal, isInput ? Direction.Input : Direction.Output,
Capacity.Multi, type)
{
m_EdgeConnector = new EdgeConnector<Edge>(connectorListener),
};
port.AddManipulator(port.m_EdgeConnector);
return port;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0dd88ad7d397423897de6832d315ee7f
timeCreated: 1745310679

View File

@ -0,0 +1,18 @@
using UnityEngine;
namespace ImageProcessingGraph.Editor
{
#if true
[CreateAssetMenu(menuName = "PreferenceCreate")]
#endif
public class IPT_Preferences : ScriptableObject
{
[Header("Grid Settings")]
public float thickLines;
public float spacing;
public Color gridBackgroundColour;
public Color lineColour;
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 80dcc02594d68e3439df7dc743c9d4b2

View File

@ -0,0 +1,65 @@
using Unity.Collections;
using UnityEngine;
/// <summary>
/// A structure that holds image pixel data and its dimensions.
/// </summary>
public struct ImageData
{
/// <summary>
/// The pixel data of the image in Color32 format.
/// </summary>
public NativeArray<Color32> PixelData;
/// <summary>
/// The width and height of the image (width, height).
/// </summary>
public (int width, int height) Dimensions;
public bool isRGBA;
/// <summary>
/// Initializes a new instance of the <see cref="ImageData"/> struct using existing pixel data and dimensions.
/// </summary>
/// <param name="imageData">The pixel data as a NativeArray of Color32.</param>
/// <param name="widthHeight">A tuple containing the width and height of the image.</param>
public ImageData(NativeArray<Color32> imageData, (int width, int height) widthHeight, bool isRgba)
{
PixelData = imageData;
Dimensions = widthHeight;
isRGBA = isRgba;
}
/// <summary>
/// Initializes a new instance of the <see cref="ImageData"/> struct from a Texture2D object.
/// </summary>
/// <param name="sourceTexture">The source texture to extract pixel data from.</param>
public ImageData(Texture2D sourceTexture)
{
PixelData = sourceTexture.GetPixelData<Color32>(0);
Dimensions = (sourceTexture.width, sourceTexture.height);
isRGBA = sourceTexture.format == TextureFormat.RGBA32;
}
/// <summary>
/// Gets the width of the image.
/// </summary>
public int Width => Dimensions.width;
/// <summary>
/// Gets the height of the image.
/// </summary>
public int Height => Dimensions.height;
/// <summary>
/// Converts the ImageData back into a new Texture2D.
/// </summary>
/// <returns>A Texture2D object created from the stored pixel data.</returns>
public Texture2D ToTexture2D()
{
var texture = new Texture2D(Width, Height, TextureFormat.RGBA32, false);
texture.LoadRawTextureData(PixelData);
texture.Apply();
return texture;
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2bb77fbc2c734e888e52e39ab92264a9
timeCreated: 1745264169

View File

@ -0,0 +1,47 @@
using UnityEngine;
/// <summary>
/// Represents a single image channel (e.g., Red, Green, Blue, Alpha) as a 1D byte array,
/// along with the original image dimensions.
/// </summary>
public struct SplitChannelData
{
/// <summary>
/// The 8-bit intensity values for a single image channel, stored in row-major order.
/// </summary>
public byte[] ChannelData;
/// <summary>
/// The width and height of the channel data (width, height).
/// </summary>
public (int width, int height) Dimensions;
/// <summary>
/// Initializes a new instance of the <see cref="SplitChannelData"/> struct
/// using channel data and dimensions.
/// </summary>
/// <param name="channelData">The byte array representing the single channel values.</param>
/// <param name="widthHeight">A tuple of (width, height) representing the dimensions.</param>
public SplitChannelData(byte[] channelData, (int width, int height) widthHeight)
{
ChannelData = channelData;
Dimensions = widthHeight;
}
/// <summary>
/// Gets the width of the channel data.
/// </summary>
public int Width => Dimensions.width;
/// <summary>
/// Gets the height of the channel data.
/// </summary>
public int Height => Dimensions.height;
/// <summary>
/// Checks whether the channel data is valid (non-null and matches the expected size).
/// </summary>
public bool IsValid => ChannelData != null && ChannelData.Length == Width * Height;
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c36c5c00054e46b191b4d21913512433
timeCreated: 1745278300

View File

@ -0,0 +1,18 @@
{
"name": "ImageProcessingGraphEditor",
"rootNamespace": "ImageProcessingGraph.Editor",
"references": [
"GUID:2665a8d13d1b3f18800f46e256720795"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 3f5213b0645cf234f941e3b3d706a65a
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,150 @@
using ImageProcessingGraph.Editor.Windows;
using UnityEngine;
using UnityEditor;
using UnityEditor.Callbacks;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using UnityEditor.Experimental.GraphView;
using Debug = UnityEngine.Debug;
// ReSharper disable once CheckNamespace
namespace ImageProcessingGraph.Editor
{
[CreateAssetMenu(menuName = "Image Processing Graph/New Graph")]
public class ImageProcessingGraphAsset : ScriptableObject
{
[SerializeReference] private List<BaseImageNode> nodes;
[SerializeField] private List<GraphConnection> connections;
[SerializeField] public List<BaseImageNode> runOrder;
[SerializeField] public List<StickyNote> stickyNotes;
public List<BaseImageNode> Nodes => nodes;
public List<GraphConnection> Connections => connections;
public ImageProcessingGraphAsset()
{
nodes = new List<BaseImageNode>();
connections = new List<GraphConnection>();
}
[OnOpenAsset(1)]
public static bool OpenGraphAsset(int instanceID, int line)
{
var asset = EditorUtility.InstanceIDToObject(instanceID) as ImageProcessingGraphAsset;
if (asset != null)
{
ImageProcessingGraphEditorWindow.Open(asset);
return true;
}
return false;
}
public void RunGraph()
{
// Create and start the stopwatch to measure time
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
if (runOrder == null)
runOrder = GetExecutionOrder(this.nodes, this.connections);
foreach (var VARIABLE in runOrder)
{
VARIABLE.RunNode();
}
// Stop the stopwatch after running the nodes
stopwatch.Stop();
// Log the elapsed time
UnityEngine.Debug.Log($"Graph execution took {stopwatch.ElapsedMilliseconds} milliseconds.");
}
/// <summary>
/// Computes a topological execution order of nodes based on their dependencies.
/// Throws if a cycle is detected or nodes are missing from the input list.
/// </summary>
public List<BaseImageNode> GetExecutionOrder(List<BaseImageNode> nodes, List<GraphConnection> connections, bool debug = false)
{
// === Initialization ===
var nodeMap = new Dictionary<string, BaseImageNode>(nodes.Count);
var adjList = new Dictionary<string, List<string>>(nodes.Count);
var inDegree = new Dictionary<string, int>(nodes.Count);
foreach (var node in nodes)
{
string id = node.ID;
nodeMap[id] = node;
adjList[id] = new List<string>();
inDegree[id] = 0;
}
// === Build Graph ===
foreach (var conn in connections)
{
string from = conn.outputPort.nodeID;
string to = conn.inputPort.nodeID;
if (!nodeMap.ContainsKey(from) || !nodeMap.ContainsKey(to))
throw new System.Exception($"Invalid connection: '{from}' → '{to}' (One or both node IDs not found)");
adjList[from].Add(to);
inDegree[to]++;
}
if (debug)
{
Debug.Log("=== Dependency Graph ===");
foreach (var from in adjList.Keys)
{
var outputs = string.Join(", ", adjList[from].Select(t => $"{nodeMap[t].typeName} ({t})"));
Debug.Log($"[{nodeMap[from].typeName}] ({from}) → [{outputs}]");
}
Debug.Log("=========================");
}
// === Topological Sort (Kahn's Algorithm) ===
var executionOrder = new List<BaseImageNode>(nodes.Count);
var queue = new Queue<string>(nodes.Count);
foreach (var kvp in inDegree)
{
if (kvp.Value == 0)
queue.Enqueue(kvp.Key);
}
while (queue.Count > 0)
{
string currentID = queue.Dequeue();
executionOrder.Add(nodeMap[currentID]);
foreach (var neighbor in adjList[currentID])
{
inDegree[neighbor]--;
if (inDegree[neighbor] == 0)
queue.Enqueue(neighbor);
}
}
if (executionOrder.Count != nodes.Count)
{
var remaining = string.Join(", ", inDegree.Where(p => p.Value > 0).Select(p => $"{nodeMap[p.Key].typeName} ({p.Key})"));
throw new System.Exception($"Cycle detected in graph. Remaining nodes: {remaining}");
}
if (debug)
{
Debug.Log("=== Execution Order ===");
foreach (var n in executionOrder)
Debug.Log($"→ {n.typeName} ({n.ID})");
}
return executionOrder;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1da462fd3f736d04e80556b4ac8b470f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 91cfc70686fca0145b2b37b8b1db5dff, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8726affebc717064db4f447f8569089d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b0d7dde0b49a3224f9876502af464973
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,117 @@
using System;
using System.Configuration;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using ImageProcessingGraph.Editor.Nodes.NodeAttributes;
using System.Collections.Generic;
using Input = ImageProcessingGraph.Editor.Nodes.NodeAttributes.Input;
using System.Linq;
using System.Reflection;
namespace ImageProcessingGraph.Editor
{
[System.Serializable]
public abstract class BaseImageNode
{
[SerializeField] private string guid;
[SerializeField] private Rect position;
[SerializeField] public string typeName;
[SerializeField] public (int, int) widthHeight;
public string ID => guid;
public Rect Position => position;
public ImageProcessingGraphAsset asset;
public BaseImageNode()
{
guid = Guid.NewGuid().ToString();
/*Type t = this.GetType();
Debug.Log(t.Name);*/
}
public void SetNodeInputs()
{
Type type = this.GetType();
string t = type.Name;
FieldInfo[] properties = type.GetFields();
var inputProperties = properties
.Where(p => p.IsDefined(typeof(Input), false)).ToList();
foreach (var inputProperty in inputProperties)
{
// Find the connection that leads to this input property
GraphConnection connection = default;
foreach (var conn in asset.Connections)
{
if (conn.inputPort.nodeID == this.ID)
{
if (conn.inputPort.portID == inputProperties.IndexOf(inputProperty))
{
connection = conn;
break;
}
}
}
if (connection.Equals((default(GraphConnection))))
return;
// Get the output node from the connection
var outputNode = asset.Nodes.FirstOrDefault(n => n.ID == connection.outputPort.nodeID);
if (outputNode != null)
{
// Use reflection to get the output data from the output node's corresponding output property
Type outputType = outputNode.GetType();
FieldInfo[] fields = outputType.GetFields();
var outputFields = fields
.Where(p => p.IsDefined(typeof(Output), false)).ToList();
FieldInfo outputProperty = null;
foreach (var da in outputFields)
{
if (outputFields.IndexOf(da) == connection.outputPort.portID)
{
outputProperty = da;
break;
}
}
/*var outputProperty = outputNode.GetType().GetProperties()
.FirstOrDefault(p => p.IsDefined(typeof(Output), false) &&
outputFields == connection.outputPort.portID);*/
if (outputProperty != null)
{
// Assign the output data to the input property
var outputData = outputProperty.GetValue(outputNode);
inputProperty.SetValue(this, outputData);
}
}
}
}
public void RunNode()
{
SetNodeInputs();
this.Process();
}
public virtual void Process()
{
Debug.Log("Uppies");
}
public void SetPosition(Rect position) => this.position = position;
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 16aeb4367cd62fa4f8a0f72ee6eaa03b

View File

@ -0,0 +1,13 @@
using System;
using UnityEditor.Experimental.GraphView;
namespace ImageProcessingGraph.Editor
{
public class ExposedPropertyPort : Port
{
protected ExposedPropertyPort(Orientation portOrientation, Direction portDirection, Capacity portCapacity, Type type) : base(portOrientation, portDirection, portCapacity, type)
{
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 31313dec455d4407bb6fffc7b167dabb
timeCreated: 1743744035

View File

@ -0,0 +1,36 @@
namespace ImageProcessingGraph.Editor
{
[System.Serializable]
public struct GraphConnection
{
public GraphPort inputPort;
public GraphPort outputPort;
public GraphConnection(GraphPort inputPort, GraphPort outputPort)
{
this.inputPort = inputPort;
this.outputPort = outputPort;
}
public GraphConnection(string inputNodeGuid, int inputPortID, string inputNodeType, string outputNodeGuid, int outputPortID, string outputNodeType)
{
this.inputPort = new GraphPort(inputNodeGuid, inputPortID, inputNodeType);
this.outputPort = new GraphPort(outputNodeGuid, outputPortID, outputNodeType);
}
}
[System.Serializable]
public struct GraphPort
{
public string nodeID;
public string nodeType;
public int portID;
public GraphPort(string nodeID, int portID, string nodeType)
{
this.nodeID = nodeID;
this.portID = portID;
this.nodeType = nodeType;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 10b473e8e8494d6eb4c4f34a4b41d4bd
timeCreated: 1743739124

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ca37b9337d41484892c89933479f1e7f
timeCreated: 1743745541

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1646a2bcaf6b4de488cadad1d7cdf795
timeCreated: 1743747481

View File

@ -0,0 +1,75 @@
using ImageProcessingGraph.Editor.Nodes.NodeAttributes;
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;
namespace ImageProcessingGraph.Editor.Nodes.Fun_Nodes.Texture
{
[NodeInfo("RGBA Combine", "Channels/RGBA Combine", true)]
public class RGBASCombine : BaseImageNode
{
[NodeAttributes.Input("R")]
public SplitChannelData r;
[NodeAttributes.Input("G")]
public SplitChannelData g;
[NodeAttributes.Input("B")]
public SplitChannelData b;
[NodeAttributes.Input("A")]
public SplitChannelData a;
[NodeAttributes.Output("")]
public ImageData inputTexture;
// Job struct for combining RGBA channels
struct RGBACombineJob : IJob
{
public NativeArray<byte> rData;
public NativeArray<byte> gData;
public NativeArray<byte> bData;
public NativeArray<byte> aData;
public NativeArray<Color32> outputData;
public int length;
// Execute method to combine the RGBA channels into a Color32 array
public void Execute()
{
for (int i = 0; i < length; i++)
{
outputData[i] = new Color32(rData[i], gData[i], bData[i], aData[i]);
}
}
}
public override void Process()
{
int length = r.ChannelData.Length;
// Allocate NativeArrays for the RGBA channels and the output pixel data
NativeArray<byte> rChannel = new NativeArray<byte>(r.ChannelData, Allocator.Persistent);
NativeArray<byte> gChannel = new NativeArray<byte>(g.ChannelData, Allocator.Persistent);
NativeArray<byte> bChannel = new NativeArray<byte>(b.ChannelData, Allocator.Persistent);
NativeArray<byte> aChannel = new NativeArray<byte>(a.ChannelData, Allocator.Persistent);
NativeArray<Color32> outputPixels = new NativeArray<Color32>(length, Allocator.Persistent);
// Create the job to combine RGBA channels
RGBACombineJob combineJob = new RGBACombineJob
{
rData = rChannel,
gData = gChannel,
bData = bChannel,
aData = aChannel,
outputData = outputPixels,
length = length
};
combineJob.Run();
// Create the ImageData object with the combined pixel data
inputTexture = new ImageData(outputPixels, (r.Width, r.Height), false);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3fa83fcfe5464559975d25d6d55cb799
timeCreated: 1743750468

View File

@ -0,0 +1,78 @@
using ImageProcessingGraph.Editor.Nodes.NodeAttributes;
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;
namespace ImageProcessingGraph.Editor.Nodes.Fun_Nodes.Texture
{
[NodeInfoAttribute("RGBA Split", "Channels/RGBA Split", true)]
public class RGBASplit : BaseImageNode
{
[NodeAttributes.Input("")]
public ImageData inputTexture;
[NodeAttributes.Output("R")]
public SplitChannelData r;
[NodeAttributes.Output("G")]
public SplitChannelData g;
[NodeAttributes.Output("B")]
public SplitChannelData b;
[NodeAttributes.Output("A")]
public SplitChannelData a;
public override void Process()
{
int length = inputTexture.PixelData.Length;
// Allocate NativeArrays for the pixel data and the individual RGBA channels
NativeArray<Color32> pixelData = new NativeArray<Color32>(inputTexture.PixelData, Allocator.Persistent);
NativeArray<byte> rChannel = new NativeArray<byte>(length, Allocator.Persistent);
NativeArray<byte> gChannel = new NativeArray<byte>(length, Allocator.Persistent);
NativeArray<byte> bChannel = new NativeArray<byte>(length, Allocator.Persistent);
NativeArray<byte> aChannel = new NativeArray<byte>(length, Allocator.Persistent);
// Create the job and set up the input/output data
RGBAJob rgbaJob = new RGBAJob
{
pixelData = pixelData,
rData = rChannel,
gData = gChannel,
bData = bChannel,
aData = aChannel,
length = length
};
rgbaJob.Run();
// Store the results in the SplitChannelData objects
r = new SplitChannelData(rChannel.ToArray(), (inputTexture.Width, inputTexture.Height));
g = new SplitChannelData(gChannel.ToArray(), (inputTexture.Width, inputTexture.Height));
b = new SplitChannelData(bChannel.ToArray(), (inputTexture.Width, inputTexture.Height));
a = new SplitChannelData(aChannel.ToArray(), (inputTexture.Width, inputTexture.Height));
}
}
// Job struct for processing the image data
struct RGBAJob : IJob
{
public NativeArray<Color32> pixelData;
public NativeArray<byte> rData;
public NativeArray<byte> gData;
public NativeArray<byte> bData;
public NativeArray<byte> aData;
public int length;
// Execute method that splits the RGBA channels
public void Execute()
{
for (int i = 0; i < length; i++)
{
Color32 pixel = pixelData[i];
rData[i] = pixel.r;
gData[i] = pixel.g;
bData[i] = pixel.b;
aData[i] = pixel.a;
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c185fc298d59474cb453bf54b4f0aea8
timeCreated: 1743747489

View File

@ -0,0 +1,53 @@
using ImageProcessingGraph.Editor.Nodes.NodeAttributes;
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;
namespace ImageProcessingGraph.Editor.Nodes.Fun_Nodes.Texture
{
[NodeInfoAttribute("Desaturate", "Adjustments/Desaturate", true)]
public class Texture2DDesaturate : BaseImageNode
{
[NodeAttributes.Input("")]
public ImageData inputTexture; // Changed to ImageData
[NodeAttributes.Output("")]
public ImageData outputTexture; // Changed to ImageData
public override void Process()
{
NativeArray<Color32> output = new NativeArray<Color32>(inputTexture.PixelData.Length, Allocator.Persistent);
DesaturateJob job = new DesaturateJob
{
pixels = inputTexture.PixelData,
outputPixels = output
};
job.Run();
outputTexture = new ImageData(output, (inputTexture.Width, inputTexture.Height), inputTexture.isRGBA);
}
}
public struct DesaturateJob : IJob
{
[ReadOnly] public NativeArray<Color32> pixels;
public NativeArray<Color32> outputPixels;
public void Execute()
{
for (int i = 0; i < pixels.Length; i++)
{
Color32 pixel = pixels[i];
byte grayValue = (byte)(0.2989f * pixel.r + 0.5870f * pixel.g + 0.1140f * pixel.b);
outputPixels[i] = new Color32(grayValue, grayValue, grayValue, pixel.a);
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a3e2d8c461684005a1286dcbc985dbbf
timeCreated: 1745291300

View File

@ -0,0 +1,59 @@
using ImageProcessingGraph.Editor.Nodes.NodeAttributes;
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;
namespace ImageProcessingGraph.Editor.Nodes.Fun_Nodes.Texture
{
[NodeInfoAttribute("Invert", "Adjustments/Invert", true)]
public class Texture2DInvert : BaseImageNode
{
[NodeAttributes.Input("")]
public ImageData inputTexture; // Changed to ImageData
[NodeAttributes.Output("")]
public ImageData outputTexture; // Changed to ImageData
public override void Process()
{
// Create an empty NativeArray for the output
NativeArray<Color32> output = new NativeArray<Color32>(inputTexture.PixelData.Length, Allocator.Persistent);
// Create and run the InvertJob
InvertJob job = new InvertJob
{
pixels = inputTexture.PixelData,
outputPixels = output
};
job.Run();
// Store the result in the outputImage as an ImageData instance
outputTexture = new ImageData(output, (inputTexture.Width, inputTexture.Height), inputTexture.isRGBA);
}
}
[BurstCompile]
public struct InvertJob : IJob
{
[ReadOnly] public NativeArray<Color32> pixels; // Input pixels
[WriteOnly] public NativeArray<Color32> outputPixels; // Output pixels
public void Execute()
{
int length = pixels.Length;
// Invert each pixel color
for (int i = 0; i < length; i++)
{
Color32 pixel = pixels[i];
outputPixels[i] = new Color32(
(byte)(255 - pixel.r),
(byte)(255 - pixel.g),
(byte)(255 - pixel.b),
pixel.a);
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d95b796b51a64fac8947aa4325b0373d
timeCreated: 1743747802

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e0ffc7091a5ca0244a56716dc57b6c86
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 22b0f0e553dc85e489979a232505a332
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,34 @@
using System.IO;
using ImageProcessingGraph.Editor.Nodes.NodeAttributes;
using Unity.Collections;
using UnityEditor;
using UnityEngine;
namespace ImageProcessingGraph.Editor.Nodes.Import_Nodes
{
[NodeInfo("Texture Import", "Imports/Texture2D", true)]
public class Texture2DImport : BaseImageNode
{
[NodeAttributes.Input("")]
public Texture2D textureImport;
[NodeAttributes.Output("")]
public ImageData textureOutput;
[NodeAttributes.Output("File Name")]
public string fileName;
[NodeAttributes.Output("File Path")]
public string filePath;
public override void Process()
{
if (this.textureImport != null)
{
this.textureOutput = new ImageData(textureImport);
this.fileName = textureImport.name;
this.filePath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(textureImport));
}
else
Debug.LogError("UH!");
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 349192a0abdc4544888b8b537dea9c74
timeCreated: 1743745590

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: dbd7cd37cae147f3a54f12c52ef54217
timeCreated: 1742158168

View File

@ -0,0 +1,17 @@
using UnityEngine;
using System.Collections;
public class NewMonoBehaviour : MonoBehaviour
{
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 78c0de359ceae406cb2985637a2e6c97

View File

@ -0,0 +1,45 @@
using System;
namespace ImageProcessingGraph.Editor.Nodes.NodeAttributes
{
[AttributeUsage(AttributeTargets.Class)]
public class NodeInfoAttribute : Attribute
{
private string name;
private string menuItem;
private string ussPath;
public string Title => name;
public string MenuItem => menuItem;
public string UssPath => ussPath;
public NodeInfoAttribute(string name, string menuItem = "", bool requiresImage = false, string ussPath = null)
{
this.name = name;
this.menuItem = menuItem;
this.ussPath = ussPath;
}
}
[AttributeUsage(AttributeTargets.Field)]
public class Input : Attribute
{
public string Label { get; }
public Input(string _label)
{
Label = _label;
}
}
[AttributeUsage(AttributeTargets.Field)]
public class Output : Attribute
{
public string Label { get; }
public Output(string _label)
{
Label = _label;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a46f5cb221ec44348c340aeb91b54b6c
timeCreated: 1742158180

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 80a64ea121f9494d931173b10cce68b3
timeCreated: 1743749784

View File

@ -0,0 +1,20 @@
using ImageProcessingGraph.Editor.Nodes.NodeAttributes;
using Unity.Collections;
using UnityEditor;
using UnityEngine;
namespace ImageProcessingGraph.Editor.Nodes.Output
{
[NodeInfo("Texture Export", "Export/Texture2D", true)]
public class Texture2DOutput : BaseImageNode
{
[NodeAttributes.Input("")] public ImageData inputPixels;
[NodeAttributes.Input("File Name")] public string fileName;
[NodeAttributes.Input("File Path")] public string fileDirectory;
public override void Process()
{
AssetDatabase.CreateAsset(inputPixels.ToTexture2D(), $"{fileDirectory}/{fileName}.asset");
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 10f83f7df222436c8495916067139b91
timeCreated: 1743750878

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 587f3b2d6fad453fbf6664066f807f21
timeCreated: 1745299284

View File

@ -0,0 +1,18 @@
using ImageProcessingGraph.Editor.Nodes.NodeAttributes;
namespace ImageProcessingGraph.Editor.Nodes.String_Nodes
{
[NodeInfo("String Append", "String/Append")]
public class StringAppend : BaseImageNode
{
[NodeAttributes.Input("String A")] public string baseString;
[NodeAttributes.Input("String B")] public string appendString;
[NodeAttributes.Output("Appended String")] public string output;
public override void Process()
{
this.output = baseString + appendString;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 52ee2568ed5f4c5da8fb920672d1aa96
timeCreated: 1745299310

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1754e13556323a64ea0fe2a83fe4c82d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,30 @@
using UnityEditor;
using UnityEngine;
namespace ImageProcessingGraph.Editor.Windows
{
[CustomEditor(typeof(ImageProcessingGraphAsset))]
public class ImageProcessingGraphAssetEditorWindow : UnityEditor.Editor
{
public override void OnInspectorGUI()
{
if (GUILayout.Button("Open"))
{
ImageProcessingGraphEditorWindow.Open((ImageProcessingGraphAsset)target);
}
if(GUILayout.Button("Calculate Dependancy Graph"))
{
var bleh = (ImageProcessingGraphAsset)target;
bleh.runOrder = bleh.GetExecutionOrder(bleh.Nodes, bleh.Connections, true);
}
if(GUILayout.Button("Run Graph"))
{
var bleh = (ImageProcessingGraphAsset)target;
bleh.RunGraph();
}
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 5341664b296612f4dbc6d242c853bd7d

View File

@ -0,0 +1,67 @@
using System.Collections.Generic;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.UIElements;
namespace ImageProcessingGraph.Editor.Unity_Image_Processing.Scripts.Editor.Windows
{
public class ImageProcessingGraphEdgeConnectorListener : IEdgeConnectorListener
{
private GraphViewChange m_GraphViewChange;
private List<Edge> m_EdgesToCreate;
private List<GraphElement> m_EdgesToDelete;
private ImageProcessingGraphViewWindow window;
public ImageProcessingGraphEdgeConnectorListener(ImageProcessingGraphViewWindow window)
{
this.m_EdgesToCreate = new List<Edge>();
this.m_EdgesToDelete = new List<GraphElement>();
this.m_GraphViewChange.edgesToCreate = this.m_EdgesToCreate;
this.window = window;
}
public void OnDropOutsidePort(Edge edge, Vector2 position)
{
window.searchProvider.target = (VisualElement)window.focusController.focusedElement;
SearchWindow.Open(new SearchWindowContext(position), window.searchProvider);
}
public void OnDrop(UnityEditor.Experimental.GraphView.GraphView graphView, Edge edge)
{
this.m_EdgesToCreate.Clear();
this.m_EdgesToCreate.Add(edge);
this.m_EdgesToDelete.Clear();
if (edge.input.capacity == Port.Capacity.Single)
{
foreach (Edge connection in edge.input.connections)
{
if (connection != edge)
this.m_EdgesToDelete.Add((GraphElement)connection);
}
}
if (edge.output.capacity == Port.Capacity.Single)
{
foreach (Edge connection in edge.output.connections)
{
if (connection != edge)
this.m_EdgesToDelete.Add((GraphElement)connection);
}
}
if (this.m_EdgesToDelete.Count > 0)
graphView.DeleteElements((IEnumerable<GraphElement>)this.m_EdgesToDelete);
List<Edge> edgesToCreate = this.m_EdgesToCreate;
if (graphView.graphViewChanged != null)
edgesToCreate = graphView.graphViewChanged(this.m_GraphViewChange).edgesToCreate;
foreach (Edge edge1 in edgesToCreate)
{
graphView.AddElement((GraphElement)edge1);
edge.input.Connect(edge1);
edge.output.Connect(edge1);
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e55abc4baf7246aca9ebafb2c3aa793b
timeCreated: 1745309249

View File

@ -0,0 +1,71 @@
using System;
using UnityEditor;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
namespace ImageProcessingGraph.Editor.Windows
{
public class ImageProcessingGraphEditorWindow : EditorWindow
{
[SerializeField] private ImageProcessingGraphAsset currentGraph;
[SerializeField] private SerializedObject serializedObject;
[SerializeField] private ImageProcessingGraphViewWindow currentView;
public ImageProcessingGraphAsset CurrentGraph => currentGraph;
public static void Open(ImageProcessingGraphAsset asset)
{
ImageProcessingGraphEditorWindow[] windows = Resources.FindObjectsOfTypeAll<ImageProcessingGraphEditorWindow>();
foreach (var w in windows)
{
w.Focus();
return;
}
ImageProcessingGraphEditorWindow window =
CreateWindow<ImageProcessingGraphEditorWindow>(typeof(ImageProcessingGraphEditorWindow),
typeof(SceneView));
window.titleContent = new GUIContent($"{asset.name}", EditorGUIUtility.ObjectContent(null, typeof(ImageProcessingGraphAsset)).image
);
window.Load(asset);
}
void OnEnable()
{
if(currentGraph != null)
DrawGraph();
}
private void OnGUI()
{
if (currentGraph != null)
{
if(EditorUtility.IsDirty(currentGraph))
this.hasUnsavedChanges = true;
else
this.hasUnsavedChanges = false;
}
}
public void Load(ImageProcessingGraphAsset asset)
{
currentGraph = asset;
DrawGraph();
}
public void DrawGraph()
{
serializedObject = new SerializedObject(currentGraph);
currentView = new ImageProcessingGraphViewWindow(serializedObject, this);
currentView.graphViewChanged += OnChange;
rootVisualElement.Add(currentView);
}
private GraphViewChange OnChange(GraphViewChange graphviewchange)
{
EditorUtility.SetDirty(currentGraph);
return graphviewchange;
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 42279c09a8e81c844ab9651b6165a1e8

View File

@ -0,0 +1,245 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using ImageProcessingGraph.Editor.Nodes.NodeAttributes;
using UnityEditor.Experimental.GraphView;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
using Input = ImageProcessingGraph.Editor.Nodes.NodeAttributes.Input;
namespace ImageProcessingGraph.Editor.Unity_Image_Processing.Scripts.Editor.Windows
{
public class ImageProcessingGraphNodeVisual : Node
{
private BaseImageNode graphNode;
public BaseImageNode GraphNode => graphNode;
public List<Port> InputPorts { get; }
public List<Port> OutputPorts { get; }
private ImageProcessingGraphViewWindow window;
public ImageProcessingGraphNodeVisual(BaseImageNode node, ImageProcessingGraphViewWindow window)
{
this.AddToClassList("image-node-visual");
this.window = window;
graphNode = node;
Type typeInfo = node.GetType();
NodeInfoAttribute info = typeInfo.GetCustomAttribute<NodeInfoAttribute>();
title = info.Title;
string[] depths = info.MenuItem.Split('/');
foreach (var depth in depths)
{
this.AddToClassList(depth.ToLower().Replace(' ', '-'));
}
this.InputPorts = new List<Port>();
this.OutputPorts = new List<Port>();
List<Input> inputs = new List<Input>();
List<FieldInfo> inputFieldInfo = new List<FieldInfo>();
List<FieldInfo> outputFieldInfo = new List<FieldInfo>();
FieldInfo[] fields = typeInfo.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
foreach (var field in fields)
{
if (field.GetCustomAttribute(typeof(Input)) != null)
{
Input input = field.GetCustomAttribute<Input>();
inputs.Add(input);
inputFieldInfo.Add(field);
}
if (field.GetCustomAttribute(typeof(Output)) != null)
{
Output output = field.GetCustomAttribute<Output>();
outputFieldInfo.Add(field);
}
}
CreateInputPorts(inputFieldInfo);
CreateOutputPorts(outputFieldInfo);
this.name = typeInfo.Name;
}
private void CreateInputPorts(List<FieldInfo> fields)
{
for (var index = 0; index < fields.Count; index++)
{
var field = fields[index];
/*
Port port = InstantiatePort(Orientation.Horizontal, Direction.Input, Port.Capacity.Multi, field.FieldType);
*/
var port = IPTPort.Create(window.edgeConnectorListener, true, field.FieldType);
string label = field.GetCustomAttribute<Input>().Label;
if (label != "")
port.portName = label;
InputPorts.Add(port);
inputContainer.Add(port);
ExposeVariableToPort(port, field);
}
}
private void CreateOutputPorts(List<FieldInfo> fields)
{
for (var index = 0; index < fields.Count; index++)
{
var field = fields[index];
var port = IPTPort.Create(window.edgeConnectorListener, false, field.FieldType);
string label = field.GetCustomAttribute<Output>().Label;
if (label != "")
port.portName = label;
OutputPorts.Add(port);
outputContainer.Add(port);
}
}
// Exposes a variable on the port for editing when it's not connected
private void ExposeVariableToPort(Port port, FieldInfo field)
{
// Only expose when the port is not connected
if (port.connections.Count() == 0)
{
var propertyFieldContainer = new VisualElement();
propertyFieldContainer.name = "property-field-container";
var propertyField = CreatePropertyFieldForType(field.FieldType, field.GetValue(graphNode));
if (propertyField != null)
{
// Register a callback for when the value changes
if (propertyField is IntegerField intField)
{
intField.RegisterValueChangedCallback(evt =>
{
field.SetValue(graphNode, evt.newValue); // Update the field with the new value
});
}
else if (propertyField is FloatField floatField)
{
floatField.RegisterValueChangedCallback(evt =>
{
field.SetValue(graphNode, evt.newValue); // Update the field with the new value
});
}
else if (propertyField is Toggle boolField)
{
boolField.RegisterValueChangedCallback(evt =>
{
field.SetValue(graphNode, evt.newValue); // Update the field with the new value
});
}
else if (propertyField is TextField stringField)
{
stringField.RegisterValueChangedCallback(evt =>
{
field.SetValue(graphNode, evt.newValue); // Update the field with the new value
});
}
else if (propertyField is ColorField colorField)
{
colorField.RegisterValueChangedCallback(evt =>
{
field.SetValue(graphNode, evt.newValue); // Update the field with the new value
});
}
else if (propertyField is Vector3Field vector3Field)
{
vector3Field.RegisterValueChangedCallback(evt =>
{
field.SetValue(graphNode, evt.newValue); // Update the field with the new value
});
}
else if (propertyField is Vector2Field vector2Field)
{
vector2Field.RegisterValueChangedCallback(evt =>
{
field.SetValue(graphNode, evt.newValue); // Update the field with the new value
});
}
else if (propertyField is ObjectField objectField)
{
objectField.RegisterValueChangedCallback(evt =>
{
field.SetValue(graphNode, evt.newValue); // Update the field with the new value
});
}
propertyFieldContainer.Add(propertyField);
port.Add(propertyFieldContainer);
}
}
else
{
// If the port is connected, remove the exposed UI element
var existingPropertyFieldContainer = port.Q<VisualElement>("property-field-container");
if (existingPropertyFieldContainer != null)
{
port.Remove(existingPropertyFieldContainer);
}
}
}
// Create appropriate property field based on the type of the variable
private VisualElement CreatePropertyFieldForType(Type type, object value)
{
if (type == typeof(int))
{
var intField = new IntegerField { value = (int)value };
return intField;
}
else if (type == typeof(float))
{
var floatField = new FloatField { value = (float)value };
return floatField;
}
else if (type == typeof(bool))
{
var boolField = new Toggle { value = (bool)value };
return boolField;
}
else if (type == typeof(string))
{
var stringField = new TextField { value = (string)value };
return stringField;
}
else if (type == typeof(Color))
{
var colorField = new ColorField() { value = (Color)value };
return colorField;
}
else if (type == typeof(Vector3))
{
var vector3Field = new Vector3Field { value = (Vector3)value };
return vector3Field;
}
else if (type == typeof(Vector2))
{
var vector2Field = new Vector2Field { value = (Vector2)value };
return vector2Field;
}
else if (type == typeof(Texture2D))
{
var objectField = new ObjectField { value = (Texture2D)value, objectType = typeof(Texture2D) };
return objectField;
}
// Add more types as needed (Vector3, etc.)
return null;
}
public void SavePosition() => graphNode.SetPosition(GetPosition());
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4f6cc3303a2442938105c3bc990cfd18
timeCreated: 1742158018

View File

@ -0,0 +1,138 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Codice.Client.Common;
using ImageProcessingGraph.Editor.Nodes.NodeAttributes;
using UnityEditor;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.UIElements;
namespace ImageProcessingGraph.Editor.Unity_Image_Processing.Scripts.Editor.Windows
{
public struct SearchContextElement
{
public object target { get; private set; }
public string title { get; private set; }
public SearchContextElement(object target, string title)
{
this.target = target;
this.title = title;
}
}
public class ImageProcessingGraphSearchProvider : ScriptableObject, ISearchWindowProvider
{
public ImageProcessingGraphViewWindow graph;
public VisualElement target;
public static List<SearchContextElement> elements;
private Assembly[] assemblies;
public List<SearchTreeEntry> CreateSearchTree(SearchWindowContext context)
{
List<SearchTreeEntry> tree = new List<SearchTreeEntry>();
tree.Add(new SearchTreeGroupEntry(new GUIContent("Nodes"), 0));
elements = new List<SearchContextElement>();
/*
assemblies = AppDomain.CurrentDomain.GetAssemblies();
*/
/*foreach (var assembly in assemblies)
{
foreach (Type type in assembly.GetTypes())
{
if (type.CustomAttributes.ToList() != null)
{
var attr = type.GetCustomAttribute(typeof(NodeInfoAttribute));
if (attr != null)
{
NodeInfoAttribute info = attr as NodeInfoAttribute;
var node = Activator.CreateInstance(type);
if(string.IsNullOrEmpty(info.MenuItem)) continue;
elements.Add(new SearchContextElement(node, info.MenuItem));
}
}
}
}*/
foreach (var type in TypeCache.GetTypesWithAttribute<NodeInfoAttribute>())
{
var attr = type.GetCustomAttribute<NodeInfoAttribute>();
NodeInfoAttribute info = attr as NodeInfoAttribute;
var node = Activator.CreateInstance(type);
if(string.IsNullOrEmpty(info.MenuItem)) continue;
elements.Add(new SearchContextElement(node, info.MenuItem));
}
elements.Sort((entry1, entry2) =>
{
string[] splits1 = entry1.title.Split('/');
string[] splits2 = entry2.title.Split('/');
for (int i = 0; i < splits1.Length; i++)
{
if (i >= splits2.Length) return 1;
int value = splits1[i].CompareTo(splits2[i]);
if (value != 0)
{
if(splits1.Length != splits2.Length && (i == splits1.Length - 1 || i == splits2.Length - 1))
return splits1.Length < splits2.Length ? 1 : -1;
return value;
}
}
return 0;
});
List<string> groups = new List<string>();
foreach (var element in elements)
{
string[] entryTitle = element.title.Split('/');
string groupName = "";
for (int i = 0; i < entryTitle.Length - 1; i++)
{
groupName += entryTitle[i];
if (!groups.Contains(groupName))
{
tree.Add(new SearchTreeGroupEntry(new GUIContent(groupName), i + 1));
groups.Add(groupName);
}
groupName += '/';
}
SearchTreeEntry entry = new SearchTreeEntry(new GUIContent(entryTitle.Last()));
entry.level = entryTitle.Length;
entry.userData = new SearchContextElement(element.target, element.title);
tree.Add(entry);
}
return tree;
}
public bool OnSelectEntry(SearchTreeEntry SearchTreeEntry, SearchWindowContext context)
{
var mousePos = graph.ChangeCoordinatesTo(graph, context.screenMousePosition - graph.Window.position.position);
var graphMousePosition = graph.contentViewContainer.WorldToLocal(mousePos);
SearchContextElement element = (SearchContextElement)SearchTreeEntry.userData;
BaseImageNode node = (BaseImageNode)element.target;
node.SetPosition(new Rect(graphMousePosition, new Vector2()));
graph.Add(node);
node.asset = graph.asset;
return true;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4b3b053637c34e86b2bda50c9cc5ccbb
timeCreated: 1742159126

View File

@ -0,0 +1,342 @@
using System.Collections.Generic;
using System.Linq;
using ImageProcessingGraph.Editor.Unity_Image_Processing.Scripts.Editor.Windows;
using ImageProcessingGraph.Editor.Windows;
using UnityEditor;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.UIElements;
namespace ImageProcessingGraph.Editor
{
public class ImageProcessingGraphViewWindow : GraphView
{
internal ImageProcessingGraphAsset asset;
private SerializedObject serializedObject;
private ImageProcessingGraphEditorWindow window;
public ImageProcessingGraphEditorWindow Window => window;
public List<ImageProcessingGraphNodeVisual> graphNodes;
public Dictionary<string, ImageProcessingGraphNodeVisual> nodeDictionary;
public Dictionary<Edge, GraphConnection> connectionDictionary;
internal ImageProcessingGraphSearchProvider searchProvider;
internal ImageProcessingGraphEdgeConnectorListener edgeConnectorListener;
public ImageProcessingGraphViewWindow(SerializedObject obeject, ImageProcessingGraphEditorWindow window)
{
this.serializedObject = obeject;
this.asset = obeject.targetObject as ImageProcessingGraphAsset;
this.graphNodes = new List<ImageProcessingGraphNodeVisual>();
nodeDictionary = new Dictionary<string, ImageProcessingGraphNodeVisual>();
connectionDictionary = new Dictionary<Edge, GraphConnection>();
searchProvider = ScriptableObject.CreateInstance<ImageProcessingGraphSearchProvider>();
searchProvider.graph = this;
edgeConnectorListener = new ImageProcessingGraphEdgeConnectorListener(this);
this.nodeCreationRequest = ShowSearchWindow;
this.window = window;
StyleSheet styleSheet = AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/Unity Image Processing/GraphView.uss");
styleSheets.Add(styleSheet);
GridBackground background = new GridBackground();
background.name = "Grid";
Add(background);
background.SendToBack();
this.AddManipulator(new ContentDragger());
this.AddManipulator(new SelectionDragger());
this.AddManipulator(new RectangleSelector());
this.AddManipulator(new ClickSelector());
this.AddManipulator(new ContentZoomer() );
DrawNodes();
DrawConnections();
graphViewChanged += OnGraphViewChanged;
Undo.undoRedoEvent += UndoEvent;
}
private ImageProcessingGraphNodeVisual GetNode(string NodeID)
{
ImageProcessingGraphNodeVisual node = null;
nodeDictionary.TryGetValue(NodeID, out node);
return node;
}
public override List<Port> GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter)
{
List<Port> compatiblePorts = new List<Port>();
foreach (var node in graphNodes)
{
// Prevent connections to self
if (node == startPort.node)
continue;
foreach (var port in node.inputContainer.Children().Concat(node.outputContainer.Children()).OfType<Port>())
{
// Prevent connecting input to input or output to output
if (port.direction == startPort.direction)
continue;
if (port.portType != startPort.portType)
{
if (DoesConversionNodeExist())
{
}
else
continue;
}
// Prevent connection if it creates a cycle
if (startPort.direction == Direction.Output && CreatesCycle(startPort, port))
continue;
if (startPort.direction == Direction.Input && CreatesCycle(port, startPort))
continue;
compatiblePorts.Add(port);
}
}
return compatiblePorts;
}
private void UndoEvent(in UndoRedoInfo undo)
{
DrawNodes();
}
private GraphViewChange OnGraphViewChanged(GraphViewChange graphviewchange)
{
if (graphviewchange.movedElements != null)
{
Undo.RecordObject(serializedObject.targetObject, "Moved Graph Elements");
foreach (var VARIABLE in graphviewchange.movedElements.OfType<ImageProcessingGraphNodeVisual>())
{
VARIABLE.SavePosition();
}
}
if (graphviewchange.elementsToRemove != null)
{
List<ImageProcessingGraphNodeVisual> nodesToRemove = graphviewchange.elementsToRemove.OfType<ImageProcessingGraphNodeVisual>().ToList();
if (nodesToRemove.Count > 0)
{
Undo.RecordObject(serializedObject.targetObject, "Remove Node");
foreach (var VARIABLE in nodesToRemove)
{
RemoveNode(VARIABLE);
}
}
foreach (var VARIABLE in graphviewchange.elementsToRemove.OfType<Edge>())
{
RemoveEdge(VARIABLE);
}
}
if (graphviewchange.edgesToCreate != null)
{
foreach (Edge edge in graphviewchange.edgesToCreate)
{
Undo.RecordObject(serializedObject.targetObject, "Created Connection");
CreateEdge(edge);
}
}
return graphviewchange;
}
#region Edges
void CreateEdge(Edge edge)
{
ImageProcessingGraphNodeVisual outputNode = (ImageProcessingGraphNodeVisual)edge.output.node;
ImageProcessingGraphNodeVisual inputNode = (ImageProcessingGraphNodeVisual)edge.input.node;
int outputIndex = outputNode.OutputPorts.IndexOf(edge.output);
int inputIndex = inputNode.InputPorts.IndexOf(edge.input);
string inputType = inputNode.GraphNode.GetType().Name;
string outputType = outputNode.GraphNode.GetType().Name;
GraphConnection connection = new GraphConnection(inputNode.GraphNode.ID,inputIndex, inputType,outputNode.GraphNode.ID, outputIndex, outputType);
asset.Connections.Add(connection);
}
private void RemoveEdge(Edge variable)
{
if (connectionDictionary.TryGetValue(variable, out GraphConnection connection))
{
asset.Connections.Remove(connection);
connectionDictionary.Remove(variable);
}
}
private void DrawConnections()
{
if (asset.Connections != null)
{
foreach (GraphConnection conn in asset.Connections)
{
ImageProcessingGraphNodeVisual inputNode = GetNode(conn.inputPort.nodeID);
ImageProcessingGraphNodeVisual outputNode = GetNode(conn.outputPort.nodeID);
if (inputNode != null && outputNode != null)
{
Port inPort = inputNode.InputPorts[conn.inputPort.portID];
Port outPort = outputNode.OutputPorts[conn.outputPort.portID];
Edge edge = inPort.ConnectTo(outPort);
AddElement(edge);
connectionDictionary.Add(edge, conn);
}
}
}
}
private bool DoesConversionNodeExist()
{
return false;
}
#region Cycle Logic
private bool CreatesCycle(Port fromPort, Port toPort)
{
var visited = new HashSet<Node>();
return HasPathTo(toPort.node, fromPort.node, visited);
}
private bool HasPathTo(Node current, Node target, HashSet<Node> visited)
{
if (current == target)
return true;
if (visited.Contains(current))
return false;
visited.Add(current);
foreach (var outputPort in current.outputContainer.Children().OfType<Port>())
{
foreach (var edge in outputPort.connections)
{
var nextNode = edge.input.node;
if (HasPathTo(nextNode, target, visited))
return true;
}
}
return false;
}
#endregion
#endregion
#region Nodes
private void DrawNodes()
{
foreach (ImageProcessingGraphNodeVisual node in graphNodes)
{
RemoveElement(node);
}
graphNodes.Clear();
foreach (KeyValuePair<string, ImageProcessingGraphNodeVisual> node in nodeDictionary)
{
RemoveElement(node.Value);
}
nodeDictionary.Clear();
foreach (var variable in asset.Nodes)
{
AddNodeToGraph(variable);
}
}
private void AddNodeToGraph(BaseImageNode node)
{
node.typeName = node.GetType().AssemblyQualifiedName;
ImageProcessingGraphNodeVisual editorNode = new ImageProcessingGraphNodeVisual(node, this);
editorNode.SetPosition(node.Position);
graphNodes.Add(editorNode);
nodeDictionary.Add(node.ID, editorNode);
AddElement(editorNode);
}
public void Add(BaseImageNode node)
{
Undo.RecordObject(serializedObject.targetObject, "Added Node");
asset.Nodes.Add(node);
serializedObject.Update();
AddNodeToGraph(node);
}
private void RemoveNode(ImageProcessingGraphNodeVisual variable)
{
List<GraphConnection> connectionsToRemove = new List<GraphConnection>();
foreach (var connection in asset.Connections)
{
if (connection.inputPort.nodeID == variable.GraphNode.ID || connection.outputPort.nodeID == variable.GraphNode.ID)
connectionsToRemove.Add(connection);
}
foreach (var connection in connectionsToRemove)
{
asset.Connections.Remove(connection);
}
asset.Nodes.Remove(variable.GraphNode);
nodeDictionary.Remove(variable.GraphNode.ID);
graphNodes.Remove(variable);
serializedObject.Update();
}
#endregion
#region Search Window
private void ShowSearchWindow(NodeCreationContext obj)
{
searchProvider.target = (VisualElement)focusController.focusedElement;
SearchWindow.Open(new SearchWindowContext(obj.screenMousePosition), searchProvider);
}
#endregion
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: f8b07435c36617f48bbb9c51889caf81

8
Test Assets.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a4036f11a5b3def48b6cf5e8b0654a54
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,18 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 80dcc02594d68e3439df7dc743c9d4b2, type: 3}
m_Name: New IPT_Preferences
m_EditorClassIdentifier:
thickLines: 0
spacing: 0
gridBackgroundColour: {r: 0, g: 0, b: 0, a: 0}
lineColour: {r: 0, g: 0, b: 0, a: 0}

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d4bfee84a7579474c8626fb17fcc299b
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,658 @@
{
"m_SGVersion": 3,
"m_Type": "UnityEditor.ShaderGraph.GraphData",
"m_ObjectId": "a14387ccdc0e4230b24cf16376062b37",
"m_Properties": [],
"m_Keywords": [],
"m_Dropdowns": [],
"m_CategoryData": [
{
"m_Id": "71cd3153db9241d78583f494f3175e65"
}
],
"m_Nodes": [
{
"m_Id": "0e3586066bf84a19b29835e8f00f18c8"
},
{
"m_Id": "4a4c9b7678bf48649738dd347fbf691d"
},
{
"m_Id": "6cc2f2b53819431db80cdc902c44b0a2"
},
{
"m_Id": "170a5a0274d84f83b5b3409d7ebccc3c"
},
{
"m_Id": "b6f01d1b41104807b982a044c5e1e005"
},
{
"m_Id": "329dddc156c148b887205cd362845c53"
},
{
"m_Id": "574823597594424bb34f730b62c44aef"
},
{
"m_Id": "a77037c58c28419ba14f3220b7d8fbff"
},
{
"m_Id": "265ae6dabc6f4c57bb9681736466b11f"
}
],
"m_GroupDatas": [],
"m_StickyNoteDatas": [],
"m_Edges": [],
"m_VertexContext": {
"m_Position": {
"x": 0.0,
"y": 0.0
},
"m_Blocks": [
{
"m_Id": "0e3586066bf84a19b29835e8f00f18c8"
},
{
"m_Id": "4a4c9b7678bf48649738dd347fbf691d"
},
{
"m_Id": "6cc2f2b53819431db80cdc902c44b0a2"
}
]
},
"m_FragmentContext": {
"m_Position": {
"x": 0.0,
"y": 200.0
},
"m_Blocks": [
{
"m_Id": "170a5a0274d84f83b5b3409d7ebccc3c"
},
{
"m_Id": "b6f01d1b41104807b982a044c5e1e005"
},
{
"m_Id": "329dddc156c148b887205cd362845c53"
},
{
"m_Id": "574823597594424bb34f730b62c44aef"
},
{
"m_Id": "a77037c58c28419ba14f3220b7d8fbff"
},
{
"m_Id": "265ae6dabc6f4c57bb9681736466b11f"
}
]
},
"m_PreviewData": {
"serializedMesh": {
"m_SerializedMesh": "{\"mesh\":{\"instanceID\":0}}",
"m_Guid": ""
},
"preventRotation": false
},
"m_Path": "Shader Graphs",
"m_GraphPrecision": 1,
"m_PreviewMode": 2,
"m_OutputNode": {
"m_Id": ""
},
"m_SubDatas": [],
"m_ActiveTargets": [
{
"m_Id": "7dffcc0f872e4798bc7d7c277c01ca46"
}
]
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.ColorRGBMaterialSlot",
"m_ObjectId": "0000b8c7f15240e8a92c2c75a833f48f",
"m_Id": 0,
"m_DisplayName": "Base Color",
"m_SlotType": 0,
"m_Hidden": false,
"m_ShaderOutputName": "BaseColor",
"m_StageCapability": 2,
"m_Value": {
"x": 0.5,
"y": 0.5,
"z": 0.5
},
"m_DefaultValue": {
"x": 0.5,
"y": 0.5,
"z": 0.5
},
"m_Labels": [],
"m_ColorMode": 0,
"m_DefaultColor": {
"r": 0.5,
"g": 0.5,
"b": 0.5,
"a": 1.0
}
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot",
"m_ObjectId": "0468751a1c344e38b0aec9b2b4467e38",
"m_Id": 0,
"m_DisplayName": "Smoothness",
"m_SlotType": 0,
"m_Hidden": false,
"m_ShaderOutputName": "Smoothness",
"m_StageCapability": 2,
"m_Value": 0.5,
"m_DefaultValue": 0.5,
"m_Labels": []
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.BlockNode",
"m_ObjectId": "0e3586066bf84a19b29835e8f00f18c8",
"m_Group": {
"m_Id": ""
},
"m_Name": "VertexDescription.Position",
"m_DrawState": {
"m_Expanded": true,
"m_Position": {
"serializedVersion": "2",
"x": 0.0,
"y": 0.0,
"width": 0.0,
"height": 0.0
}
},
"m_Slots": [
{
"m_Id": "8e9794e0177a4feebf5eb676d84fe1f3"
}
],
"synonyms": [],
"m_Precision": 0,
"m_PreviewExpanded": true,
"m_DismissedVersion": 0,
"m_PreviewMode": 0,
"m_CustomColors": {
"m_SerializableColors": []
},
"m_SerializedDescriptor": "VertexDescription.Position"
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot",
"m_ObjectId": "0f43a512a2ae49f3959b2c0347ca55b2",
"m_Id": 0,
"m_DisplayName": "Ambient Occlusion",
"m_SlotType": 0,
"m_Hidden": false,
"m_ShaderOutputName": "Occlusion",
"m_StageCapability": 2,
"m_Value": 1.0,
"m_DefaultValue": 1.0,
"m_Labels": []
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.BlockNode",
"m_ObjectId": "170a5a0274d84f83b5b3409d7ebccc3c",
"m_Group": {
"m_Id": ""
},
"m_Name": "SurfaceDescription.BaseColor",
"m_DrawState": {
"m_Expanded": true,
"m_Position": {
"serializedVersion": "2",
"x": 0.0,
"y": 0.0,
"width": 0.0,
"height": 0.0
}
},
"m_Slots": [
{
"m_Id": "0000b8c7f15240e8a92c2c75a833f48f"
}
],
"synonyms": [],
"m_Precision": 0,
"m_PreviewExpanded": true,
"m_DismissedVersion": 0,
"m_PreviewMode": 0,
"m_CustomColors": {
"m_SerializableColors": []
},
"m_SerializedDescriptor": "SurfaceDescription.BaseColor"
}
{
"m_SGVersion": 2,
"m_Type": "UnityEditor.Rendering.Universal.ShaderGraph.UniversalLitSubTarget",
"m_ObjectId": "1fe22ff03eb64399a2fd9c06b88eafa8",
"m_WorkflowMode": 1,
"m_NormalDropOffSpace": 0,
"m_ClearCoat": false,
"m_BlendModePreserveSpecular": true
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.BlockNode",
"m_ObjectId": "265ae6dabc6f4c57bb9681736466b11f",
"m_Group": {
"m_Id": ""
},
"m_Name": "SurfaceDescription.Occlusion",
"m_DrawState": {
"m_Expanded": true,
"m_Position": {
"serializedVersion": "2",
"x": 0.0,
"y": 0.0,
"width": 0.0,
"height": 0.0
}
},
"m_Slots": [
{
"m_Id": "0f43a512a2ae49f3959b2c0347ca55b2"
}
],
"synonyms": [],
"m_Precision": 0,
"m_PreviewExpanded": true,
"m_DismissedVersion": 0,
"m_PreviewMode": 0,
"m_CustomColors": {
"m_SerializableColors": []
},
"m_SerializedDescriptor": "SurfaceDescription.Occlusion"
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.BlockNode",
"m_ObjectId": "329dddc156c148b887205cd362845c53",
"m_Group": {
"m_Id": ""
},
"m_Name": "SurfaceDescription.Metallic",
"m_DrawState": {
"m_Expanded": true,
"m_Position": {
"serializedVersion": "2",
"x": 0.0,
"y": 0.0,
"width": 0.0,
"height": 0.0
}
},
"m_Slots": [
{
"m_Id": "bd184b28488f4573bef8c2af64be7436"
}
],
"synonyms": [],
"m_Precision": 0,
"m_PreviewExpanded": true,
"m_DismissedVersion": 0,
"m_PreviewMode": 0,
"m_CustomColors": {
"m_SerializableColors": []
},
"m_SerializedDescriptor": "SurfaceDescription.Metallic"
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.TangentMaterialSlot",
"m_ObjectId": "32e096cd3bb849e7bb32f646989794db",
"m_Id": 0,
"m_DisplayName": "Tangent",
"m_SlotType": 0,
"m_Hidden": false,
"m_ShaderOutputName": "Tangent",
"m_StageCapability": 1,
"m_Value": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_DefaultValue": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_Labels": [],
"m_Space": 0
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.ColorRGBMaterialSlot",
"m_ObjectId": "382845f601e84d2292ccb7886a370bcb",
"m_Id": 0,
"m_DisplayName": "Emission",
"m_SlotType": 0,
"m_Hidden": false,
"m_ShaderOutputName": "Emission",
"m_StageCapability": 2,
"m_Value": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_DefaultValue": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_Labels": [],
"m_ColorMode": 1,
"m_DefaultColor": {
"r": 0.0,
"g": 0.0,
"b": 0.0,
"a": 1.0
}
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.BlockNode",
"m_ObjectId": "4a4c9b7678bf48649738dd347fbf691d",
"m_Group": {
"m_Id": ""
},
"m_Name": "VertexDescription.Normal",
"m_DrawState": {
"m_Expanded": true,
"m_Position": {
"serializedVersion": "2",
"x": 0.0,
"y": 0.0,
"width": 0.0,
"height": 0.0
}
},
"m_Slots": [
{
"m_Id": "83dd0d2576664436bb795eba7ffb4883"
}
],
"synonyms": [],
"m_Precision": 0,
"m_PreviewExpanded": true,
"m_DismissedVersion": 0,
"m_PreviewMode": 0,
"m_CustomColors": {
"m_SerializableColors": []
},
"m_SerializedDescriptor": "VertexDescription.Normal"
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.BlockNode",
"m_ObjectId": "574823597594424bb34f730b62c44aef",
"m_Group": {
"m_Id": ""
},
"m_Name": "SurfaceDescription.Smoothness",
"m_DrawState": {
"m_Expanded": true,
"m_Position": {
"serializedVersion": "2",
"x": 0.0,
"y": 0.0,
"width": 0.0,
"height": 0.0
}
},
"m_Slots": [
{
"m_Id": "0468751a1c344e38b0aec9b2b4467e38"
}
],
"synonyms": [],
"m_Precision": 0,
"m_PreviewExpanded": true,
"m_DismissedVersion": 0,
"m_PreviewMode": 0,
"m_CustomColors": {
"m_SerializableColors": []
},
"m_SerializedDescriptor": "SurfaceDescription.Smoothness"
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.BlockNode",
"m_ObjectId": "6cc2f2b53819431db80cdc902c44b0a2",
"m_Group": {
"m_Id": ""
},
"m_Name": "VertexDescription.Tangent",
"m_DrawState": {
"m_Expanded": true,
"m_Position": {
"serializedVersion": "2",
"x": 0.0,
"y": 0.0,
"width": 0.0,
"height": 0.0
}
},
"m_Slots": [
{
"m_Id": "32e096cd3bb849e7bb32f646989794db"
}
],
"synonyms": [],
"m_Precision": 0,
"m_PreviewExpanded": true,
"m_DismissedVersion": 0,
"m_PreviewMode": 0,
"m_CustomColors": {
"m_SerializableColors": []
},
"m_SerializedDescriptor": "VertexDescription.Tangent"
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.CategoryData",
"m_ObjectId": "71cd3153db9241d78583f494f3175e65",
"m_Name": "",
"m_ChildObjectList": []
}
{
"m_SGVersion": 1,
"m_Type": "UnityEditor.Rendering.Universal.ShaderGraph.UniversalTarget",
"m_ObjectId": "7dffcc0f872e4798bc7d7c277c01ca46",
"m_Datas": [],
"m_ActiveSubTarget": {
"m_Id": "1fe22ff03eb64399a2fd9c06b88eafa8"
},
"m_AllowMaterialOverride": false,
"m_SurfaceType": 0,
"m_ZTestMode": 4,
"m_ZWriteControl": 0,
"m_AlphaMode": 0,
"m_RenderFace": 2,
"m_AlphaClip": false,
"m_CastShadows": true,
"m_ReceiveShadows": true,
"m_DisableTint": false,
"m_AdditionalMotionVectorMode": 0,
"m_AlembicMotionVectors": false,
"m_SupportsLODCrossFade": false,
"m_CustomEditorGUI": "",
"m_SupportVFX": false
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.NormalMaterialSlot",
"m_ObjectId": "83dd0d2576664436bb795eba7ffb4883",
"m_Id": 0,
"m_DisplayName": "Normal",
"m_SlotType": 0,
"m_Hidden": false,
"m_ShaderOutputName": "Normal",
"m_StageCapability": 1,
"m_Value": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_DefaultValue": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_Labels": [],
"m_Space": 0
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.PositionMaterialSlot",
"m_ObjectId": "8e9794e0177a4feebf5eb676d84fe1f3",
"m_Id": 0,
"m_DisplayName": "Position",
"m_SlotType": 0,
"m_Hidden": false,
"m_ShaderOutputName": "Position",
"m_StageCapability": 1,
"m_Value": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_DefaultValue": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_Labels": [],
"m_Space": 0
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.NormalMaterialSlot",
"m_ObjectId": "a72d7540c45d4b7e8a8d554f6274d745",
"m_Id": 0,
"m_DisplayName": "Normal (Tangent Space)",
"m_SlotType": 0,
"m_Hidden": false,
"m_ShaderOutputName": "NormalTS",
"m_StageCapability": 2,
"m_Value": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_DefaultValue": {
"x": 0.0,
"y": 0.0,
"z": 0.0
},
"m_Labels": [],
"m_Space": 3
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.BlockNode",
"m_ObjectId": "a77037c58c28419ba14f3220b7d8fbff",
"m_Group": {
"m_Id": ""
},
"m_Name": "SurfaceDescription.Emission",
"m_DrawState": {
"m_Expanded": true,
"m_Position": {
"serializedVersion": "2",
"x": 0.0,
"y": 0.0,
"width": 0.0,
"height": 0.0
}
},
"m_Slots": [
{
"m_Id": "382845f601e84d2292ccb7886a370bcb"
}
],
"synonyms": [],
"m_Precision": 0,
"m_PreviewExpanded": true,
"m_DismissedVersion": 0,
"m_PreviewMode": 0,
"m_CustomColors": {
"m_SerializableColors": []
},
"m_SerializedDescriptor": "SurfaceDescription.Emission"
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.BlockNode",
"m_ObjectId": "b6f01d1b41104807b982a044c5e1e005",
"m_Group": {
"m_Id": ""
},
"m_Name": "SurfaceDescription.NormalTS",
"m_DrawState": {
"m_Expanded": true,
"m_Position": {
"serializedVersion": "2",
"x": 0.0,
"y": 0.0,
"width": 0.0,
"height": 0.0
}
},
"m_Slots": [
{
"m_Id": "a72d7540c45d4b7e8a8d554f6274d745"
}
],
"synonyms": [],
"m_Precision": 0,
"m_PreviewExpanded": true,
"m_DismissedVersion": 0,
"m_PreviewMode": 0,
"m_CustomColors": {
"m_SerializableColors": []
},
"m_SerializedDescriptor": "SurfaceDescription.NormalTS"
}
{
"m_SGVersion": 0,
"m_Type": "UnityEditor.ShaderGraph.Vector1MaterialSlot",
"m_ObjectId": "bd184b28488f4573bef8c2af64be7436",
"m_Id": 0,
"m_DisplayName": "Metallic",
"m_SlotType": 0,
"m_Hidden": false,
"m_ShaderOutputName": "Metallic",
"m_StageCapability": 2,
"m_Value": 0.0,
"m_DefaultValue": 0.0,
"m_Labels": []
}

View File

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: c56761e16709479478032d95d74c0274
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 11500000, guid: 625f186215c104763be7675aa2d941aa, type: 3}

View File

@ -0,0 +1,95 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1da462fd3f736d04e80556b4ac8b470f, type: 3}
m_Name: Test Graph One
m_EditorClassIdentifier:
nodes:
- rid: 6869590814762467392
- rid: 6869590814762467393
- rid: 6869590814762467394
- rid: 6869590814762467395
connections:
- inputPort:
nodeID: 64b814fe-8177-4620-9cf6-cacbe0b8ddd7
nodeType: Texture2DDesaturate
portID: 0
outputPort:
nodeID: b8924b16-c816-4168-8ee6-9ee30c6b63a9
nodeType: Texture2DImport
portID: 0
- inputPort:
nodeID: aa4b4ff2-61d6-4f84-a4ab-5b6b15c2ba97
nodeType: Texture2DOutput
portID: 0
outputPort:
nodeID: 64b814fe-8177-4620-9cf6-cacbe0b8ddd7
nodeType: Texture2DDesaturate
portID: 0
references:
version: 2
RefIds:
- rid: 6869590814762467392
type: {class: Texture2DImport, ns: ImageProcessingGraph.Editor.Nodes.Import_Nodes, asm: ImageProcessingGraphEditor}
data:
guid: b8924b16-c816-4168-8ee6-9ee30c6b63a9
position:
serializedVersion: 2
x: -1110
y: 171.5
width: 311
height: 77
typeName: ImageProcessingGraph.Editor.Nodes.Import_Nodes.Texture2DImport,
ImageProcessingGraphEditor, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
asset: {fileID: 11400000}
textureImport: {fileID: 2800000, guid: 727a75301c3d24613a3ebcec4a24c2c8, type: 3}
- rid: 6869590814762467393
type: {class: Texture2DDesaturate, ns: ImageProcessingGraph.Editor.Nodes.Fun_Nodes.Texture, asm: ImageProcessingGraphEditor}
data:
guid: 64b814fe-8177-4620-9cf6-cacbe0b8ddd7
position:
serializedVersion: 2
x: -782
y: 171.5
width: 186
height: 77
typeName: ImageProcessingGraph.Editor.Nodes.Fun_Nodes.Texture.Texture2DDesaturate,
ImageProcessingGraphEditor, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
asset: {fileID: 11400000}
- rid: 6869590814762467394
type: {class: Texture2DOutput, ns: ImageProcessingGraph.Editor.Nodes.Output, asm: ImageProcessingGraphEditor}
data:
guid: aa4b4ff2-61d6-4f84-a4ab-5b6b15c2ba97
position:
serializedVersion: 2
x: -541
y: 186
width: 129.5
height: 125
typeName: ImageProcessingGraph.Editor.Nodes.Output.Texture2DOutput, ImageProcessingGraphEditor,
Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
asset: {fileID: 11400000}
fileName: test123432
fileDirectory: Assets/
- rid: 6869590814762467395
type: {class: Texture2DImport, ns: ImageProcessingGraph.Editor.Nodes.Import_Nodes, asm: ImageProcessingGraphEditor}
data:
guid: 31f0135e-bc96-4c58-b808-210652f702bb
position:
serializedVersion: 2
x: 152
y: -9
width: 311
height: 77
typeName: ImageProcessingGraph.Editor.Nodes.Import_Nodes.Texture2DImport,
ImageProcessingGraphEditor, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
asset: {fileID: 11400000}
textureImport: {fileID: 0}

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: cef427fd668d96d47b164a934e97ba0d
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant: