入門(mén)指南
本文檔介紹如何使用實(shí)驗(yàn)性的 Cardboard SDK for Android 創(chuàng)建您自己的虛擬實(shí)境 (VR) 體驗(yàn)。
Android 演示版應(yīng)用:Treasure Hunt
本教程中的代碼示例摘自“Treasure Hunt”Android 演示版應(yīng)用丑掺。
Cardboard 是一個(gè)簡(jiǎn)單的設(shè)備,可讓智能手機(jī)發(fā)揮虛擬實(shí)境平臺(tái)的威力胆屿。 Cardboard 可與手機(jī)配合使用,從而在雙眼中呈現(xiàn)三維場(chǎng)景、跟蹤響應(yīng)頭部移動(dòng)以及通過(guò)磁鐵輸入與應(yīng)用進(jìn)行交互铭段。 演示版應(yīng)用“Treasure Hunt”可展示上述功能瞧毙。 在此游戲中胧华,用戶(hù)在數(shù)字化的世界里四處觀(guān)望,目的是盡快尋找和搜集物品宙彪。 這是一款很基本的游戲矩动,但它展示了 Cardboard 的核心功能。
游戲特性
“Treasure Hunt”一開(kāi)場(chǎng)是以三維立體文字呈現(xiàn)的游戲說(shuō)明释漆。 當(dāng)用戶(hù)發(fā)現(xiàn)物品后悲没,系統(tǒng)會(huì)指示用戶(hù)拉動(dòng)磁鐵。
cube1.png
這就是屏幕上顯示的內(nèi)容男图。 在 Cardboard 中觀(guān)看時(shí)示姿,這些將以三維場(chǎng)景呈現(xiàn)。
當(dāng)用戶(hù)在屏幕中間的中心位置發(fā)現(xiàn)立方體時(shí)逊笆,立方體通過(guò)將其顏色更改為黃色進(jìn)行指示峻凫。 用戶(hù)在立方體變?yōu)辄S色時(shí)拉動(dòng)磁鐵,用戶(hù)的得分就會(huì)增加览露,隨后立方體將移動(dòng)到新的位置荧琼。
cube2.png
此應(yīng)用使用OpenGL ES 2.0 顯示物品。 它演示了一些基本的功能,如燈光命锄、在空間的移動(dòng)和著色堰乔。 展示了如何使用磁鐵作為輸入、如何知道用戶(hù)是否正在看某樣?xùn)|西脐恩,以及如何通過(guò)為每只眼睛提供不同的視圖來(lái)呈現(xiàn)圖像镐侯。
現(xiàn)在,我們看下如何構(gòu)建演示版應(yīng)用驶冒,并在手機(jī)上運(yùn)行它苟翻。
打開(kāi)并運(yùn)行 Treasure Hunt
開(kāi)始前的準(zhǔn)備工作
構(gòu)建演示版應(yīng)用需要:
- Android Studio 1.0 或更高版本
- Android SDK 19 版本
- 運(yùn)行 Android 16 (Jelly Bean) 或更高版本的 Android 物理設(shè)備
下載示例代碼
通過(guò)運(yùn)行以下命令,從cardboard-java
GitHub 存儲(chǔ)庫(kù)克隆演示版應(yīng)用
git clone https://github.com/googlesamples/cardboard-java.git```
###構(gòu)建演示版應(yīng)用
1. 打開(kāi) Android Studio骗污,在 **Welcome** 頁(yè)面上崇猫,選擇**Import Non-Android Studio Project**。 選擇位于您剛下載的示例代碼文件根目錄處的 **build.gradle** 文件需忿,然后點(diǎn)擊 **OK**诅炉。
這會(huì)在編輯器視圖中打開(kāi)一個(gè)名為 <b>CardboardSample</b> 的項(xiàng)目,其包含我們上面介紹的 Treasure Hunt 示例應(yīng)用屋厘。
2. 將手機(jī)連接到裝置上涕烧,點(diǎn)擊**Run**,然后**運(yùn)行“CardboardSample”**以在手機(jī)上編譯和運(yùn)行應(yīng)用汗洒。
###代碼概覽
清單文件
Cardboard SDK 需要以下清單文件標(biāo)簽:
```xml
<manifest
...
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.VIBRATE" />
...
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="19"/>
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
<application ...
<activity android:name=".MainActivity"
android:screenOrientation="landscape">
...
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="com.google.intent.category.CARDBOARD" />
</intent-filter>
</activity>
</application>
</manifest>```
請(qǐng)注意以下事項(xiàng):
```xml
<uses-sdk android:minSdkVersion="16"/>```
表示設(shè)備必須運(yùn)行 API 級(jí)別 16 (Jellybean) 或更高版本议纯。
```xml
<uses-sdk android:targetSdkVersion="19"/>```
表示應(yīng)用針對(duì)的是 API 級(jí)別 19 (KitKat)。
```xml
<uses-feature android:glEsVersion="0x00020000" android:required="true" />```
表示設(shè)備必須支持 OpenGL ES 2.0 才能運(yùn)行演示版應(yīng)用溢谤。
```xml
android:screenOrientation="landscape"```
表示 Activity 要求屏幕方向?yàn)?橫向瞻凤。" 您必須將 VR 應(yīng)用的方向設(shè)為橫向。 Cardboard SDK 使用的視圖溯香、 [CardboardView](https://developers.google.com/cardboard/android/latest/reference/com/google/vrtoolkit/cardboard/CardboardView)
只能在全屏和橫向(landscape、reverseLandscape浓恶、sensorLandscape)模式下呈現(xiàn)玫坛。
另外,推薦使用設(shè)置 android:configChanges="orientation|keyboardHidden"包晰,但并不強(qiáng)制湿镀。
Cardboard SDK 需要具有 android.permission.NFC 權(quán)限才能訪(fǎng)問(wèn) Cardboard 的 NFC 標(biāo)簽。
```android.permission.READ_EXTERNAL_STORAGE``` 和 ```android.permission.WRITE_EXTERNAL_STORAGE```伐憾。Cardboard SDK 需要具有這些權(quán)限才能將用戶(hù)的手機(jī)和他們的 VR 查看器進(jìn)行配對(duì)勉痴。
演示版應(yīng)用需要具有 ```android.permission.VIBRATE``` 權(quán)限才能使手機(jī)發(fā)生震動(dòng),以通知用戶(hù)發(fā)生了一些事树肃。
intent-filter蒸矛,特別是 ```com.google.intent.category.CARDBOARD```,聲明此 Activity 與類(lèi)似Cardboard 的查看器兼容。 [Cardboard 應(yīng)用](https://play.google.com/store/apps/details?id=com.google.samples.apps.cardboarddemo)使用此類(lèi)別列出用戶(hù)手機(jī)上安裝的兼容應(yīng)用雏掠。
##擴(kuò)展 CardboardActivity
[CardboardActivity](https://developers.google.com/cardboard/android/latest/reference/com/google/vrtoolkit/cardboard/CardboardActivity) 是對(duì) Cardboard 應(yīng)用進(jìn)行編碼的起點(diǎn)斩祭。 CardboardActivity 是一個(gè)基礎(chǔ) Activity,可與 Cardboard 設(shè)備輕松集成乡话。 它將事件公開(kāi)摧玫,以便與 Cardboard 進(jìn)行交互,并處理為 VR 呈現(xiàn)創(chuàng)建 Activity 時(shí)通常要求的眾多細(xì)節(jié)绑青。
請(qǐng)注意诬像,CardboardActivity 使用粘滯的沉浸模式,在該模式下闸婴,系統(tǒng) UI 處于隱藏狀態(tài)坏挠,且內(nèi)容會(huì)占用整個(gè)屏幕。 這是對(duì) VR 應(yīng)用的一項(xiàng)要求掠拳,原因是 CardboardView 僅在 Activity 處于全屏模式時(shí)才會(huì)呈現(xiàn)癞揉。 有關(guān)此功能的更多討論,請(qǐng)參見(jiàn)[使用沉浸式全屏模式](http://developer.android.com/training/system-ui/immersive.html#sticky)溺欧。
演示版應(yīng)用的 MainActivity 可擴(kuò)展 [CardboardActivity](https://developers.google.com/cardboard/android/latest/reference/com/google/vrtoolkit/cardboard/CardboardActivity)喊熟。 MainActivity 可實(shí)現(xiàn)以下界面:
- [CardboardView.StereoRenderer](https://developers.google.com/cardboard/android/latest/reference/com/google/vrtoolkit/cardboard/CardboardView.StereoRenderer):渲染器界面,將所有立體影像渲染細(xì)節(jié)分配到視圖姐刁。 實(shí)現(xiàn)者在渲染視圖時(shí)芥牌,采用的方式應(yīng)與以往一樣(使用提供的變換參數(shù))。 所有的立體影像呈現(xiàn)和失真校正細(xì)節(jié)都是從渲染器提取的聂使,并通過(guò)視圖在內(nèi)部管理壁拉。
###定義 CardboardView
Android 應(yīng)用中的所有用戶(hù)界面元素都是使用視圖構(gòu)建的。 Cardboard SDK for Android 可提供自己的視圖[CardboardView](https://developers.google.com/cardboard/android/latest/reference/com/google/vrtoolkit/cardboard/CardboardView)柏靶,這是[GLSurfaceView](http://developer.android.com/reference/android/opengl/GLSurfaceView.html)的簡(jiǎn)單擴(kuò)展弃理,可用于 VR 呈現(xiàn)。 CardboardView 使內(nèi)容呈現(xiàn)出立體感屎蜓。 您可以查看演示版應(yīng)用如何通過(guò)以下方式將 CardboardView
定義到其 Activity 布局 xml 文件中:
```xml
<com.google.vrtoolkit.cardboard.CardboardView
android:id="@+id/cardboard_view
android:layout_width="fill_parent"
android:layout_height="fill_parent" />```
然后痘昌,它在主 Activity 類(lèi)中初始化 CardboardView(以 onCreate() 方法):
```java
**
* Sets the view to our CardboardView and initializes the transformation matrices we will use
* to render our scene.
* @param savedInstanceState
*/@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.common_ui);
CardboardView cardboardView = (CardboardView) findViewById(R.id.cardboard_view);
// Associate a CardboardView.StereoRenderer with cardboardView.
cardboardView.setRenderer(this);
// Associate the cardboardView with this activity.
setCardboardView(cardboardView);
// Initialize other objects here
....
}```
###呈現(xiàn)視圖
在獲得 CardboardView 后,將其與渲染器關(guān)聯(lián)炬转,然后將 CardboardView 與 Activity 進(jìn)行關(guān)聯(lián)辆苔。 Cardboard 支持兩類(lèi)渲染器,但入門(mén)的最快方式是使用 CardboardView.StereoRenderer扼劈,這是演示版本應(yīng)用使用的內(nèi)容驻啤。
CardboardView.StereoRenderer
包括以下兩個(gè)關(guān)鍵方法:
- [onNewFrame()](https://developers.google.com/cardboard/android/latest/reference/com/google/vrtoolkit/cardboard/CardboardView.StereoRenderer#onNewFrame(com.google.vrtoolkit.cardboard.HeadTransform)),應(yīng)用每次進(jìn)行渲染時(shí)調(diào)用荐吵。
- [onDrawEye()](https://developers.google.com/cardboard/android/latest/reference/com/google/vrtoolkit/cardboard/CardboardView.StereoRenderer#onDrawEye(com.google.vrtoolkit.cardboard.Eye))骑冗,針對(duì)眼睛參數(shù)不同的每只眼睛進(jìn)行調(diào)用赊瞬。
實(shí)現(xiàn)這些的方法與針對(duì) OpenGL 應(yīng)用的普遍做法相似。 將在后面的部分中詳細(xì)闡述這些方法沐旨。
###實(shí)現(xiàn) onNewFrame
在呈現(xiàn)到人眼之前森逮,使用 onNewFrame() 方法對(duì)呈現(xiàn)邏輯進(jìn)行編碼。任何不屬于單個(gè)視圖特有的按幀操作都應(yīng)在此處進(jìn)行磁携。此處非常適合更新您的模型褒侧。在此代碼段中,變量 mHeadView 包含頭部的位置谊迄。 需要保存此值以便日后使用(用于了解用戶(hù)是否正在尋寶):
```java
/**
* Prepares OpenGL ES before we draw a frame.
* @param headTransform The head transformation in the new frame.
*/
@Override
public void onNewFrame(HeadTransform headTransform) {
...
headTransform.getHeadView(mHeadView, 0);
...
}```
###實(shí)現(xiàn) onDrawEye
實(shí)現(xiàn) onDrawEye() 以執(zhí)行每只眼睛的配置闷供。
這是呈現(xiàn)代碼的重要部分,與構(gòu)建常見(jiàn)的 OpenGL ES2 應(yīng)用非常相似统诺。 以下代碼段顯示如何獲取視圖變換矩陣歪脏,也稱(chēng)為透視變換矩陣。 您必須確保低延時(shí)呈現(xiàn)粮呢。 Eye 對(duì)象包含眼睛的變換和投影矩陣婿失。 以下是事件的順序:
- 寶物進(jìn)入眼睛的空間。
- 應(yīng)用投影矩陣啄寡。 這可以提供為指定的眼睛呈現(xiàn)的場(chǎng)景豪硅。
- Cardboard SDK 自動(dòng)應(yīng)用失真,以呈現(xiàn)最終的場(chǎng)景挺物。
```java
/**
* Draws a frame for an eye.
*
* @param eye The eye to render. Includes all required transformations.
*/
@Override
public void onDrawEye(Eye eye) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
...
// Apply the eye transformation to the camera.
Matrix.multiplyMM(mView, 0, eye.getEyeView(), 0, mCamera, 0);
// Set the position of the light
Matrix.multiplyMV(mLightPosInEyeSpace, 0, mView, 0, LIGHT_POS_IN_WORLD_SPACE, 0);
// Build the ModelView and ModelViewProjection matrices
// for calculating cube position and light.
float[] perspective = eye.getPerspective(Z_NEAR, Z_FAR);
Matrix.multiplyMM(mModelView, 0, mView, 0, mModelCube, 0);
Matrix.multiplyMM(mModelViewProjection, 0, perspective, 0, mModelView, 0);
drawCube();
// Draw rest of the scene
...
}```
###處理輸入
Cardboard 觀(guān)片器包含一個(gè)使用磁鐵的按鈕懒浮。 推動(dòng)磁鐵時(shí),磁場(chǎng)會(huì)發(fā)生變化识藤,而手機(jī)的磁力計(jì)可以檢測(cè)到這種變化砚著。 因此,Cardboard SDK 可以為您檢測(cè)到這些磁鐵事件痴昧。
若要提供用戶(hù)拉動(dòng)磁鐵時(shí)的自定義行為稽穆,請(qǐng)?jiān)趹?yīng)用的 Activity 中重寫(xiě)CardboardActivity.onCardboardTrigger()。 在 treasure hunt 應(yīng)用中赶撰,如果您發(fā)現(xiàn)了寶物并拉動(dòng)磁鐵舌镶,您就可以留下寶物:
```java
/**
* Increment the score, hide the object, and give feedback if the user pulls the magnet while
* looking at the object. Otherwise, remind the user what to do.
*/@Override
public void onCardboardTrigger() {
if (isLookingAtObject()) {
mScore++;
mOverlayView.show3DToast("Found it! Look around for another one.\nScore = " + mScore);
...
} else {
mOverlayView.show3DToast("Look around to find the object!");
}
// Always give user feedback
mVibrator.vibrate(50);
}```
##開(kāi)始創(chuàng)建您自己的項(xiàng)目
現(xiàn)在,您對(duì) Cardboard SDK for Android 有了更多的了解扣囊,可以創(chuàng)建您自己的應(yīng)用了乎折。
無(wú)論是從頭開(kāi)始創(chuàng)建一個(gè)新項(xiàng)目還是使用現(xiàn)有項(xiàng)目绒疗,均應(yīng)按照以下步驟操作:
首先侵歇,從示例的 **libs** 文件夾(或 [從此處進(jìn)行下載](https://developers.google.com/cardboard/android/download))采集所有 jar 文件,并將其復(fù)制到項(xiàng)目的 **app/libs** 文件夾吓蘑。
然后惕虑,確保項(xiàng)目的 **app/build.gradle** 文件中存在下列行:
```gradle
dependencies {
...
compile fileTree(dir: 'libs', include: ['*.jar'])
}```
現(xiàn)在坟冲,您可以使用 Cardboard SDK for Android 了!