目录:
       HTC Vive之Unity3d开发日记

You can fool all the people some of the time,and some of the people all the time,but you can`t fool all the people all the time.  __Abraham Lincoln , American president
你可以在某些时间里欺骗所有的人,也可以在所有的时间里欺骗某些人,但你决不能在所有的时间里欺骗所有的人.
先引用俺的偶像之一林肯的一句名言,我们也许暂时不知道事情的真相,但是我们总有一天会知道的!
B格有了!继上一篇,如果你已经把设备和插件准备就绪,这一篇将先对目前的开发资源进一步整理,然后再对SteamVR Plugin进行解析.

这两篇算是一个前期准备工作指南!
这一篇算是一个基础教学!
这一篇算是一个中级教学,我从中学到了不少知识,但是缺乏对代码的深度解析,而这个将是我接下来要做的.当然,我希望阁下可以抽时间对这些资源进行深入的理解,这将有利于我们之后可以一起来探讨!
 
如图,我们要实现的是:通过代码来实现对手柄的全面掌控,重点在于交互,至于如何开发一款VR游戏是在实现交互以后需要探讨的事情,我们一步一个脚印来探索!
 
第一步,如图,我们已经导入了SteamVR Plugin,下面的SteamVR绿色图标表明Htc Vive的硬件也已经准备就绪,这是SteamVR_TestThrow场景,也是我们展开分析的入手点.这个测试很简单,就是你按下Trigger的时候,手柄上会实例化一个圆球+cube的结合体,当然松开Trigger的时候这个结合体就会脱离手柄,当然,你还可以施加一个扔的动作,这样的话结合体会有一个对应的加速度.
 

手柄是HTC Vive的重要交互手段,我们通过第一个图片应该对其有一个直观的了解了,总共是九个按钮:

  • 第一个是菜单按钮;
  • 2,3,4,5分别对应的是Trackpad/Touchpad的上下左右,有时候对应的是XBox手柄的▲OX囗四个按钮或者摇杆;
  • 6对应的是系统按钮/Steam;
  • 7是Trigger/扳机,对应大多数FPS游戏里面的枪械的Shoot/Fire;
  • 8对应的Grip/紧握在手柄的左右两侧各有一个,有时候我们用它来翻页;
  • 9其实是Trackpad/Touchpad在Z轴的一个延伸,相当于是点击事件Click.

接下来就可以直接上代码了!

[C#] 
纯文本查看 
复制代码
?
 
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
using
UnityEngine;
using
System.Collections;
 
[RequireComponent(
typeof
(SteamVR_TrackedObject))]
public
class
SteamVR_TestThrow : MonoBehaviour
{
        
//预设,用于投掷的物体
        
public
GameObject prefab;
        
//位于手柄上的刚体,也就是预设物体出现的地方
        
public
Rigidbody attachPoint;
 
        
//追踪的设备,这里是我们的手柄
        
SteamVR_TrackedObject trackedObj;
        
//固定关节
        
FixedJoint joint;
 
        
void
Awake()
        
{
                
//获取追踪的设备,即手柄
                
trackedObj = GetComponent<SteamVR_TrackedObject>();
        
}
 
        
void
FixedUpdate()
        
{
                
//获取手柄的输入,也就是用户的输入
                
var device = SteamVR_Controller.Input((
int
)trackedObj.index);
                
//如果关节为空 且 用户按下扳机
                
if
(joint ==
null
&& device.GetTouchDown(SteamVR_Controller.ButtonMask.Trigger))
                
{
                        
//把预设实例化并设置其位置在手柄上的指定位置,这个指定位置就是手柄上的那个圈圈
                        
var go = GameObject.Instantiate(prefab);
                        
go.transform.position = attachPoint.transform.position;
 
                        
//把关节组件添加到实例化的对象上,链接的位置就是这个刚体,添加这个组件的目的就是为了当你松开Trigger的时候分开手柄和预设物体
                        
//这个FixedJoint组件实际上就是一个关节,作用是链接两个物体
                        
joint = go.AddComponent<FixedJoint>();
                        
joint.connectedBody = attachPoint;
                
}
                
//又如果关节不为空 且 手柄上的扳机Trigger松开的时候
                
else
if
(joint !=
null
&& device.GetTouchUp(SteamVR_Controller.ButtonMask.Trigger))
                
{
                        
//获取关节上的游戏对象,获取其刚体
                        
var go = joint.gameObject;
                        
var rigidbody = go.GetComponent<Rigidbody>();
                        
//立即摧毁关节,并置为空
                        
Object.DestroyImmediate(joint);
                        
joint =
null
;
                        
//15秒后摧毁该对象
                        
Object.Destroy(go, 15.0f);
 
                        
// We should probably apply the offset between trackedObj.transform.position
                        
// and device.transform.pos to insert into the physics sim at the correct
                        
// location, however, we would then want to predict ahead the visual representation
                        
// by the same amount we are predicting our render poses.
                        
//大概意思是:我们也许应该在正确的位置应用trackedObj.transform.position和device.transform.pos之间的偏移量到物理模拟中去
                        
//然而,如果那样的话我们就想要预测和渲染动作同样数量的视觉位置
 
                        
//原始位置有的话就是原始位置,没有的话取其父类
                        
var origin = trackedObj.origin ? trackedObj.origin : trackedObj.transform.parent;
                        
if
(origin !=
null
)
                        
{
                                
//取其速度和角度
                                
rigidbody.velocity = origin.TransformVector(device.velocity);
                                
rigidbody.angularVelocity = origin.TransformVector(device.angularVelocity);
                        
}
                        
else
                        
{
                                
rigidbody.velocity = device.velocity;
                                
rigidbody.angularVelocity = device.angularVelocity;
                        
}
                        
//最大角速度
                        
rigidbody.maxAngularVelocity = rigidbody.angularVelocity.magnitude;
                
}
        
}
}

Ok,在下已经注释得非常清楚了,重点在于Trigger/扳机的交互:device.GetTouchDown(SteamVR_Controller.ButtonMask.Trigger)按下扳机时返回真和device.GetTouchUp(SteamVR_Controller.ButtonMask.Trigger)松开扳机时返回真.
更进一步,我们通过解析SteamVR_TrackedController来看看其他按钮事件:

[C#] 
纯文本查看 
复制代码
?
 
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
using
UnityEngine;
using
Valve.VR;
 
//结构体,点击事件参数
public
struct
ClickedEventArgs
{
//控制器索引
public
uint
controllerIndex;
//标记
public
uint
flags;
//控制板上的坐标
public
float
padX, padY;
}
 
//委托,点击事件句柄
public
delegate
void
ClickedEventHandler(
object
sender, ClickedEventArgs e);
 
public
class
SteamVR_TrackedController : MonoBehaviour
{
//控制器索引
public
uint
controllerIndex;
//控制器状态
public
VRControllerState_t controllerState;
//按下扳机与否
public
bool
triggerPressed =
false
;
//这个是正面最下方的按钮,对应Steam系统
public
bool
steamPressed =
false
;
//这个是最上方的菜单按钮
public
bool
menuPressed =
false
;
//这个pad控制板是中间的圆形触摸区域,功能比较多
public
bool
padPressed =
false
;
public
bool
padTouched =
false
;
//这个是负责判断是否握住了手柄
public
bool
gripped =
false
;
 
//菜单点击事件句柄
public
event
ClickedEventHandler MenuButtonClicked;
public
event
ClickedEventHandler MenuButtonUnclicked;
//扳机扣动事件句柄
public
event
ClickedEventHandler TriggerClicked;
public
event
ClickedEventHandler TriggerUnclicked;
//Steam点击事件句柄
public
event
ClickedEventHandler SteamClicked;
//触摸板点击事件句柄
public
event
ClickedEventHandler PadClicked;
public
event
ClickedEventHandler PadUnclicked;
//触摸板触摸事件句柄
public
event
ClickedEventHandler PadTouched;
public
event
ClickedEventHandler PadUntouched;
//抓取事件句柄
public
event
ClickedEventHandler Gripped;
public
event
ClickedEventHandler Ungripped;
 
// Use this for initialization
void
Start()
{
//如果没有SteamVR_TrackedObject组件,则添加该组件
if
(
this
.GetComponent<SteamVR_TrackedObject>() ==
null
)
{
gameObject.AddComponent<SteamVR_TrackedObject>();
}
 
//索引赋值
this
.GetComponent<SteamVR_TrackedObject>().index = (SteamVR_TrackedObject.EIndex)controllerIndex;
//如果有SteamVR_RenderModel组件则对该组件索引进行赋值
if
(
this
.GetComponent<SteamVR_RenderModel>() !=
null
)
{
this
.GetComponent<SteamVR_RenderModel>().index = (SteamVR_TrackedObject.EIndex)controllerIndex;
}
}
 
/// <summary>
/// 引发扳机按下事件
/// </summary>
/// <param name="e">E.</param>
public
virtual
void
OnTriggerClicked(ClickedEventArgs e)
{
if
(TriggerClicked !=
null
)
TriggerClicked(
this
, e);
}
 
/// <summary>
/// 引发扳机松开事件
/// </summary>
/// <param name="e">E.</param>
public
virtual
void
OnTriggerUnclicked(ClickedEventArgs e)
{
if
(TriggerUnclicked !=
null
)
TriggerUnclicked(
this
, e);
}
 
/// <summary>
/// 引发菜单点击事件
/// </summary>
/// <param name="e">E.</param>
public
virtual
void
OnMenuClicked(ClickedEventArgs e)
{
if
(MenuButtonClicked !=
null
)
MenuButtonClicked(
this
, e);
}
 
/// <summary>
/// 引发菜单松开事件
/// </summary>
/// <param name="e">E.</param>
public
virtual
void
OnMenuUnclicked(ClickedEventArgs e)
{
if
(MenuButtonUnclicked !=
null
)
MenuButtonUnclicked(
this
, e);
}
 
/// <summary>
/// 引发系统按钮点击事件
/// </summary>
/// <param name="e">E.</param>
public
virtual
void
OnSteamClicked(ClickedEventArgs e)
{
if
(SteamClicked !=
null
)
SteamClicked(
this
, e);
}
 
/// <summary>
/// 引发触摸板点击事件
/// </summary>
/// <param name="e">E.</param>
public
virtual
void
OnPadClicked(ClickedEventArgs e)
{
if
(PadClicked !=
null
)
PadClicked(
this
, e);
}
 
/// <summary>
/// 引发触摸板未点击事件
/// </summary>
/// <param name="e">E.</param>
public
virtual
void
OnPadUnclicked(ClickedEventArgs e)
{
if
(PadUnclicked !=
null
)
PadUnclicked(
this
, e);
}
 
/// <summary>
/// 引发触摸板触摸事件
/// </summary>
/// <param name="e">E.</param>
public
virtual
void
OnPadTouched(ClickedEventArgs e)
{
if
(PadTouched !=
null
)
PadTouched(
this
, e);
}
 
/// <summary>
/// 引发触摸板没有触摸事件
/// </summary>
/// <param name="e">E.</param>
public
virtual
void
OnPadUntouched(ClickedEventArgs e)
{
if
(PadUntouched !=
null
)
PadUntouched(
this
, e);
}
 
/// <summary>
/// 引发握紧事件
/// </summary>
/// <param name="e">E.</param>
public
virtual
void
OnGripped(ClickedEventArgs e)
{
if
(Gripped !=
null
)
Gripped(
this
, e);
}
 
/// <summary>
/// 引发未握紧事件
/// </summary>
/// <param name="e">E.</param>
public
virtual
void
OnUngripped(ClickedEventArgs e)
{
if
(Ungripped !=
null
)
Ungripped(
this
, e);
}
 
// Update is called once per frame
void
Update()
{
//OpenVR是在GitHub上开源的,详情见之前发的资源帖,此处引用
var system = OpenVR.System;
//系统不为空 且 成功获取手柄控制器状态
if
(system !=
null
&& system.GetControllerState(controllerIndex,
ref
controllerState))
{
//手柄状态中的无符号64位整数按钮按下 且 扳机按钮左移一个单位(此处要参考OpenVR)
ulong
trigger = controllerState.ulButtonPressed & (1UL << ((
int
)EVRButtonId.k_EButton_SteamVR_Trigger));
//针对扳机点击事件属性的一系列赋值
if
(trigger > 0L && !triggerPressed)
{
triggerPressed =
true
;
ClickedEventArgs e;
e.controllerIndex = controllerIndex;
e.flags = (
uint
)controllerState.ulButtonPressed;
e.padX = controllerState.rAxis0.x;
e.padY = controllerState.rAxis0.y;
OnTriggerClicked(e);
 
}
else
if
(trigger == 0L && triggerPressed)
{
triggerPressed =
false
;
ClickedEventArgs e;
e.controllerIndex = controllerIndex;
e.flags = (
uint
)controllerState.ulButtonPressed;
e.padX = controllerState.rAxis0.x;
e.padY = controllerState.rAxis0.y;
OnTriggerUnclicked(e);
}
 
//同上,紧握赋值
ulong
grip = controllerState.ulButtonPressed & (1UL << ((
int
)EVRButtonId.k_EButton_Grip));
//同上,针对紧握事件属性的一系列赋值
if
(grip > 0L && !gripped)
{
gripped =
true
;
ClickedEventArgs e;
e.controllerIndex = controllerIndex;
e.flags = (
uint
)controllerState.ulButtonPressed;
e.padX = controllerState.rAxis0.x;
e.padY = controllerState.rAxis0.y;
OnGripped(e);
 
}
else
if
(grip == 0L && gripped)
{
gripped =
false
;
ClickedEventArgs e;
e.controllerIndex = controllerIndex;
e.flags = (
uint
)controllerState.ulButtonPressed;
e.padX = controllerState.rAxis0.x;
e.padY = controllerState.rAxis0.y;
OnUngripped(e);
}
 
//同上,触摸板按下事件赋值
ulong
pad = controllerState.ulButtonPressed & (1UL << ((
int
)EVRButtonId.k_EButton_SteamVR_Touchpad));
if
(pad > 0L && !padPressed)
{
padPressed =
true
;
ClickedEventArgs e;
e.controllerIndex = controllerIndex;
e.flags = (
uint
)controllerState.ulButtonPressed;
e.padX = controllerState.rAxis0.x;
e.padY = controllerState.rAxis0.y;
OnPadClicked(e);
}
else
if
(pad == 0L && padPressed)
{
padPressed =
false
;
ClickedEventArgs e;
e.controllerIndex = controllerIndex;
e.flags = (
uint
)controllerState.ulButtonPressed;
e.padX = controllerState.rAxis0.x;
e.padY = controllerState.rAxis0.y;
OnPadUnclicked(e);
}
 
//同上,菜单赋值
ulong
menu = controllerState.ulButtonPressed & (1UL << ((
int
)EVRButtonId.k_EButton_ApplicationMenu));
if
(menu > 0L && !menuPressed)
{
menuPressed =
true
;
ClickedEventArgs e;
e.controllerIndex = controllerIndex;
e.flags = (
uint
)controllerState.ulButtonPressed;
e.padX = controllerState.rAxis0.x;
e.padY = controllerState.rAxis0.y;
OnMenuClicked(e);
}
else
if
(menu == 0L && menuPressed)
{
menuPressed =
false
;
ClickedEventArgs e;
e.controllerIndex = controllerIndex;
e.flags = (
uint
)controllerState.ulButtonPressed;
e.padX = controllerState.rAxis0.x;
e.padY = controllerState.rAxis0.y;
OnMenuUnclicked(e);
}
 
//触摸板触摸事件赋值
pad = controllerState.ulButtonTouched & (1UL << ((
int
)EVRButtonId.k_EButton_SteamVR_Touchpad));
if
(pad > 0L && !padTouched)
{
padTouched =
true
;
ClickedEventArgs e;
e.controllerIndex = controllerIndex;
e.flags = (
uint
)controllerState.ulButtonPressed;
e.padX = controllerState.rAxis0.x;
e.padY = controllerState.rAxis0.y;
OnPadTouched(e);
 
}
else
if
(pad == 0L && padTouched)
{
padTouched =
false
;
ClickedEventArgs e;
e.controllerIndex = controllerIndex;
e.flags = (
uint
)controllerState.ulButtonPressed;
e.padX = controllerState.rAxis0.x;
e.padY = controllerState.rAxis0.y;
OnPadUntouched(e);
}
}
}
}

SteamVR_TrackedController是基于OpenVR来实现手柄交互的,虽然是开源的,可惜我的水平有限,希望有大神可以讲讲OpenVR,当然,我们理解OpenVR的话当然是最好,如果不知道也是可以实现交互的,我们只需要去调用就可以了.
我这里也没有解析清楚,大家作为涉猎即可,大概知道有这么回事儿,下一篇我们可以继续研究SteamVR_GazeTracker,SteamVR_LaserPointer,SteamVR_Teleporter,敬请期待!
BTW,如果你有HTC Vive的开源程序希望可以分享一个给我,用于研究学习,在此谢谢了先!
其实我最希望Valve能开源The Lab,或者哪位大神有源码!





unity3d fps 游戏源码;unity3d的fps游戏源码

开发
日记 , 
话题

HTC Vive之Unity3d开发日记——手柄交互编程的更多相关文章

  1. HTC VIVE SDK 中的例子 hellovr_opengl 程序流程分析

    最近Vive的VR头盔设备很火,恰逢项目需求,所以对 SDK 中的例子 hellovr_opengl 做了比较细致的代码分析,先将流程图绘制如下,便于大家理解. 在ViVe头盔中实现立体效果的技术核心 ...

  2. HTC Vive开之unity3d开发

    常用的几款插件 Steam VR,  SteamVR Unity Toolkit 配置要求:显卡不低于GTX960性能的主机 一.引入手柄交互 1.通过Asset Store导入SteamVR Plu ...

  3. 用Unity开发HTC VIVE——手柄控制篇

    写这篇文章的原因主要是因为现在虚拟现实非常的火爆但目前主流的虚拟现实设备(HTC VIVE)的教程却少的可怜,这个我深有体会.所以,我想将我平时开发中遇到的问题以及解决方法记录下来,分享给大家,若其中 ...

  4. HTC Vive开发笔记之手柄控制

    怎么安装设备,配置环境我就不说了,自行百度,教程很多也很简单.接下来说下Vive手柄的控制. 手柄是HTC Vive的重要交互手段,我们通过第一个图片应该对其有一个直观的了解了,总共是九个按钮: 第一 ...

  5. Unity的HTC VIVE SDK研究(手柄按键功能的研究,比较详细)

    http://blog.csdn.net/ystistheking/article/details/51553237 想交流的朋友我们可以微博互粉,我的微博黑石铸造厂厂长 ,缺粉丝啊 .....求粉求 ...

  6. HTC vive VR设备软硬件安装+运行unity开发的VR程序

    总结在HTC vive VR开发过程中的HTC vive的安装调试 1.首先确保电脑的配置满足要求: 进入官网,测试电脑是否满足要求 链接:https://www.vive.com/us/produc ...

  7. 如何低成本的打造HTC Vive虚拟演播室直播MR视频?

    http://m.toutiao.com/i6298923859378700802/?tt_from=weixin&utm_campaign=client_share&from=gro ...

  8. Unity 5.4大赞:HTC Vive经典The lab渲染器开源

    HTC Vive提供了一个不错的免费VR demo,最近1周仔细体验了一番. 仔细看了其安装文件,竟然是Unity 5.4beta版本(通过查log,知道Valve公司用的是最新的5.4.0b11版本 ...

  9. 如何透过HTC Vive拍摄Mixed Reality (混合现实)影片

    https://www.vive.com/cn/forum/1706?extra=page%3D1 也许你是一位开发者,想为自己的HTC Vive游戏制作酷炫的宣传片:或者你是游戏主播,想为观众带来高 ...

  10. HTC Vive 基础入门 基于Unreal Engine 4引擎

    主要以讲解介绍HTC Vive设备以及Unreal继承的Steam VR Plugin为主 使用最新的虚幻引擎与Plugin完成VR环境的搭建 然后完成一个基本的VR Games. 任务5: 04-配 ...

随机推荐

  1. OpenCV开发笔记(七十六):相机标定(一):识别棋盘并绘制角点

    前言   知道图像畸变矫映射的原理之后,那么如何得到相机的内参是矫正的第一步,内参决定了内参矩阵(中心点.焦距等),用内参矩阵才能计算出投影矩阵,从而将原本畸变的图像矫正为平面投影图像.  本篇描述了 ...

  2. 补日志log chrome Sources snippet

    补日志log chrome Sources snippet var addWindows =$("#table1").children(); var temp = addWindo ...

  3. 基于python的opus编解码实力解析

    一 opus   pyogg是一个非常不错的库,用这个做音频的编码和解码非常方便.   二 源码解析   import wave from pyogg import OpusEncoder from ...

  4. Nodejs 命令行调用 exec 与 spawn 差异--- 解决 spawn yarn ENOENT error

    Nodejs 命令行调用 exec 与 spawn 差异 比如在前端工程项目中 Nodejs 要调用命令行命令如: yarn electron:build exec 调用 yarn 命令,为了能使命令 ...

  5. Git进阶命令-revert

    有关Git,之前有写过两篇文章: Git五个常见问题及解决方法 Git进阶命令-reset 一.revert命令使用场景 有一天项目经理跟你说,你开发上线的代码有问题,需要马上撤回. 撤回?你第一反应 ...

  6. Windows下写脚本无法运行在linux上?怎麽办?

    Windows下写脚本无法运行在linux上?怎麽办? $'\r': command not found的解决方法 在Linux系统中,运行Shell脚本,出现了如下错误: one-more.sh: ...

  7. 5G+云渲染:如何快速推进XR和元宇宙实现?

    XR(扩展现实)领域正在以惊人的速度增长.目前,到 2024 年,一些专家表示这个行业的价值将达到 3000 亿美元. 这个行业发展如此迅速的部分原因是 XR 将在商业环境中的带来巨大利益.近年来,很 ...

  8. C#调用百度翻译API自动将中文转化为英文

    1.百度翻译开放平台在平台申请你自己的appid,和密钥 2.开通后就在我提供的gitee链接下载代码,直接修改秘钥和appid就能使用如下图所示 3.Gitee链接:链接 4.https://git ...

  9. 记录--三分钟打造自己专属的uni-app工具箱

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 介绍 可曾想过我们每次创建新项目,或者换地方写程序,都要把之前写过的工具类找出来又要复制粘贴一遍有些麻烦,尤其是写uni-app自定义模板 ...

  10. 记录--手把手带你开发一个uni-app日历插件(并发布)

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 相信我们在开发各类小程序或者H5,甚至APP时,会把uni-app作为一个技术选型,其优点在于一键打包多端运行,较为强大的跨平台的性能.但 ...