#ChannelPlayer · Unity · VRソフト

FishEye180 Side by Side対応

昨日リリースした#ChannelPlayer 1.09では、VR180において、Equirectangular180 Side By Sideとは異なる形式であるFishEye180 Side by Side対応を以下のShaderソースコードを移植して対応しました。

Unity Asset Store https://assetstore.unity.com/packages/tools/utilities/panorama180-render-141234
Panorama180 Render FT-LAB
上のAsset Storeのものか、あるいは以下のgithubのShaderコードを参考にしています。
https://github.com/ft-lab/Unity_Panorama180View/blob/master/README_jp.md
MIT License. Copyright (c) 2019 ft-lab.
https://github.com/ft-lab/Unity_Panorama180View/blob/master/Panorama180View/Assets/Panorama180View/Panorama180View/Resources/Shaders/panoramaSphereRendering.shader

AVPro Video Assetで言うところのHIGH_QUALITYと、scaleOffsetによる補正が実現できていないので以下のコードでは、FishEye180時にそれらは機能していませんが、一応絵は出せるようなったので、1.09では、一旦以下のコードでフリーズとしました。AVProのShaderに明るい方で、こうすれば良いよという御助言が頂ければ幸いです。

AVProVideo-VR-InsideSphere-Transparent.shader

Shader "AVProVideo/VR/InsideSphere Unlit Transparent(stereo+color+fog+alpha)"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "black" {}
        _ChromaTex("Chroma", 2D) = "white" {}
        _Color("Main Color", Color) = (1,1,1,1)

        [KeywordEnum(None, Top_Bottom, Left_Right, Custom_UV)] Stereo ("Stereo Mode", Float) = 0
        [KeywordEnum(None, Top_Bottom, Left_Right)] AlphaPack("Alpha Pack", Float) = 0
        [Toggle(STEREO_DEBUG)] _StereoDebug ("Stereo Debug Tinting", Float) = 0
        [KeywordEnum(None, EquiRect180, Fisheye180)] Layout("Layout", Float) = 0
        [Toggle(HIGH_QUALITY)] _HighQuality ("High Quality", Float) = 1
        [Toggle(APPLY_GAMMA)] _ApplyGamma("Apply Gamma", Float) = 0
        [Toggle(USE_YPCBCR)] _UseYpCbCr("Use YpCbCr", Float) = 0
        [Toggle(FLIPX)] _FlipX("X Flip", Float) = 0
        [Toggle(FLIPY)] _FlipY("Y Flip", Float) = 0
        _Strech ("Strech", Vector)=(1,1,0,0)
        _EdgeFeather("Edge Feather", Range (0, 1)) = 0.02
        _Fov("Fov", Range (0,360)) = 180
    }
    SubShader
    {
        Tags { "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" }
        ZWrite On
        //ZTest Always
        Blend SrcAlpha OneMinusSrcAlpha
        Cull Front
        Lighting Off

        Pass
        {
            CGPROGRAM
            #include "UnityCG.cginc"
            #include "AVProVideo.cginc"
            #define MY_PI (3.1415926535897932384626433832795)
            #define MY_PI2 (2.0 * 3.1415926535897932384626433832795)

#if HIGH_QUALITY || APPLY_GAMMA
            #pragma target 3.0
#endif
            #pragma vertex vert
            #pragma fragment frag

            #pragma multi_compile_fog
            #pragma multi_compile MONOSCOPIC STEREO_TOP_BOTTOM STEREO_LEFT_RIGHT STEREO_CUSTOM_UV
            #pragma multi_compile ALPHAPACK_NONE ALPHAPACK_TOP_BOTTOM ALPHAPACK_LEFT_RIGHT

            // TODO: Change XX_OFF to __ for Unity 5.0 and above
            // this was just added for Unity 4.x compatibility as __ causes
            // Android and iOS builds to fail the shader
            #pragma multi_compile STEREO_DEBUG_OFF STEREO_DEBUG
            #pragma multi_compile HIGH_QUALITY_OFF HIGH_QUALITY
            #pragma multi_compile APPLY_GAMMA_OFF APPLY_GAMMA
            #pragma multi_compile USE_YPCBCR_OFF USE_YPCBCR
            #pragma multi_compile LAYOUT_NONE LAYOUT_EQUIRECT180 LAYOUT_FISHEYE180

            struct appdata
            {
                float4 vertex : POSITION; // vertex position
#if HIGH_QUALITY
                float3 normal : NORMAL;
#else
                float2 uv : TEXCOORD0; // texture coordinate            
    #if STEREO_CUSTOM_UV
                float2 uv2 : TEXCOORD1;    // Custom uv set for right eye (left eye is in TEXCOORD0)
    #endif
#endif
                
            };

            struct v2f
            {
                float4 vertex : SV_POSITION; // clip space position
#if HIGH_QUALITY
                float3 normal : TEXCOORD0;
                
    #if STEREO_TOP_BOTTOM || STEREO_LEFT_RIGHT
                float4 scaleOffset : TEXCOORD1; // texture coordinate
        #if UNITY_VERSION >= 500
                UNITY_FOG_COORDS(2)
        #endif
    #else
        #if UNITY_VERSION >= 500
                UNITY_FOG_COORDS(1)
        #endif
    #endif
#else
                float4 uv : TEXCOORD0; // texture coordinate
    #if UNITY_VERSION >= 500
                UNITY_FOG_COORDS(1)
    #endif
#endif

#if STEREO_DEBUG
                float4 tint : COLOR;
#endif
            };

            uniform sampler2D _MainTex;
#if USE_YPCBCR
            uniform sampler2D _ChromaTex;
            uniform float4x4 _YpCbCrTransform;
#endif
            uniform float4 _MainTex_ST;
            uniform float4 _MainTex_TexelSize;
            uniform float3 _cameraPosition;
            uniform fixed4 _Color;
            uniform float _EdgeFeather;
            uniform float _FlipX;
            uniform float _FlipY;
            uniform float4 _Strech;
            uniform float _Fov;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = XFormObjectToClip(v.vertex);
#if !HIGH_QUALITY
                o.uv.zw = 0.0;
                o.uv.xy = TRANSFORM_TEX(v.uv, _MainTex);
    #if !LAYOUT_FISHEYE180                
        #if LAYOUT_EQUIRECT180
                o.uv.x = ((o.uv.x - 0.5) * 2.0) + 0.5;
                // Set value for clipping if UV area is behind viewer
                o.uv.z = -1.0;
                if (v.uv.x > 0.25 && v.uv.x < 0.75)
                {
                    o.uv.z = 1.0;
                }
        #endif
    #endif    
                o.uv.xy = float2(1.0 - o.uv.x, o.uv.y);    // 反転
#endif

#if LAYOUT_FISHEYE180 && ( STEREO_TOP_BOTTOM || STEREO_LEFT_RIGHT ) && HIGH_QUALITY
                o.scaleOffset = 1.0;
#endif
#if !LAYOUT_FISHEYE180
    #if STEREO_TOP_BOTTOM || STEREO_LEFT_RIGHT
                float4 scaleOffset = GetStereoScaleOffset(IsStereoEyeLeft(_cameraPosition, UNITY_MATRIX_V[0].xyz), _MainTex_ST.y < 0.0);

        #if !HIGH_QUALITY
                o.uv.xy *= scaleOffset.xy;
                o.uv.xy += scaleOffset.zw;
        #else
                o.scaleOffset = scaleOffset;
        #endif
    #elif STEREO_CUSTOM_UV && !HIGH_QUALITY
                if (!IsStereoEyeLeft(_cameraPosition, UNITY_MATRIX_V[0].xyz))
                {
                    o.uv.xy = TRANSFORM_TEX(v.uv2, _MainTex);
                    o.uv.xy = float2(1.0 - o.uv.x, o.uv.y);    // 反転
                }
    #endif
#endif
#if !HIGH_QUALITY
    #if ALPHAPACK_TOP_BOTTOM || ALPHAPACK_LEFT_RIGHT
                o.uv = OffsetAlphaPackingUV(_MainTex_TexelSize.xy, o.uv.xy, _MainTex_ST.y > 0.0);
    #endif
#endif
#if HIGH_QUALITY
                o.normal = v.normal;
#endif

#if STEREO_DEBUG
                o.tint = GetStereoDebugTint(IsStereoEyeLeft(_cameraPosition, UNITY_MATRIX_V[0].xyz));
#endif

#if UNITY_VERSION >= 500
                UNITY_TRANSFER_FOG(o, o.vertex);
#endif
                return o;
            }

            float2 calcUV (float2 _uv) {
                // from https://github.com/ft-lab/Unity_Panorama180View/blob/master/README_jp.md
                // MIT License. Copyright (c) 2019 ft-lab.
                float2 uv = _uv;

                // FishEyeからequirectangularの変換.
                // reference : http://paulbourke.net/dome/fish2/
                float theta = MY_PI2 * (uv.x - 0.5);
                float phi   = MY_PI * (uv.y - 0.5);
                float FOV   = ( MY_PI / 180 ) * _Fov;
                float sinP = sin(phi);
                float cosP = cos(phi);
                float sinT = sin(theta);
                float cosT = cos(theta);
                float3 vDir = float3(cosP * sinT, cosP * cosT, sinP);

                theta = atan2(vDir.z, vDir.x);
                phi   = atan2(sqrt(vDir.x * vDir.x + vDir.z * vDir.z), vDir.y);
                float r = phi / FOV; 

                // 左右の映像が横50%のサイズで正面(180度)出力。
                uv.x = 0.5 + r * cos(theta);
                uv.y = 0.5 + r * sin(theta);

                // 左右を2倍(0.5倍すると2倍になる)にする。360度出力。
                uv.x *= 0.5;

                // 右を描画しているときは、+0.5して移動させる。
                if (unity_StereoEyeIndex == 1) {
                    uv.x += 0.5;
                }
                return uv;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                float4 uv = 0;
#if HIGH_QUALITY
                float3 n = normalize(i.normal);
                #if LAYOUT_EQUIRECT180 || LAYOUT_FISHEYE180
                clip(-n.z);    // Clip pixels on the back of the sphere
                #endif

    #if LAYOUT_NONE || LAYOUT_EQUIRECT180
                float M_1_PI = 1.0 / MY_PI;
                float M_1_2PI = 1.0 / MY_PI2;
                uv.x = 0.5 - atan2(n.z, n.x) * M_1_2PI;
                uv.y = 0.5 - asin(-n.y) * M_1_PI;
                uv.x += 0.75;
                uv.x = fmod(uv.x, 1.0);
                //uv.x = uv.x % 1.0;
    #elif LAYOUT_FISHEYE180
                uv.xy = calcUV(uv.xy);
    #endif
                uv.xy = TRANSFORM_TEX(uv, _MainTex);
    #if LAYOUT_EQUIRECT180 || LAYOUT_FISHEYE180
                uv.x = ((uv.x - 0.5) * 2.0) + 0.5;
    #endif
    #if STEREO_TOP_BOTTOM || STEREO_LEFT_RIGHT
                uv.xy *= i.scaleOffset.xy;
                uv.xy += i.scaleOffset.zw;
    #endif
    #if ALPHAPACK_TOP_BOTTOM || ALPHAPACK_LEFT_RIGHT
                uv = OffsetAlphaPackingUV(_MainTex_TexelSize.xy, uv.xy, _MainTex_ST.y < 0.0);
    #endif
#else    // !HIGH_QUALITY
                uv = i.uv;
    #if LAYOUT_FISHEYE180
                // FOVを変更したときに、描画スタート位置と終了位置を設定する。180度の場合は0.25から0.75
                float _start = 0.5 - ( _Fov / 720 );
                float _end = _start + ( _Fov/ 360 );
                if (uv.x < _start || uv.x > _end) return float4(0.0, 0.0, 0.0, 1.0);
                uv.xy = calcUV(uv.xy);
    #elif LAYOUT_EQUIRECT180 //|| LAYOUT_FISHEYE180
                clip(i.uv.z);    // Clip pixels on the back of the sphere
    #endif
#endif  // HIGH_QUALITY
                // 鏡像 _FlipX, _FlipY
                if(_FlipX > 0) uv.xy = float2(1.0 - uv.x, uv.y); // 反転
                if(_FlipY > 0) uv.xy = float2(uv.x, 1.0 - uv.y); // 反転

                // ストレッチ _Strech.xy と、歪み補正 _Strech.zw
                uv.xy = uv + float2(sin(uv.x * MY_PI2) * _Strech.z, sin(uv.y * MY_PI2) * _Strech.w);
                uv.xy = 0.5 + (uv - 0.5) / _Strech.xy;
                fixed4 col;
#if USE_YPCBCR
                col = SampleYpCbCr(_MainTex, _ChromaTex, uv.xy, _YpCbCrTransform);
#else
                col = SampleRGBA(_MainTex, uv.xy);
#endif

#if ALPHAPACK_TOP_BOTTOM || ALPHAPACK_LEFT_RIGHT
                col.a = SamplePackedAlpha(_MainTex, uv.zw);
#endif

#if STEREO_DEBUG
                col *= i.tint;
#endif

                col *= _Color;

#if UNITY_VERSION >= 500
                UNITY_APPLY_FOG(i.fogCoord, col);
#endif

#if LAYOUT_EQUIRECT180 || LAYOUT_FISHEYE180
                // Apply edge feathering based on UV mapping - this is useful if you're using a hemisphere mesh for 180 degree video and want to have soft edges
                if (_EdgeFeather > 0.0)
                {
                    float4 featherDirection = float4(0.0, 0.0, 1.0, 1.0);
                    
#if STEREO_TOP_BOTTOM 
                    if (uv.y > 0.5)
                    {
                        featherDirection.y = 0.5;
                    }
                    else
                    {
                        featherDirection.w = 0.5;
                    }
#endif

#if STEREO_LEFT_RIGHT
                    if (uv.x > 0.5)
                    {
                        featherDirection.x = 0.5;
                    }
                    else
                    {
                        featherDirection.z = 0.5;
                    }
#endif


#if ALPHAPACK_TOP_BOTTOM
                    featherDirection.w *= 0.5;
#endif

#if ALPHAPACK_LEFT_RIGHT
                    featherDirection.z *= 0.5;
#endif

                    float d = min(uv.x - featherDirection.x, min((uv.y - featherDirection.y), min(featherDirection.z - uv.x, featherDirection.w - uv.y)));
                    float a = smoothstep(0.0, _EdgeFeather, d);
                    col.a *= a;
                }
#endif

                return col;

            }
            ENDCG
        }
    }
}


広告

FishEye180 Side by Side対応” への2件のフィードバック

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中