二、制作VR全景图播放器 (Google VR for

作者: 庸碌无为 | 来源:发表于2016-08-08 15:45 被阅读7683次

    原文地址:
    http://blog.csdn.net/qq_24889075/article/details/52128463
    http://www.jianshu.com/p/104251a3153d

    相关阅读:
    一、初识GVR (Google VR for Android):http://www.jianshu.com/p/09c0822b9d1e
    三、制作VR视频播放器 (Google VR for Android):http://www.jianshu.com/p/82163453ed30

    这篇看下SimpleVrPanorama这个栗子

    SimpleVrPanorama

    其实这篇应该写SimpleVrPanorama和simplevideowidget 两个,但是由于篇幅过长就分开写了

    演示

    用AS录的没有触摸点显示,先凑合看吧

    预览图观看

    介绍

    官方在这里介绍了VR view 、支持平台等。我挑几个相对重要的介绍一下:
    1、图像规格

    VR查看图像可以保存为PNG,JPEG或GIF。Google建议使用JPEG改进压缩。  
    为了获得最大的兼容性和性能,图像尺寸应该是2的倍数(例如,2048或4096)。
    单个图像应为2:1纵横比(例如4096×2048)。  
    立体图像应为1:1纵横比(例如4096×4096)。
    

    如图:


    2、 视频规格

    VR view视频应该被存储为H264编码的mp4文件。
    单个视频应是2:1纵横比。
    立体视频应是1:1纵横比。
    一些较旧的设备不能解码的视频最大不能超过超过1080(192​​0×1080)。最大的兼容性和质量是头等大事,Google建议用户同时提供平面视觉1920x1080的视频和2048×2048处以上的立体视频。  
    

    3、如何录制VR视频

    生活中拍摄:

    360度拍摄的照片和视频越来越方便和实惠。 VR视图可以使用由支持上述equirect-全景格式的任何摄像机产生的图像。对于有兴趣在快速入门用户来说,我们最喜欢的解决方案如下:

    Cardboard Camera App:这个免费的Andr​​oid应用程序,允许用户快速捕捉立体图像360。

    Ricoh Theta:一个非常流行的,用于捕获单360度的图像和视频相对廉价的解决方案。

    CG(计算机动画)拍摄:

    遥感影像数据的VR观点并没有从现实世界限于捕获。 CGI软件可以生成360图像和视频,一切从建筑到演练预演的电影。我们的一些最流行的捕获解决方案的列举如下:

    360 Panorama Capture for Unity:一个免费的,易于使用的360捕获了Unity插件。

    Unreal(虚幻):UE4的最新版本内置了360捕获解决方案。

    Domemaster3D for Maya :从玛雅捕获单声道和立体声图像360免费的解决方案。

    Renderman:开源库,用于捕捉360的内容。

    Rendering Omnidirectional Stereo Content:一个有兴趣的人都在书写自己360捕获解决方案白皮书。

    Android平台

    这里官方有这Android平台的详细介绍,主要内容如下:

    有这表明在官方SDK中的VR View 功能的两个示例应用程序:simplepanowidgetsimplevideowidget。这两个样品的是显示分别使用VrPanoramaViewVrVideoView嵌入全景图像和视频。

    这里写图片描述
    允许用户通过旋转他们的电话,看全景的不同部分。
    simplevideowidget示例还允许用户暂停(点击 VR View就暂停了。 VR View也就是视频那个区域),可以使用进度条改变进度。允许用户更改模式,分别是全屏模式纸板模式

    全屏模式:


    这里写图片描述

    纸板模式:


    这里写图片描述

    代码分析

    _ 为了方便学习与理解,基于官方Demo的代码进行了修改 )

    前言

    这个栗子中需要注意几个知识点:

     VrPanoramaView //Google提供给我们现实全景图片的View
     Options //VrPanoramaView 所需的设置
     VrPanoramaEventListener//为 VrPanoramaView 设置监听
     loadImageFromBitmap//加载图片的主要方法
    

    AndroidManifest

        <!--Demo需要的两个权限-->
        <uses-permission android:name="android.permission.INTERNET" />
        <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
        
        <application android:label="SimpleVrPanoramaActivity"
          android:largeHeap="true"
          android:theme="@android:style/Theme.Holo.Light">
            <!-- 这里原本有个 launchMode ,方便阅读 把这个和Activity中相关代码(onNewIntent) 删掉了 后面部介-->
            <activity android:name=".SimpleVrPanoramaActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                    <category android:name="com.google.intent.category.CARDBOARD" />
                </intent-filter>
            </activity>
        </application>
    

    build.gradle

    上一篇文章有介绍到这些库

    dependencies {
        compile project(':libraries-common')
        compile project(':libraries-commonwidget')
        compile project(':libraries-panowidget')
    }
    

    布局文件

    只有一个主要标签

      <com.google.vr.sdk.widgets.pano.VrPanoramaView
            android:id="@+id/pano_view"
            android:layout_width="match_parent"
            android:layout_height="250dip"
            android:layout_margin="5dip"
            android:scrollbars="@null"/>
    

    SimpleVrPanoramaActivity

    正题来了~
    看下我为了本次学习更改过的代码:
    不了解Pair的请看这里: http://blog.csdn.net/qq_24889075/article/details/52127398

    
    package com.google.vr.sdk.samples.simplepanowidget;
    
    import android.app.Activity;
    import android.graphics.BitmapFactory;
    import android.os.AsyncTask;
    import android.os.Bundle;
    import android.util.Log;
    import android.util.Pair;
    
    import com.google.vr.sdk.widgets.pano.VrPanoramaEventListener;
    import com.google.vr.sdk.widgets.pano.VrPanoramaView;
    import com.google.vr.sdk.widgets.pano.VrPanoramaView.Options;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    public class SimpleVrPanoramaActivity extends Activity {
    
        private static final String TAG = "VrPanorama";
        private VrPanoramaView panoWidgetView;//上面说的Google提供给我们现实全景图片的View
        private String fileUri = "first.jpg";//assets文件夹下的文件名
    
        private Options panoOptions = new Options();//VrPanoramaView需要的设置
        private ImageLoaderTask backgroundImageLoaderTask;//异步加载图片
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main_layout);//布局上面贴了
    
            panoWidgetView = (VrPanoramaView) findViewById(R.id.pano_view);//初始化VrPanoramaView
            panoWidgetView.setEventListener(new ActivityEventListener());//为VrPanoramaView添加监听
    
            //如果有任务在执行则停止它
            if (backgroundImageLoaderTask != null) {
                backgroundImageLoaderTask.cancel(true);
            }
             //设置inputType 为TYPE_STEREO_OVER_UNDER. 在后面会介绍TYPE_STEREO_OVER_UNDER的,暂时当做一个图片的显示类型就行
            panoOptions.inputType = Options.TYPE_STEREO_OVER_UNDER;
            //创建一个任务
            backgroundImageLoaderTask = new ImageLoaderTask();
            //执行任务。将图片名(根据项目实际情况传吧)和设置传入
            backgroundImageLoaderTask.execute(Pair.create(fileUri, panoOptions));
        }
            //异步任务
        class ImageLoaderTask extends AsyncTask<Pair<String, Options>, Void, Boolean> {
            @Override
            protected Boolean doInBackground(Pair<String, Options>... fileInformation) {//真正写项目根据情况添加条件判断吧
            
                InputStream istr = null;
                try {
                    istr = getAssets().open(fileInformation[0].first);//获取图片的输入流
                } catch (IOException e) {
                    Log.e(TAG, "Could not decode default bitmap: " + e);
                    return false;
                }
    
                Bitmap bitmap = BitmapFactory.decodeStream(istr);//创建bitmap
                panoWidgetView.loadImageFromBitmap(bitmap, fileInformation[0].second);//参数一为图片的bitmap,参数二为 VrPanoramaView 所需要的设置
    
                try {
                    istr.close();//关闭InputStream
                } catch (IOException e) {
                    Log.e(TAG, "Could not close input stream: " + e);
                }
            
                return true;
            }
        }
    
        private class ActivityEventListener extends VrPanoramaEventListener {
    
            @Override
            public void onLoadSuccess() {//图片加载成功
                Log.e(TAG, "onLoadSuccess");
            }
    
    
            @Override
            public void onLoadError(String errorMessage) {//图片加载失败
                Log.e(TAG, "Error loading pano: " + errorMessage);
            }
    
            @Override
            public void onClick() {//当我们点击了VrPanoramaView 时候出发
                super.onClick();
                Log.e(TAG, "onClick");
            }
    
            @Override
            public void onDisplayModeChanged(int newDisplayMode) {//改变显示模式时候出发(全屏模式和纸板模式)
                super.onDisplayModeChanged(newDisplayMode);
                Log.e(TAG, "onDisplayModeChanged");
            }
        }
    
    
        @Override
        protected void onPause() {
            panoWidgetView.pauseRendering();//暂停3D渲染和跟踪
            super.onPause();
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            panoWidgetView.resumeRendering();//恢复3D渲染和跟踪
        }
    
        @Override
        protected void onDestroy() {
            panoWidgetView.shutdown();//关闭渲染下并释放相关的内存
    
            if (backgroundImageLoaderTask != null) {
                backgroundImageLoaderTask.cancel(true);//停止异步任务
            }
            super.onDestroy();
        }
    }
    
    

    看完了有木有感觉炒鸡简单啊?现在你已经掌握了如何使用 VrPanoramaView 了吧。

    用 VrPanoramaView 的确简单,但是局限性特别大,后面有机会 会详细说的。

    再介绍下代码中没提到的两个方法:

    setFullscreenButtonEnabled (false); //隐藏全屏模式按钮
    setVrModeButtonEnabled(false); //隐藏VR模式按钮
    
    

    Options

    接下来看看刚刚的VrPanoramaView.Options吧,上文中 是这么设置的

    panoOptions.inputType = Options.TYPE_STEREO_OVER_UNDER;
    

    那么为什么要这样设置呢?先看官方对Options中标签的介绍:

    public static final int TYPE_MONO = 1;
    
        图像被预期以覆盖沿着其水平轴360度,而垂直范围是根据图像的宽高比来计算。例如,如果一个1000x250像素的图像,给出所述全景将覆盖360x90度与垂直范围是-45至+45度。  
      
    public static final int TYPE_STEREO_OVER_UNDER = 2;
        包含两个大小相等的投影 全景图垂直叠加。顶部图像被显示给左眼、底部图像被显示给右眼。//看下图你就懂了   
        
        图像将覆盖沿水平轴360度,而垂直范围是根据图像的宽高比来计算。例如,如果一个1000x500像素的图像中给出(即1000x250像素每个眼睛),全景将覆盖360x90度与垂直范围是-45至+45度。
    
    这里写图片描述

    我要显示的图片是下图这样的,所以就要设置为 'TYPE_STEREO_OVER_UNDER'


    这里写图片描述

    那么什么样的图片设置为 'TYPE_MONO' 呢?
    请看:


    这里写图片描述

    不知道有没有眼神好的同学发现这个问题:TYPE_STEREO_OVER_UNDER类型的图片每次切换模式时候 图片中间都会有一条垂直于水平线的分割线(很浅 很浅 然后逐渐消失),TYPE_MONO 就没有 _

    Options类中的代码也十分简单

    public static class Options {
            private static final int TYPE_START_MARKER = 0;//起始标记
            public static final int TYPE_MONO = 1;
            public static final int TYPE_STEREO_OVER_UNDER = 2;
            private static final int TYPE_END_MARKER = 3;//结束标记
            public int inputType = 1;//默认为一
    
            public Options() {
            }
    
            void validate() {
                if(this.inputType <= 0 || this.inputType >= 3) {//标记错误处理
                    String var10000 = VrPanoramaView.TAG;
                    int var1 = this.inputType;
                    Log.e(var10000, (new StringBuilder(38)).append("Invalid Options.inputType: ").append(var1).toString());
                    this.inputType = 1;
                }
    
            }
        }
    

    调皮的你如果在loadImageFromBitmap(bitmap,options)方法中 将options不小心设置为null了,也没关系。我在源码中我发现下面的代码,感觉挺温馨的

    public void loadImageFromBitmap(Bitmap bitmap, VrPanoramaView.Options options) {
            //有木有那里暖暖的 ^_^
            if(options == null) {
                options = new VrPanoramaView.Options();
            } else {
                options.validate();
            }
        //重点不在这里 可以无视它
            this.renderer.loadImageFromBitmap(bitmap, options, this.eventListener);
        }
    

    至此com.google.vr.sdk.widgets.common包、com.google.vr.sdk.widgets.pano包和com.google.vr.sdk.widgets.video包(代码下一篇介绍) 的主要内容都介绍完了,总结下吧

    总结

    总结下如何在Android设备上用Google的SDK做一款全景图的显示器(播放器?查看器?... 不知道叫什么合适):

    1. 导入google的库
    2. 在相应的布局文件中引入控件 com.google.vr.sdk.widgets.pano.VrPanoramaView
    3. 初始化控件
    4. 为VrPanoramaView设置options
    5. 找到图片的Bitmap
    6. 调用VrPanoramaView的loadImageFromBitmap方法
    7. 在onPause、onResume、onDestroy中做出相应处理

    原文地址:
    http://blog.csdn.net/qq_24889075/article/details/52128463
    http://www.jianshu.com/p/104251a3153d

    相关文章

      网友评论

      • 骚年_金闪闪:怎么调用手机全景相机模式来拍摄全景图呢?有没有想过整一个:joy:
      • 小熊ing:作者有没有研究过全景图上添加热点
      • 程序员铁人:你知道如何在网站上插入一个vr图片吗
      • 任性丶:像720云那种全景图必须用这个控件来显示么,但其实他是一个网址,为什么webview显示不出来
        波v波:@任性丶 和我最开始的想法一样,看样子是换不了其他方案:sweat:
        任性丶:@波v波 做好了,直接用webview可以显示
        波v波:请问你的720°做好了?用的什么显示?
      • zxy816:能在doInBackground()方法中更新界面吗?
        panoWidgetView.loadImageFromBitmap(bitmap, fileInformation[0].second);这句有问题吧?
        庸碌无为:@SoftOfAndroid 感谢指点,代码好久以前写的了 见谅。
      • 草蜢的逆袭:是在as上开发的吗
        庸碌无为:@syusikoku 是的
      • 风雪:一个问题,如何拍摄vr照片啊
        庸碌无为:@风雪 一个单反 一个鱼眼镜头 后期图片合成就ok,自己玩的话还可以架个支架用手机拍,有那种拍全景图片的软件。专业点的就是 十多个单反 放到支架上固定角度的牌。根据使用情景选择拍摄方式
      • 捡淑:66666

      本文标题: 二、制作VR全景图播放器 (Google VR for

      本文链接:https://www.haomeiwen.com/subject/szdrsttx.html