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

扫一扫,访问微社区

开发者专栏

关注:2103

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

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

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

[alayeshi] HTC vive 手柄转动阀门功能

[复制链接]  [移动端链接]
排名
2559
昨日变化
1

68

主题

289

帖子

1413

积分

Rank: 9Rank: 9Rank: 9

UID
54986
好友
11
蛮牛币
11761
威望
0
注册时间
2014-11-12
在线时间
412 小时
最后登录
2018-2-12

专栏作家

发表于 2018-1-19 10:28:48 | 显示全部楼层 |阅读模式

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

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

x
本帖最后由 alayeshi 于 2018-1-19 10:30 编辑

HTC vive设备结合unity开发手柄转动阀门功能
现在需求是:使用手柄握住一个阀门,进行旋转。
如下图:
fa.gif


所有的交互都是要在两个互动的物体之间做文章,VIVE里也是一样,所有要在手柄和阀门两个方面进行“加工”。

先看手柄需要做哪些“加工”
程序现在都在走“短小快”的路线。所以插件VRTK肯定是很好的选择
在手柄上加上VRTK里的交互必要的脚本,这些脚本插件里都有,如下图(蓝色箭头标记为必须加的脚本)。
在本案例中我使用的是Grab的方式进行转动阀的,所以添加的是VRTK_Interact Grab的脚本。也可以根据需求自己修改。修改方法为在Events脚本里有各种触发方式的进行对应按键的选择。如下图:
12.png


有了这些脚本手柄的交互功能就已经具备了。只剩下被触碰的物体了。

接受触碰的物体需要进行的准备:
因为需要交互所以collider是必不可少的,还有rigidbody,记住不要勾选重力选项。因为这个要配合下面的VRTK_Knob脚本使用。Device_Value是我自己写的传值脚本,此处只讲转动方法不需要添加该脚本。如下图:

32.png


上图中的Clickpress脚本继承了VRTK_InteractableObject脚本,这个脚本也是VRTK插件里的。如果只是单纯实现本案例的转动功能完全可以使用VRTK_InteractableObject脚本。此处要注意转动的原理是采用unity里的铰链的方法,所以在该脚本里有一次选择抓取机制方法的地方要选择Spring_Joint的方法。同样既然是要抓取那肯定要勾选抓取的选项 ,如下图:
66.png



如果要添加其他功能,需要继承该脚本重写某些方法。下面的代码是最常用 的几个方法也是我的脚本Clickpress里用的方法:
55.png


VRTK_Knob脚本是一个用来转动跟随的脚本。
既然转动那可得要选择转动的物体和轴向,如图:
77.png

DIrection就是要转动的轴向,下面的两个参数是转动最大小的限度,step size是转动数值的精确度。

根据需求本案例选择Y轴,如图:
88.png


GO物体就是要被旋转的物体,使用时直接拖动过来就可以。这个GO物体原本脚本是没有的,我把原本的脚本稍稍做了加工。
代码如下:
[C#] 纯文本查看 复制代码
namespace VRTK
{
    using UnityEngine;
    
    public class VRTK_Knob : VRTK_Control
    {


        public GameObject go;

        public enum KnobDirection
        {
            x, y, z // TODO: autodetect not yet done, it's a bit more difficult to get it right
        }
        
        public KnobDirection direction = KnobDirection.x;
        public float min = 0f;
        public float max = 100f;
        public float stepSize = 1f;

        private static float MAX_AUTODETECT_KNOB_WIDTH = 3; // multiple of the knob width

        private KnobDirection finalDirection;
        private Quaternion initialRotation;
        private Vector3 initialLocalRotation;
        private Rigidbody rb;
        private VRTK_InteractableObject io;

        protected override void InitRequiredComponents()
        {
            initialRotation = transform.rotation;
            initialLocalRotation = transform.localRotation.eulerAngles;
            InitRigidBody();
            InitInteractable();
            SetContent(go,false);//cdl
        }

        protected override bool DetectSetup()
        {
            finalDirection = direction;
            SetConstraints(finalDirection);

            return true;
        }

        protected override ControlValueRange RegisterValueRange()
        {
            return new ControlValueRange() { controlMin = min, controlMax = max };
        }

        protected override void HandleUpdate()
        {
          
            value = CalculateValue();
        }

        private void InitRigidBody()
        {
            rb = GetComponent<Rigidbody>();
            if (rb == null)
            {
                rb = gameObject.AddComponent<Rigidbody>();
            }
            rb.isKinematic = false;
            rb.useGravity = false;
            rb.angularDrag = 10; // otherwise knob will continue to move too far on its own
        }

        private void SetConstraints(KnobDirection direction)
        {
            if (!rb) return;

            rb.constraints = RigidbodyConstraints.FreezeAll;
            switch (direction)
            {
                case KnobDirection.x:
                    rb.constraints -= RigidbodyConstraints.FreezeRotationX;
                    break;
                case KnobDirection.y:
                    rb.constraints -= RigidbodyConstraints.FreezeRotationY;
                    break;
                case KnobDirection.z:
                    rb.constraints -= RigidbodyConstraints.FreezeRotationZ;
                    break;
            }
        }

        private void InitInteractable()
        {
            io = GetComponent<VRTK_InteractableObject>();
            if (io == null)
            {
                io = gameObject.AddComponent<VRTK_InteractableObject>();
            }
            io.isGrabbable = true;
            io.precisionSnap = true;
            io.grabAttachMechanic = VRTK_InteractableObject.GrabAttachType.Spring_Joint;
          
        }

        private KnobDirection DetectDirection()
        {
            KnobDirection direction = KnobDirection.x;
            Bounds bounds = Utilities.GetBounds(transform);

            // shoot rays in all directions to learn about surroundings
            RaycastHit hitForward;
            RaycastHit hitBack;
            RaycastHit hitLeft;
            RaycastHit hitRight;
            RaycastHit hitUp;
            RaycastHit hitDown;
            Physics.Raycast(bounds.center, Vector3.forward, out hitForward, bounds.extents.z * MAX_AUTODETECT_KNOB_WIDTH, Physics.DefaultRaycastLayers, QueryTriggerInteraction.UseGlobal);
            Physics.Raycast(bounds.center, Vector3.back, out hitBack, bounds.extents.z * MAX_AUTODETECT_KNOB_WIDTH, Physics.DefaultRaycastLayers, QueryTriggerInteraction.UseGlobal);
            Physics.Raycast(bounds.center, Vector3.left, out hitLeft, bounds.extents.x * MAX_AUTODETECT_KNOB_WIDTH, Physics.DefaultRaycastLayers, QueryTriggerInteraction.UseGlobal);
            Physics.Raycast(bounds.center, Vector3.right, out hitRight, bounds.extents.x * MAX_AUTODETECT_KNOB_WIDTH, Physics.DefaultRaycastLayers, QueryTriggerInteraction.UseGlobal);
            Physics.Raycast(bounds.center, Vector3.up, out hitUp, bounds.extents.y * MAX_AUTODETECT_KNOB_WIDTH, Physics.DefaultRaycastLayers, QueryTriggerInteraction.UseGlobal);
            Physics.Raycast(bounds.center, Vector3.down, out hitDown, bounds.extents.y * MAX_AUTODETECT_KNOB_WIDTH, Physics.DefaultRaycastLayers, QueryTriggerInteraction.UseGlobal);

            // shortest valid ray wins
            float lengthX = (hitRight.collider != null) ? hitRight.distance : float.MaxValue;
            float lengthY = (hitDown.collider != null) ? hitDown.distance : float.MaxValue;
            float lengthZ = (hitBack.collider != null) ? hitBack.distance : float.MaxValue;
            float lengthNegX = (hitLeft.collider != null) ? hitLeft.distance : float.MaxValue;
            float lengthNegY = (hitUp.collider != null) ? hitUp.distance : float.MaxValue;
            float lengthNegZ = (hitForward.collider != null) ? hitForward.distance : float.MaxValue;

            // TODO: not yet the right decision strategy, works only partially
            if (Utilities.IsLowest(lengthX, new float[] { lengthY, lengthZ, lengthNegX, lengthNegY, lengthNegZ }))
            {
                direction = KnobDirection.z;
            }
            else if (Utilities.IsLowest(lengthY, new float[] { lengthX, lengthZ, lengthNegX, lengthNegY, lengthNegZ }))
            {
                direction = KnobDirection.y;
            }
            else if (Utilities.IsLowest(lengthZ, new float[] { lengthX, lengthY, lengthNegX, lengthNegY, lengthNegZ }))
            {
                direction = KnobDirection.x;
            }
            else if (Utilities.IsLowest(lengthNegX, new float[] { lengthX, lengthY, lengthZ, lengthNegY, lengthNegZ }))
            {
                direction = KnobDirection.z;
            }
            else if (Utilities.IsLowest(lengthNegY, new float[] { lengthX, lengthY, lengthZ, lengthNegX, lengthNegZ }))
            {
                direction = KnobDirection.y;
            }
            else if (Utilities.IsLowest(lengthNegZ, new float[] { lengthX, lengthY, lengthZ, lengthNegX, lengthNegY }))
            {
                direction = KnobDirection.x;
            }

            return direction;
        }

        private float CalculateValue()
        {
            float angle = 0;
            switch (finalDirection)
            {
                case KnobDirection.x:
                    angle = transform.localRotation.eulerAngles.x - initialLocalRotation.x;
                    break;
                case KnobDirection.y:
                    angle = transform.localRotation.eulerAngles.y - initialLocalRotation.y;
                    break;
                case KnobDirection.z:
                    angle = transform.localRotation.eulerAngles.z - initialLocalRotation.z;
                    break;
            }
            angle = Mathf.Round(angle * 1000f) / 1000f; // not rounding will produce slight offsets in 4th digit that mess up initial value

            // Quaternion.angle will calculate shortest route and only go to 180
            float value = 0;
            if (angle > 0 && angle <= 180)
            {
                value = 360 - Quaternion.Angle(initialRotation, transform.rotation);
            }
            else
            {
                value = Quaternion.Angle(initialRotation, transform.rotation);
            }

            // adjust to value scale
            value = Mathf.Round((min + Mathf.Clamp01(value / 360f) * (max - min)) / stepSize) * stepSize;
            if (min > max && angle != 0)
            {
                value = (max + min) - value;
            }
           
            return value;
        }
    }
}


这样手柄和被接触物体需要的东西都满足了就实现了该功能。


回复

使用道具 举报

排名
18578
昨日变化
4

0

主题

34

帖子

93

积分

Rank: 2Rank: 2

UID
173004
好友
0
蛮牛币
116
威望
0
注册时间
2016-11-17
在线时间
37 小时
最后登录
2018-2-6
发表于 2018-1-19 10:49:51 | 显示全部楼层
项目刚好遇到,学到了

回复 支持 反对

使用道具 举报

排名
34660
昨日变化
5

0

主题

2

帖子

13

积分

Rank: 1

UID
195320
好友
0
蛮牛币
76
威望
0
注册时间
2016-12-22
在线时间
6 小时
最后登录
2018-1-30
发表于 2018-1-19 10:52:17 | 显示全部楼层
666 get X新技能

回复

使用道具 举报

排名
34660
昨日变化
5

0

主题

2

帖子

13

积分

Rank: 1

UID
195320
好友
0
蛮牛币
76
威望
0
注册时间
2016-12-22
在线时间
6 小时
最后登录
2018-1-30
发表于 2018-1-19 10:54:15 | 显示全部楼层

回复

使用道具 举报

4四处流浪
478/500
排名
4930
昨日变化
23

0

主题

109

帖子

478

积分

Rank: 4

UID
247653
好友
0
蛮牛币
970
威望
0
注册时间
2017-10-9
在线时间
129 小时
最后登录
2018-2-22
发表于 2018-1-19 11:33:20 | 显示全部楼层
谢谢分享

回复

使用道具 举报

4四处流浪
343/500

0

主题

218

帖子

343

积分

Rank: 4

UID
109564
好友
0
蛮牛币
100
威望
0
注册时间
2015-6-20
在线时间
125 小时
最后登录
2018-2-9
发表于 2018-1-19 12:19:03 | 显示全部楼层

谢谢分享
[发帖际遇]: 一个袋子砸在了 azone 头上,azone 赚了 1 蛮牛币. 幸运榜 / 衰神榜

回复

使用道具 举报

7日久生情
1990/5000
排名
1436
昨日变化

10

主题

303

帖子

1990

积分

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

UID
159103
好友
6
蛮牛币
5484
威望
0
注册时间
2016-8-29
在线时间
889 小时
最后登录
2018-2-22

活力之星

发表于 2018-1-19 13:50:23 | 显示全部楼层
谢谢分享  又学到了VR的新应用了

回复 支持 反对

使用道具 举报

7日久生情
1610/5000
排名
4822
昨日变化
46

0

主题

1162

帖子

1610

积分

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

UID
219676
好友
0
蛮牛币
1474
威望
0
注册时间
2017-7-12
在线时间
198 小时
最后登录
2018-2-22
发表于 2018-1-19 15:38:47 | 显示全部楼层
[发帖际遇]: 一个袋子砸在了 夜雨微凉 头上,夜雨微凉 赚了 1 蛮牛币. 幸运榜 / 衰神榜

回复

使用道具 举报

3偶尔光临
159/300
排名
13830
昨日变化
3

2

主题

56

帖子

159

积分

Rank: 3Rank: 3Rank: 3

UID
144233
好友
0
蛮牛币
622
威望
0
注册时间
2016-4-1
在线时间
51 小时
最后登录
2018-2-15
发表于 2018-1-19 16:31:51 | 显示全部楼层
谢谢分享

回复

使用道具 举报

3偶尔光临
163/300
排名
9784
昨日变化
3

0

主题

47

帖子

163

积分

Rank: 3Rank: 3Rank: 3

UID
248343
好友
0
蛮牛币
323
威望
0
注册时间
2017-10-12
在线时间
26 小时
最后登录
2018-2-11
发表于 2018-1-22 09:39:46 | 显示全部楼层
V5V5V5V5V5
[发帖际遇]: Hult 被钱袋砸中进医院,看病花了 2 蛮牛币. 幸运榜 / 衰神榜

回复

使用道具 举报

排名
17970
昨日变化
2

4

主题

12

帖子

77

积分

Rank: 2Rank: 2

UID
201261
好友
0
蛮牛币
1142
威望
0
注册时间
2017-2-15
在线时间
35 小时
最后登录
2018-2-5
发表于 2018-1-22 11:44:30 | 显示全部楼层
学到了学到了

回复

使用道具 举报

4四处流浪
325/500
排名
7981
昨日变化
2

0

主题

55

帖子

325

积分

Rank: 4

UID
44562
好友
0
蛮牛币
11
威望
0
注册时间
2014-9-12
在线时间
144 小时
最后登录
2018-2-5
发表于 2018-1-22 11:51:33 | 显示全部楼层
项目刚好遇到

回复

使用道具 举报

2初来乍到
122/150
排名
11951
昨日变化
2

2

主题

17

帖子

122

积分

Rank: 2Rank: 2

UID
181721
好友
0
蛮牛币
67
威望
0
注册时间
2016-11-7
在线时间
43 小时
最后登录
2018-2-11
QQ
发表于 2018-1-22 15:57:28 | 显示全部楼层
感谢分享,不错不错

回复 支持 反对

使用道具 举报

6蛮牛粉丝
1211/1500
排名
3716
昨日变化

1

主题

596

帖子

1211

积分

Rank: 6Rank: 6Rank: 6

UID
216583
好友
1
蛮牛币
1947
威望
0
注册时间
2017-4-7
在线时间
284 小时
最后登录
2018-2-22
发表于 2018-1-22 17:05:40 | 显示全部楼层
多谢分享

回复

使用道具 举报

6蛮牛粉丝
1058/1500
排名
5784
昨日变化
2

6

主题

638

帖子

1058

积分

Rank: 6Rank: 6Rank: 6

UID
236677
好友
0
蛮牛币
1693
威望
0
注册时间
2017-8-9
在线时间
218 小时
最后登录
2018-2-22
发表于 2018-1-22 17:28:36 | 显示全部楼层
感谢分享

回复

使用道具 举报

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

本版积分规则

关闭

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

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