夜風のMixedReality

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

プラットフォームによってShaderのUV座標が上下反転する問題

本日はShaderのトラブル解消を行います。

先日MixedRealityGraphicsToolsの拡大鏡機能をHoloLensで実行した際にUV座標のV座標が反転する現象を確認しました。

redhologerbera.hatenablog.com

 取り急ぎの対処としてV座標に-1をかけ合わせてトラブルを回避しました。

redhologerbera.hatenablog.com

この方法ではHoloLens 2実機に合わせてShaderを書き換えたため今度はUntiyEditorや他のプラットフォームでV座標が反転する問題が発生します。

〇プラットフォーム毎よってUV座標が反転する原因

今回の原因はグラフィックスAPIによる座標系の定義の違いです。

redhologerbera.hatenablog.com

 HoloLens 2ではDirectX、QuestなどのAndroidデバイスではOpenGL やVulkanなどが使用されています。

UV座標に関しての原点(0,0)はそれぞれ次のように定義されています。

〇UNITY_UV_STARTS_AT_TOP

UNITY_UV_STARTS_AT_TOPはUnityで提供されている定義済みマクロ(条件コンパイル)です。

 返り値として0or1が定まっていますが、実行環境のプラットフォームによって自動的に割り振られます。

この仕組みはマルチプラットフォームでの稼働を想定して設計されているGraphicsTools/Standardシェーダーにも採用されています。

MixedReality-GraphicsTools-Unity/GraphicsToolsStandardProgram.hlsl at 9f4e35db81b680060d70609e61a47e0efddba1de · microsoft/MixedReality-GraphicsTools-Unity · GitHub

 GraphicsToolsStandardシェーダーでもブラーなどのスクリーン座標の処理が行われており、同様の仕組みが実装されています、。

#if defined(_UV_SCREEN)
    output.uvScreen = ComputeScreenPos(output.position);
    // Flip vertical UV for orthographic projections (if not already flipped) to ensure the image is not upside down.
#if defined(UNITY_UV_STARTS_AT_TOP)
    output.uvScreen.y = unity_OrthoParams.w ? (1.0 - output.uvScreen.y) : output.uvScreen.y;
#else
    output.uvScreen.y = unity_OrthoParams.w ? output.uvScreen.y : (1.0 - output.uvScreen.y);
#endif
#elif (_BLUR_TEXTURE_PREBAKED_BACKGROUND)
    output.uvBackgroundRect = float2((vertexPosition.x - _BlurBackgroundRect.x) / (_BlurBackgroundRect.z - _BlurBackgroundRect.x), 
                                     (vertexPosition.y - _BlurBackgroundRect.y) / (_BlurBackgroundRect.w - _BlurBackgroundRect.y));
#endif 

DirectX環境であるHoloLensではUNITY_UV_STARTS_AT_TOPの処理が走り、スクリーン座標のV座標が反転されるようになっています。

#if defined(UNITY_UV_STARTS_AT_TOP)
    output.uvScreen.y = unity_OrthoParams.w ? (1.0 - output.uvScreen.y) : output.uvScreen.y;
#else

unity_OrthoParamsはカメラが遠視投影を使用している場合は1,平行投影を使用している場合は0が返され、通常の場合 (1.0 - output.uvScreen.y)が実行されV座標が反転されています。

docs.unity3d.com

スクリーン座標を使用する場合同様の仕組みを実装することであらゆるプラットフォームで対応できるシェーダーになりそうです。

〇参考

以下の記事を参考にさせていただきました。

dench.flatlib.jp

 またUNITY_UV_STARTS_AT_TOPに関しては先日の拡大鏡機能に関するバグレポートを提出した際にリーダーのCameronさんより教えていただきました。

github.com