前言: 2016年被称为VR元年,VR的火热就像当年的andorid刚进入中国市场一样。或许VR在发展上还有很多障碍,但却挡不住我们体验VR虚拟效果时带给我们的惊艳。下面就通过android做一个简单的VR全景图效果。
实现VR全景图效果 首先我们要下载VR库文件。Google官网为我们提供了VR资源的下载: https://github.com/googlevr/gvr-android-sdk/ 实现VR步骤: 0.0 在项目里新建一个资产目录assets,把图片放入资产目录下。 1.0 在清单文件下Application节点中加入android:largeHeap=”true”的属下节点. 2.0 导入VR需要依赖的library库,以导module的方式去导入:Common,Commonwidge,Panowidget 3.0 在Module的build.gradle文件里dependencies,添加:compile ‘com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-7’ 4.0 完成项目XML布局,VrPanoramaView 5.0 由于VR资源数据量大,获取需要时间,故把加载图片放到子线程中进行,主线程来显示图片,可以使用一个异步线程AsyncTask或EventBus技术完成 6.0 因为VR很占用内存,所以当界面进入onPause状态,暂停VR视图显示,进入onResume状态,继续VR视图显示,进入onDestroy状态,杀死VR,关闭异步任务 7.0 设置对VR运行状态的监听,如果VR运行出现错误,可以及时的处理. 8.0 播放VR效果,只需执行异步任务即可. 步骤演示: 1.在项目main下新建一个资产目录:assets,放入VR图片 2.在清单文件下Application节点中加入 android:largeHeap=”true”的属下节点(使用VR的资源很消耗内存,所以我们为了避免OOM(内存溢出)的问题,要把警报权限提高,从192提高到512m) 3.在Module的build.gradle文件里dependencie中加入:compile ‘com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-7’ 导入VR需要依赖的library库,以导model的方式去导入:Common,Commonwidge,Panowidget 4.关联你的库文件:ctrl+alt+shift+s在打开的对话框中,选择你原本的项目app,选择第四个Dependencise,点击右上角”+”,选择第三个Module dependency,在打开的对话框中,选择之前导入的库文件。
5.导入完毕后,修改你的minSdkVersion 为导入库的最低版本相匹配,6.在xml中验证是否导入成功: 在MainActivity中的代码: 1.实例化VR控件: 2..因为读取VR的资源是一个耗时操作(VR资源非常大,读取需要时间)所以我们不能在主线程去做读取操作,但是只有在主线程才能做UI的更新,故我们使用AsyncTask线程去读取。 到这基本上就已经可以基本实现VR全景图的效果啦。但是在异常情况下我们还是要做一下处理,下面是我的总代码,都写有注释:
import android.graphics.Bitmap;import android.graphics.BitmapFactory; import android.os.AsyncTask; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.Toast;
import com.google.vr.sdk.widgets.common.VrWidgetView; import com.google.vr.sdk.widgets.pano.VrPanoramaEventListener; import com.google.vr.sdk.widgets.pano.VrPanoramaView;
import java.io.IOException; import java.io.InputStream;
// 导入三个库文件,common:基本库文件 commonwidget:基本视图控件文件 ,panowidget:全景图 public class MainActivity extends AppCompatActivity {
private ImagerLoaderTask imagerLoaderTask; private VrPanoramaView mVrPanoramaView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //A 对VR控件初始化 ctrl+alt+f 抽取成员变量 mVrPanoramaView = (VrPanoramaView) findViewById(R.id.VRP); // 隐藏掉VR效果左下角的信息按钮显示 mVrPanoramaView.setInfoButtonEnabled(false); // 隐藏VR效果右下角全屏显示的按钮 mVrPanoramaView.setFullscreenButtonEnabled(false); // 切换VR的模式 参数:VrWidgetView.DisplayMode.FULLSCREEN_STEREO设备模式(手机横看)(.FULLSCREEN_MONO手机模式) mVrPanoramaView.setDisplayMode(VrWidgetView.DisplayMode.FULLSCREEN_STEREO); // 设置对VR运行状态的监听,如果VR运行出现错误,可以及时处理 mVrPanoramaView.setEventListener(new MVREventListener()); // B 使用自定义的AsyncTask,播放VR效果 imagerLoaderTask = new ImagerLoaderTask(); imagerLoaderTask.execute(); } // 因为读取VR的资源是一个耗时操作(VR资 源非常大,读取需要时间)所以我们不能再主线程去做读取操作, // 但是只有在主线程才能做UI的更新,故我们使用AsyncTask private class ImagerLoaderTask extends AsyncTask<Void,Void,Bitmap>{// 以后EventBus去替代 // B 该方法在子线程运行,从本地文件中把资源加载到内存中 // 此方法中定义要执行的后台任务,在这个方法中可以调用publishProgress来更新任务进度 @Override protected Bitmap doInBackground(Void... params) { try { // 从资产目录拿到资源,返回结果是字节流 InputStream inputStream = getAssets().open("andes.jpg"); // 把字节流转换成Bitmap对象 Bitmap bitmap = BitmapFactory.decodeStream(inputStream); // 返回出bitmap return bitmap; } catch (IOException e) { e.printStackTrace(); } return null; } // 接收bitmap运行在主线程中 @Override protected void onPostExecute(Bitmap bitmap) { // 创建VrPanoramaView.Options,去决定显示VR是普通效果,还是立体效果 VrPanoramaView.Options options = new VrPanoramaView.Options(); // TYPE_STEREO_OVER_UNDER立体效果:图片的上半部分放在左眼显示,下半部分放在右眼显示 TYPE_MONO:普通效果 options.inputType = VrPanoramaView.Options.TYPE_STEREO_OVER_UNDER; // 使用VR控件对象,显示效果 参数1:Bitmap对象 2.VrPanoramaView.Options对象,决定显示的效果 mVrPanoramaView.loadImageFromBitmap(bitmap,options); super.onPostExecute(bitmap); } } // 因为VR很占用内存,所以当界面进入onPause状态,暂停VR视图显示,进入onResume状态,继续VR视图显示,进入onDestroy,杀死VR,关闭异步任务 // 当失去焦点时,回调 @Override protected void onPause() { // 暂停渲染和显示 mVrPanoramaView.pauseRendering(); super.onPause(); } // 当重新获取焦点时,回调 @Override protected void onResume() { super.onResume(); // 继续渲染和显示 resumeRendering();重新阅读 mVrPanoramaView.resumeRendering(); } // 当Activity销毁时,回调 @Override protected void onDestroy() { // 关闭渲染视图 mVrPanoramaView.shutdown(); if (imagerLoaderTask!=null){ // 退出activity时,如果异步任务没有取消,就取消 if (imagerLoaderTask.isCancelled()){ imagerLoaderTask.cancel(true); } } super.onDestroy(); } // VR运行状态监听类,自定义一个类,继承 private class MVREventListener extends VrPanoramaEventListener{ // 当VR视图加载成功的时候,回调 @Override public void onLoadSuccess() { super.onLoadSuccess(); Toast.makeText(MainActivity.this, "加载成功", Toast.LENGTH_SHORT).show(); } public void onLoadError(String errorMessage){ super.onLoadError(errorMessage); Toast.makeText(MainActivity.this, "加载失败", Toast.LENGTH_SHORT).show(); } }} 最后还是要展示一下炫酷的效果: 最后希望共同学习,共同进步。