Untiy HTC Vive VRTK 开发记录
目录
一.概述
二.功能实现
1.模型抓取
1)基础抓取脚本
2)抓取物体在手柄上的角度
2.模型放置区域高亮并吸附
1)VRTK_SnapDropZone
2)VRTK_PolicyList
3)VRTK_SnapDropZone_UnityEvents
3.交互滑动条
4.交互旋转模型
5.设置手柄半透明
三.其他
一.概述
此篇记录在开发过程中所使用到的VR功能,不针对VRTK或SteamVR的插件进行解释,或导入等等基础内容的说明,如正在开发VR项目或许可以借鉴本篇中解释的相关功能~
二.功能实现
1.模型抓取
1)基础抓取脚本
给需要被手柄抓取的模型添加图例脚本,必须添加的有VRTK_InteractableObject、VRTK_SwapControllerGrabAction
再给手柄添加这些脚本即可,不需要单独去记,因为笔者犯懒,也是直接从VRTK的预制体直接拖拽到场景中的,程序和人有一个能跑就行不是吗~
2)抓取物体在手柄上的角度
通常,在抓取到物体的时候,被抓取的物体只是相对于手柄当时的抓取位置被吸附到手柄上,但一般在做项目,比如使用放大镜的时候肯定要保证抓起放大镜的时候保持镜面在最上面,主要是用户体验感上的功能。
给需要被抓取的物体(笔者这里叫气钻)添加VRTK_TrackObjectGrabAttach,在需要被抓取的物体下创建一个空物体(SnapPoint),给这个空物体添加VRTK_SDKTransformModify。
在新建的这个空物体下的脚本组件VRTK_SDKTransformModify—Sdk Overrides—Element0—Transform Override Settings中设置位置信息和旋转信息,这里设置的信息会直接覆盖掉被抓取物体相对于手柄的局部位置、局部旋转的信息,建议在运行起来将物体抓到手柄上去调这个参数,最后结束运行复制出来,因为在非运行状态下这个信息很难调。
最后就是需要将携带VRTK_SDKTransformModify的这个空物体添加到需要被抓取的物体(父物体)的VRTK_TrackObjectGrabAttach—Right Snap Handle中,这个只是代表右手手柄抓起来之后会使用这个空间信息,需要根据项目要求自行选择添加到左手柄还是右手柄。
2.模型放置区域高亮并吸附
这个功能主要是使用手柄拾取模型后,需要将这个模型放置到特定的位置上。比如有一条直线,需要用到尺子去测量这条直线的长度,那么在拾取这个尺子在直线附近释放的时候直接将直尺完美贴合到直线上。
首先在Project文件夹下直接搜索SnapDropZone,将预制体拖拽到场景中。
可以看到这个预制体上默认携带了碰撞器、刚体、VRTK_SnapDropZone.cs组件,但这些组件还不足以实现高亮和吸附的功能,需要再给这个预制体(SnapDropZone)添加两个脚本,分别为VRTK_PolicyList、VRTK_MaterialColorSwapHighlighter。
1)VRTK_SnapDropZone
VRTK_SnapDropZone的作用主要是高亮和吸附的脚本的集成和控制,先主要对两个参数进行修改,分别是Highlight Object Prefab、Highlight Color。
- Highlight Object Prefab用于在当前区域绘制高亮,类型是GameObject,就是说你他的高亮信息就是你往这个参数里拖拽的任何物体,如果是空物体那什么也没有,如果有网格那就对网格高亮。
- Highlight Color高亮颜色,类型是Color,直接设置成自己喜欢的高亮颜色就行了。
关于高亮颜色也可以添加VRTK_MaterialColorSwapHighlighter脚本,在这个脚本上添加材质球会直接覆盖掉VRTK_SnapDropZone的Highlight Color参数。因为项目中可能会有大量的VRTK_SnapDropZone脚本,那么如果策划说高亮颜色需要从蓝色调整为黄色就得一个个去调整了,所以添加统一的颜色管理对于笔者而言还是很有必要的~
2)VRTK_PolicyList
在说VRTK_PolicyList前先要说一下这个物体上的碰撞器的作用,在这里碰撞器的大小就是用于判断哪些物体被放置到这个检测范围之内。
VRTK_PolicyList的作用主要是设置高亮的目标,设置哪些物体进入到这个区域(也就是碰撞器区域)的时候触发高亮,主要判断依据是碰撞器+标签,碰撞器主要检测物体是否进入到这个区域,标签主要检测是哪个物体进入到了这个区域,两者结合在开发起来其实还是比较舒服的,而这个脚本主要就是标签的设置。
首先给需要进入到这个区域的物体(我这里是气钻)添加并设置一个标签(我这里是Module_3_Qizuan),再给VRTK_PolicyList下的Size—Element0设置一致的标签,最后把它自身给拖拽到VRTK_SnapDropZone组件的Valid Object List Policy中。
到此,就可以把拖拽物体放置到高亮区域进行高亮的显示了,但实际做项目的时候肯定不能是把这个物体放置到位之后就万事大吉了,所以还需要添加一个将物体放上去之后的事件VRTK_SnapDropZone_UnityEvents,这个添加方式和给Button添加事件没有区别,自己公开一个方法添加即可。
3)VRTK_SnapDropZone_UnityEvents
给高亮检测物体添加事件监听脚本VRTK_SnapDropZone_UnityEvents。
- ObjectEnteredSnapDropZone:对象进入捕捉放置区域
- ObjectExitedSnapDropZone:对象退出捕捉区域
- ObjectSnappedToDropZone:捕捉到放置区域的对象
- ObjectUnsnappedFromDropZone:从放置区域取消捕捉的对象
一般给ObjectSnappedToDropZone添加事件即可,这个将物体放下吸附上之后会调用,比如我要拿直尺去测量一条直线的长度,那么我的直尺放下之后就会调用具体测量的逻辑代码。
3.交互滑动条
使用VRTK脚本VRTK_ArtificialSlider.cs,需要设置的重要参数分别为滑动轴和最大长度,滑动轴用于控制XYZ三个方向的拖拽,
最大长度用于限制和触发拖拽到终点的事件,这里设置为0.2和0.01,既代表该物体限制x:0.01—0.2之间。
通过VRTK_BaseControllable.cs脚本给物体添加滑动到最小值和最大值的事件。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using VRTK.Controllables;public class TestSlider : MonoBehaviour
{public VRTK_BaseControllable _Controllable;private void OnEnable(){_Controllable.MaxLimitReached += MaxLimitReached;_Controllable.MinLimitReached += MinLimitReached;}protected virtual void MaxLimitReached(object sender, ControllableEventArgs e){Debug.Log("滑动到最大值");}protected virtual void MinLimitReached(object sender, ControllableEventArgs e){Debug.Log("滑动到最小值");}}
4.交互旋转模型
需要用到VRTK的脚本为VRTK_ArtificialRotator.cs,需要设置的内容为旋转方向和旋转最小最大值,比交互滑动条需要多设置一个Hinge Point(铰链点),可以理解为需要被旋转的物体是基于这个铰链点的位置信息进行轴的旋转,这个可以帮助我们做一些不规则物体(见下图)的正常旋转(毕竟不能啥玩意都像老年健身区的转盘那样直溜溜的转)
VRTK_ArtificialRotator的重要参数
通过VRTK_BaseControllable.cs脚本给物体添加旋转到最小值和最大值的事件。因为代码写的太烂大家自行参考自带案例025_Controls_Overview,只对这个功能的实现逻辑大概说一下,是通过VRTK_Control_UnityEvents.cs的OnValueChanged获取旋转量,通过VRTK_BaseControllable来处理旋转量。
5.设置手柄半透明
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using VRTK;public class _Device : MonoBehaviour
{public GameObject 传入右手物体RightController;public GameObject 传入左手物体LeftController;IEnumerator Start(){yield return new WaitForSeconds(1);VRTK_ObjectAppearance.SetOpacity(VRTK_DeviceFinder.GetModelAliasController(传入右手物体RightController), 0.5f);VRTK_ObjectAppearance.SetOpacity(VRTK_DeviceFinder.GetModelAliasController(传入左手物体LeftController), 0.5f);}}
三.其他
这里记录使用VR开发遇到的一些问题
1.因为需求是左手柄有UI持续跟随悬浮,所以在左手柄的子物体列表下添加了可交互UI,而右手柄无法对UI进行交互,左手柄本身做一些尝试可以进行交互,解决方案是通过Update持续更新UI的位置在左手柄下。
2.手柄半透明的脚本因为写在了Start下,在启动软件的时候刚好手柄丢失定位的情况下会导致手柄的半透明设置失效,我这里写了协程延迟Start一秒,逻辑不严谨建议不要照搬。
3.尽量不要做UI持续在相机上的功能,因为体验感极差....如果非要做的话尽量让UI往屏幕下方下调一些。如果为了第三者在屏幕观看效果的话尽量让UI向上调,另外在屏幕上观看只能看到右眼的画面,和头盔左右眼结合的画面稍有偏离,可以通过SteamVR来调出“显示VR视图—左上角菜单—双眼-xxxxx”的功能。
相关文章:

Untiy HTC Vive VRTK 开发记录
目录 一.概述 二.功能实现 1.模型抓取 1)基础抓取脚本 2)抓取物体在手柄上的角度 2.模型放置区域高亮并吸附 1)VRTK_SnapDropZone 2)VRTK_PolicyList 3)VRTK_SnapDropZone_UnityEvents 3.交互滑动条 4.交互旋…...

机器学习指南:如何学习机器学习?
机器学习 一、介绍 你有没有想过计算机是如何从数据中学习和变得更聪明的?这就是机器学习 (ML) 的魔力!这就像计算机科学和统计学的酷炫组合,计算机从大量信息中学习以解决问题并做出预测,就像人类一样。 …...

使用numpy处理图片——分离通道
大纲 读入图片分离通道堆叠法复制修改法 生成图片 在《使用numpy处理图片——滤镜》中,我们剥离了RGB中的一个颜色,达到一种滤镜的效果。 如果我们只保留一种元素,就可以做到PS中分离通道的效果。 读入图片 import numpy as np import PIL.…...
metartc5_jz源码阅读-yang_rtcpush_on_rtcp_ps_feedback
// (Payload-specific FB messages,有效载荷反馈信息),这个函数处理Payload重传 int32_t yang_rtcpush_on_rtcp_ps_feedback(YangRtcContext *context,YangRtcPushStream *pub, YangRtcpCommon *rtcp) {if (context NULL || pub NULL)return ERROR_RTC…...

计算机毕业设计 | SpringBoot+vue的家庭理财 财务管理系统(附源码)
1,绪论 1.1 项目背景 网络的发展已经过去了七十多年,网络技术的发展,将会影响到人类的方方面面,网络的出现让各行各业都得到了极大的发展,为整个社会带来了巨大的生机。 现在许多的产业都与因特网息息相关ÿ…...
前端面试题集合三(js)
目录 1. 介绍 js 的基本数据类型。2. JavaScript 有几种类型的值?你能画一下他们的内存图吗?3. 什么是堆?什么是栈?它们之间有什么区别和联系?4. 内部属性 [[Class]] 是什么?5. 介绍 js 有哪些内置对象&am…...

ssm基于JAVA的酒店客房管理系统论文
摘 要 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本酒店客房管理系统就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息…...

杨中科 .NETCORE ENTITY FRAMEWORK CORE-1 EFCORE 第一部分
一 、什么是EF Core 什么是ORM 1、说明: 本课程需要你有数据库、SOL等基础知识。 2、ORM: ObjectRelational Mapping。让开发者用对象操作的形式操作关系数据库 比如插入: User user new User(Name"admin"Password"123”; orm.Save(user);比如查询: Book b…...

微信小程序 全局配置||微信小程序 页面配置||微信小程序 sitemap配置
全局配置 小程序根目录下的 app.json 文件用来对微信小程序进行全局配置,决定页面文件的路径、窗口表现、设置网络超时时间、设置多 tab 等。 以下是一个包含了部分常用配置选项的 app.json : {"pages": ["pages/index/index",&q…...

使用ffmpeg对视频进行静音检测
1 原始视频信息 通过ffmpeg -i命令查看视频基本信息 ffmpeg version 6.1-essentials_build-www.gyan.dev Copyright (c) 2000-2023 the FFmpeg developersbuilt with gcc 12.2.0 (Rev10, Built by MSYS2 project)configuration: --enable-gpl --enable-version3 --enable-sta…...

Servlet-Request
一、预览 在上一篇Servlet体系结构中,我们初步了解了怎么快速本篇将介绍Servlet中请求Request的相关内容,包括Request的体系结构,Request常用API。 二、Request体系结构 我们注意到我们定义的Servlet类若实现Servlet接口时,请求…...
数据结构-怀化学院期末题(490)
哈希查找 题目描述: 实现哈希查找。要求根据给定的哈希函数进行存储,并查找相应元素的存储位置。本题目使用的哈希函数为除留取余法,即H(key)key%m,其中m为存储空间,冲突处理方法采用开放定址法中的线性探测再散列&am…...

Matlab字符识别实验
Matlab 字符识别OCR实验 图像来源于屏幕截图,要求黑底白字。数据来源是任意二进制文件,内容以16进制打印输出,0-9a-f’字符被16个可打印字符替代,这些替代字符经过挑选,使其相对容易被识别。 第一步进行线分割和字符…...

MySQL夯实之路-存储引擎深入浅出
innoDB Mysql4.1以后的版本将表的数据和索引放在单独的文件中 采用mvcc来支持高并发,实现了四个标准的隔离级别,默认为可重复读,并且通过间隙锁(next-key locking)策略防止幻读(查询的行中的间隙也会锁定…...

内存卡为什么会提示格式化,内存卡提示格式化还能恢复吗
对于许多电脑用户来说,执行内存卡格式化操作导致数据丢失是一个常见的问题。在日常生活中,数据丢失的情况并不少见,但内存卡格式化后的数据恢复相对较难。目前,能够使用的方法较少,且成功率较低,但并不是没…...

阅读文献-胃癌
写在前面 今天先不阅读肺癌的了,先读一篇胃癌的文章 文献 An individualized stemness-related signature to predict prognosis and immunotherapy responses for gastric cancer using single-cell and bulk tissue transcriptomes IF:4.0 中科院分区:2区 医学…...
水仙花数(Java解法)
什么是水仙花数? 水仙花数是指一个 3 位数,它每位上的数字的 3 次幂之和等于它本身(例如: 1 5 3 153 ),水仙花数的取值范围在 100~1000 之间。 解题思路: 这个题需要把所以的数字都拿到&…...
vue3 源码解析(3)— computed 计算属性的实现
前言 本文是 vue3 源码分析系列的第三篇文章,主要介绍 vue3 computed 原理。computed 是 vue3 的一个特性,可以根据其他响应式数据创建响应式的计算属性。计算属性的值会根据依赖的数据变化而自动更新,而且具有缓存机制,提高了性…...

Alibaba-> EasyExcel 整理3
1 导入依赖 <!-- easyExcel --><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version >3.2.1</version><exclusions><exclusion><artifactId>poi-ooxml-schemas</art…...

创建组-RibbonGroup
使用实例如下: 1、main中: #include "QRibbonDemo.h" #include <QtWidgets/QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); a.setStyle(new RibbonStyle()); a.setApplicationName(&quo…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...

【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...

P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...

高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...

MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...
根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:
根据万维钢精英日课6的内容,使用AI(2025)可以参考以下方法: 四个洞见 模型已经比人聪明:以ChatGPT o3为代表的AI非常强大,能运用高级理论解释道理、引用最新学术论文,生成对顶尖科学家都有用的…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...