目录:
       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. 专访容智信息柴亚团:最低调的公司如何炼成最易用的RPA?

    专访容智信息柴亚团:最低调的公司如何炼成最易用的RPA? 专访容智信息柴亚团:终极愿景是助力天下企业成为数字化孪生组织 文/王吉伟 6月,容智信息(容智)正式发布了全新的移动端RPA产品iBot Mo ...

  2. GitHUb上渗透测试工具

    来自GitHub的系列渗透测试工具渗透测试 Kali - GNU / Linux发行版,专为数字取证和渗透测试而设计.(https://www.kali.org/)ArchStrike - 为安全专业 ...

  3. Mysql查询数据量大小

    --按实例 SELECT CONCAT(round(sum(DATA_LENGTH/1024/1024/1024),2),"GB") as datazise FROM inform ...

  4. dbvisualizer之编辑区中文乱码问题

    !在SQL Commander中,sql语句中如果有中文,显示是'口口口'. 解决办法如下: 在Tools->tool Properties->General->Appearance ...

  5. 计算机网络-DNS以及FastGitHub

    前言 你是否观察到过这种现象,在访问Github时,有的时候能正常访问,有的时候再次刷新就访问不了,那么能不能有什么办法能一直访问.答案是有,就是在DNS层面能保证一直稳定获取可用并且快速的IP,这就 ...

  6. 03.Android崩溃Crash库之ExceptionHandler分析

    目录总结 00.异常处理几个常用api 01.UncaughtExceptionHandler 02.Java线程处理异常分析 03.Android中线程处理异常分析 04.为何使用setDefaul ...

  7. 三维模型3DTILE格式轻量化压缩主要技术方法浅析

    三维模型3DTILE格式轻量化压缩主要技术方法浅析 三维模型3DTILE格式轻量化压缩主要技术方法浅析 随着三维地理空间数据的应用日益广泛,为了更快速地传输和存储这些大规模数据,3DTile格式的轻量 ...

  8. 用免费GPU部署自己的stable-diffusion项目(AI生成图片)

    2021年时出现了 openAI 的 DALL,但是不开源.2022年一开年,DALL-E 2发布,依然不开源.同年7月,Google 公布其 Text-to-Image 模型 Imagen,并且几乎 ...

  9. 【教程】深入探究 JS代码混淆与加密技术

    引言 在网络世界中,保护代码安全是至关重要的一环.JS代码混淆与加密技术则成为了开发者们常用的手段之一.本文将深入探讨混淆和加密的概念,以及其实现原理和应用方法,帮助读者更好地了解并运用这些技术. 概 ...

  10. [前端原生技术]jsonp

    [版权声明]未经博主同意,谢绝转载!(请尊重原创,博主保留追究权)https://www.cnblogs.com/cnb-yuchen/p/18031965出自[进步*于辰的博客] 在学习了Jsoup ...