U3D VR场景中如何瞬移。不用插件的情况下

Hello,我是KitStar

以下文章整理的不对。还请见谅。




一.什么是瞬移功能?

瞬移就是使用手柄选取一个位置,通过扳机键进行瞬间移动。
因为HTC Vive活动范围有限制(3m * 5m),所以我们在实际的使用中,为了更好的浏览场景,查看场景,会使用这种移动的方式,达到游戏中的视野移动。
移动的方式有两种:一种是水平移动即X,Z轴移动;另一种就是垂直移动,即Y轴移动。
PS : 我们通过射线检测的方法进行开发,因为HTC Vive有类似的脚本。所以我们只需更改脚本的某些部分就可实现瞬移功能。

技术难点

想要移动玩家的位置,就需要改变游戏中camera物体的位置。而这个位置是受定位系统控制的。

每帧SteamVR_TrackedObject(一个贴在camera和controller上的组件)都会获取新的玩家所戴的HMD在房间中的位置和朝向,然后将camera与之同步。

所以仅仅设置camera.transform.position是不可以的——下一帧它就会被设置回去。

那如何做到移动玩家位置,并且不打断定位系统对camera的同步?答案是CameraRig。

图中的camera (head)就是位置会和HMD同步的camera,它的代表了玩家在游戏中的位置。

注意,他的父物体是CameraRig,通常情况下它的位置和朝向都是归零的,这种情况下camera (head)的位置=HMD的位置;

而如果改变它的位置,玩家的位置就会在camera (head)的本地位置(local position)没有变,可绝对位置会受影响。

比如把cameraRig的y设置为2,玩家就会感觉在空中两米的位置飘浮着。

所以想要瞬移,只要改变CameraRig的位置和朝向即可。


二.案例详解
1.下载Steam VR,导入资源

Paste_Image.png
2.将脚本复制,修改类名(部分脚本)

Paste_Image.png
using UnityEngine;
using System.Collections;

public class SteamVR_LaserPointer : MonoBehaviour
{
public bool active = true;
public Color color;
public float thickness = 0.002f;
public GameObject holder;
public GameObject pointer;
bool isActive = false;
public bool addRigidBody = false;
public Transform reference;
public event PointerEventHandler PointerIn;
public event PointerEventHandler PointerOut;
public Vector3 HitPoint;


Transform previousContact = null;

// Use this for initialization
void Start ()
{
    holder = new GameObject();
    holder.transform.parent = this.transform;
    holder.transform.localPosition = Vector3.zero;
    holder.transform.localRotation = Quaternion.identity;

    pointer = GameObject.CreatePrimitive(PrimitiveType.Cube);
    pointer.transform.parent = holder.transform;
    pointer.transform.localScale = new Vector3(thickness, thickness, 100f);
    pointer.transform.localPosition = new Vector3(0f, 0f, 50f);
    pointer.transform.localRotation = Quaternion.identity;
    BoxCollider collider = pointer.GetComponent<BoxCollider>();
    if (addRigidBody)
    {
        if (collider)
        {
            collider.isTrigger = true;
        }
        Rigidbody rigidBody = pointer.AddComponent<Rigidbody>();
        rigidBody.isKinematic = true;
    }
    else
    {
        if(collider)
        {
            Object.Destroy(collider);
        }
    }
    Material newMaterial = new Material(Shader.Find("Unlit/Color"));
    newMaterial.SetColor("_Color", color);
    pointer.GetComponent<MeshRenderer>().material = newMaterial;
}

public virtual void OnPointerIn(PointerEventArgs e)
{
    if (PointerIn != null)
        PointerIn(this, e);
}

public virtual void OnPointerOut(PointerEventArgs e)
{
    if (PointerOut != null)
        PointerOut(this, e);
}


// Update is called once per frame
void Update ()
{
    if (!isActive)
    {
        isActive = true;
        this.transform.GetChild(0).gameObject.SetActive(true);
    }

    float dist = 100f;

    SteamVR_TrackedController controller = GetComponent<SteamVR_TrackedController>();

    Ray raycast = new Ray(transform.position, transform.forward);
    RaycastHit hit;
    bool bHit = Physics.Raycast(raycast, out hit);

    if(previousContact && previousContact != hit.transform)
    {
        PointerEventArgs args = new PointerEventArgs();
        if (controller != null)
        {
            args.controllerIndex = controller.controllerIndex;
        }
        args.distance = 0f;
        args.flags = 0;
        args.target = previousContact;
        OnPointerOut(args);
        previousContact = null;
    }
    if(bHit && previousContact != hit.transform)
    {
        PointerEventArgs argsIn = new PointerEventArgs();
        if (controller != null)
        {
            argsIn.controllerIndex = controller.controllerIndex;
        }
        argsIn.distance = hit.distance;
        argsIn.flags = 0;
        argsIn.target = hit.transform;
        OnPointerIn(argsIn);
        previousContact = hit.transform;
    }
    if(!bHit)
    {
        previousContact = null;
    }
    if (bHit)
    {
        HitPoint = hit.point;
    }
    if (bHit && hit.distance < 100f)
    {
        dist = hit.distance;
    }

    if (controller != null && controller.triggerPressed)
    {
        pointer.transform.localScale = new Vector3(thickness * 5f, thickness * 5f, dist);
    }
    else
    {
        pointer.transform.localScale = new Vector3(thickness, thickness, dist);
    }
    pointer.transform.localPosition = new Vector3(0f, 0f, dist/2f);
   }
}


3.添加脚本

Paste_Image.png

Paste_Image.png
4.添加传送脚本
using UnityEngine;
using System.Collections;

public class SteamVR_LaserPointer : MonoBehaviour
{
public bool active = true;
public Color color;
public float thickness = 0.002f;
public GameObject holder;
public GameObject pointer;
bool isActive = false;
public bool addRigidBody = false;
public Transform reference;
public event PointerEventHandler PointerIn;
public event PointerEventHandler PointerOut;
public Vector3 HitPoint;


Transform previousContact = null;

// Use this for initialization
void Start ()
{
    holder = new GameObject();
    holder.transform.parent = this.transform;
    holder.transform.localPosition = Vector3.zero;
    holder.transform.localRotation = Quaternion.identity;

    pointer = GameObject.CreatePrimitive(PrimitiveType.Cube);
    pointer.transform.parent = holder.transform;
    pointer.transform.localScale = new Vector3(thickness, thickness, 100f);
    pointer.transform.localPosition = new Vector3(0f, 0f, 50f);
    pointer.transform.localRotation = Quaternion.identity;
    BoxCollider collider = pointer.GetComponent<BoxCollider>();
    if (addRigidBody)
    {
        if (collider)
        {
            collider.isTrigger = true;
        }
        Rigidbody rigidBody = pointer.AddComponent<Rigidbody>();
        rigidBody.isKinematic = true;
    }
    else
    {
        if(collider)
        {
            Object.Destroy(collider);
        }
    }
    Material newMaterial = new Material(Shader.Find("Unlit/Color"));
    newMaterial.SetColor("_Color", color);
    pointer.GetComponent<MeshRenderer>().material = newMaterial;
}

public virtual void OnPointerIn(PointerEventArgs e)
{
    if (PointerIn != null)
        PointerIn(this, e);
}

public virtual void OnPointerOut(PointerEventArgs e)
{
    if (PointerOut != null)
        PointerOut(this, e);
}


// Update is called once per frame
void Update ()
{
    if (!isActive)
    {
        isActive = true;
        this.transform.GetChild(0).gameObject.SetActive(true);
    }

    float dist = 100f;

    SteamVR_TrackedController controller = GetComponent<SteamVR_TrackedController>();

    Ray raycast = new Ray(transform.position, transform.forward);
    RaycastHit hit;
    bool bHit = Physics.Raycast(raycast, out hit);

    if(previousContact && previousContact != hit.transform)
    {
        PointerEventArgs args = new PointerEventArgs();
        if (controller != null)
        {
            args.controllerIndex = controller.controllerIndex;
        }
        args.distance = 0f;
        args.flags = 0;
        args.target = previousContact;
        OnPointerOut(args);
        previousContact = null;
    }
    if(bHit && previousContact != hit.transform)
    {
        PointerEventArgs argsIn = new PointerEventArgs();
        if (controller != null)
        {
            argsIn.controllerIndex = controller.controllerIndex;
        }
        argsIn.distance = hit.distance;
        argsIn.flags = 0;
        argsIn.target = hit.transform;
        OnPointerIn(argsIn);
        previousContact = hit.transform;
    }
    if(!bHit)
    {
        previousContact = null;
    }
    if (bHit)
    {
        HitPoint = hit.point;
    }
    if (bHit && hit.distance < 100f)
    {
        dist = hit.distance;
    }

    if (controller != null && controller.triggerPressed)
    {
        pointer.transform.localScale = new Vector3(thickness * 5f, thickness * 5f, dist);
    }
    else
    {
        pointer.transform.localScale = new Vector3(thickness, thickness, dist);
    }
    pointer.transform.localPosition = new Vector3(0f, 0f, dist/2f);
   }
}

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值