Skip to main content
AR论坛
 首页 » 资源教程

Daydream从入门到精通教程三:SimpleVrPanorama制作VR全景应用

2016年11月18日 15:27:561720Jaiky_杰哥

前言

前两篇介绍了Daydream Android VR开发环境的搭建和官方VR Demo寻宝游戏的演示,这篇我们来一起研究下示例项目SimpleVrPanorama,同时通过了解它来了解如何开发一款VR全景图形应用。

--------------------------------------------------------------------------------------------------------------------

Daydream快速入门开发基础教程一:Android端开发环境配置一

http://www.chinaar.com/ZYJC/3718.html

Daydream快速入门开发基础教程二:Android端开发环境配置二

http://www.chinaar.com/ZYJC/3719.html

--------------------------------------------------------------------------------------------------------------------

全景效果:

 Daydream从入门到精通教程三:SimpleVrPanorama制作VR全景应用 资源教程 第1张

 

SimpleVrPanorama例子介绍

 

SimpleVrPanorama VR 运行后效果图如下,运行效果有两种,分别是全景效果和分屏效果,分屏效果主要用于Cardboard纸盒(尝试录制gif,发现太大了,无法上传,只能这样了):

分屏效果(Cardboard纸盒模式):

Daydream从入门到精通教程三:SimpleVrPanorama制作VR全景应用 资源教程 第2张

很简单的一个Demo,就是一张“安第斯山脉”全景图,没有其他交互,内容也没什么好说的,你可以转动头部查看四周的环境,受制于手机硬件配置,不同的设备在转动时,延迟可能不同,反正我的测试机对VR的体验不算太好,是时候换个pixel XL或华为Mate9了。

 

 

VR view简单介绍

 

接下来我们来研究下它的源代码,整个APP模块的结构如下:

Daydream从入门到精通教程三:SimpleVrPanorama制作VR全景应用 资源教程 第3张

整体上没多少东西,注意看下assets资源文件夹中有个andes.jpg,也就是我们的“安第斯山脉”全景图了,打开图片看看,也就是我们在APP中看到的全景效果:

Daydream从入门到精通教程三:SimpleVrPanorama制作VR全景应用 资源教程 第4张

为什么是两张一模一样的呢?因为这是分别给左右眼观看的,遵循了VR view视图的基本规则,关于VR view,VR view是Google在2016年4月推出的一个VR基本概念,是一种“客户端”VR显示技术,可将 360 度照片或视频部署在各种设备上的简易方式,本篇文章就不做详细介绍了,想了解的请看看这篇Blog:

--------------------------------------------------------------------------------------------------------------------

Daydream VR入门基础教程,VR开发基础知识——VR view基本介绍

http://blog.csdn.net/jaikydota163/article/details/53049230

--------------------------------------------------------------------------------------------------------------------

 

 

源码研究

 

首先还是我们还是先从程序的入口Manifest文件看看有什么:

[html] view plain copy

<applicationandroid:label="SimpleVrPanoramaActivity"

  1.   android:largeHeap="true"

  2.   android:theme="@android:style/Theme.Holo.Light">

  3.     <!-- This demo is singleTask since it makes launching via custom adb intents easier. -->

  4.     <activityandroid:name=".SimpleVrPanoramaActivity"

  5.       android:launchMode="singleTask">

  6.         <intent-filter>

  7.             <!-- Primary intent when launching from the home screen -->

  8.             <actionandroid:name="android.intent.action.MAIN"/>

  9.             <categoryandroid:name="android.intent.category.LAUNCHER"/>

  10.             <categoryandroid:name="com.google.intent.category.CARDBOARD"/>

  11.         </intent-filter>

  12.     </activity>

  13. </application>

  14.  

  15. <!-- These permissions are used by Google VR SDK to get the best Google VR headset profiles. !-->

  16. <uses-permissionandroid:name="android.permission.INTERNET"/>

  17. <uses-permissionandroid:name="android.permission.READ_EXTERNAL_STORAGE"/>

没什么特别的东西,可以看到主要用到的权限:

 ●  android.permission.INTERNET : 获取网络权限

 ●  android.permission.READ_EXTERNAL_STORAGE  : 读取拓展内容。

intent-filter过滤分类:

 ●  com.google.intent.category.CARDBOARD : 兼容Cardboard纸盒

然后看看布局文件main_layout.xml:

[html] view plain copy

<com.google.vr.sdk.widgets.pano.VrPanoramaView

  1.             android:id="@+id/pano_view"

  2.             android:layout_margin="5dip"

  3.             android:layout_width="match_parent"

  4.             android:scrollbars="@null"

  5.             android:layout_height="250dip"/>

整个布局文件中唯一特别的就是这个VrPanoramaView了,也就是VR全景视图组件。

com.google.vr.sdk.widgets.pano : VR全景视图组件,也就是在项目的libraries-panowidget模块下。

它在gradle中被引用:

[html] view plain copy

dependencies {  

  1.     compile project(':libraries-common') //Google VR API的公共代码。  

  2.     compile project(':libraries-commonwidget') //Google VR API的公共组件。  

  3.     compile project(':libraries-panowidget') //VR全景视图组件  

  4.  

  5.     compile 'com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-7' //序列化数据结构的方案  

  6. }  

然后我们看看主代码(官方代码过于冗余,为方便新人理解学习,修改成如下):

[java] view plain copy

Daydream从入门到精通教程三:SimpleVrPanorama制作VR全景应用 资源教程 第5张

Daydream从入门到精通教程三:SimpleVrPanorama制作VR全景应用 资源教程 第6张

  1. package com.google.vr.sdk.samples.simplepanowidget;  

  2.  

  3. import android.app.Activity;  

  4. import android.graphics.BitmapFactory;  

  5. import android.os.AsyncTask;  

  6. import android.os.Bundle;  

  7. import android.util.Log;  

  8. import android.util.Pair;  

  9.  

  10. import com.google.vr.sdk.widgets.pano.VrPanoramaEventListener;  

  11. import com.google.vr.sdk.widgets.pano.VrPanoramaView;  

  12. import com.google.vr.sdk.widgets.pano.VrPanoramaView.Options;  

  13.  

  14. import java.io.IOException;  

  15. import java.io.InputStream;  

  16.  

  17. publicclass SimpleVrPanoramaActivity extends Activity {  

  18.  

  19.     privatestaticfinal String TAG = "SimpleVrPanoramaActivity";  

  20.     private VrPanoramaView panoWidgetView;//VR全景图形组件

  21.     private String fileUri = "andes.jpg";//assets文件夹下的文件名

  22.  

  23.     private Options panoOptions = new Options();//VrPanoramaView需要的设置

  24.     private ImageLoaderTask backgroundImageLoaderTask;//异步加载图片

  25.  

  26.     @Override

  27.     protectedvoid onCreate(Bundle savedInstanceState) {  

  28.         super.onCreate(savedInstanceState);  

  29.         setContentView(R.layout.main_layout);//获取布局

  30.  

  31.         panoWidgetView = (VrPanoramaView) findViewById(R.id.pano_view);//初始化VrPanoramaView

  32.         panoWidgetView.setEventListener(new ActivityEventListener());//为VrPanoramaView添加监听

  33.  

  34.         //如果有任务在执行则停止它

  35.         if (backgroundImageLoaderTask != null) {  

  36.             backgroundImageLoaderTask.cancel(true);  

  37.         }  

  38.          //设置inputType 为TYPE_STEREO_OVER_UNDER. 在后面会介绍TYPE_STEREO_OVER_UNDER的,暂时当做一个图片的显示类型就行

  39.         panoOptions.inputType = Options.TYPE_STEREO_OVER_UNDER;  

  40.         //创建图片异步加载任务

  41.         backgroundImageLoaderTask = new ImageLoaderTask();  

  42.         //执行任务。将图片名(根据项目实际情况传吧)和设置传入

  43.         backgroundImageLoaderTask.execute(Pair.create(fileUri, panoOptions));  

  44.     }  

  45.     //异步任务

  46.     class ImageLoaderTask extends AsyncTask<Pair<String, Options>, Void, Boolean> {  

  47.         @Override

  48.         protected Boolean doInBackground(Pair<String, Options>... fileInformation) {//真正写项目根据情况添加条件判断吧

  49.  

  50.             InputStream istr = null;  

  51.             try {  

  52.                 istr = getAssets().open(fileInformation[0].first);//获取图片的输入流

  53.             } catch (IOException e) {  

  54.                 Log.e(TAG, "Could not decode default bitmap: " + e);  

  55.                 returnfalse;  

  56.             }  

  57.  

  58.             Bitmap bitmap = BitmapFactory.decodeStream(istr);//创建bitmap

  59.             panoWidgetView.loadImageFromBitmap(bitmap, fileInformation[0].second);//参数一为图片的bitmap,参数二为 VrPanoramaView 所需要的设置

  60.  

  61.             try {  

  62.                 istr.close();//关闭InputStream

  63.             } catch (IOException e) {  

  64.                 Log.e(TAG, "Could not close input stream: " + e);  

  65.             }  

  66.  

  67.             returntrue;  

  68.         }  

  69.     }  

  70.  

  71.     privateclass ActivityEventListener extends VrPanoramaEventListener {  

  72.  

  73.         @Override

  74.         publicvoid onLoadSuccess() {//图片加载成功

  75.             Log.e(TAG, "onLoadSuccess");  

  76.         }  

  77.  

  78.  

  79.         @Override

  80.         publicvoid onLoadError(String errorMessage) {//图片加载失败

  81.             Log.e(TAG, "Error loading pano: " + errorMessage);  

  82.         }  

  83.  

  84.         @Override

  85.         publicvoid onClick() {//当我们点击了VrPanoramaView 时候出发

  86.             super.onClick();  

  87.             Log.e(TAG, "onClick");  

  88.         }  

  89.  

  90.         @Override

  91.         publicvoid onDisplayModeChanged(int newDisplayMode) {//改变显示模式时候出发(全屏模式和纸板模式)

  92.             super.onDisplayModeChanged(newDisplayMode);  

  93.             Log.e(TAG, "onDisplayModeChanged");  

  94.         }  

  95.     }  

  96.  

  97.  

  98.     @Override

  99.     protectedvoid onPause() {  

  100.         panoWidgetView.pauseRendering();//暂停3D渲染和跟踪

  101.         super.onPause();  

  102.     }  

  103.  

  104.     @Override

  105.     protectedvoid onResume() {  

  106.         super.onResume();  

  107.         panoWidgetView.resumeRendering();//恢复3D渲染和跟踪

  108.     }  

  109.  

  110.     @Override

  111.     protectedvoid onDestroy() {  

  112.         panoWidgetView.shutdown();//关闭渲染下并释放相关的内存

  113.  

  114.         if (backgroundImageLoaderTask != null) {  

  115.             backgroundImageLoaderTask.cancel(true);//停止异步任务

  116.         }  

  117.         super.onDestroy();  

  118.     }  

  119. }  

代码很简单,流程就是获取VrPanoramaView组件——添加事件监听——异步载入图片。

如果想要隐藏VrPanoramaView组件的按钮:

[java] view plain copy

panoWidgetView.setFullscreenButtonEnabled(false); // 是否启用全屏按钮

  1. panoWidgetView.setStereoModeButtonEnabled(false); // 是否启用纸盒按钮

了解Options

这是设置Options的两个主要属性:

[java] view plain copy

//图像被预期以覆盖沿着其水平轴360度,而垂直范围是根据图像的宽高比来计算。例如,如果一个1000x250像素的图像,给出所述全景将覆盖360x90度与垂直范围是-45至+45度。

  1. publicstaticfinalint TYPE_MONO = 1;  

  2.  

  3. //包含两个大小相等的投影 全景图垂直叠加。顶部图像被显示给左眼、底部图像被显示给右眼。   

  4. 图像将覆盖沿水平轴360度,而垂直范围是根据图像的宽高比来计算。例如,如果一个1000x500像素的图像中给出(即1000x250像素每个眼睛),全景将覆盖360x90度与垂直范围是-45至+45度。  

  5. publicstaticfinalint TYPE_STEREO_OVER_UNDER = 2;  

也就是上面VR view文章中介绍的(360度单图和立体图),想实现左边的效果设置为TYPE_MONO,右边的设置为TYPE_STEREO_OVER_UNDER:

Daydream从入门到精通教程三:SimpleVrPanorama制作VR全景应用 资源教程 第7张

Options的源代码:

[java] view plain copy

  1. publicstaticclass Options {  

  2.         privatestaticfinalint TYPE_START_MARKER = 0;//起始标记

  3.         publicstaticfinalint TYPE_MONO = 1;  

  4.         publicstaticfinalint TYPE_STEREO_OVER_UNDER = 2;  

  5.         privatestaticfinalint TYPE_END_MARKER = 3;//结束标记

  6.         publicint inputType = 1;//默认为一

  7.  

  8.         public Options() {  

  9.         }  

  10.  

  11.         void validate() {  

  12.             if(this.inputType <= 0 || this.inputType >= 3) {//标记错误处理

  13.                 String var10000 = VrPanoramaView.TAG;  

  14.                 int var1 = this.inputType;  

  15.                 Log.e(var10000, (new StringBuilder(38)).append("Invalid Options.inputType: ").append(var1).toString());  

  16.                 this.inputType = 1;  

  17.             }  

  18.         }  

  19. }  

 

 

如何开发一款VR图形全景应用

 

通过研究SimpleVrPanorama的源代码,我们来总结下如何通过GVR的安卓SDK在Android Studio上开发一款VR图形全景应用:

 ●  在Gradle模块中引用GVR的库,如compile project(':libraries-panowidget')。

 ●  准备好遵循VR view基本准则的全景图片。

 ●  在布局XML中添加com.google.vr.sdk.widgets.pano.VrPanoramaView控件。

 ●  在主代码中初始化VrPanoramaView控件,并设置options模式。

 ●  调用VrPanoramaView的loadImageFromBitmap方法异步加载图片

 ●  在onPause、onResume、onDestroy中做出相应处理

通过对SimpleVrPanorama示例项目的研究,我们理解了Android VR图形全景应用的开发方式,所以我们不难理解,在Gvr-Android-SDK源代码内的另外一个示例项目samples-sdk-simplevideowidget也是同样的道理,只不过它是对VR全景视频的应用,视频格式也是遵循VR view的基本准则。如果有时间,我会写一篇关于simplevideowidget的应用和研究,看看如何通过gvr创建Android全景视频应用。


评论列表暂无评论
发表评论