夜風のMixedReality

xRと出会って変わった人生と出会った技術を書き残すためのGeekなHoloRangerの居場所

GraphicsToolsStandardShaderのMetaShaderに関して学ぶ

本日はMRGT勉強枠です。

現在MRGTのプロジェクトへPRを提出しています。

 レビューアーの方がチェックしていただいており、いくつかの修正依頼が来ています。

 今回は残す最後の修正依頼にトライします。

〇メタシェーダーの役割と実装

最後に残った修正依頼はMetaShaderに関するものでした。

Could you update the meta shader to also sample this emissive map? That way when generating static lighting (light maps) this texture is considered.

メタシェーダを更新して、このエミッシブマップもサンプリングできるようにできませんか?

MetaShaderとはGraphicsToolsStandardMetaProgram.hlslのことでGraphicsToolsStandardShaderでメインの処理の次に2つ目のSubShaderとして記述されているシェーダーです。

github.com

        // Extracts information for lightmapping, GI (emission, albedo, ...)
        // This pass it not used during regular rendering.
        Pass
        {
            Name "Meta"
            Tags { "LightMode" = "Meta" }

            HLSLPROGRAM

            #define _URP

            #include_with_pragmas "GraphicsToolsStandardMetaProgram.hlsl"
            
            ENDHLSL
        }

このシェーダーは実機上で実行されることはなくエディタ上のみで実行されます。

役割としてはライトベイクなどの静的ライティングなどで使用されます。

処理内容としてはメインの処理よりもはるかに短くなっています。

/// <summary>
/// Fragment (pixel) shader entry point.
/// </summary>
half4 PixelStage(MetaVaryings input) : SV_Target
{
#if defined(_URP)
    MetaInput output = (MetaInput)0;
    output.Albedo = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, input.uv).rgb * _Color.rgb;
#if defined(_EMISSION)
#if defined(_CHANNEL_MAP)
    output.Emission = SAMPLE_TEXTURE2D(_ChannelMap, sampler_ChannelMap, input.uv) * _EmissiveColor;
#endif
#endif

    return MetaFragment(output);
#else
    UnityMetaInput output = (UnityMetaInput)0;
    output.Albedo = tex2D(_MainTex, input.uv) * _Color;
#if defined(_EMISSION)
#if defined(_CHANNEL_MAP)
    output.Emission += tex2D(_ChannelMap, input.uv).b * _EmissiveColor;
#else
    output.Emission += _EmissiveColor;
#endif
#endif
    output.SpecularColor = _LightColor0.rgb;

    return UnityMetaFragment(output);
#endif
}

ここでMetaInput,UnityMetaInputはURPのShaderlibraryから提供されている型(Packages/com.unity.render-pipelines.universal/ShaderLibrary/MetaInput.hlsl" )でURPの場合MetaInput,ビルドインの場合UnityMetaInputが使用されます。

 これらはUnityのライトマップに使用される専用のシェーダーで、ライトマップ用のテクスチャ座標で値が返されます。

docs.unity3d.com

今回は追加実装した発光マップを使用してemissionとして登録されるようにそれぞれoutput.Emissionに_EmissiveMapの処理を追加しました。

half4 PixelStage(MetaVaryings input) : SV_Target
{
 ...
#if defined(_EMISSION)
#if defined(_CHANNEL_MAP)
    output.Emission = SAMPLE_TEXTURE2D(_ChannelMap, sampler_ChannelMap, input.uv) * _EmissiveColor;
#else
    output.Emission = SAMPLE_TEXTURE2D(_EmissiveMap, sampler_EmissiveMap, input.uv) * _EmissiveColor; //追加
#endif
#endif

    return MetaFragment(output);
#else
    UnityMetaInput output = (UnityMetaInput)0;
    output.Albedo = tex2D(_MainTex, input.uv) * _Color;
#if defined(_EMISSION)
#if defined(_CHANNEL_MAP)
    output.Emission += tex2D(_ChannelMap, input.uv).b * _EmissiveColor;
#else
    output.Emission += _EmissiveColor;
    output.Emission = tex2D(_EmissiveMap, input.uv) * _EmissiveColor;//追加
#endif
#endif
    output.SpecularColor = _LightColor0.rgb;
    return UnityMetaFragment(output);
#endif
}

本日は以上です。

これでPRに対してのフィードバックはすべて修正しました。 再びレビューしていただいていきます。

Shaderの変更を保持して使用できるAssignNewShaderToMaterial を触る その② プロパティを保持する処理を実装する

本日はMRGT枠です。

現在MRGTのプロジェクトへ機能開発を行いプルリクエストを提出しています。

github.com

ここでは修正のリクエストが来ており、以下のようにAssignNewShaderToMaterialを編集してStanardShaderなどの発光マップがシェーダー変更時にMRGTStandardShaderの_EmittiveMapに引き継がれるように依頼が来ていました。

Could you also copy the emission map property from the standard shader in the AssignNewShaderToMaterial function below?

This way users will keep their settings when switching shaders.

今回はこの修正に取り掛かります。

〇AssignNewShaderToMaterial

AssignNewShaderToMaterialはShaderGUIクラスで提供されるShaderに関する関数です。

これはマテリアルに割り当てられたShaderを別のシェーダーに変更した際に発火されます。

redhologerbera.hatenablog.com

 つまりUnityStandardShaderなど従来のシェーダーからMRGTStandardShaderに変更した際などに処理が働き、一部の共通プロパティを引き継ぐ仕組みです。

〇_EmittiveMapの追加

今回のPRではMRGTStandardShaderに発光マップ(_EmissiveMap)を追加しました。

redhologerbera.hatenablog.com

これはMRGTStandardShaderの特殊なプロパティではなくUnityのStandardShaderなどにも共通して提供されているプロパティです。

そのためこの発光マップをShader変更時に保持されるようにしていきます。

AssignNewShaderToMaterial関数にemissionMapTextureを追加します。

    public override void AssignNewShaderToMaterial(Material material, Shader oldShader, Shader newShader)
        {
         ・・・
            float? emission = null;
            Color? emissionColor = GetColorProperty(material, "_EmissionColor");
            Texture emissionMapTexture = material.HasProperty("_EmissionMap") ? material.GetTexture("_EmissionMap") : null; //追加
            ・・・

②次にemissionMapTextureが存在する場合新たなマテリアルのプロパティとしてセットする処理を加えます。

            if (emissionMapTexture)
            {
                material.SetTexture("_EmissiveMap", emissionMapTexture);
            }

以上でプロパティを保持してシェーダーの変更が可能になりました。

PRの修正点はあと一か所なので今週中に仕上げていきたいです。

MixedReality-GraphicsTools-Unityを触る その⑩ MaterialGalleryサンプル Stencil

本日はMRTK3調査枠です。

現在GraphicsToolsを読み解いています。

今回はGraphicsTools/StandardシェーダーのサンプルであるMaterialGalleryサンプルシーンを見ていきます。

〇Stencil Portal

ステンシル(Stencil)とは切り抜きを意味します。

 ステンシルを使用することであるオブジェクトを通してみることができるような表現が行えます。

Stencil PortalShaderBallPlacardの二つのオブジェクトで構成されています。

Placardは各機能を示すプラカードなので実質ShaderBallオブジェクトで構成されています。

ShaderBallの子オブジェクトには透明な板であるPortalとフレームの位置を示すための枠であるFrameがあります。

 肝となる仕組みはPortalオブジェクトとShaderBallオブジェクトで行われています。

ShaderBallオブジェクトのマテリアルを見るとEnable Stencil Testingの機能が有効化されています。

 

ShaderBall側のMRGTStandardShader

ステンシルはステンシルバッファに基づきピクセルマスクを作成し、マスクごとにピクセルを保持するか?破棄するか?を決めています。

 このステンシルバッファというものはすべてのピクセルが持つ値です。  8bitであらわされます。

 既に描かれているオブジェクトのステンシルバッファと新たに描画するピクセルのステンシルバッファを比較しフラグメントシェーダーで描画を破棄することができます。

ShaderLab: ステンシル - Unity マニュアル

MRGTStandardShaderではStencilバッファの処理があります。

            Stencil
            {
                Ref[_StencilReference]
                Comp[_StencilComparison]
                Pass[_StencilOperation]
                ReadMask[_StencilReadMask]
                WriteMask[_StencilWriteMask]
            }

ここでPortal側のマテリアルを見るとこちらもEnable Stencil Testingが有効化されており、ここではStencil ComparisonStencil Operationの値がここなっています。

 

またRenderQueueが1999でありShaderBallよりも先に描画が行われています。

 ここでStencil Comparisonはステンシルバッファの比較する方法であり、Akwaysの場合は常に描画が行われます。 またShaderBallEqualの場合Stencil Referenceの値に当たるステンシルバッファがイコールの場合描画が行われます。

 つまり先に描画されるPortalの持つステンシルバッファをもとに後に描画されるShaderBallのステンシルバッファの値が同じ部分(Portal部のみ)が描画されるようになっています。

 

 以上でステンシルを読み解いていきました。

Shaderの変更を保持して使用できるAssignNewShaderToMaterialを触る その①AssignNewShaderToMateria

本日はShader学習枠です。

 現在MixedRealityToolkitのGraphicsToolsに対して機能開発を行いPRを出しています。

 ここではShaderに新しい関数を実装し、表現の幅を広げる実装を行いましたが、PRで次のような修正依頼のフィードバックをいただきました。

Could you also copy the emission map property from the standard shader in the AssignNewShaderToMaterial function below?

This way users will keep their settings when switching shaders. 😊

github.com

ここでUnityのShaderGUIクラスによって提供されているAssignNewShaderToMaterialという関数を知らなかったので今回PRでいただいた変更を行う前に勉強していきます。

〇AssignNewShaderToMaterial

AssignNewShaderToMaterialはShaderGUIクラスで提供されている関数になります。

この関数はUnityのインスペクタウィンドウからマテリアルに割り当てられているShaderを変更した際に発火する処理で、あるシェーダーで設定したパラメータを差し替えた別のシェーダーで同じパラメータがある場合情報を引き継ぐという役割があります。

 3つの引数を持ちそれぞれ差し替えるShaderのパラメータを保持したMaterial、差し替える前のShaderであるOldShader、差し替える先のShaderdであるNewShaderを持っています

MRGTのStandardShaderGUI.csでは440行目付近に関数があります。

        public override void AssignNewShaderToMaterial(Material material, Shader oldShader, Shader newShader)
        {
            ...
        }

ShaderGUI-AssignNewShaderToMaterial - Unity スクリプトリファレンス

〇AssignNewShaderToMateriaの使い方 ①

MRGTStandardShaderではまずもともとのシェーダー変数名と新たな変数名で異なる可能性があるものをキャッシュとして宣言しています。

  public override void AssignNewShaderToMaterial(Material material, Shader oldShader, Shader newShader)
        {
            float? smoothness = GetFloatProperty(material, "_Glossiness");
            float? diffuse = GetFloatProperty(material, "_UseDiffuse");
            float? specularHighlights = GetFloatProperty(material, "_SpecularHighlights");
            float? normalMap = null;
            Texture normalMapTexture = material.HasProperty("_BumpMap") ? material.GetTexture("_BumpMap") : null;
            float? emission = null;
            Color? emissionColor = GetColorProperty(material, "_EmissionColor");
            float? reflections = null;
            float? rimLighting = null;
            Vector4? textureScaleOffset = null;
            float? cullMode = GetFloatProperty(material, "_Cull");
            bool newShaderIsStandardCanvas = newShader.name == StandardShaderUtility.GraphicsToolsStandardCanvasShaderName;

         ...

ここでは以下のプロパティに関してキャッシュ保持が働いています。

 ・Smoothness

 ・BumpMap

 ・emissionColor

 ・rimLighting

・cullMode

これはoldShaderのプロパティ(MRGTStandardに変更する前のShaderの持つプロパティ)でありこれは次の行処理で宣言されています。

  if (oldShader)
            {
                if (oldShader.name.Contains("Standard"))
                {
                    normalMap = material.IsKeywordEnabled("_NORMALMAP") ? 1.0f : 0.0f;
                    emission = material.IsKeywordEnabled("_EMISSION") ? 1.0f : 0.0f;
                    reflections = GetFloatProperty(material, "_GlossyReflections");
                }
                else if (oldShader.name.Contains("Fast Configurable"))
                {
                    normalMap = material.IsKeywordEnabled("_USEBUMPMAP_ON") ? 1.0f : 0.0f;
                    emission = GetFloatProperty(material, "_UseEmissionColor");
                    reflections = GetFloatProperty(material, "_UseReflections");
                    rimLighting = GetFloatProperty(material, "_UseRimLighting");
                    textureScaleOffset = GetVectorProperty(material, "_TextureScaleOffset");
                }
            }

ここではOldShaderの名前がStandardである場合及びDast Configurableの場合とそれ以外で分岐しています。

 StandardのシェーダーからMRGTStandardShaderへ変更する場合ノーマルマップが使用されているか? 発光は使用されているか? リフレクションは使用されているか?の3つの情報を取得しています。

 今回は長くなってしまったので続きは明日の記事でまとめていきます。

MRDevDays MixedRealityGraphicsToolsのセッションを読み解く

本日はMRTK3枠です。

6月の頭にMictosoft社によるMixedRealityのワールドワイドなイベント、MRDevDaysが開催されていました。

ここでは先日紹介したMovingPlatformMode(MPM)に関するセッションやMRTK3のパブリックプレビューに合わせてセッションが行われていました。

redhologerbera.hatenablog.com

redhologerbera.hatenablog.com

 今回はGraphics Tools for Unity in MRTK3のセッション(ディスカッション)で挙げられた情報をまとめていきます。

〇Discussion on Graphic Tools for Unity in MRTK3

 MRGTのリーダーであるCameronさんがディスかんしょんに参加されていました。

 Cameronさんはディスカッションの中で10年間UnityやUnrealEngineでスターウォーズなどのゲームを開発するプロジェクトにかかわったのち2016年よりMicrosoftに入社し、現在活躍されているそうです。

www.youtube.com

〇MixedRealityGraphicsToolsの概要(MRGT)

 MRGTはMRTKのコアパッケージの一つでMixedRealityデバイスでパフォーマンスを向上しつつ体験においての高度なグラフィックを提供するためのモデル、シェーダーなど様々なツールとそれを使用したサンプル群で構成されています。

 MRTKv2までで多くの開発者からStandardShaderなどのshaderシステムをMRTKのコアから独立して使用したいというフィードバックが集まり、その中では開発者自身でコアからの切り離しに取り組む例もあったそうです。

 これらのフィードバックを受け取り、Microsoft社内で独立したパッケージの必要性を認め新たに再構築してGraphicsToolsがリリースされました。

 MRGTでは例えばシェーダーだけを使用したい場合Unityプロジェクトに単独で取り組むことができるなど完全にスタンドアロンなパッケージとなっています。

github.com

 

〇サンプル

半ダースほどのサンプルが提供されており、開発者はUnity PackageManagerを使用して使用したいサンプルをシーン単位でインポートできます。

 Cameronさんおお気に入りの一つはMaterialGalleryと呼ばれるパッケージです。

 このシーンでは筆者も中身を読み解いている途中ですが、GraphicsToolsStandardシェーダーを用いてすべての表現を行っています。

 これはUberシェーダーシステムと呼ばれ、機能ごとに必要なものを切り替えたりすることで非常に高い柔軟性を持っています。

 これは使用している機能にのみ処理が走る仕組みのため、同一のシェーダーを使用しながらも必要な機能にのみ必要な描画コストを支払う仕組みになっています。

 

〇MRTK2とMRTK3の大きな違い

従来のMRTKのグラフィックシステムとMRTK3のグラフィックシステムでは、ほかのMRTKの機能との独立性のほかにUnityUIのサポートがあります。

Unity UIはUnityが提供する推奨UIシステムです。

 これはMRTK2ではUnityUIがサポートされていませんでしたが、継続的に多くの開発者がUnityUIを使用していることをMRTKチームが把握したことでMRGTではUnityUIがデフォルトでサポートされるようになりました。

 優れたUIを3D空間に配置するためのツールであり、優れたユーザーエクスペリエンスを簡単に構築できるようになります。

〇MRGTチーム構成

 MRTKグラフィックチームはシアトルのMicrosoft本社で活動されるCameronさんを代表として、世界で分散してメンバーがいるようです。

 ほかの拠点としてはナイジェリアやドイツに拠点があり、異なるタイムゾーンでリモートで作業が進んでいるようです。

 先日筆者が出したプルリクエストに関してもCameronさんが日本時間の早朝(現地時間午後)にレビューが行われ、日本時間の夜ドイツのMartinさんによるレビューが行われていました。

 日本時間でちょうどお昼のタイミングは現在の拠点ではタイムゾーンから外れているようです。

 本日は以上です。

 MRTKチームを主体としてコミュニティの参画も歓迎しているようなので筆者もぜひ、日本のMRGTコミュニティチームとして貢献していきたいです。

 

MixedReality GraphicsToolsにプルリクエストを提出する

本日はMRTK3枠です。

MixedRealityToolkitはMicrosoft社主導によるオープンソースプロジェクトです。

 特徴として誰もが開発にかかわることができます。Microsoft社のMRTKチームも常にフィードバックを求めており、 SNSなどで#MRTKのハッシュタグをチェックしているようです。

 今回はGraphicsToolsにプルリクエストを提出しましたので流れをまとめます。

〇MixedReality-GraphicsTools-Unity

MixedReality-GraphicsTools-Unity(MRGT)はMRTK3のパッケージでMRTKのグラフィック周りの機能を含んだパッケージになります。

 MRGTにはGraphicsToolsStandardShader(MRTKStandardShasderの後継機)やBlurなどの機能が提供されており、これらはxRデバイスに特化かつ軽量化が行われています。

 今回はGraphicsToolsStandardShaderへの新規機能開発とPRを行いました。(本記事執筆時27日夜現在Seattleは日曜日なのでまだ確認されていません。)

〇EmissionMap

今回はEmissionMapの機能提案、開発を行いました。

MRTKに貢献するためには最初にイシューを建てる必要があります。

  github.com

イシューではプロジェクトに関するあらゆる報告を行います。

 enhancementbugdocumentationquestionなど様々なラベルがあり、今回行った機能開発に当たるenhancementの報告のほかにプロジェクトにおいての問題点を質問として聞くこともできます。

 この質問はプロジェクトにとって新たなバグが見つかる場合や次の機能開発につながる場合もあります。

 今回は次のようなイシューを建てました。

ざっくりと概要をまとめると次のようになります。

URP/Litなど多くのEmissionを扱うShaderにはEmissionMapの画像を指定することでより様々な表現がありますが、 GraphicsToolsStandardShaderにはそれがありませんので作っていいですか?

これに加えOKなら勉強がてら取り組むよ!と書きました。

 If this proposal is approved, I will incorporate the functionality and publish a PR while also learning GraphicsTools.

これに対してプロジェクトリーダーであるCameronさんはよい提案と了承していただきました。

また、この時点でAssignees(担当者)に私が割り当てられました。

〇プロジェクトのFork

作業に当たるためにプロジェクトをフォークします。

これはオリジナル(microsoft/MixedReality-GraphicsTools-Unity)のリポジトリを自身のリポジトリ(HoloMoto/MixedReality-GraphicsTools-Unity)としてコピーすることを指します。

自身のプロジェクトとして作業を行います。

最初のやり取りで「週末に取り組むね!」といっていましたが、実際に取り組むと惜しいところで壁に当たってしまいました。

 そこで新たに進捗として現状を報告しました。

 ここではtex2Dに関するエラーが発生するという報告でしたが、Cameronさんは翌日には考えられる修正点が含まれるファイルの場所を共有していただきました。

作業が完了しEmissionMapの機能を無事に実装出来たところでHoloMoto/MixedReality-GraphicsTools-UnityにPushし、そこからオリジナルのMicrosoft/MixedReality-GraphicsTools-Unityにプルリクエストを出します。

github.com

これによってプロジェクトリーダーであるCameronさんにチェック、レビューをいただき場合によっては修正依頼、完全の場合microsoft/MixedReality-GraphicsTools-Unityの本ブランチにマージしていただけます。

 マージされた場合私の変更点が次回以降のリリースパッケージに含まれます。

 コード面での変更点などはマージされたタイミングで記載します。

本日は以上です。

MRDevDays MovingPlatformModeセッションを読み解く その② DownDirection

本日はイベント枠です。

 6月の頭Microsoft社によるMixedReality関連のワールドワイドなイベントMRDevDaysが開催されていました。   昨日よりMRDevDaysで公開されたMovingPlatformModeに関するセッションを読み解いています。

昨日はMPMの基本的な概要と開発タイムラインを読み解きました。

redhologerbera.hatenablog.com

〇Down Direction

 通常HoloLensで描画されるホログラムは重力が下向きとして定義して配置されます。

 この重力はIMUで取得された情報をもとに使用されています。

 MovingPlatformMode(MPM)使用時は前回読み解いたように通常時環境カメラとIMUを併用して行われているSLAMとは別のアルゴリズムが動いています。

 この重力があることによってアプリ内で力学的なインタラクションやアプリ内での方向の定義が決定しています。

 通常この重力方向はアプリ起動時に調整されています。

MPM有効時は重力向きと実際の床の位置がずれることが想定されるためGravityではなくDown Directionという新たな軸定義で上書きしています。

Down Directionは加速度情報による向きに依存せず、環境が回転していても一定の値を返します。

〇Down Directionの設定

Down Directionの設定は2つの方法があります。

①自動調整  これは特に何もしないデフォルトの設定で、20秒間にわたる重力の値で計算されます。

②現在の頭の向きにより設定

 これは設定アプリから行えるもので、現在の頭の位置を基準にDownDirectionを決定してます。

 主導でDownDirectionを設定する利点としては宇宙空間での使用などあらゆる状況に対応できる点があります。

 このような特殊環境下では、例えばある壁に対してDownDirectionを設定し、壁に対して平行にUIなどが配置されるようにすることができます。

 また、宇宙空間などの環境的な特殊要因がなくても、例えば寝たきりの人なども自分に対してUIが水平に表示されるようにしたいといったアクセシビリティでの側面も持っています

〇MPMを使用すれば無重力空間でもSLAMが使用できるか?

セッション内の質問では無重力空間で使用できるか?という質問がありました。

これに対しスピーカーのJoshuaさんはよい質問といい 可能であると、そして実際にNASAのようなパートナーとやり取りしながら前述のように宇宙ステーションで使用してたようです。

 HoloLensデバイスがMPMの機能を使用している際デバイスの電源がオン人なった起動時にDonwDirectionを検索しており、測定された重力の値が一定値より下回っている場合手動でDownDirectionを設定するのと同様にユーザーの下向き方向をDownDirectionとして設定しています。

 設計としては上記のようになっているそうですが、実際に無重力化での試験は行われておらず、Microsoftとしての正式に無重力で使用が可能というサポートはされていないようです。

〇寝ながらHoloLensを動作する。

 セッションでは横になりながらのHoloLensの使用は『正式にはサポートされているものではない』と述べられていますが、今回筆者の環境で横になりながらHoloLens 2の使用を行ってみました。

youtu.be

DownDirectionを手動で設定することで、自身の重力的な立ち位置に関係なく重力方向を設定できます。

本日は以上です。

前回の内容でMPMはアルゴリズムを変えているという話がありましたが、これに加え基準となるDownDirectionを理解できたことで場合によって自動、場合によって手動でDownDirectionを設定することでよりあらゆる環境に対応したHoloLensが使えそうです。