【译】尝试制作将RICOH THETA S的拍摄视角用Unity生成实时全天球观看的效果

发表于2015-11-18
评论1 2.3k浏览

翻译原文链接:http://tips.hecomi.com/

前言

THETA S 是10月23号预定发售的全天球相机,此相机添加了当前版本相机m15没有的Dual-Fisheye(双鱼眼)的usb相机视频流(1280*720 15FPS)和HDMI相机视频流(1920*1080 30FPS)传输功能。为了也可以在unity上面观看,我制作了UV展开的球体和利用shader将边界调整为适当的alpha值。后面,stereoarts直接利用Equirectangular(圆柱投影)算法,只用fragmentshader可以做出平面mesh。我想将THETA S 做出全天球时利用这个算法效率会很高而且方便(也能做天空盒)。

Stereoarts首页  http://stereoarts.jp

解析了Theta Shader Pack。这里提供了面向Unity的将THETA/THETA S 的全天球图像实时Equirectangular变换的shder和相关辅助脚本。http://t.co/mmrKXr6MH0

实例链接:https://dl.dropboxusercontent.com/u/7131835/Programs/ThetaS_LiveView_Sample.unitypackage

提取THETA的画面的例子

虽然THETA 15m 的视频画面是重叠的圆的形状,但THETA S的画面有所不同。方圆包围的半球图像角度略大于180度。

调整了利用WebCamTexture拍摄的样本纹理。

 

制作uv设置好的球体

使用Maya LT。一般制作好的球体UV展开是下面这个样子。                                                 

将此在适当的平面上进行UV展开。效果如下

选择球体面的一半,制作半球uv。


       
由于实际想在边界部分使用alpha通道,于是没有制作球体而是制作了两个重叠半球。边界部分的UV可以     手动适当拉伸就好。
       

      还有将面的法线设置为全部向内侧反转。UV的位置和大小在后面利用shader进行细微调整。

    用Unity进行调整

      将Maya LT制作的模型导入Unity并将相机放置在球体中心。为了细微调整模型的位置和使用alpha通道,      添加shader。为了防止边界错位控制绘制顺序,每个半球使用各自独立的shader。

    Shader "Theta/Sphere1" {

    Properties {

        _MainTex ("Base (RGB)", 2D) = "white" {}

        _AlphaBlendTex ("Alpha Blend (RGBA)", 2D) = "white" {}

        _OffsetU ("Offset U", Range(-0.50.5)) = 0 

        _OffsetV ("Offset V", Range(-0.50.5)) = 0

        _ScaleU ("Scale U", Range(0.81.2)) = 1

        _ScaleV ("Scale V", Range(0.81.2)) = 1

        _ScaleCenterU ("Scale Center U", Range(0.01.0)) = 0 

        _ScaleCenterV ("Scale Center V", Range(0.01.0)) = 0

    }

    SubShader {

        Tags { "RenderType" = "Transparent" "Queue" = "Background" }

        Pass {

            Name "BASE"

            

            Blend SrcAlpha OneMinusSrcAlpha

            Lighting Off

            ZWrite Off

            

            CGPROGRAM            #pragma vertex vert_img            #pragma fragment frag

            #include "UnityCG.cginc"

 

            uniform sampler2D _MainTex;

            uniform sampler2D _AlphaBlendTex;

            uniform float _OffsetU;

            uniform float _OffsetV;

            uniform float _ScaleU;

            uniform float _ScaleV;

            uniform float _ScaleCenterU;

            uniform float _ScaleCenterV;

 

            float4 frag(v2f_img i) : COLOR {

                // 微调位置和大小

                float2 uvCenter = float2(_ScaleCenterU, _ScaleCenterV);

                float2 uvOffset = float2(_OffsetU, _OffsetV);

                float2 uvScale = float2(_ScaleU, _ScaleV);

                float2 uv =  (i.uv - uvCenter) * uvScale + uvCenter + uvOffset;

                // alpha调整

                float4 tex = tex2D(_MainTex, uv);

                tex.a *= pow(1.0 - tex2D(_AlphaBlendTex, i.uv).a, 2);

                return tex;

            }

            ENDCG

        }

     }

   }

 

    Shader "Theta/Sphere2" {

    Properties {

        _MainTex ("Base (RGB)", 2D) = "white" {}

        _AlphaBlendTex ("Alpha Blend (RGBA)", 2D) = "white" {}

        _OffsetU ("Offset U", Range(-0.50.5)) = 0 

        _OffsetV ("Offset V", Range(-0.50.5)) = 0

        _ScaleU ("Scale U", Range(0.81.2)) = 1

        _ScaleV ("Scale V", Range(0.81.2)) = 1

        _ScaleCenterU ("Scale Center U", Range(0.01.0)) = 0 

        _ScaleCenterV ("Scale Center V", Range(0.01.0)) = 0

    }

    SubShader {

        Tags { "RenderType" = "Transparent" "Queue" = "Background+1" }

        UsePass "Theta/Sphere1/BASE"

     }

   }

 

  为使用alpha通道,制作的下面这样的配合UV的alpha调整好的纹理贴图。我先用postscript导入UV,然后导入    到Illustrator对应大小进行调整制作生成出来(内侧白色圆alpha=1,圆边从内侧到外侧alpha值从1到0变化,最外    面一侧不会使用所以随便都可以)。

      
 然后细微调整参数,全天球就做好。                                                                                                        

  Equirectangular 化

      利用vertexshader对顶点进行变形。

    Shader "Theta/Equirectangular1" {

    Properties {

        _MainTex ("Base (RGB)"2D) = "white" {}

        _AlphaBlendTex ("Alpha Blend (RGBA)"2D) = "white" {}

        _OffsetU ("Offset U", Range(-0.50.5)) = 0 

        _OffsetV ("Offset V", Range(-0.50.5)) = 0

        _ScaleU ("Scale U", Range(0.81.2)) = 1

        _ScaleV ("Scale V", Range(0.81.2)) = 1

        _ScaleCenterU ("Scale Center U", Range(0.01.0)) = 0 

        _ScaleCenterV ("Scale Center V", Range(0.01.0)) = 0

        _Aspect ("Aspect", Float) = 1.777777777

    }

    SubShader {

        Tags { "RenderType" = "Transparent" "Queue" = "Background" }

        Pass {

            Name "BASE"

            

            Blend SrcAlpha OneMinusSrcAlpha

            Lighting Off

            ZWrite Off

            

            CGPROGRAM

            #pragma vertex vert

            #pragma fragment frag            #define PI 3.1415925358979

 

            #include "UnityCG.cginc"

 

            uniform sampler2D _MainTex;

            uniform sampler2D _AlphaBlendTex;

            uniform float _OffsetU;

            uniform float _OffsetV;

            uniform float _ScaleU;

            uniform float _ScaleV;

            uniform float _ScaleCenterU;

            uniform float _ScaleCenterV;

            uniform float _Aspect;

            

            struct v2f {

                float4 position : SV_POSITION;

                float2 uv       : TEXCOORD0;

            };

 

            v2f vert(appdata_base v) {

                float4 modelBase = mul(_Object2World, float4(0001));

                float4 modelVert = mul(_Object2World, v.vertex);

                

                float x = modelVert.x;

                float y = modelVert.y;

                float z = modelVert.z;

                

                float r = sqrt(x*x + y*y + z*z);

                x /= 2 * r;

                y /= 2 * r;

                z /= 2 * r;

                

                float latitude  = atan2(0.5, -y);

                float longitude = atan2(x, z);  

                

                float ex = longitude / (2 * PI);

                float ey = (latitude - PI / 2) / PI * 2;

                float ez = 0;

                

                ex *= _Aspect;

                

                modelVert = float4(float3(ex, ey, ez) * 2 * r, 1);

 

                v2f o;

                o.position = mul(UNITY_MATRIX_VP, modelVert);

                o.uv       = MultiplyUV(UNITY_MATRIX_TEXTURE0, v.texcoord);

                return o;

            }    

 

            float4 frag(v2f i) : COLOR {

                float2 uvCenter = float2(_ScaleCenterU, _ScaleCenterV);

                float2 uvOffset = float2(_OffsetU, _OffsetV);

                float2 uvScale = float2(_ScaleU, _ScaleV);

                float2 uv =  (i.uv - uvCenter) * uvScale + uvCenter + uvOffset;

                float4 tex = tex2D(_MainTex, uv);

                tex.a *= pow(1.0 - tex2D(_AlphaBlendTex, i.uv).a, 2);

                return tex;

            }

            ENDCG

         }

       }

    }

    Shader "Theta/Equirectangular2" {

    Properties {

        _MainTex ("Base (RGB)"2D) = "white" {}

        _AlphaBlendTex ("Alpha Blend (RGBA)"2D) = "white" {}

        _OffsetU ("Offset U", Range(-0.50.5)) = 0 

        _OffsetV ("Offset V", Range(-0.50.5)) = 0

        _ScaleU ("Scale U", Range(0.81.2)) = 1

        _ScaleV ("Scale V", Range(0.81.2)) = 1

        _ScaleCenterU ("Scale Center U", Range(0.01.0)) = 0 

        _ScaleCenterV ("Scale Center V", Range(0.01.0)) = 0

        _Aspect ("Aspect", Float) = 1.777777777

    }

    SubShader {

        Tags { "RenderType" = "Transparent" "Queue" = "Background+1" }

        UsePass "Theta/Equirectangular1/BASE"

      }

    }

      

点击网格查看发现网格被变换成了下面的样子

      

   多边形的中心一端没有连接到一起有一小段空白。可以利用fragmentshader进行处理来回避这个问题。

  结语

  全天球的AR和防抖动(スタビライズ我就直接翻译为防抖动了((o(。 >ω<。)o)))等各种内容十分有意思。   开卖了的话可以拿来做各种有意思的东西玩哈哈。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引