3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Unity6.3のUIToolkitの新機能を触ってみる

Last updated at Posted at 2025-12-10

本記事は サムザップ Advent Calendar 2025 11日目の記事です。

はじめに

Unity6.3からUIToolkitがShaderGraphに対応しました。
また、Filterと呼ばれるポストプロセスのような機能にも対応したので触ってみようと思います。

環境

Unity 6000.3.0b10

自作したShaderGraph対応

ShaderGraphの生成

Projectウィンドウで右クリックを押下し、
Create/Shader Graph/URP/UI Shader Graph から生成するだけで完了です。

CreateShaderGraph.png

もしくは既に生成したShaderGraphのGraphInspectorの、
Universl/MaterialUI にしてください。

GraphInspector.png

ShaderGraphの中身

ポスタライズするだけにしています。

ShaderGraphView.png

Value 変数はfloat型を指定しているだけです。

ValueProperty.png

DefaultTextureノードについて

UIToolkit専用のノードで、UI側で指定されているテクスチャを取得した結果を返すノードです。
Sample Texture 2D ノードと似た機能ですが、こちらはTextureを指定しなくてもUI側で指定しているものを自動で取得してくれます。

DefultTexture.png

RenderTypeBranchノードについて

UIToolkit専用のノードで、テクスチャの種類を見て適した結果を返してくれるノードです。
このノードの出力を Fragment ノードに接続する必要があります。

RenderTypeBranch.png

生成されたコードは以下のようになっています。

生成されたコード
[branch] if (_UIE_RENDER_TYPE_TEXTURE || _UIE_RENDER_TYPE_ANY && round(IN.typeTexSettings.x) == k_FragTypeTexture)
{
    TextureFragInput Unity_UIE_EvaluateTextureNode_Input;
    Unity_UIE_EvaluateTextureNode_Input.tint = IN.color;
    Unity_UIE_EvaluateTextureNode_Input.textureSlot = IN.typeTexSettings.y;
    Unity_UIE_EvaluateTextureNode_Input.uv = (_Posterize_42247c5b519243acba20130591f25500_Out_2_Vector4.xy);
    Unity_UIE_EvaluateTextureNode_Input.isArc = false;
    Unity_UIE_EvaluateTextureNode_Input.outer = float2(-10000, -10000);
    Unity_UIE_EvaluateTextureNode_Input.inner = float2(-10000, -10000);
    CommonFragOutput Unity_UIE_EvaluateTextureNode_Output = uie_std_frag_texture(Unity_UIE_EvaluateTextureNode_Input);
    _DefaultTexture_d275e0be703a447d99a4926b24d80a2c_Texture_2_Vector4 = Unity_UIE_EvaluateTextureNode_Output.color;
}
float3 _RenderTypeBranch_d1b1e877eeff451b928a39fae1df6953_Color_5_Vector3 = float3(0, 0, 0);
float _RenderTypeBranch_d1b1e877eeff451b928a39fae1df6953_Alpha_6_Float = 1.0;
[branch] if (_UIE_RENDER_TYPE_SOLID || _UIE_RENDER_TYPE_ANY && TestType(IN.typeTexSettings.x, k_FragTypeSolid))
{
    SolidFragInput Unity_UIE_RenderTypeSwitchNode_Solid_Input;
    Unity_UIE_RenderTypeSwitchNode_Solid_Input.tint = IN.color;
    Unity_UIE_RenderTypeSwitchNode_Solid_Input.isArc = false;
    Unity_UIE_RenderTypeSwitchNode_Solid_Input.outer = float2(-10000, -10000);
    Unity_UIE_RenderTypeSwitchNode_Solid_Input.inner = float2(-10000, -10000);
    CommonFragOutput Unity_UIE_RenderTypeSwitchNode_Output = uie_std_frag_solid(Unity_UIE_RenderTypeSwitchNode_Solid_Input);
    _RenderTypeBranch_d1b1e877eeff451b928a39fae1df6953_Color_5_Vector3 = Unity_UIE_RenderTypeSwitchNode_Output.color.rgb;
    _RenderTypeBranch_d1b1e877eeff451b928a39fae1df6953_Alpha_6_Float = Unity_UIE_RenderTypeSwitchNode_Output.color.a;
}
else [branch] if (_UIE_RENDER_TYPE_TEXTURE || _UIE_RENDER_TYPE_ANY && TestType(IN.typeTexSettings.x, k_FragTypeTexture))
{
    _RenderTypeBranch_d1b1e877eeff451b928a39fae1df6953_Color_5_Vector3 = _DefaultTexture_d275e0be703a447d99a4926b24d80a2c_Texture_2_Vector4.rgb;
    _RenderTypeBranch_d1b1e877eeff451b928a39fae1df6953_Alpha_6_Float = _DefaultTexture_d275e0be703a447d99a4926b24d80a2c_Texture_2_Vector4.a;
}
else [branch] if ((_UIE_RENDER_TYPE_TEXT || _UIE_RENDER_TYPE_ANY) && TestType(IN.typeTexSettings.x, k_FragTypeText))
{
    [branch] if (GetTextureInfo(IN.typeTexSettings.y).sdfScale > 0.0)
    {
        SdfTextFragInput Unity_UIE_RenderTypeSwitchNode_SdfText_Input;
        Unity_UIE_RenderTypeSwitchNode_SdfText_Input.tint = IN.color;
        Unity_UIE_RenderTypeSwitchNode_SdfText_Input.textureSlot = IN.typeTexSettings.y;
        Unity_UIE_RenderTypeSwitchNode_SdfText_Input.uv = IN.uvClip.xy;
        Unity_UIE_RenderTypeSwitchNode_SdfText_Input.extraDilate = IN.circle.x;
        Unity_UIE_RenderTypeSwitchNode_SdfText_Input.textCoreLoc = round(IN.textCoreLoc);
        Unity_UIE_RenderTypeSwitchNode_SdfText_Input.opacity = IN.typeTexSettings.z;
        CommonFragOutput Unity_UIE_RenderTypeSwitchNode_Output = uie_std_frag_sdf_text(Unity_UIE_RenderTypeSwitchNode_SdfText_Input);
        _RenderTypeBranch_d1b1e877eeff451b928a39fae1df6953_Color_5_Vector3 = Unity_UIE_RenderTypeSwitchNode_Output.color.rgb;
        _RenderTypeBranch_d1b1e877eeff451b928a39fae1df6953_Alpha_6_Float = Unity_UIE_RenderTypeSwitchNode_Output.color.a;
    }
    else
    {
        BitmapTextFragInput Unity_UIE_RenderTypeSwitchNode_BitmapText_Input;
        Unity_UIE_RenderTypeSwitchNode_BitmapText_Input.tint = IN.color;
        Unity_UIE_RenderTypeSwitchNode_BitmapText_Input.textureSlot = IN.typeTexSettings.y;
        Unity_UIE_RenderTypeSwitchNode_BitmapText_Input.uv = IN.uvClip.xy;
        Unity_UIE_RenderTypeSwitchNode_BitmapText_Input.opacity = IN.typeTexSettings.z;
        CommonFragOutput Unity_UIE_RenderTypeSwitchNode_Output = uie_std_frag_bitmap_text(Unity_UIE_RenderTypeSwitchNode_BitmapText_Input);
        _RenderTypeBranch_d1b1e877eeff451b928a39fae1df6953_Color_5_Vector3 = Unity_UIE_RenderTypeSwitchNode_Output.color.rgb;
        _RenderTypeBranch_d1b1e877eeff451b928a39fae1df6953_Alpha_6_Float = Unity_UIE_RenderTypeSwitchNode_Output.color.a;
    }
}
else
{
    SvgGradientFragInput Unity_UIE_RenderTypeSwitchNode_SvgGradient_Input;
    Unity_UIE_RenderTypeSwitchNode_SvgGradient_Input.settingIndex = round(IN.typeTexSettings.z);
    Unity_UIE_RenderTypeSwitchNode_SvgGradient_Input.textureSlot = round(IN.typeTexSettings.y);
    Unity_UIE_RenderTypeSwitchNode_SvgGradient_Input.uv = IN.uvClip.xy;
    Unity_UIE_RenderTypeSwitchNode_SvgGradient_Input.isArc = false;
    Unity_UIE_RenderTypeSwitchNode_SvgGradient_Input.outer = float2(-10000, -10000);
    Unity_UIE_RenderTypeSwitchNode_SvgGradient_Input.inner = float2(-10000, -10000);
    CommonFragOutput Unity_UIE_RenderTypeSwitchNode_Output = uie_std_frag_svg_gradient(Unity_UIE_RenderTypeSwitchNode_SvgGradient_Input);
    _RenderTypeBranch_d1b1e877eeff451b928a39fae1df6953_Color_5_Vector3 = Unity_UIE_RenderTypeSwitchNode_Output.color.rgb * IN.color.rgb;
    _RenderTypeBranch_d1b1e877eeff451b928a39fae1df6953_Alpha_6_Float = Unity_UIE_RenderTypeSwitchNode_Output.color.a * IN.color.a;
}

少し冗長に見えますが、

  • Universl/MaterialUIにした時点でバリアントは生まれてしまう
  • 公式ドキュメントに、何も接続しなければ分岐をよしなにしてくれるとの記載
  • MainPreview が恐らくこれを用いてプレビューしている

から、ボトルネックにならない限りはこのままでも良さそうです。

UIToolkitに反映させる

制作したShaderGraphをUIToolkitに反映させます。

右クリックから、
Create/UI Toolkit/UI Docment(UXML) を押下します。

CreateUXML.png

生成されたファイルをダブルクリックで、UIBuilderを開きます。
そして、ImageをHierarchyにドラッグアンドドロップします。

AttachImage.png

ImageのInspectorを開き、
Sourceの項目にUIとして表示させたい画像を、Materialに今回制作したShaderGraphのマテリアルをアタッチします。

ImageInspector.png

Materialの+ボタンを押下し、ShaderGraph側で設定したPropertyであるValueを選択します。

MaterialValueProp.png

結果

添付動画のようにUIToolkitで自作したShaderGraphが動いていれば成功です。

Filterについて

ポストプロセスのようなことが出来るFilterもUnity6.3から追加されました。

Filterの追加方法

といっても追加方法は簡単で、UIBuilderを開き
Filter/Functionで任意のフィルターを選択するだけです。

AddFilter.png

組み合わせることもでき、このような形でFilterをかけることができます。

Filterをコードで書く

コードで書くことも出来るので、コードでも書いてみます。

まずはUIBuilderを開き、左上の+ボタンから
Create New USS を押します。

CreateNewUss.png

生成されたUSSをIDE等で開き、以下のように記載します。

.hover-transition {
    filter: blur(0) invert(0%);
    transition: filter 0.5s;
}

.hover-transition:hover {
    filter: blur(10px) invert(100%);
}

UIBuilderに戻り、StyleClassListに
.hover-transition と入力し、エンターキーを押します。

AddStyleClassList.png

以下のように入力されたものが追加されていれば成功です。

AddStyleClassListResult.png

UnityからGameObjectを作り、

  • UI Document をアタッチ
  • 制作したUXMLを Source Asset にアタッチ

の操作を行います。

UnityGameObject.png

結果

コードでFilterを適応させることができました。
また、マウスカーソルを重ねたときにFilterがかかっています。

自作Filterの作成

自作したシェーダーを、Filterとして適応させてみます。

筆者が確認した限り、ShaderGraphの対応はしていなさそうでした。
なので今回は.shaderで制作します。

シェーダーの作成

テクスチャをサンプリングし、パラメータによって色を変えることの出来るシンプルなシェーダーを用意します。

UIToolkitには強制的にGammaに変換する Force Gammma Rendering というパラメータがあります。
Linearワークフローで作業している場合、UIE_OUTPUT_LINEAR というディレクティブを追加することで、このパラメータに対応することができます。

Shader "UI/Filters/Color"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }

    SubShader
    {
        Tags
        {
            "RenderType"="Transparent"
            "Queue"="Transparent"
            "RenderPipeline"="UniversalPipeline"
        }

        Cull Off
        ZWrite Off
        ZTest Always
        Blend SrcAlpha OneMinusSrcAlpha

        Pass
        {
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile _ UIE_OUTPUT_LINEAR

            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

            struct appdata
            {
                float4 positionOS : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 positionCS : SV_POSITION;
            };

            TEXTURE2D(_MainTex);
            SAMPLER(sampler_MainTex);
            float4 _MainTex_ST;
            half3 _Color;
            float _Intensity;

            half3 GammaToLinearSpace (half3 sRGB)
            {
                return sRGB * (sRGB * (sRGB * 0.305306011h + 0.682171111h) + 0.012522878h);
            }

            v2f vert (appdata v)
            {
                v2f o;
                o.positionCS = TransformObjectToHClip(v.positionOS.xyz);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            half4 frag (v2f i) : SV_Target
            {
                float2 uv = i.uv;
                half4 col = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv);
                
                col.rgb *= _Color * _Intensity;

                // UIToolkit
                #ifdef UIE_OUTPUT_LINEAR
                    col.rgb = GammaToLinearSpace(col.rgb);
                #endif

                return col;
            }
            ENDHLSL
        }
    }
}

FilterFunctionDefinition の生成

シェーダーで制作したものをUIToolkitに反映させるため、FilterFunctionDefinitionを制作します。
これはUIToolkitで、どのマテリアルの何のパラメータを操作できるようにするかを明示するものです。

まずは、Projectウィンドウで右クリックを押下し、
Create/UI Toolkit/Filter Function Definition を押下します。

FilterFunction.png

そうすると、FilterFunctionDefinitionが生成されるので以下のように入力します。

ColorFunctionFilter.png

パラメータの詳細は以下です。

名前 意味
Filter Name フィルター名
Parameters
- Name UIToolkit上で表示される名前
- Type このパラメータの型
float もしくは color
- Interpolation Default デフォルト値
Passes
- Material このFilterのシェーダーのマテリアル
- Pass Index シェーダーのPassのIndex
- Parameter Bindings
- - Index Nameに紐付くParametersのIndex
- - Name シェーダーのパラメータ名

FilterFunctionDefinition をScriptで生成する

詳細は割愛しますが、C#で生成出来たほうが便利なケースもあるかと思います。
ですので、サンプルコードを乗せます。


using UnityEngine;
using UnityEditor;
using UnityEngine.UIElements;

public class CreateFilter : Editor
{
    [MenuItem("Assets/Create/UI Toolkit/Create Custom Filter")]
    public static void CreateColorFilterAsset()
    {
        var shader = Shader.Find("UI/Filters/Color");
        var material = new Material(shader)
        {
            name = "colorFilterMaterial"
        };

        AssetDatabase.CreateAsset(material, "Assets/colorFilterMaterial.mat");

        var colorFilter = CreateInstance<FilterFunctionDefinition>();
        colorFilter.name = "colorFilter";

        colorFilter.parameters = new[]
        {
            // 操作できるパラメータ
            new FilterParameterDeclaration 
            {
                name = "color", // 名前
                interpolationDefaultValue = new FilterParameter(Color.black) // デフォルト値
            },
            new FilterParameterDeclaration
            {
                name = "intensity",
                interpolationDefaultValue = new FilterParameter(1f)
            }
        };

        // レンダリングパス定義
        colorFilter.passes = new[] 
        {
            new PostProcessingPass 
            {
                material = material,
                passIndex = 0,  // ShaderのPassのindex
                parameterBindings = new[] 
                {
                    new ParameterBinding
                    {
                        index = 0,  // parameters配列のインデックス
                        name = "_Color" // シェーダープロパティ名
                    },
                    new ParameterBinding
                    {
                        index = 0,
                        name = "_Intensity"
                    }
                }
            }
        };

        AssetDatabase.CreateAsset(colorFilter, "Assets/colorFilter.asset");
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();

        Selection.activeObject = colorFilter;
    }
}


UIBuilderの操作

UIBuilderに戻り、Filterを以下のように設定します。

  • Function : Custom
  • Definition : 生成したFilterFunctionDefinition

CustomFilter.png

結果

動画のようにパラメータによって画像の色が変わっていれば成功です。

最後に

UI Toolkit × Shader Graph / Filter 対応のおかげで、UIToolkitも段々扱いやすくなってきたのではないでしょうか。
今回の記事が皆さんのプロジェクトでお役に立てば幸いです。

明日は、 @Haru184 さんの記事になります。お楽しみに!!

参考サイト様

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?