博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Google VR技术大揭秘
阅读量:6074 次
发布时间:2019-06-20

本文共 10234 字,大约阅读时间需要 34 分钟。

VR

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

附:

VR产品

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选项。点击上图红色框中的按钮即可进入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为19minSdkVersion 19//添加依赖compile 'com.google.vr:sdk-panowidget:1.20.0'

2. 配置AndroidManifest.xml

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

3. 加载全景图

private class LoadPanoramaImageTask extends AsyncTask
{ @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. 生命周期管理

@Overrideprotected void onPause() {    mVrPanoramaView.pauseRendering();    super.onPause();}@Overrideprotected void onResume() {    super.onResume();    mVrPanoramaView.resumeRendering();}@Overrideprotected 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 (已经配置则忽略)

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. 生命周期管理

@Overrideprotected 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;}@Overrideprotected void onResume() {    super.onResume();    mVrVideoView.resumeRendering();}@Overrideprotected 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);//隐藏信息按钮    mVrPanoramaView.setStereoModeButtonEnabled(false);//隐藏cardboard按钮    mVrPanoramaView.setFullscreenButtonEnabled(false);//隐藏全屏按钮    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();        }    }}

生命周期管理

@Overrideprotected void onResume() {    super.onResume();    mVrPanoramaView.resumeRendering();}@Overrideprotected void onPause() {    super.onPause();    mVrPanoramaView.pauseRendering();    if (mMediaPlayer != null) {        mMediaPlayer.pause();    }}@Overrideprotected 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要求的内容呢?

真实世界中的拍摄

,用这个app可以和方便的拍摄360照片,拍摄完成后需要通过来创建一个立体声的360照片。

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

1,CG 拍摄

VR view的图片不仅仅限制在真实世界中拍摄。CGI(计算机合成图像)可以为所有的东西生成360度全景照片和视频,最流行拍摄解决方案如下:

Unity插件

虚幻引擎
一个开源库

下面用伪代码展示如何用VrPanoramaView和VrVideoView展示360度图片和视频。

//展示全景图片 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()时调用,用来释放占用内存。

附:

你可能感兴趣的文章
字符设备与块设备的区别
查看>>
为什么我弃用GNOME转向KDE(2)
查看>>
Redis学习记录初篇
查看>>
爬虫案例若干-爬取CSDN博文,糗事百科段子以及淘宝的图片
查看>>
Web实时通信技术
查看>>
第三章 计算机及服务器硬件组成结合企业运维场景 总结
查看>>
IntelliJ IDEA解决Tomcal启动报错
查看>>
默认虚拟主机设置
查看>>
七周五次课(1月26日)
查看>>
Linux系统一些系统查看指令
查看>>
php中的短标签 太坑人了
查看>>
[译] 可维护的 ETL:使管道更容易支持和扩展的技巧
查看>>
### 继承 ###
查看>>
数组扩展方法之求和
查看>>
astah-professional-7_2_0安装
查看>>
函数是对象-有属性有方法
查看>>
uva 10107 - What is the Median?
查看>>
Linux下基本栈溢出攻击【转】
查看>>
c# 连等算式都在做什么
查看>>
使用c:forEach 控制5个换行
查看>>