zoukankan      html  css  js  c++  java
  • Google VR技术大揭秘

    VR

    虚拟现实(Virtual Reality)技术是一种能够创建和体验虚拟世界的计算机仿真系统。它利用计算机生成一种模拟环境。是一种多源信息融合的、交互式的三维动态视景和实体行为的系统仿真, 使用户沉浸到该环境中。

    附:Wikipedia

    VR产品

    Google VR
    Oculus
    HTC Vivi

    Google VR for Android

    Google VR SDK同一时候支持DayDream和CardBoard。 包括了一些用于创建App的简单API和支持DayDream手机、DayDream控制器的复杂API。同一时候涵盖了Android、iOS、Unity三大平台。

    SDK下载

    sdk地址:

    git clone https://github.com/googlevr/gvr-android-sdk.git
    

    执行官网项目

    在使用之前,我们先执行下官网的项目。导入gvr-android-sdk到Android Studio, 同步的过程中须要下载非常多库所以会比較耗时,另外可能出现build失败的情况,这时能够尝试使用本地的gradle来编译。


    gradle版本号最好为最新版本号。


    这里写图片描写叙述

    项目展示了印加文明遗迹马丘比丘的全景图(Panorama):
    这里写图片描写叙述

    在真机上执行时。会有一个Cardboard选项。点击上图红色框中的button就可以进入Cardboard模式。
    这里写图片描写叙述

    Demo代码的主要逻辑就是载入一张全景图放入VrPanoramaView中。

    panoOptions = new Options();
    panoOptions.inputType = Options.TYPE_STEREO_OVER_UNDER;//图像类型为立体图像
    istr = assetManager.open("andes.jpg");//载入assets文件夹下的全景图
    panoWidgetView.loadImageFromBitmap(BitmapFactory.decodeStream(istr), panoOptions);

    全景图片andes是由两张图片组成,上面一张是给左眼看。以下一张是给右眼看。

    这里写图片描写叙述

    Demo的声音的实现是载入assets文件夹下的congo.mp4视频到VrVideoView中。

    videoWidgetView.loadVideoFromAsset("congo.mp4", options);

    congo.mp4的视频内容也是分为上下部分。上面给左眼看,以下给右眼看。

    treasurehunt

    treasurehunt展示了一个简单到离谱的寻宝游戏。当vr世界中矩形变成金黄色时。点击手机屏幕或者使用Daydream的控制器。就可以完毕寻宝。游戏还伴有音效。


    这里写图片描写叙述

    controllerclient

    接收DayDream控制器输入演示样例

    videoplayer

    使用Asynchronous Reprojection播放视频演示样例

    全景图(PanoramaActivity)

    1. 配置build.gradle

    //改动minSDK为19
    minSdkVersion 19
    //加入依赖
    compile 'com.google.vr:sdk-panowidget:1.20.0'

    2. 配置AndroidManifest.xml

    因为全景图占内存较大,当载入多张全景图时可能存在内存溢出的情况,所以这里开启largeHeap。

    <application android:largeHeap="true"></application>

    3. 载入全景图

    private class LoadPanoramaImageTask extends AsyncTask<Void, Void, Bitmap> {
    
        @Override
        protected Bitmap doInBackground(Void... params) {
            try {
                //载入assets文件夹下的全景图片
                AssetManager assetManager = getAssets();
                InputStream open = assetManager.open("andes.jpg");
                return BitmapFactory.decodeStream(open);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        @Override
        protected void onPostExecute(Bitmap bitmap) {
            VrPanoramaView.Options options = new VrPanoramaView.Options();
            //图片类型为立体图像
            options.inputType = VrPanoramaView.Options.TYPE_STEREO_OVER_UNDER;
            mVrPanoramaView.loadImageFromBitmap(bitmap, options);
        }
    }

    4. 生命周期管理

    @Override
    protected void onPause() {
        mVrPanoramaView.pauseRendering();
        super.onPause();
    }
    
    @Override
    protected void onResume() {
        super.onResume();
        mVrPanoramaView.resumeRendering();
    }
    
    @Override
    protected void onDestroy() {
        // Destroy the widget and free memory.
        mVrPanoramaView.shutdown();
        // The background task has a 5 second timeout so it can potentially stay alive for 5 seconds
        // after the activity is destroyed unless it is explicitly cancelled.
        if (mLoadPanoramaImageTask != null) {
            mLoadPanoramaImageTask.cancel(true);
        }
        super.onDestroy();
    }
    

    5. 事件监听

    mVrPanoramaView.setEventListener(mVrPanoramaEventListener);
    
    private VrPanoramaEventListener mVrPanoramaEventListener = new VrPanoramaEventListener() {
        /**
         * 点击回调
         */
        @Override
        public void onClick() {
            super.onClick();
        }
    
        /**
         * 载入数据成功回调
         */
        @Override
        public void onLoadSuccess() {
            super.onLoadSuccess();
        }
    
        /**
         * 载入数据失败回调
         */
        @Override
        public void onLoadError(String errorMessage) {
            super.onLoadError(errorMessage);
        }
    };
    

    360 视频

    1. 配置build.gradle

    //加入依赖//
    minSdkVersion 19
    //已经配置则忽略
    compile 'com.google.vr:sdk-videowidget:1.20.0'

    2. 配置AndroidManifest.xml (已经配置则忽略)

    <application android:largeHeap="true"></application>

    3. 载入视频

    VrVideoView.Options options = new VrVideoView.Options();
    //视频类型为立体视频
    options.inputType = VrVideoView.Options.TYPE_STEREO_OVER_UNDER;
    try {
        mVrVideoView.loadVideoFromAsset("congo.mp4", options);
    } catch (IOException e) {
        e.printStackTrace();
    }

    4. 生命周期管理

    @Override
    protected void onPause() {
        super.onPause();
        // Prevent the view from rendering continuously when in the background.
        mVrVideoView.pauseRendering();
        // If the video is playing when onPause() is called, the default behavior will be to pause
        // the video and keep it paused when onResume() is called.
        isPaused = true;
    }
    
    @Override
    protected void onResume() {
        super.onResume();
        mVrVideoView.resumeRendering();
    }
    
    @Override
    protected void onDestroy() {
        // Destroy the widget and free memory.
        mVrVideoView.shutdown();
        super.onDestroy();
    }
    

    5. 事件监听

    private VrVideoEventListener mVrEventListener = new VrVideoEventListener() {
    
        @Override
        public void onLoadError(String errorMessage) {
            Toast.makeText(VrVideoActivity.this, "onLoadError", Toast.LENGTH_SHORT).show();
        }
    
        @Override
        public void onLoadSuccess() {
            Toast.makeText(VrVideoActivity.this, "onLoadSuccess", Toast.LENGTH_SHORT).show();
        }
    
        @Override
        public void onNewFrame() {
        }
    
        @Override
        public void onCompletion() {
            Toast.makeText(VrVideoActivity.this, "onCompletion", Toast.LENGTH_SHORT).show();
            mVrVideoView.seekTo(0);//播放结束后又一次開始播放
        }
    
        @Override
        public void onClick() {
            togglePause();//点击暂停或者播放
        }
    };

    Demo

    这里写图片描写叙述

    本demo实现一个全景图控制显示的效果。

    这里主要演示下VrPanoramaView控件的使用。

    初始化VrPanoramaView

    private void initPanoramaView() {
        mVrPanoramaView = (VrPanoramaView) findViewById(R.id.vr_panorama_view);
        //mVrPanoramaView.setDisplayMode(VrWidgetView.DisplayMode.FULLSCREEN_MONO);//全屏模式,弹出一个全屏的Dialog
        mVrPanoramaView.setInfoButtonEnabled(false);//隐藏信息button
        mVrPanoramaView.setStereoModeButtonEnabled(false);//隐藏cardboardbutton
        mVrPanoramaView.setFullscreenButtonEnabled(false);//隐藏全屏button
        mUrl = getIntent().getStringExtra("url");
        OkGo.get(mUrl).cacheKey(mUrl).tag(mUrl).execute(new BitmapCallback() {
    
            @Override
            public void onSuccess(Bitmap bitmap, Call call, Response response) {
                VrPanoramaView.Options options = new VrPanoramaView.Options();
                //设置图片类型为单通道图片
                options.inputType = VrPanoramaView.Options.TYPE_MONO;
                mVrPanoramaView.loadImageFromBitmap(bitmap, options);
            }
        });
    }

    初始化MediaPlayer

    /**
     * 假设有音乐数据则播放音乐
     */
    private void initMediaPlayer() {
        String mp3 = getIntent().getStringExtra("mp3");
        if (mp3 != null) {
            mMediaPlayer = new MediaPlayer();
            try {
                mMediaPlayer.setDataSource(this, Uri.parse(mp3));
                mMediaPlayer.setOnPreparedListener(mOnPreparedListener);
                mMediaPlayer.prepareAsync();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    生命周期管理

    @Override
    protected void onResume() {
        super.onResume();
        mVrPanoramaView.resumeRendering();
    }
    
    @Override
    protected void onPause() {
        super.onPause();
        mVrPanoramaView.pauseRendering();
        if (mMediaPlayer != null) {
            mMediaPlayer.pause();
        }
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        mVrPanoramaView.shutdown();
        OkGo.getInstance().cancelTag(mUrl);//取消请求
        if (mMediaPlayer != null) {
            mMediaPlayer.release();
            mMediaPlayer = null;
        }
    }
    

    VR View

    VR View同意开发人员在站点或app中嵌入360度全景多媒体文件(图片和视频)。

    这个技术主要是提供给传统的开发人员。能够通过在app中加入动态内容来提升用户体验。比方旅行或房地产类型的app,能够让用户足不出户就体验到虚拟场景。VR View同一时候支持web和Native app。
    VR View同一时候支持单声道和立体声的图片和视频,可是图片和视频的存储格式必须为equirectangular-panoramic格式,这是一种常见的摄像头尺寸支持的格式。
    VR view是客户端的显示技术,那么我们怎么去拍摄符合VR view要求的内容呢?

    真实世界中的拍摄

    Cardboard Camera App ,用这个app能够和方便的拍摄360照片。拍摄完毕后须要通过conversion tool来创建一个立体声的360照片。

    Ricoh Theta 一个非常流行的,相对便宜的用来拍摄单声道相片和视频的设备。

    1,CG 拍摄
    VR view的图片不只限制在真实世界中拍摄。CGI(计算机合成图像)能够为全部的东西生成360度全景照片和视频,最流行拍摄解决方式例如以下:

    360 Panorama Capture for Unity Unity插件
    Unreal 虚幻引擎
    Domemaster3D for Maya
    Renderman 一个开源库
    Rendering Omnidirectional Stereo Content

    以下用伪代码展示怎样用VrPanoramaView和VrVideoView展示360度图片和视频。

    <com.google.vr.sdk.widgets.pano.VrPanoramaView
                android:id="@+id/pano_view"
                android:layout_margin="5dip"
                android:layout_width="match_parent"
                android:scrollbars="@null"
                android:layout_height="250dip"/>
    
    <com.google.vr.sdk.widgets.video.VrVideoView
              android:id="@+id/video_view"
              android:layout_width="match_parent"
              android:scrollbars="@null"
              android:layout_height="250dip"/>
    //展示全景图片
     panoWidgetView = (VrPanoramaView) findViewById(R.id.pano_view);
    //图片载入结果回调
    private class ActivityEventListener extends VrPanoramaEventListener {
        /**
         * Called by pano widget on the UI thread when it's done loading the image.
         */
        @Override
        public void onLoadSuccess() {
          loadImageSuccessful = true;
        }
    
        /**
         * Called by pano widget on the UI thread on any asynchronous error.
         */
        @Override
        public void onLoadError(String errorMessage) {
          loadImageSuccessful = false;
          Toast.makeText(
              SimpleVrPanoramaActivity.this, "Error loading pano: " + errorMessage, Toast.LENGTH_LONG)
              .show();
          Log.e(TAG, "Error loading pano: " + errorMessage);
        }
      }
    //设置图片载入监听
        panoWidgetView.setEventListener(new ActivityEventListener());
    
    //载入图像的Bitmap数据 istr是一个文件输入流
    //VrPanoramaView.Options是用来配置图片格式的
    // TYPE_MONO 包括单一圆柱的全景图像
    // TYPE_STEREO_OVER_UNDER 图像包括了两个大小相等、垂直相交的圆柱全景图像。上图展示给左眼,下图展示给右眼。

    panoWidgetView.loadImageFromBitmap(BitmapFactory.decodeStream(istr), panoOptions); //展示全景视频 videoWidgetView = (VrVideoView) findViewById(R.id.video_view); videoWidgetView.setEventListener(new ActivityEventListener()); //VrVideoEventListener同一时候对视频载入和操作的回调 private class ActivityEventListener extends VrVideoEventListener { /** * Called by video widget on the UI thread when it's done loading the video. */ @Override public void onLoadSuccess() { Log.i(TAG, "Sucessfully loaded video " + videoWidgetView.getDuration()); loadVideoStatus = LOAD_VIDEO_STATUS_SUCCESS; seekBar.setMax((int) videoWidgetView.getDuration()); updateStatusText(); } /** * Called by video widget on the UI thread on any asynchronous error. */ @Override public void onLoadError(String errorMessage) { // An error here is normally due to being unable to decode the video format. loadVideoStatus = LOAD_VIDEO_STATUS_ERROR; Toast.makeText( SimpleVrVideoActivity.this, "Error loading video: " + errorMessage, Toast.LENGTH_LONG) .show(); Log.e(TAG, "Error loading video: " + errorMessage); } @Override public void onClick() { togglePause(); } /** * Update the UI every frame. */ @Override public void onNewFrame() { updateStatusText(); seekBar.setProgress((int) videoWidgetView.getCurrentPosition()); } /** * Make the video play in a loop. This method could also be used to move to the next video in * a playlist. */ @Override public void onCompletion() { videoWidgetView.seekTo(0); } } //支持两种载入方式,从asset文件夹中或从一个uri中读取视频数据 //VrVideoView.Options相同是用来配置视频格式的 videoWidgetView.loadVideoFromAsset("congo.mp4", options); 或 videoWidgetView.loadVideo(fileInformation[0].first, fileInformation[0].second) //除此外另一些控制渲染、播放的方法: videoWidgetView.pauseRendering(); videoWidgetView.resumeRendering(); videoWidgetView.shutdown(); videoWidgetView.playVideo(); videoWidgetView.pauseVideo(); //shutdown()一定要在onDestroy()时调用,用来释放占用内存。

    附:VRDemo

  • 相关阅读:
    20180404
    20180323
    20180315
    mongodb
    linux 集群 读写分离 session入库 负载均衡 配置
    linux 搭建配置 lnmp搭建
    有语义标签
    CSS标签属性
    使用QQ登录商城
    ajax 跨域
  • 原文地址:https://www.cnblogs.com/llguanli/p/7324951.html
Copyright © 2011-2022 走看看