diff options
| author | yum <yum.food.vr@gmail.com> | 2025-07-30 13:09:19 -0700 |
|---|---|---|
| committer | yum <yum.food.vr@gmail.com> | 2025-07-30 13:16:57 -0700 |
| commit | 65797304fb21181e1fcbd45dfebd0d2cf159ea6b (patch) | |
| tree | e5580c68d1f1f791d5a801ede40b83dce92cc745 /Scripts | |
| parent | 341ea861c8189cefe8689bd41d8adbe2cd2d87b2 (diff) | |
- Add a script to create a pipeline & assets in a single click
- Add pipeline executor concept. This exists to (theoretically) let
users merge the results of multiple pipelines.
Diffstat (limited to 'Scripts')
| -rw-r--r-- | Scripts/Editor/LinearPipelineEditor.cs | 339 | ||||
| -rw-r--r-- | Scripts/Editor/PipelineExecutorEditor.cs | 70 | ||||
| -rw-r--r-- | Scripts/LinearPipeline.asset | 134 | ||||
| -rw-r--r-- | Scripts/LinearPipeline.cs | 127 | ||||
| -rw-r--r-- | Scripts/PipelineExecutor.asset | 113 | ||||
| -rw-r--r-- | Scripts/PipelineExecutor.cs | 23 | ||||
| -rw-r--r-- | Scripts/PipelineExecutor.cs.meta | 11 |
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: |
