GoogleVR
GoogleVR是google出的VR库,随着google在VR方面的尝试失败,这套SDK也不再维护了,github(github.com/googlevr/gv... )上的更新停留在三年前了。
不过对于Android开发者来说,通过这套SDK来了解VR非常方便,所以在这个系列的一开始,我打算通过GoogleVR来带大家先了解一下VR。
使用GoogleVR很简单,只要依赖几个库即可,如下:
java
implementation 'com.google.vr:sdk-base:1.180.0'
implementation 'com.google.vr:sdk-panowidget:1.180.0'
implementation 'com.google.vr:sdk-videowidget:1.180.0'
Panorama
Panorama就是全景图,上面的sdk-panowidget库就是用来展示全景图的,使用起来非常简单。
首先在页面中添加VrPanoramaView
,如下:
xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".PanoViewFragment">
<com.google.vr.sdk.widgets.pano.VrPanoramaView
android:id="@+id/vr_pano"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
然后通过它的loadImageFromBitmap
来加载图片即可,比如我们使用官方DEMO中的一张神庙图片andes.jpeg
将它放到assets目录下,然后通过下面代码加载即可:
kotlin
val option = VrPanoramaView.Options()
var bitmap = BitmapFactory.decodeStream(assets.open("andes.jpeg"))
option.inputType = VrPanoramaView.Options.TYPE_STEREO_OVER_UNDER
_binding?.vrPano?.loadImageFromBitmap(bitmap, option)
在生命周期中做相应的处理即可,如下:
kotlin
override fun onResume() {
super.onResume()
_binding?.vrPano?.resumeRendering()
}
override fun onPause() {
super.onPause()
_binding?.vrPano?.pauseRendering()
}
override fun onDestroyView() {
super.onDestroyView()
_binding?.vrPano?.shutdown()
}
这样我们就可以看到全景图了,效果如下:
可以看到随着我们手机的移动,画面也会跟着移动,就好像是真的在现场似的。
这时候我们点击下面眼镜那个图标就会进入vr眼睛的模式,效果如下:
将手机放入vr眼镜中就可以身临其境的看到神庙了。
单通道和双通道
上面我们可以看到原图是上下两个部分,这两个部分基本一样,这是为什么?
因为上图是双通道全景图,上下其实不一样,是专门的摄像机模拟人的左右眼拍摄的两张不同的照片,然后以上下的形式放在了一起。
这样当我们切换到VR眼镜的模式的时候,两个眼镜的部分就会展示不同的图片,这样模拟了人眼的模式,就会有景深和立体的感觉,更加真实。
所以我们在上面加载图片的时候type设置为TYPE_STEREO_OVER_UNDER
。这个type还有另外一个值TYPE_MONO
,即单通道。
单通道就是一个摄像头拍摄的全景图,如下:
代码都一样,只不过加载的时候将type改成TYPE_MONO
即可。运行效果如下:
这个与双通道的差距不大,然后来看看VR眼镜效果:
小伙伴可能就有疑问了,不是只有一个通道么,那么左右眼显示的是一个图片么?
大家仔细观察可以发现,虽然展示的是一个图片,但是明显偏移及角度不同,Google通过计算的方式来模拟双眼的感觉。在VR眼镜中可以感受到,确实有那么一点立体感,但是明显没有双通道那么真实,因为双眼看一个物体的角度不同成像也是不同的,单通道毕竟只有一张图片。
原理
实际上是将全景图映射渲染到球的内壁上,我们则在球的内部观察,这样我们上下左右都可以看到相应的景象(与地球仪正好相反,地球仪是将地图渲染到球的外壁,我们在外部观察)。上面其实可以看到全景图越靠近两侧拉伸越大,因为最终要收缩成球。
而进入VR眼镜模式的时候,左右眼就会分别绘制,也就是说实际上是两个球绘制不同的图片。
下面我们会讲视频也是一样的原理。
Video
只看图片太low了,还可以播放全景视频(全景视频是通过全景相机拍摄的视频)。上面sdk-videowidget
库就用来播放视频的。
首先定义一个布局,添加VrVideoView:
xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".VrVideoFragment">
<com.google.vr.sdk.widgets.video.VrVideoView
android:id="@+id/vr_video"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
然后通过它就可以播放全景视频了,流程跟图片差不多,代码如下:
kotlin
var options = VrVideoView.Options()
options.inputFormat = VrVideoView.Options.FORMAT_DEFAULT
options.inputType = VrVideoView.Options.TYPE_STEREO_OVER_UNDER
_binding?.vrVideo?.loadVideoFromAsset("congo.mp4", options)
_binding?.vrVideo?.setEventListener(object : VrVideoEventListener() {
override fun onLoadSuccess() {
super.onLoadSuccess()
_binding?.vrVideo?.playVideo()
}
override fun onLoadError(errorMessage: String?) {
super.onLoadError(errorMessage)
}
override fun onClick() {
super.onClick()
}
override fun onDisplayModeChanged(newDisplayMode: Int) {
super.onDisplayModeChanged(newDisplayMode)
}
override fun onCompletion() {
super.onCompletion()
}
override fun onNewFrame() {
super.onNewFrame()
}
})
这里我们通过VrVideoView的loadVideoFromAsset来播放assets目录下的视频资源,也可以通过它的loadVideo来播放本地资源和网络资源。
VrVideoView也包含一些视频的常规操作,比如play、pause、seek等等,大家自行查阅源码即可。
然后在生命周期中做一些处理即可:
kotlin
override fun onResume() {
super.onResume()
_binding?.vrVideo?.resumeRendering()
}
override fun onPause() {
super.onPause()
_binding?.vrVideo?.pauseRendering()
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
_binding?.vrVideo?.shutdown()
}
在上面的例子中我们使用的官方demo中的一段视频,最终效果如下:
可以看到因为是视频,所以真实感更加强烈,再来看看AR效果:
单通道双通道
与图片一样,视频也有单通道和双通道两种模式,比如上面例子中的congo.mp4就是双通道视频,所以type是VrVideoView.Options.TYPE_STEREO_OVER_UNDER,双通道视频与双通道图片原理一样,左右眼分别录制两个视频然后上下拼在一起;而单通道就是全景相机录制一个视频,type是VrVideoView.Options.TYPE_MONO,下面来看看一个单通道视频的效果:
也是那种身临其境的感觉,再来看看VR效果:
与图片的原理差不多,也是通过计算的方式将一个视频模拟出双眼的效果,带上眼镜就会发现还是很逼真的。
总结
通过这两个demo我们就基本掌握来GoogleVR sdk的用法,主要目的还是了解一下VR到底是什么。下一篇文章我们来着重讲一讲如何渲染一个VR场景,介绍一下VR世界是如果构建的。