当前位置: 首页 > news >正文

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 项目背景 网络的发展已经过去了七十多年,网络技术的发展,将会影响到人类的方方面面,网络的出现让各行各业都得到了极大的发展,为整个社会带来了巨大的生机。 现在许多的产业都与因特网息息相关&#xff…...

前端面试题集合三(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

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

面试题目1

文章目录 1、安装系统的方法2、总线型3、OSL参考模型&#xff08;网络七层模型&#xff09;4、计算机系统的组成5、计算机硬件 1、安装系统的方法 U盘安装 硬盘安装 刻光盘安装 PE系统中安装 网络安装 2、总线型 所有设备都连接到公共总线上&#xff0c;结点间使用广播通信方…...

考古学家 - 华为OD统一考试

OD统一考试 分值: 200分 题解: Java / Python / C++ 题目描述 有一个考古学家发现一个石碑,但是很可惜发现时其已经断成多段。 原地发现N个断口整齐的石碑碎片,为了破解石碑内容,考古学家希望有程序能帮忙计算复原后的石碑文字组合数,你能帮忙吗? 备注: 如果存在石碑…...

Linux服务器安全配置基线

基线要求: 安全类别 检查项 检查要求 检查步骤 备注 账户及口令安全 1.1 检查是否设置口令生存周期 应配置口令生存周期,密码最长使用期限应小于等于90天,密码最短使用期限应非0。 执行:cat /etc/login.defs,检查是否配置了以下参数。 PASS_MAX_DAYS 配置项决定密码最长使…...

Kafka外网访问

文章目录 一、背景二、需求三、调研四、配置内外网访问 一、背景 kafka机器只有内网IP&#xff0c;没有绑定外网网卡&#xff0c;但是可以在防火墙或通过其他有公网IP的设备上进行公网IP端口的映射。 二、需求 kafka集群端口映射后&#xff0c;可以通过外网IP端口进行数据生…...

Vant2组件库van-list+Toast下拉加载滚动条回顶问题

目录 List 列表 Toast 轻提示 解决方案 1、不使用 Toast 的 加载提示 2、修改调整 pointer-event 属性值 3、判断是否为第一次加载再使用 背景 &#xff1a; 移动端项目 开发时&#xff0c;有数据长列表展示的场景需求&#xff0c;此时就用到了 Vant2 组件库里面的 <v…...

使用 C++/WinRT 创作 API

如果 API 位于 Windows 命名空间中 这是你使用 Windows 运行时 API 最常见的情况。 对于元数据中定义的 Windows 命名空间中的每个类型&#xff0c;C/WinRT 都定义了 C 友好等效项&#xff08;称为投影类型 &#xff09;。 投影类型具有与 Windows 类型相同的完全限定名称&…...

C#写windows服务,实现把检测软件崩溃工具写成服务 自动运行

一、打开Visual Studio&#xff0c;创建项目->Windows 服务(.NET Framework) 二、点击Service.cs 点击切换到代码视图 static Timer Timer; private Thread monitorThread; private static string logFilePath; private static Process winFormsProcess; public Service1(…...

QT中线程的退出分析

QT中线程的退出分析 前言开发环境代码的整改第一次修改第一次修改引起的问题问题原因分析解决方法第二次修改前言 软件实际开发过程中有好几处要实现这么一个功能:PC端软件“应用程序重启” ,本来这是一段比较简单的事情,但是因为重启软件报通信异常(错误日志中有记录通信…...

进程的创建

关于进程创建的一些细节都在注释中 /*#include <sys/types.h>#include <unistd.h>pid_t fork(void);函数的作用&#xff1a;用于创建子进程。返回值&#xff1a;fork()的返回值会返回两次。一次是在父进程中&#xff0c;一次是在子进程中。在父进程中返回创建的子…...

day-08 构造限制重复的字符串

思路 首先统计每个字符的个数&#xff0c;然后从后向前按照题意添加字符 解题方法 从后向前添加字符&#xff1a;1.当前字符个数<repeatLimit,直接添加 2.当前字符个数>repeatLimit,添加repeatLimit个&#xff0c;然后插入一个下一级字符 时间复杂度:O(n) 空间复杂度:…...