Cardboard虛擬現實開發技巧(一)之放置一個固定在視野中的物體

Google Cardboard 虛擬現實眼鏡開發技巧(一)之放置一個固定在視野中的物體

利用CardboardMain下的Head輕鬆放置一個固定在視野中的物體

大家知道在遊戲開發中,我們經常會需要放置一些操作面板啊,血量槽啊,比如CS中的槍械,子彈,血量等等,這些UI因素是應該永遠顯示在用戶視野當中的,而不是一轉頭就看不到自己的血量了。

這個問題在傳統的Unity遊戲開發中自然是小菜一碟,但是在虛擬現實應用裏就不一樣了,我們的手機屏幕被分成了兩部分,所以這些UI也應該是相應的分離顯示,而如果在開發中使用傳統的解決方案自然是不可以了,因爲只會在屏幕上層顯示一個UI,這顯然在虛擬現實眼睛裏就沒法看了。而且根據我的嘗試和對API的閱讀,CardBoard好像甚至禁止了GUI等UI的顯示,而提供了一個CardBoard專用的UI接口,至於這個所謂的CardBoard GUI我並沒有嘗試過,因爲我們直接去讓某個組件一直相對於視野不變就可以了,這樣的可擴展性更強,而且最關鍵的是非常簡單,一會下面就會爲大家介紹具體的做法。

另外去實現一個固定在視野中的物體的應用可不是僅僅侷限於UI的,虛擬現實中的注視點(之前提到的那個小黃點)就是一個永遠在視野中央的物體,再比如我之前的項目裏是開發了一個基於虛擬現實的無人機駕駛,用戶是坐在虛擬機艙裏進行操作的,虛擬機艙是一個模型場景,視角是要隨着用戶轉頭而改變的,比如用戶低頭會看到操縱桿,回頭會看到自己的座椅背,但是窗外的景象是無人機實時傳回的視頻,因此需要一個不隨視角變動的視頻播放器,顯然用代碼讓視頻播放器隨着視角動是非常麻煩的,需要考慮相位和旋轉,而利用這個方法就很輕鬆的解決了這個問題。

CardboardMain下的Head組件的理解

這裏寫圖片描述

大家看到CardboardMain,其下層爲Head,我們去看Head的Inspector面板:

這裏寫圖片描述

我們看到Head綁定了一個CardboardHead的腳本,這個腳本是Cardboard Unity SDK所提供的一個腳本,在API中CardboardHead.cs的描述部分的第一句是這樣敘述的:將此腳本附加到任何與用戶頭部運動相匹配的遊戲對象上。也就是說Head模擬了現實中用戶的頭,Head下的部分都是頭的一部分,所以也就不難理解Head下的Main Camera與GazePointer了。

Main Camera其實就是用戶的雙眼,下屬的Main Camera Left 和 Main Camera Right就是用戶的左眼和右眼,雙眼毫無疑問是頭部的一部分,所以Main Camera作爲Head的下屬,也就是頭的一部分。也因此模擬雙眼的兩個自攝像頭是隨着頭部運動而運動的,所以我們在轉動頭部的時候才具有不同的視角。

GazePointer其實就是之前提到多次的注視點的實體,將這個注視點作爲頭部的一部分可以這樣理解,如果想象一個戴着摩托車頭盔的人,就可以理解爲這個光標是頭盔前擋風玻璃上的一個點,無論這個人把頭轉向哪,這個點總是在他的視野中央。

所以如果我們需要去放置一個固定在視野中的物體,遵循GazePoint的想法,我們就應該把這個物體放在人的頭盔前玻璃上,所以我們只需要把物體放在Head下並且調整好位置和角度就可以讓這個物體成爲人頭部的一部分隨頭部運動而運動了。也就是實現了本篇所說的放置一個固定在視野中的物體,比如一些血槽之類UI。

Demo:放置一個顯示幀數的UI

現在理解了原理,下面我會基於官方的Demo去實現一個很簡單的UI,具體功能就是能夠在視野中的固定位置顯示目前的幀數。

所以先在Head下放置一個能顯示Text的組件,我是用的Demo中顯示腳下按鈕的方式,在Head下新建了一個Canvas(GameObjects - UI - Canvas),RenderMode選擇World Space。canvas下是一個Panel(GameObjects - UI - Panel),Panel下是一個Text(GameObjects - UI - Text),並且給這個Text組件加了一個TextView1的Tag,方便在腳本中使用,具體結構和組件屬性參考下圖:

這裏寫圖片描述

將UI(紅框部分)放在Head下

這裏寫圖片描述

Canvas組件,不要忘記設置World Space,不然不能調大小

這裏寫圖片描述

Panel組件

這裏寫圖片描述

Text組件,這裏設置了一個TextView1的Tag

這裏寫圖片描述

將UI放置在攝像頭正前方

代碼方面相對於Cardboard虛擬現實開發初步(四)中講解的Demo代碼修改很少,就是在Teleport.cs中通過Tag獲取到Text組件並且在update()方法中設置文字爲幀速(這裏我爲了簡單用的是1/Time.deltaTime.嚴格講這不是精確的fps)

代碼:

// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using UnityEngine;
using System.Collections;

[RequireComponent(typeof(Collider))]

/*
 * 瞬移類 cube的腳本代碼
 */
public class Teleport : MonoBehaviour
{

    //定義開始的位置向量
    private Vector3 startingPosition;

    /**
     * UI TextView
     */
    public UnityEngine.UI.Text textView;

    /*
     * start()方法
     * 如果腳本實例是enabled的,則Start函數在第一幀更新之前被調用,在腳本實例生命週期中僅被調用一次
     */
    void Start()
    {

        //獲得當前位置
        startingPosition = transform.localPosition;

        //關閉線
        Cardboard.SDK.EnableAlignmentMarker = true;

        //關閉設置
        Cardboard.SDK.EnableSettingsButton = true;

        Cardboard.SDK.NeckModelScale = 1f;

        //初始化注視狀態爲false
        SetGazedAt(false);

        //初始化TextView
        textView = GameObject.FindGameObjectWithTag("TextView1").GetComponent<UnityEngine.UI.Text>();

    }

    /**
     * 假如MonoBehaviour是enabled時,該函數每幀被調用一次,是最主要最常用的幀更新函數
     */
    void Update()
    {
        //顯示FPS(近似)
        textView.text = "FPS:" + 1/Time.deltaTime;

    }


    /*
     * SetGazedAt(bool gazedAt)方法
     * 根據是否凝視方塊改變方塊的顏色
     */
    public void SetGazedAt(bool gazedAt)
    {
        GetComponent<Renderer>().material.color = gazedAt ? Color.green : Color.red;
    }

    /*
     * Reset()方法
     * 將方塊位置設置爲初始位置
     * 由ButtonCanvas -> Panel -> ResetButton調用
     */
    public void Reset()
    {
        transform.localPosition = startingPosition;
    }

    /*
     * ToggleVRMode()方法
     * 切換VR模式
     * 由ButtonCanvas -> Panel -> VRModeButton調用
     */
    public void ToggleVRMode()
    {

        //打開關閉VR模式
        Cardboard.SDK.VRModeEnabled = !Cardboard.SDK.VRModeEnabled;

    }

    /*
     * TeleportRandomly()方法
     * 將方塊位置設置爲隨機位置
     * 由Cardboard.SDK.Triggered && isLookedAt調用
     */
    public void TeleportRandomly()
    {

        //返回半徑爲1的球體在表面上的一個隨機點
        Vector3 direction = Random.onUnitSphere;

        //static function Clamp (value : float, min : float, max : float) : float
        //限制value的值在min和max之間, 如果value小於min,返回min。 如果value大於max,返回max,否則返回value
        direction.y = Mathf.Clamp(direction.y, 0.5f, 1f);

        // Random.value 返回一個隨機數,在0.0(包括)~1.0(包括)之間
        // 返回1.5 ~ 3.5 之間的隨機數
        float distance = 2 * Random.value + 1.5f;

        // 位置爲半徑爲1.5~3.5的球面上的隨機點
        transform.localPosition = direction * distance;

    }

}

然後運行就可以看到最終效果了:

這裏寫圖片描述

這裏寫圖片描述

這裏寫圖片描述

我們可以看到無論怎麼樣移動視角或者歪頭,UI總是顯示在視野的固定位置

結語

作爲虛擬現實眼鏡開發技巧這個系列的第一篇教程,本篇通過一個小Demo講解了如何去設置一個位置相對於視野不發生變換的物體。虛擬現實眼鏡開發技巧這個系列的初衷是想能給大家帶來實質性的幫助,因爲不可能講到面面俱到,所以摘出一些大家都會遇到的問題來敘述。

關於CardBoard虛擬現實眼鏡開發的知識,之前已經我已經寫了虛擬現實開發初步系列的1-4篇來幫助大家入門,英文的API也從長城網外的谷歌官網搬運過來了,我還自己翻譯了一篇中文版的文檔,以上內容都在我博客的分類和專欄中,大家可以自己去翻閱,希望這些內容能幫助到大家~

發佈了87 篇原創文章 · 獲贊 204 · 訪問量 76萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章