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也从长城网外的谷歌官网搬运过来了,我还自己翻译了一篇中文版的文档,以上内容都在我博客的分类和专栏中,大家可以自己去翻阅,希望这些内容能帮助到大家~

时间: 2024-08-03 14:02:08

Cardboard虚拟现实开发技巧(一)之放置一个固定在视野中的物体的相关文章

Cardboard虚拟现实开发技巧(二)之保持手机常亮

Google Cardboard 虚拟现实眼镜开发技巧(二)之保持手机常亮 快速解决Android与Ios平台的屏幕常亮问题 大家知道我们使用Google的Cardboard为基础去开发虚拟现实应用,是需要把手机放置在CardBoard中或者是形形色色的各种眼镜盒,如暴风魔镜中,然后戴上眼镜去使用虚拟现实应用,欣赏模型也好,看全景视频也好,玩体感游戏也好,没有人希望在使用过程中被频频的手机自动熄屏所打扰,所以自动熄屏这个问题是开发AR和VR应用必须解决的一个问题. 以安卓为例,很多同学可能会去用

Lotus开发技巧与讨论帖汇总...讨论正在进行中

问题描述 LotusGateway社区网站也是一个不可多得的学习资源集中地去看看>>www.lotus-gateway.com/forumLotusScript程序开发经验总结http://www.lotus-gateway.com/forum/topic?f=2&t=288关于如何优化LotusScript程序http://www.lotus-gateway.com/forum/topic?f=2&t=282LotusScript基本语法知识(一)http://www.lot

关于Gradle的日常开发技巧的总结

本文讲的是关于Gradle的日常开发技巧的总结,Gradle是Android Studio中默认的构建系统.Gradle 采用了 Groovy 语言作为主要的脚本语言.我们app项目的 build.gradle 和APP Moudle里的build.gradle文件,就是一个 Groovy 类.接下来让我就介绍下Gradle的基本功能和高级技巧. 基本用法 apply plugin: 'com.android.application'    android {      compileSdkVe

《Unity虚拟现实开发实战》——第3章,第3.4节为Google Cardboard构建项目

3.4为Google Cardboard构建项目 如果你的Google Cardboard的目标平台是Android或iOS,请阅读本节. <适用于Unity的Google Cardboard入门指南>是一个很好的切入点. 3.4.1配置Android环境 如果你从来没在Android环境上开发过,那么需要先下载和安装Android SDK.看一下Unity手册中关于Android SDK安装的文章,还需要安装Android Developer Studio(或至少要安装SDK工具包)和其他相

《Unity虚拟现实开发实战》——第1章,第1.7节VR必备技能

1.7 VR必备技能 本书每章都介绍了一些对于构建属于自己的虚拟现实应用非常重要的新技巧和概念.你可以在本书中学习到以下内容: 空间缩放比例:当构建一个VR体验时,重视3D空间和缩放是很重要的.Unity的1个单位通常等于虚拟世界中的1m. 第一人称控制:有很多种技术可以用来控制你的虚拟角色(第一人称摄像机)的移动,基于凝视的选择器.游戏控制器和头部移动. UI控件:不同于传统的视频游戏(和手机游戏),所有的UI组件都处于VR中的世界坐标系中,而不是屏幕坐标系.我们将探讨如何向用户显示提醒.按钮

企业Java技术开发技巧2则

技巧 欢迎阅读本期的 Enterprise Java Technologies Tech Tips.下面你将获得使用企业 Java 技术和 API 的技巧,如 Java 2 Platform 和 Enterprise Edition (J2EE) 中的 Java 技术和技巧. 本文讨论: 自定义标记文件 和 JSP Pages 一同使用 Enterprise Beans 这些技巧是使用 Java 2, Enterprise Edition, v 1.4 SDK 开发的.您可以下载 SDK,网址为

Struts开发技巧

技巧 Struts开发技巧在经历了<中国电信大客户贴心服务>项目的开发以及目前正在进行开发中的<中国电信总部经营分析>项目,累计了一些对于Struts1.1和Tiles开发的一些技术和技巧,特写出来,方便以后的开发,同时也相信能给读者在开发Struts提供一些帮助模块配置1. Struts配置文件定义对于系统中的某个模块,需要在开发前定义该模块的配置,该struts的配置文件命名为:struts-config-xxx.xml xxx为模块的小写英文名或缩写,如:struts-con

asp.net控件开发技巧(2)关闭基类不必要的功能

1.关闭容器 Control类有Controls集合属性,即继承Control类的控件都是一个容器控件,asp.net控件内置的有PlaceHolder控件,其只继承自Control类,什么也没做.但所有控件都是继承自Control类的.如一个label控件,照样可以当容器使用. label1.Controls.add(control) 有些控件则不需要这个功能,如Literal控件,只输出纯文字,不允许添加子控件 开发技巧(2)关闭基类不必要的功能-"> 很简单,重写CreateCont

60个很实用的jQuery代码开发技巧收集_jquery

由于内容比较多建议用CTRL+F搜索 偶然在网上看到这些不错的jQuery代码开发技巧.原文收集了30个,另外查找的时候发现了还有20个.加上另外十个实用的jQuery代码片段,共60个代码技巧,收集在一起分享给大家. 1. 创建一个嵌套的过滤器 .filter(":not(:has(.selected))") //去掉所有不包含class为.selected的元素 2. 重用你的元素查询 var allItems = $("div.item"); var keep