Created
November 17, 2025 00:49
-
-
Save wotakuro/fc13d755ba3734b2460602655505de13 to your computer and use it in GitHub Desktop.
GraphicsStateCollectionをMergeしたり、分割するサンプル
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using UnityEngine; | |
| using UnityEditor; | |
| using UnityEngine.UIElements; | |
| using UnityEditor.UIElements; | |
| using UnityEngine.Experimental.Rendering; | |
| using UnityEditor.Playables; | |
| namespace UTJ.Sample | |
| { | |
| public class GraphicsStateCollectionSeparatorUI : EditorWindow | |
| { | |
| [MenuItem("Tools/GraphicsStateCollection/SplitByShader")] | |
| public static void Create() | |
| { | |
| GraphicsStateCollectionSeparatorUI.GetWindow<GraphicsStateCollectionSeparatorUI>(); | |
| } | |
| private GraphicsStateCollection target; | |
| private void OnEnable() | |
| { | |
| ObjectField field = new ObjectField(); | |
| field.objectType = typeof(GraphicsStateCollection); | |
| field.RegisterValueChangedCallback(OnChangeObject); | |
| Button button = new Button(); | |
| button.text = "split by Shader"; | |
| button.clicked += this.OnClickButton; | |
| this.rootVisualElement.Add(field); | |
| this.rootVisualElement.Add(button); | |
| } | |
| private void OnClickButton() | |
| { | |
| var originalPath = AssetDatabase.GetAssetPath(target); | |
| var directory = originalPath.Substring(0, originalPath.LastIndexOf('.')); | |
| if (!System.IO.Directory.Exists(directory)) | |
| { | |
| System.IO.Directory.CreateDirectory(directory); | |
| } | |
| Debug.Log(directory); | |
| var splitDictionary = GraphicsStateCollectionUtility.SplitByShader(target); | |
| foreach (var kvp in splitDictionary) | |
| { | |
| var shader = kvp.Key; | |
| var savePath = System.IO.Path.Combine(directory, shader.name.Replace('/','_').Replace('|','-')+ ".graphicsstate"); | |
| GraphicsStateCollectionUtility.SaveAsAsset(kvp.Value, savePath); | |
| } | |
| } | |
| private void OnChangeObject(ChangeEvent<UnityEngine.Object> changeEvent) | |
| { | |
| this.target = changeEvent.newValue as GraphicsStateCollection; | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System.Collections.Generic; | |
| using UnityEngine; | |
| using UnityEngine.Experimental.Rendering; | |
| namespace UTJ.Sample | |
| { | |
| /// <summary> | |
| /// GraphicsStateCollectionのUtility | |
| /// </summary> | |
| public static class GraphicsStateCollectionUtility | |
| { | |
| /// <summary> | |
| /// GraphicsStateCollectionをShaderで分割を行います | |
| /// </summary> | |
| /// <param name="graphicsStateCollection">分割したGraphicsStateCollection</param> | |
| /// <returns>分割元のデータ</returns> | |
| public static Dictionary<Shader, GraphicsStateCollection> SplitByShader(GraphicsStateCollection graphicsStateCollection) | |
| { | |
| Dictionary<Shader, GraphicsStateCollection> dictionary = new Dictionary<Shader, GraphicsStateCollection>(); | |
| // GraphicsStateCollectionがないなら、空のDictionaryを返します | |
| if (!graphicsStateCollection) | |
| { | |
| return dictionary; | |
| } | |
| var variants = new List<GraphicsStateCollection.ShaderVariant>(graphicsStateCollection.variantCount); | |
| var variantStatesBuffer = new List<GraphicsStateCollection.GraphicsState>(); | |
| // GraphicsStateCollectionにあるVariantでループを回します | |
| graphicsStateCollection.GetVariants(variants); | |
| foreach (var variant in variants) | |
| { | |
| var shader = variant.shader; | |
| if(!shader) | |
| { | |
| continue; | |
| } | |
| // 分割後のGraphicsStateCollectionを得ます | |
| GraphicsStateCollection splitGraphicsState; | |
| if (!dictionary.TryGetValue(shader, out splitGraphicsState)) | |
| { | |
| splitGraphicsState = new GraphicsStateCollection(); | |
| splitGraphicsState.graphicsDeviceType = graphicsStateCollection.graphicsDeviceType; | |
| splitGraphicsState.runtimePlatform = graphicsStateCollection.runtimePlatform; | |
| dictionary.Add(shader, splitGraphicsState); | |
| } | |
| // Shaderに対応する Variantを設定します | |
| splitGraphicsState.AddVariant(shader, variant.passId, variant.keywords); | |
| // Variantに対応する | |
| // Pipeline State Objectを設定していきます | |
| variantStatesBuffer.Clear(); | |
| graphicsStateCollection.GetGraphicsStatesForVariant(variant, variantStatesBuffer); | |
| foreach (var variantState in variantStatesBuffer) | |
| { | |
| splitGraphicsState.AddGraphicsStateForVariant(shader, | |
| variant.passId, variant.keywords, variantState); | |
| } | |
| } | |
| return dictionary; | |
| } | |
| /// <summary> | |
| /// 複数のGraphicsStateCollectionをマージします | |
| /// </summary> | |
| /// <param name="mergedGraphicsStateCollection">マージ先のGraphicsStateCollectionを指定します</param> | |
| /// <param name="graphicsStateCollections">マージしたいList等を渡します</param> | |
| public static void MergeGraphicsStateCollection( | |
| GraphicsStateCollection mergedGraphicsStateCollection, | |
| IEnumerable<GraphicsStateCollection> graphicsStateCollections) | |
| { | |
| var variantBuffer = new List<GraphicsStateCollection.ShaderVariant>(); | |
| var variantStatesBuffer = new List<GraphicsStateCollection.GraphicsState>(); | |
| // 渡されたリスト等を順次回します | |
| foreach (var gscObjecgt in graphicsStateCollections) | |
| { | |
| // 無効なGraphicsStateCollectionはスキップします | |
| if (!gscObjecgt) | |
| { | |
| continue; | |
| } | |
| variantBuffer.Clear(); | |
| gscObjecgt.GetVariants(variantBuffer); | |
| foreach (var variant in variantBuffer) | |
| { | |
| // マージ後にVariant追加 | |
| // (追加成功時にはaddVariantResult にtrueが入ります。既にあって追加されない場合 falseとなります | |
| bool addVariantResult = mergedGraphicsStateCollection.AddVariant(variant.shader, variant.passId, variant.keywords); | |
| variantStatesBuffer.Clear(); | |
| gscObjecgt.GetGraphicsStatesForVariant(variant, variantStatesBuffer); | |
| foreach(var variantState in variantStatesBuffer) | |
| { | |
| // マージ後にState追加 | |
| // (追加成功時にはaddVariantResult にtrueが入ります。既にあって追加されない場合 falseとなります | |
| bool addStateResult = mergedGraphicsStateCollection.AddGraphicsStateForVariant(variant.shader,variant.passId,variant.keywords, variantState); | |
| } | |
| } | |
| } | |
| } | |
| /// <summary> | |
| /// GraphicsStateCollectionをAssetとして保存します | |
| /// </summary> | |
| /// <param name="graphicsStateCollection">保存したいGraphicsStateCollectionを指定します</param> | |
| /// <param name="path">保存パス</param> | |
| /// <returns>保存に成功するとTrueを返します</returns> | |
| public static bool SaveAsAsset(GraphicsStateCollection graphicsStateCollection, string path) | |
| { | |
| if (!graphicsStateCollection) | |
| { | |
| return false; | |
| } | |
| return graphicsStateCollection.SaveToFile(path); | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using UnityEditor; | |
| using System.Collections.Generic; | |
| using UnityEngine; | |
| using UnityEditor.UIElements; | |
| using UnityEngine.UIElements; | |
| using UnityEngine.Experimental.Rendering; | |
| using UTJ.Sample; | |
| using UnityEditor.Playables; | |
| public class GraphicsStateMergeTool : EditorWindow | |
| { | |
| /// <summary> | |
| /// マージ先の指定 | |
| /// </summary> | |
| private ObjectField baseGraphicsStateCollectionField; | |
| /// <summary> | |
| /// ScrollView | |
| /// </summary> | |
| private ScrollView scrollView; | |
| [MenuItem("Tools/GraphicsStateCollection/MergeTool")] | |
| public static void Create() | |
| { | |
| GraphicsStateMergeTool.GetWindow<GraphicsStateMergeTool>(); | |
| } | |
| /// <summary> | |
| /// 初期化時 | |
| /// </summary> | |
| private void OnEnable() | |
| { | |
| baseGraphicsStateCollectionField = new ObjectField(); | |
| baseGraphicsStateCollectionField.objectType = typeof(GraphicsStateCollection); | |
| this.rootVisualElement.Add(new Label("マージ先GraphicsStateCollection")); | |
| this.rootVisualElement.Add(baseGraphicsStateCollectionField); | |
| var mergeButton = new Button(); | |
| mergeButton.text = "以下のものをマージする"; | |
| mergeButton.clicked += ExecuteMerge; | |
| this.rootVisualElement.Add(mergeButton); | |
| this.scrollView = new ScrollView(); | |
| this.rootVisualElement.Add(scrollView); | |
| var plusButton = new Button(); | |
| plusButton.text = "+"; | |
| plusButton.clicked += OnclickPlusButton; | |
| this.rootVisualElement.Add(plusButton); | |
| this.OnclickPlusButton(); | |
| } | |
| /// <summary> | |
| /// マージの実行 | |
| /// </summary> | |
| private void ExecuteMerge() | |
| { | |
| // ScrollView以下に下がっているオブジェクトフィールドを探してきます | |
| var objectFields = this.scrollView.Query<ObjectField>(); | |
| var graphicStateCollections = new List<GraphicsStateCollection>(); | |
| objectFields.ForEach(field => | |
| { | |
| var gcs = field.value as GraphicsStateCollection; | |
| if (gcs) | |
| { | |
| graphicStateCollections.Add(gcs); | |
| } | |
| }); | |
| var baseGcs =baseGraphicsStateCollectionField.value as GraphicsStateCollection; | |
| GraphicsStateCollectionUtility.MergeGraphicsStateCollection(baseGcs, graphicStateCollections); | |
| } | |
| /// <summary> | |
| /// +ボタンが押された時 | |
| /// </summary> | |
| private void OnclickPlusButton() | |
| { | |
| VisualElement visualElement = new VisualElement(); | |
| visualElement.style.flexDirection = FlexDirection.Row; | |
| var mergeObject = new ObjectField(); | |
| mergeObject.objectType = typeof(GraphicsStateCollection); | |
| var deleteButton = new Button(); | |
| deleteButton.text = "削除"; | |
| // 削除ボタンは、親ごと削除することで実現します | |
| deleteButton.clicked += ()=>{ | |
| deleteButton.parent.parent.Remove(deleteButton.parent); | |
| }; | |
| visualElement.Add(mergeObject); | |
| visualElement.Add(deleteButton); | |
| this.scrollView.Add(visualElement); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment