summaryrefslogtreecommitdiffstats
path: root/Scripts
diff options
context:
space:
mode:
Diffstat (limited to 'Scripts')
-rw-r--r--Scripts/Editor/LinearPipelineEditor.cs339
-rw-r--r--Scripts/Editor/PipelineExecutorEditor.cs70
-rw-r--r--Scripts/LinearPipeline.asset134
-rw-r--r--Scripts/LinearPipeline.cs127
-rw-r--r--Scripts/PipelineExecutor.asset113
-rw-r--r--Scripts/PipelineExecutor.cs23
-rw-r--r--Scripts/PipelineExecutor.cs.meta11
7 files changed, 629 insertions, 188 deletions
diff --git a/Scripts/Editor/LinearPipelineEditor.cs b/Scripts/Editor/LinearPipelineEditor.cs
new file mode 100644
index 0000000..f14eb8e
--- /dev/null
+++ b/Scripts/Editor/LinearPipelineEditor.cs
@@ -0,0 +1,339 @@
+#if UNITY_EDITOR
+
+using UnityEngine;
+using UnityEditor;
+using System.IO;
+using System.Collections.Generic;
+
+[CustomEditor(typeof(LinearPipeline))]
+public class LinearPipelineEditor : Editor
+{
+ private const string MATERIAL_SUFFIX = "_Mat";
+ private const string TEXTURE_SUFFIX = "_Tex";
+
+ private SerializedProperty pipelineGeneratedPathProperty;
+ private SerializedProperty initialStateProperty;
+
+ private static Shader shader;
+ private static int radix = 16;
+ private static int fftResolution = 256;
+ private static bool isInverse = false;
+ private static bool doBothFFTAndInverse = false;
+ private static int preFFTStages = 0;
+ private static int postFFTStages = 0;
+
+ private void OnEnable()
+ {
+ pipelineGeneratedPathProperty = serializedObject.FindProperty("pipelineGeneratedPath");
+
+ initialStateProperty = serializedObject.FindProperty("initialState");
+
+ // Set default shader if not already set
+ if (shader == null)
+ {
+ shader = Shader.Find("yum_food/fft");
+ }
+ }
+
+ public override void OnInspectorGUI()
+ {
+ serializedObject.Update();
+
+ EditorGUILayout.PropertyField(serializedObject.FindProperty("materials"), true);
+ EditorGUILayout.PropertyField(serializedObject.FindProperty("renderTextures"), true);
+
+ LinearPipeline pipeline = (LinearPipeline)target;
+
+ EditorGUILayout.Space();
+ EditorGUILayout.LabelField("Pipeline Generation", EditorStyles.boldLabel);
+
+ EditorGUILayout.PropertyField(pipelineGeneratedPathProperty);
+ EditorGUILayout.PropertyField(initialStateProperty);
+
+ serializedObject.ApplyModifiedProperties();
+
+ shader = EditorGUILayout.ObjectField("Shader", shader, typeof(Shader), false) as Shader;
+ radix = Mathf.Max(2, EditorGUILayout.IntField("Radix", radix));
+ fftResolution = Mathf.Max(2, EditorGUILayout.IntField("FFT Resolution (N)", fftResolution));
+
+ EditorGUI.BeginDisabledGroup(doBothFFTAndInverse);
+ isInverse = EditorGUILayout.Toggle("Inverse FFT", isInverse);
+ EditorGUI.EndDisabledGroup();
+
+ doBothFFTAndInverse = EditorGUILayout.Toggle("Both FFT and Inverse FFT", doBothFFTAndInverse);
+ preFFTStages = Mathf.Max(0, EditorGUILayout.IntField("Pre-FFT Stages", preFFTStages));
+ postFFTStages = Mathf.Max(0, EditorGUILayout.IntField("Post-FFT Stages", postFFTStages));
+
+ int fftStages = CalculateFFTStages(fftResolution, radix);
+ EditorGUILayout.HelpBox($"FFT stages: {fftStages} (including bit reverse)", MessageType.Info);
+
+ EditorGUILayout.Space();
+
+ GUI.enabled = shader != null;
+ if (GUILayout.Button("Create Pipeline", GUILayout.Height(30)))
+ {
+ CreatePipeline(pipeline);
+ }
+ GUI.enabled = true;
+
+ if (shader == null)
+ {
+ EditorGUILayout.HelpBox("Please specify a shader to create the pipeline.", MessageType.Warning);
+ }
+ }
+
+ private int CalculateFFTStages(int n, int radix)
+ {
+ return Mathf.CeilToInt(Mathf.Log(n) / Mathf.Log(radix)) * 2 + 1;
+ }
+
+ private void CreatePipeline(LinearPipeline pipeline)
+ {
+ string pipelineName = pipeline.gameObject.name;
+ string pipelinePath = Path.Combine(pipeline.pipelineGeneratedPath, pipelineName);
+
+ // Ensure directories exist
+ if (!AssetDatabase.IsValidFolder(pipeline.pipelineGeneratedPath))
+ {
+ CreateFolderRecursive(pipeline.pipelineGeneratedPath);
+ }
+
+ if (!AssetDatabase.IsValidFolder(pipelinePath))
+ {
+ AssetDatabase.CreateFolder(pipeline.pipelineGeneratedPath, pipelineName);
+ }
+
+ Undo.RegisterFullObjectHierarchyUndo(pipeline.gameObject, "Create Pipeline");
+
+ // Clear existing children
+ ClearChildren(pipeline.transform);
+
+ // Generate stage names
+ List<string> stageNames = GenerateStageNames();
+
+ // Create arrays for materials and textures
+ Material[] materials = new Material[stageNames.Count];
+ RenderTexture[] textures = new RenderTexture[stageNames.Count];
+
+ // Create each stage
+ for (int i = 0; i < stageNames.Count; i++)
+ {
+ CreateStage(pipeline.transform, stageNames[i], pipelinePath, i, ref materials, ref textures);
+ }
+
+ // Assign textures to materials
+ AssignTexturesToMaterials(materials, textures, pipeline.initialState);
+
+ // Update pipeline component
+ pipeline.materials = materials;
+ pipeline.renderTextures = textures;
+
+ EditorUtility.SetDirty(pipeline);
+ AssetDatabase.SaveAssets();
+
+ Debug.Log($"[LinearPipeline] Created pipeline '{pipelineName}' with {materials.Length} stages");
+ }
+
+ private List<string> GenerateStageNames()
+ {
+ List<string> names = new List<string>();
+ int totalFFTStages = CalculateFFTStages(fftResolution, radix);
+
+ // Pre-FFT stages
+ for (int i = 0; i < preFFTStages; i++)
+ {
+ names.Add($"Pre_Stage_{i:D2}");
+ }
+
+ // FFT stages
+ if (doBothFFTAndInverse || !isInverse)
+ {
+ for (int i = 0; i < totalFFTStages; i++)
+ {
+ names.Add($"FFT_Stage_{i:D2}");
+ }
+ }
+
+ // Inverse FFT stages
+ if (doBothFFTAndInverse || isInverse)
+ {
+ for (int i = 0; i < totalFFTStages; i++)
+ {
+ names.Add($"IFFT_Stage_{i:D2}");
+ }
+ }
+
+ // Post-FFT stages
+ for (int i = 0; i < postFFTStages; i++)
+ {
+ names.Add($"Post_Stage_{i:D2}");
+ }
+
+ return names;
+ }
+
+ private void CreateStage(Transform parent, string stageName, string basePath, int index,
+ ref Material[] materials, ref RenderTexture[] textures)
+ {
+ // Create stage GameObject as a quad
+ GameObject stageGO = GameObject.CreatePrimitive(PrimitiveType.Quad);
+ stageGO.name = stageName;
+ stageGO.transform.SetParent(parent);
+ stageGO.transform.localPosition = new Vector3(index * 1.0f, 0, 0); // Space 1 meter apart on X axis
+ stageGO.transform.localRotation = Quaternion.identity;
+ stageGO.transform.localScale = Vector3.one;
+
+ DestroyImmediate(stageGO.GetComponent<MeshCollider>());
+
+ // Create or update material
+ string materialPath = $"{basePath}/{stageName}{MATERIAL_SUFFIX}.mat";
+ Material material = AssetDatabase.LoadAssetAtPath<Material>(materialPath);
+
+ if (material == null)
+ {
+ material = new Material(shader);
+ AssetDatabase.CreateAsset(material, materialPath);
+ }
+ else
+ {
+ material.shader = shader;
+ EditorUtility.SetDirty(material);
+ }
+
+ // Set shader properties based on stage type
+ ConfigureMaterialProperties(material, stageName);
+
+ // Create or update render texture
+ string texturePath = $"{basePath}/{stageName}{TEXTURE_SUFFIX}.renderTexture";
+ RenderTexture texture = AssetDatabase.LoadAssetAtPath<RenderTexture>(texturePath);
+
+ if (texture == null)
+ {
+ texture = new RenderTexture(fftResolution, fftResolution, 0, RenderTextureFormat.ARGBFloat)
+ {
+ filterMode = FilterMode.Point,
+ wrapMode = TextureWrapMode.Clamp
+ };
+ AssetDatabase.CreateAsset(texture, texturePath);
+ }
+ else
+ {
+ texture.width = fftResolution;
+ texture.height = fftResolution;
+ EditorUtility.SetDirty(texture);
+ }
+
+ // Assign material to renderer
+ MeshRenderer renderer = stageGO.GetComponent<MeshRenderer>();
+ renderer.sharedMaterial = material;
+
+ // Store in arrays
+ materials[index] = material;
+ textures[index] = texture;
+ }
+
+ private void ConfigureMaterialProperties(Material material, string stageName)
+ {
+ // Set common properties
+ material.SetInt("_N", fftResolution);
+ material.SetInt("_Radix", radix);
+
+ // Reset all flags
+ material.SetFloat("_Passthrough", 0f);
+ material.SetFloat("_LDS", 0f);
+ material.SetFloat("_Luminance", 0f);
+ material.SetFloat("_Inverse", 0f);
+ material.SetFloat("_BitReversal", 0f);
+
+ // Configure based on stage type
+ if (stageName.StartsWith("Pre_Stage_"))
+ {
+ // Pre-processing stages - set as passthrough
+ material.SetFloat("_Passthrough", 1f);
+ material.SetInt("_Stage", 0);
+ }
+ else if (stageName.StartsWith("FFT_Stage_"))
+ {
+ // Extract stage number
+ string stageNumStr = stageName.Replace("FFT_Stage_", "");
+ if (int.TryParse(stageNumStr, out int stageNum))
+ {
+ material.SetInt("_Stage", stageNum);
+
+ // Last stage is bit reversal
+ int totalStages = CalculateFFTStages(fftResolution, radix);
+ if (stageNum == totalStages - 1)
+ {
+ material.SetFloat("_BitReversal", 1f);
+ }
+ }
+ material.SetFloat("_Inverse", 0f);
+ }
+ else if (stageName.StartsWith("IFFT_Stage_"))
+ {
+ // Extract stage number
+ string stageNumStr = stageName.Replace("IFFT_Stage_", "");
+ if (int.TryParse(stageNumStr, out int stageNum))
+ {
+ material.SetInt("_Stage", stageNum);
+
+ // Last stage is bit reversal
+ int totalStages = CalculateFFTStages(fftResolution, radix);
+ if (stageNum == totalStages - 1)
+ {
+ material.SetFloat("_BitReversal", 1f);
+ }
+ }
+ material.SetFloat("_Inverse", 1f);
+ }
+ else if (stageName.StartsWith("Post_Stage_"))
+ {
+ // Post-processing stages - set as passthrough
+ material.SetFloat("_Passthrough", 1f);
+ material.SetInt("_Stage", 0);
+ }
+
+ EditorUtility.SetDirty(material);
+ }
+
+ private void AssignTexturesToMaterials(Material[] materials, RenderTexture[] textures, Texture initialState)
+ {
+ for (int i = 0; i < materials.Length; i++)
+ {
+ Texture inputTexture = (i == 0) ? initialState : textures[i - 1];
+
+ if (inputTexture != null)
+ {
+ materials[i].SetTexture("_MainTex", inputTexture);
+ }
+
+ EditorUtility.SetDirty(materials[i]);
+ }
+ }
+
+ private void ClearChildren(Transform parent)
+ {
+ while (parent.childCount > 0)
+ {
+ DestroyImmediate(parent.GetChild(0).gameObject);
+ }
+ }
+
+ private void CreateFolderRecursive(string path)
+ {
+ string[] folders = path.Split('/');
+ string currentPath = folders[0];
+
+ for (int i = 1; i < folders.Length; i++)
+ {
+ string nextPath = Path.Combine(currentPath, folders[i]);
+ if (!AssetDatabase.IsValidFolder(nextPath))
+ {
+ AssetDatabase.CreateFolder(currentPath, folders[i]);
+ }
+ currentPath = nextPath;
+ }
+ }
+}
+
+#endif
diff --git a/Scripts/Editor/PipelineExecutorEditor.cs b/Scripts/Editor/PipelineExecutorEditor.cs
new file mode 100644
index 0000000..857fd84
--- /dev/null
+++ b/Scripts/Editor/PipelineExecutorEditor.cs
@@ -0,0 +1,70 @@
+#if UNITY_EDITOR
+
+using UnityEngine;
+using UnityEditor;
+using System.Linq;
+
+[CustomEditor(typeof(PipelineExecutor))]
+public class PipelineExecutorEditor : Editor
+{
+ public override void OnInspectorGUI()
+ {
+ DrawDefaultInspector();
+
+ PipelineExecutor executor = (PipelineExecutor)target;
+
+ EditorGUILayout.Space();
+
+ if (GUILayout.Button("Auto-Add All Pipelines"))
+ {
+ AutoAddPipelines(executor);
+ }
+ }
+
+ private void AutoAddPipelines(PipelineExecutor executor)
+ {
+ // Find all LinearPipeline components in the current scene
+ LinearPipeline[] allPipelines = Object.FindObjectsOfType<LinearPipeline>();
+
+ // Sort by hierarchy order
+ System.Array.Sort(allPipelines, (a, b) =>
+ {
+ // Get hierarchy paths and compare
+ string pathA = GetHierarchyPath(a.transform);
+ string pathB = GetHierarchyPath(b.transform);
+ return pathA.CompareTo(pathB);
+ });
+
+ LinearPipeline[] existingPipelines = executor.pipelines ?? new LinearPipeline[0];
+ LinearPipeline[] newPipelines = allPipelines.Where(p => p != null && !existingPipelines.Contains(p)).ToArray();
+
+ if (newPipelines.Length > 0)
+ {
+ Undo.RecordObject(executor, "Auto-Add Pipelines");
+ executor.pipelines = existingPipelines.Concat(newPipelines).ToArray();
+ EditorUtility.SetDirty(executor);
+ Debug.Log($"[PipelineExecutor] Added {newPipelines.Length} new pipelines. Total: {executor.pipelines.Length}");
+ }
+ else
+ {
+ Debug.Log("[PipelineExecutor] No new pipelines to add.");
+ }
+ }
+
+ private string GetHierarchyPath(Transform transform)
+ {
+ System.Collections.Generic.List<int> indices = new System.Collections.Generic.List<int>();
+ Transform current = transform;
+
+ while (current != null)
+ {
+ indices.Add(current.GetSiblingIndex());
+ current = current.parent;
+ }
+
+ indices.Reverse();
+ return string.Join(".", indices.Select(i => i.ToString("D4")));
+ }
+}
+
+#endif
diff --git a/Scripts/LinearPipeline.asset b/Scripts/LinearPipeline.asset
index c266faa..ae58826 100644
--- a/Scripts/LinearPipeline.asset
+++ b/Scripts/LinearPipeline.asset
@@ -50,19 +50,19 @@ MonoBehaviour:
Data:
- Name: $k
Entry: 1
- Data: sourceInput
+ Data: pipelineGeneratedPath
- Name: $v
Entry: 7
Data: 2|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
- Data: sourceInput
+ Data: pipelineGeneratedPath
- Name: <UserType>k__BackingField
Entry: 7
Data: 3|System.RuntimeType, mscorlib
- Name:
Entry: 1
- Data: UnityEngine.Texture, UnityEngine.CoreModule
+ Data: System.String, mscorlib
- Name:
Entry: 8
Data:
@@ -86,7 +86,7 @@ MonoBehaviour:
Data: 4|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
- Data: 2
+ Data: 1
- Name:
Entry: 7
Data: 5|UnityEngine.HeaderAttribute, UnityEngine.CoreModule
@@ -97,15 +97,6 @@ MonoBehaviour:
Entry: 8
Data:
- Name:
- Entry: 7
- Data: 6|UnityEngine.TooltipAttribute, UnityEngine.CoreModule
- - Name: tooltip
- Entry: 1
- Data: The initial texture to start the pipeline with.
- - Name:
- Entry: 8
- Data:
- - Name:
Entry: 13
Data:
- Name:
@@ -122,25 +113,25 @@ MonoBehaviour:
Data:
- Name: $k
Entry: 1
- Data: effectMaterials
+ Data: initialState
- Name: $v
Entry: 7
- Data: 7|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
+ Data: 6|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
- Data: effectMaterials
+ Data: initialState
- Name: <UserType>k__BackingField
Entry: 7
- Data: 8|System.RuntimeType, mscorlib
+ Data: 7|System.RuntimeType, mscorlib
- Name:
Entry: 1
- Data: UnityEngine.Material[], UnityEngine.CoreModule
+ Data: UnityEngine.Texture, UnityEngine.CoreModule
- Name:
Entry: 8
Data:
- Name: <SystemType>k__BackingField
Entry: 9
- Data: 8
+ Data: 7
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
@@ -155,19 +146,10 @@ MonoBehaviour:
Data: true
- Name: _fieldAttributes
Entry: 7
- Data: 9|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
+ Data: 8|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
- Data: 1
- - Name:
- Entry: 7
- Data: 10|UnityEngine.TooltipAttribute, UnityEngine.CoreModule
- - Name: tooltip
- Entry: 1
- Data: The materials to apply in sequence. The order matters.
- - Name:
- Entry: 8
- Data:
+ Data: 0
- Name:
Entry: 13
Data:
@@ -185,25 +167,25 @@ MonoBehaviour:
Data:
- Name: $k
Entry: 1
- Data: pipelineOutputs
+ Data: materials
- Name: $v
Entry: 7
- Data: 11|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
+ Data: 9|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
- Data: pipelineOutputs
+ Data: materials
- Name: <UserType>k__BackingField
Entry: 7
- Data: 12|System.RuntimeType, mscorlib
+ Data: 10|System.RuntimeType, mscorlib
- Name:
Entry: 1
- Data: UnityEngine.RenderTexture[], UnityEngine.CoreModule
+ Data: UnityEngine.Material[], UnityEngine.CoreModule
- Name:
Entry: 8
Data:
- Name: <SystemType>k__BackingField
Entry: 9
- Data: 12
+ Data: 10
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
@@ -218,20 +200,10 @@ MonoBehaviour:
Data: true
- Name: _fieldAttributes
Entry: 7
- Data: 13|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
+ Data: 11|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
- Data: 1
- - Name:
- Entry: 7
- Data: 14|UnityEngine.TooltipAttribute, UnityEngine.CoreModule
- - Name: tooltip
- Entry: 1
- Data: The RenderTextures to store the output of each step. MUST be the same
- size as the materials array.
- - Name:
- Entry: 8
- Data:
+ Data: 0
- Name:
Entry: 13
Data:
@@ -249,25 +221,25 @@ MonoBehaviour:
Data:
- Name: $k
Entry: 1
- Data: runOnStart
+ Data: renderTextures
- Name: $v
Entry: 7
- Data: 15|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
+ Data: 12|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
- Data: runOnStart
+ Data: renderTextures
- Name: <UserType>k__BackingField
Entry: 7
- Data: 16|System.RuntimeType, mscorlib
+ Data: 13|System.RuntimeType, mscorlib
- Name:
Entry: 1
- Data: System.Boolean, mscorlib
+ Data: UnityEngine.RenderTexture[], UnityEngine.CoreModule
- Name:
Entry: 8
Data:
- Name: <SystemType>k__BackingField
Entry: 9
- Data: 16
+ Data: 13
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
@@ -282,28 +254,10 @@ MonoBehaviour:
Data: true
- Name: _fieldAttributes
Entry: 7
- Data: 17|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
+ Data: 14|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
- Data: 2
- - Name:
- Entry: 7
- Data: 18|UnityEngine.HeaderAttribute, UnityEngine.CoreModule
- - Name: header
- Entry: 1
- Data: Execution Mode
- - Name:
- Entry: 8
- Data:
- - Name:
- Entry: 7
- Data: 19|UnityEngine.TooltipAttribute, UnityEngine.CoreModule
- - Name: tooltip
- Entry: 1
- Data: If true, the pipeline will run once when the world loads.
- - Name:
- Entry: 8
- Data:
+ Data: 0
- Name:
Entry: 13
Data:
@@ -321,16 +275,22 @@ MonoBehaviour:
Data:
- Name: $k
Entry: 1
- Data: runContinuously
+ Data: isValid
- Name: $v
Entry: 7
- Data: 20|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
+ Data: 15|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
- Data: runContinuously
+ Data: isValid
- Name: <UserType>k__BackingField
- Entry: 9
- Data: 16
+ Entry: 7
+ Data: 16|System.RuntimeType, mscorlib
+ - Name:
+ Entry: 1
+ Data: System.Boolean, mscorlib
+ - Name:
+ Entry: 8
+ Data:
- Name: <SystemType>k__BackingField
Entry: 9
Data: 16
@@ -345,23 +305,13 @@ MonoBehaviour:
Data:
- Name: <IsSerialized>k__BackingField
Entry: 5
- Data: true
+ Data: false
- Name: _fieldAttributes
Entry: 7
- Data: 21|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
+ Data: 17|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
- Data: 1
- - Name:
- Entry: 7
- Data: 22|UnityEngine.TooltipAttribute, UnityEngine.CoreModule
- - Name: tooltip
- Entry: 1
- Data: If true, the pipeline will run every frame. Use with caution, can be
- performance-intensive.
- - Name:
- Entry: 8
- Data:
+ Data: 0
- Name:
Entry: 13
Data:
diff --git a/Scripts/LinearPipeline.cs b/Scripts/LinearPipeline.cs
index ae1c65d..6087702 100644
--- a/Scripts/LinearPipeline.cs
+++ b/Scripts/LinearPipeline.cs
@@ -1,21 +1,3 @@
-/*
- Udon# Linear Pipeline Controller
-
- This script manages a linear chain of image effects. It takes a source texture
- and processes it through a sequence of materials, storing the result of each
- step in a corresponding RenderTexture.
-
- Setup:
- 1. Create an empty GameObject in your scene.
- 2. Add an UdonBehaviour component to it.
- 3. Create this Udon# script in your project and assign it to the UdonBehaviour.
- 4. Create all the Materials and RenderTextures you need for your pipeline.
- 5. In the Inspector, assign the Source Input, Materials, and Output RenderTextures.
- - The size of the Effect Materials and Pipeline Outputs arrays MUST be the same.
- - The order of materials and textures in the arrays determines the pipeline order.
- 6. Choose your desired execution mode (Run On Start, Run Continuously).
-*/
-
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
@@ -23,88 +5,41 @@ using VRC.SDKBase;
[UdonBehaviourSyncMode(BehaviourSyncMode.None)]
public class LinearPipeline : UdonSharpBehaviour
{
- [Header("Pipeline Assets")]
- [Tooltip("The initial texture to start the pipeline with.")]
- public Texture sourceInput;
-
- [Tooltip("The materials to apply in sequence. The order matters.")]
- public Material[] effectMaterials;
-
- [Tooltip("The RenderTextures to store the output of each step. MUST be the same size as the materials array.")]
- public RenderTexture[] pipelineOutputs;
-
- [Header("Execution Mode")]
- [Tooltip("If true, the pipeline will run once when the world loads.")]
- public bool runOnStart = true;
-
- [Tooltip("If true, the pipeline will run every frame. Use with caution, can be performance-intensive.")]
- public bool runContinuously = false;
-
- void Start()
+ [Header("Pipeline Assets")]
+ public string pipelineGeneratedPath = "Assets/yum_food/gpu_fft/Pipeline_Generated";
+ public Texture initialState;
+ public Material[] materials;
+ public RenderTexture[] renderTextures;
+
+ private bool isValid;
+
+ void Start()
+ {
+ ValidatePipeline();
+ }
+
+ private void ValidatePipeline()
+ {
+ isValid = materials != null &&
+ renderTextures != null &&
+ materials.Length > 0 &&
+ materials.Length == renderTextures.Length;
+
+ if (!isValid)
{
- if (runOnStart)
- {
- _RunPipeline();
- }
+ Debug.LogError($"[LinearPipeline] Invalid configuration on {gameObject.name}");
}
+ }
- void Update()
- {
- if (runContinuously)
- {
- _RunPipeline();
- }
- }
+ public void RunPipeline()
+ {
+ if (!isValid || initialState == null) return;
- /// <summary>
- /// This public method can be called by other Udon scripts or UI events to run the pipeline.
- /// </summary>
- public void _RunPipeline()
- {
- // --- Pre-flight Checks ---
- if (sourceInput == null)
- {
- Debug.LogError("[LinearPipeline] Source Input is not assigned!", this);
- return;
- }
+ VRCGraphics.Blit(initialState, renderTextures[0], materials[0], -1);
- if (effectMaterials == null || effectMaterials.Length == 0)
- {
- Debug.LogError("[LinearPipeline] No Effect Materials have been assigned!", this);
- return;
- }
-
- if (pipelineOutputs == null || pipelineOutputs.Length == 0)
- {
- Debug.LogError("[LinearPipeline] No Pipeline Outputs have been assigned!", this);
- return;
- }
-
- if (effectMaterials.Length != pipelineOutputs.Length)
- {
- Debug.LogError("[LinearPipeline] The number of materials does not match the number of output textures!", this);
- return;
- }
-
- // --- Run Pipeline ---
-
- // 1. First Blit: From the main source to the first texture in our chain.
- VRCGraphics.Blit(sourceInput, pipelineOutputs[0], effectMaterials[0], -1);
-
- // 2. Loop through the rest of the chain.
- for (int i = 1; i < effectMaterials.Length; i++)
- {
- // The source for this step is the output from the previous step.
- Texture sourceForThisStep = pipelineOutputs[i - 1];
-
- // The destination is the current output texture.
- RenderTexture destForThisStep = pipelineOutputs[i];
-
- // The material for this step.
- Material materialForThisStep = effectMaterials[i];
-
- VRCGraphics.Blit(sourceForThisStep, destForThisStep, materialForThisStep, -1);
- }
+ for (int i = 1; i < materials.Length; i++)
+ {
+ VRCGraphics.Blit(renderTextures[i-1], renderTextures[i], materials[i], -1);
}
+ }
}
-
diff --git a/Scripts/PipelineExecutor.asset b/Scripts/PipelineExecutor.asset
new file mode 100644
index 0000000..0f25570
--- /dev/null
+++ b/Scripts/PipelineExecutor.asset
@@ -0,0 +1,113 @@
+%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: c333ccfdd0cbdbc4ca30cef2dd6e6b9b, type: 3}
+ m_Name: PipelineExecutor
+ m_EditorClassIdentifier:
+ serializedUdonProgramAsset: {fileID: 11400000, guid: 1ef1a3aa7f178454d85bdad94d61f29f,
+ type: 2}
+ udonAssembly:
+ assemblyError:
+ sourceCsScript: {fileID: 11500000, guid: c5f7cea5b0013a94b9cd19ffe00f66dc, type: 3}
+ scriptVersion: 2
+ compiledVersion: 2
+ behaviourSyncMode: 0
+ hasInteractEvent: 0
+ scriptID: -1918004122012525739
+ serializationData:
+ SerializedFormat: 2
+ SerializedBytes:
+ ReferencedUnityObjects: []
+ SerializedBytesString:
+ Prefab: {fileID: 0}
+ PrefabModificationsReferencedUnityObjects: []
+ PrefabModifications: []
+ SerializationNodes:
+ - Name: fieldDefinitions
+ Entry: 7
+ Data: 0|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[UdonSharp.Compiler.FieldDefinition,
+ UdonSharp.Editor]], mscorlib
+ - Name: comparer
+ Entry: 7
+ Data: 1|System.Collections.Generic.GenericEqualityComparer`1[[System.String,
+ mscorlib]], mscorlib
+ - Name:
+ Entry: 8
+ Data:
+ - Name:
+ Entry: 12
+ Data: 1
+ - Name:
+ Entry: 7
+ Data:
+ - Name: $k
+ Entry: 1
+ Data: pipelines
+ - Name: $v
+ Entry: 7
+ Data: 2|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
+ - Name: <Name>k__BackingField
+ Entry: 1
+ Data: pipelines
+ - Name: <UserType>k__BackingField
+ Entry: 7
+ Data: 3|System.RuntimeType, mscorlib
+ - Name:
+ Entry: 1
+ Data: LinearPipeline[], Assembly-CSharp
+ - Name:
+ Entry: 8
+ Data:
+ - Name: <SystemType>k__BackingField
+ Entry: 7
+ Data: 4|System.RuntimeType, mscorlib
+ - Name:
+ Entry: 1
+ Data: UnityEngine.Component[], UnityEngine.CoreModule
+ - Name:
+ Entry: 8
+ Data:
+ - Name: <SyncMode>k__BackingField
+ Entry: 7
+ Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
+ - Name:
+ Entry: 6
+ Data:
+ - Name:
+ Entry: 8
+ Data:
+ - Name: <IsSerialized>k__BackingField
+ Entry: 5
+ Data: true
+ - Name: _fieldAttributes
+ Entry: 7
+ Data: 5|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
+ - Name:
+ Entry: 12
+ Data: 0
+ - Name:
+ Entry: 13
+ Data:
+ - Name:
+ Entry: 8
+ Data:
+ - Name:
+ Entry: 8
+ Data:
+ - Name:
+ Entry: 8
+ Data:
+ - Name:
+ Entry: 13
+ Data:
+ - Name:
+ Entry: 8
+ Data:
diff --git a/Scripts/PipelineExecutor.cs b/Scripts/PipelineExecutor.cs
new file mode 100644
index 0000000..bf40bc6
--- /dev/null
+++ b/Scripts/PipelineExecutor.cs
@@ -0,0 +1,23 @@
+using UdonSharp;
+using UnityEngine;
+using VRC.SDKBase;
+using VRC.Udon;
+
+public class PipelineExecutor : UdonSharpBehaviour
+{
+ public LinearPipeline[] pipelines;
+
+ void Update()
+ {
+ if (pipelines == null) return;
+
+ for (int i = 0; i < pipelines.Length; i++)
+ {
+ if (pipelines[i] != null)
+ {
+ pipelines[i].RunPipeline();
+ }
+ }
+ }
+}
+
diff --git a/Scripts/PipelineExecutor.cs.meta b/Scripts/PipelineExecutor.cs.meta
new file mode 100644
index 0000000..8ed362f
--- /dev/null
+++ b/Scripts/PipelineExecutor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c5f7cea5b0013a94b9cd19ffe00f66dc
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant: