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

目录
相关文章
|
3月前
|
人工智能 自动驾驶 机器人
吴泳铭:AI最大的想象力不在手机屏幕,而是改变物理世界
过去22个月,AI发展速度超过任何历史时期,但我们依然还处于AGI变革的早期。生成式AI最大的想象力,绝不是在手机屏幕上做一两个新的超级app,而是接管数字世界,改变物理世界。
2899 73
吴泳铭:AI最大的想象力不在手机屏幕,而是改变物理世界
|
3月前
|
图形学 开发者
透视与正交之外的奇妙视界:深入解析Unity游戏开发中的相机与视角控制艺术,探索打造沉浸式玩家体验的奥秘与技巧
【8月更文挑战第31天】在Unity中,相机不仅是玩家观察游戏世界的窗口,更是塑造氛围和引导注意力的关键工具。通过灵活运用相机系统,开发者能大幅提升游戏的艺术表现力和沉浸感。本文将探讨如何实现多种相机控制,包括第三人称跟随和第一人称视角,并提供实用代码示例。
152 0
|
4月前
|
图形学 开发者
【Unity光照艺术手册】掌握这些技巧,让你的游戏场景瞬间提升档次:从基础光源到全局光照,打造24小时不间断的视觉盛宴——如何运用代码与烘焙创造逼真光影效果全解析
【8月更文挑战第31天】在Unity中,合理的光照与阴影设置对于打造逼真环境至关重要。本文介绍Unity支持的多种光源类型,如定向光、点光源、聚光灯等,并通过具体示例展示如何使用着色器和脚本控制光照强度,模拟不同时间段的光照变化。此外,还介绍了动态和静态阴影、全局光照及光照探针等高级功能,帮助开发者创造丰富多样的光影效果,提升游戏沉浸感。
97 0
|
4月前
|
开发者 图形学 Java
Unity物理引擎深度揭秘:从刚体碰撞到软体模拟,全面解析实现复杂物理交互的技巧与秘诀,助你打造超真实游戏体验
【8月更文挑战第31天】物理模拟在游戏开发中至关重要,可让虚拟世界更真实。Unity作为强大的跨平台游戏引擎,内置物理系统,支持从刚体碰撞到布料模拟的多种功能。通过添加Rigidbody组件,可实现物体受力和碰撞;使用AddForce()施加力;通过关节(如Fixed Joint)连接刚体以模拟复杂结构。Unity还支持软体物理,如布料和绳索模拟,进一步增强场景丰富度。掌握这些技术,可大幅提升游戏的真实感和玩家体验。
148 0
|
4月前
|
图形学
小功能⭐️Unity 如何判断物体是否在摄像机视野内或外
小功能⭐️Unity 如何判断物体是否在摄像机视野内或外
|
6月前
全息近眼显示技术如何实现三维图像再现?
【6月更文挑战第26天】全息近眼显示技术如何实现三维图像再现?
51 4
|
6月前
|
图形学
【unity小技巧】unity3d创建和实现破碎打破物品,万物可破碎
【unity小技巧】unity3d创建和实现破碎打破物品,万物可破碎
244 0
【unity小技巧】unity3d创建和实现破碎打破物品,万物可破碎