开启辅助访问
 找回密码
 注册帐号

扫一扫,访问微社区

开发者专栏

关注:1969

当前位置:游戏蛮牛 技术专区 开发者专栏

__________________________________________________________________________________
开发者干货区版块规则:

  1、文章必须是图文形式。(至少2幅图)
      2、文章字数必须保持在1500字节以上。(编辑器右下角有字数检查)
      3、本版块只支持在游戏蛮牛原创首发,不支持转载。
      4、本版块回复不得无意义,如:顶、呵呵、不错......【真的会扣分的哦】
      5、......
__________________________________________________________________________________
查看: 3854|回复: 9

[决晴谷] SteamVR:Easy Vive(二)抛物线移动

[复制链接]  [移动端链接]
排名
13207
昨日变化
9

12

主题

51

帖子

747

积分

Rank: 9Rank: 9Rank: 9

UID
130021
好友
14
蛮牛币
418
威望
0
注册时间
2015-11-26
在线时间
162 小时
最后登录
2017-11-17

专栏作家

QQ
发表于 2016-8-4 01:11:49 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?注册帐号

x
SteamVR 抛物线移动
其实实现抛物线很简单,生成一组抛物点,然后将点渲染成线就好。渲染成线有很多方式,你可以用模型,也可以用GL的绘制线段,也可以用LineRender。重点是优化点的生成计算。
楼主上班比较忙,很少写demo。我做项目一般有严密的框架,但是为了更加简明的为大家展示功能的实现剔除了很多代码,并且写了不符合我风格的代码,就是为了让大家能看清楚功能的实现。
我不是个人开发者,家中无测试环境,如果有问题可以在下面回复。本教程中的代码已经用在实际的案例上,因为工作保密我不能截图或者共享项目源码,只是把开发过程的部分代码功能以个人的名义分享,欢迎交流。
如何生成抛物点,一个很简单的公式:
nextPos = lastPos + 水平位移 + 垂直位移。
u=2806003114,2502992636&fm=21&gp=0.jpg
稍后的代码有详尽的注释我就不多赘述了。
重点是对点集的优化,优化抛物点分两个部分,一是如何计算碰撞点,二是内存开销的优化。考虑到一般的VR项目只在水平面上进行移动,所以通过判断抛物点的y轴来判定碰撞。关于内存开销,我们可以限定生成的抛物点个数,同时优化计算。我们使用一个List来保存点集,动态的根据点的情况来生成点,或者改变点的位置。例如当手柄角度不变时,只需要将List集合中的点改变Y轴就行了。
现在思路已经明了了。以下是伪代码:
int i = 0;
while( nextPos.y>0 && maxPoint>0 ){
if(list.count<=i){
list.add(nextPos);
}
else{
list = nextPos;
}
///生成,优化,计算下一个抛物点
i++;
}
list.remove(i,list.count-i);//移除上一个点集的多余数据
生成抛物线点集后,接下来就是绘制曲线,LineRenderGL都可以很方便的绘制。但是就性能来说,GL更加快一点。建议大家用GL。当然大家也可以使用自己的模型绘制,原理就是,在对应的点生成你的模型,然后计算对应的角度即可。这几种实现方案我都会写到代码中,效果大家自己调用查看。
最后就是生成抛物线的终点,因为我是按照y轴来判断抛物线的落点,但是落点可能有障碍物等等,或者落点在墙角,这些位置显然是不能跳跃的,所以我们需要对落点进行判断。在Physics中有一个方法可以检测一个球形范围是否会碰撞,我们可以给地面添加一个层,以便忽略地面的检测,这样就可以安全的着陆了。
好了,也许你没听懂,没关系,接下来就是代码,代码中也有详尽的注释。

[C#] 纯文本查看 复制代码
using UnityEngine;
using System.Collections.Generic;
using System;

/// <summary>
/// 抛物线脚本
/// </summary>
public class HandRay : MonoBehaviour
{

    private Transform CurrentHand; //当前触发的手
    private List<Vector3> pointList; //曲线点集合
    private Quaternion lastRotation; //上一个移动的角度
    private Vector3 lastPostion; //上一个位置
    private Vector3 lastPos; //上一个点,为了优化将一个临时变量做成全局的,节省内存开销
    private Vector3 nextPos;//下一个点,理由同上
    private event Action OnChangeTransform;//一个事件,用来检测手柄位置和角度变化的
    private Material material;//渲染射线的材质球
    private Vector3 HitPoint;//抛物线的碰撞点
    private Ray ray;
    private bool canJump = false;//

    public GameObject PointEffect;//一个特效,就是在射线的终点放置一个光柱什么的,大家可以自己做这个特效

    public int MaxPoint;  //生成曲线的点最大数量
    public float Distence;//水平位移
    public float Grity;//垂直位移
    public float CheckRange;//检测位置是否存在障碍物

    public void Awake()
    {
        SetData();
    }

    public void Start()
    {
        pointList = new List<Vector3>();
        OnChangeTransform += OnChangeTransformCallBack;
        HitPoint = -Vector3.one;
        ray = new Ray();


    }
    public void Update()
    {
        //当手柄按下触摸键同时角度合适时触发事件开始计算点
        if (CurrentHand != null && ((CurrentHand.eulerAngles.x > 275 && CurrentHand.eulerAngles.x <= 360) || (CurrentHand.eulerAngles.x >= -0.01f && CurrentHand.eulerAngles.x < 85)))
        {
            if (OnChangeTransform != null) OnChangeTransform();
        }
        else
        {
            pointList.Clear();
            PointEffect.SetActive(false);
        }
    }
    /// <summary>
    /// 计算抛物线的点
    /// 此方法已经优化过性能
    /// 
    /// </summary>
    private void OnChangeTransformCallBack()
    {
        if (lastRotation != CurrentHand.rotation || lastPostion != CurrentHand.position)
        {
            lastPos = nextPos = CurrentHand.position;
            int i = 0;
            while (nextPos.y > 0 && (i < MaxPoint))
            {
                if (pointList.Count <= i)
                {
                    pointList.Add(nextPos);
                }
                else
                {
                    pointList[i] = nextPos;
                }
                if (lastRotation == CurrentHand.rotation && lastPostion != CurrentHand.position && i < pointList.Count - 1)
                {
                    nextPos = pointList[i + 1] + CurrentHand.position - lastPostion;
                }
                else
                {
                    nextPos = lastPos + CurrentHand.rotation * Vector3.forward * Distence + Vector3.up * Grity * 0.1f * i * Time.fixedDeltaTime;
                }
                lastPos = nextPos;
                i++;
            }
            if (pointList.Count > i)
            {
                pointList.RemoveRange(i, pointList.Count - i);
            }
            lastRotation = CurrentHand.rotation;
            lastPostion = CurrentHand.position;
            if (pointList.Count > 1)
            {
                HitPoint = pointList[pointList.Count - 1];
                PointEffect.SetActive(true);
                PointEffect.transform.position = HitPoint;
            }
            else
            {
                HitPoint = -Vector3.one;
                PointEffect.SetActive(false);
            }
        }
    }

    public void Enable()
    {
        SteamVR_InitManager.Instance.OnLeftDeviceActive += OnHandActive;
        SteamVR_InitManager.Instance.OnRightDeviceActive += OnHandActive;
        OnChangeTransform += OnChangeTransformCallBack;
    }
    public void OnHandActive(SteamVR_TrackedObject obj)
    {
        DeviceInput device = obj.GetComponent<DeviceInput>();
        device.OnPressDownPadV3 += OnPressDownPad;
        device.OnPressUpPad += OnPressUpPadAction;
    }

    public void OnHandDis(SteamVR_TrackedObject obj)
    {
        if (obj && obj.gameObject.activeSelf)
        {
            DeviceInput device = obj.GetComponent<DeviceInput>();
            device.OnPressDownPadV3 -= OnPressDownPad;
            device.OnPressUpPad -= OnPressUpPadAction;
        }
    }

    public void Disable()
    {
        SteamVR_InitManager.Instance.OnLeftDeviceActive -= OnHandActive;
        SteamVR_InitManager.Instance.OnRightDeviceActive -= OnHandActive;
        OnHandDis(SteamVR_InitManager.Instance.LeftObject);
        OnHandDis(SteamVR_InitManager.Instance.LeftObject);
        OnChangeTransform -= OnChangeTransformCallBack;
    }

    public void SetData()
    {
        if (PointEffect)
            PointEffect.SetActive(false);
    }

    /// <summary>
    /// 抬起触摸板时,计算落脚点
    /// </summary>
    private void OnPressUpPadAction()
    {
        if (CurrentHand == null) return;
        canJump = true;
        ray.origin = CurrentHand.position;
        Vector3 dir = HitPoint - CurrentHand.position;
        ray.direction = dir;
        if (Physics.CheckSphere(HitPoint, CheckRange, ~(1 << 8)))
        {
            canJump = false;
        }
        if (canJump)
        {
            JumpPoint(HitPoint);
        }
        CurrentHand = null;
    }
    /// <summary>
    /// 跳到指定的点
    /// </summary>
    /// <param name="point"></param>
    public void JumpPoint(Vector3 point)
    {
        point.y = transform.position.y;
        transform.position = point;
    }

    private void OnPressDownPad(Transform parent)
    {

        CurrentHand = parent;

    }

    /// <summary>
    /// 使用GL来绘制曲线
    /// 将点绘制出来
    /// </summary>
    void OnRenderObject()
    {
        material.SetPass(0);
        if (pointList == null) return;
        GL.Begin(GL.LINES);
        for (int i = 0; i < pointList.Count; i++)
        {
            GL.Vertex(pointList[i]);
        }
        GL.End();
    }

    /// <summary>
    /// 一个额外的附加方法,即用一个曲线来绘制抛物线,性能较低,因为点数比较多
    /// 感兴趣的可以把此方法添加到Update中更新
    /// </summary>

    public void ShowLineByRender()
    {

        LineRenderer line = GetComponent<LineRenderer>();
        if (line)
        {
            line.SetVertexCount(pointList.Count);
            for (int i = 0; i < pointList.Count; i++)
            {
                line.SetPosition(i, pointList[i]);
            }
        }
    }
}
下一章主要接受手柄和物体的交互事件代码,通过事件系统把射线和触碰进行封装的一个架构也是Htc Vive开发的最后一章。基本上
Vive开发相关的东西也就是这些了,其他的只要按照正常的逻辑去写,然后通过监听对应的手柄事件来调用你的代码就好,不再为外部
设备问题而烦恼。
对了,没图好像不让发……容我偷几张图。
RW[EC%L07P5Y11WS~B%H7.png




评分

参与人数 1蛮牛币 +5 收起 理由
崇慕 + 5 很给力!

查看全部评分


回复

使用道具 举报

5熟悉之中
634/1000
排名
4097
昨日变化
3

4

主题

139

帖子

634

积分

Rank: 5Rank: 5

UID
75135
好友
1
蛮牛币
357
威望
0
注册时间
2015-2-17
在线时间
213 小时
最后登录
2017-10-25
发表于 2016-8-4 09:32:00 | 显示全部楼层
写的很详细  期待跟新

回复 支持 反对

使用道具 举报

5熟悉之中
523/1000
排名
4263
昨日变化
27

0

主题

70

帖子

523

积分

Rank: 5Rank: 5

UID
88366
好友
1
蛮牛币
1400
威望
0
注册时间
2015-4-1
在线时间
187 小时
最后登录
2017-11-21
发表于 2016-8-4 09:38:34 | 显示全部楼层
学习学习

回复

使用道具 举报

4四处流浪
371/500
排名
6334
昨日变化
6

7

主题

69

帖子

371

积分

Rank: 4

UID
146196
好友
1
蛮牛币
1029
威望
0
注册时间
2016-4-20
在线时间
133 小时
最后登录
2016-12-12
发表于 2016-8-4 09:46:11 | 显示全部楼层
写的很详细  期待跟新

回复 支持 反对

使用道具 举报

头像被屏蔽
排名
28853
昨日变化
7

2

主题

22

帖子

45

积分

UID
132130
好友
0
蛮牛币
101
威望
0
注册时间
2015-12-20
在线时间
9 小时
最后登录
2017-1-23
QQ
发表于 2016-8-4 09:53:25 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽

回复 支持 反对

使用道具 举报

6蛮牛粉丝
1326/1500
排名
1596
昨日变化
4

6

主题

121

帖子

1326

积分

Rank: 6Rank: 6Rank: 6

UID
144553
好友
4
蛮牛币
4259
威望
0
注册时间
2016-4-5
在线时间
535 小时
最后登录
2017-11-22

活力之星

发表于 2016-8-4 12:52:04 | 显示全部楼层

写的很详细  期待跟新

回复 支持 反对

使用道具 举报

7日久生情
2439/5000
排名
594
昨日变化
1

6

主题

318

帖子

2439

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
137142
好友
2
蛮牛币
9598
威望
0
注册时间
2016-2-21
在线时间
945 小时
最后登录
2017-11-21
发表于 2016-8-4 13:52:59 | 显示全部楼层
没想到这一篇这么快就出来了  赞  期待后面更新

回复 支持 反对

使用道具 举报

匿名  发表于 2016-8-15 19:31:40
第83行, delte_y = Vector3.up * Grity * 0.1f * i * Time.fixedDeltaTime;是怎么推算出来的啊?实在看不懂,求高手教育!!

回复 支持 反对

使用道具

3偶尔光临
239/300
排名
7756
昨日变化
3

0

主题

35

帖子

239

积分

Rank: 3Rank: 3Rank: 3

UID
152452
好友
2
蛮牛币
162
威望
0
注册时间
2016-6-17
在线时间
84 小时
最后登录
2017-10-31
QQ
发表于 2016-11-17 11:16:37 | 显示全部楼层
请问,DeviceInput这个类是什么

回复 支持 反对

使用道具 举报

4四处流浪
324/500
排名
9953
昨日变化
5

0

主题

166

帖子

324

积分

Rank: 4

UID
180321
好友
3
蛮牛币
398
威望
0
注册时间
2016-11-21
在线时间
80 小时
最后登录
2017-9-19
发表于 2017-3-7 16:42:10 | 显示全部楼层
插件也很方便啊

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册帐号

本版积分规则

关闭

站长推荐 上一条 /1 下一条

快速回复 返回顶部 返回列表