VR凝视功能

2024-02-23 04:50
文章标签 功能 vr 凝视

本文主要是介绍VR凝视功能,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

不依赖任何插件,实现凝视功能。可以操作UI界面也可以操作3d物体。通过GazeController.cs 和 VRGazeItem.cs 两个功能类来实现对物体的凝视操作。
凝视实现思路:
其中GazeController是凝视控制类,这里可以通过射线获取到指定物体,并从物体身上获取想要的脚本或属性,然后可以对该物体进行操作和交互;而VRGazeItem就是想要实现凝视效果所必须的类,对每个想要能被凝视触发的物体挂在该脚本即可。
在实现时有几个点需要注意,
1.凝视功能缺不了凝视圈,放置凝视圈的位置很重要,往后看有具体位置讲解;
2.凝视相机的Tag和Layer的设置,用到射线查找,Tag是很好的属性;
3.凝视相机要挂载GazeController;
4.被凝视物体设置,跟相机一样设置不同的Tag和Layer,然后必须挂载VRGazeItem。
1. 首先,设置凝视相机,找到[CameraRig]>Camera(head)>Camera(eye);在这个目录下放置凝视圈,按照下图目录放置。

2. 然后创建目录RericleCanvas>RericleImage>BackGround;
RericleCanvas是凝视圈的Canvas,按照如图设置,调至合适的位置,RenderMode设置为World Space。

3. 接着在设置RericleImage,这里有个小特点,由于凝视圈,在触发时会有个旋转等待的效果,这里设置也要按照指定的目录结构设置;设置该图片的ImageType为Filled,代码中可以调节Fill Amount来实现圆形进度条填充效果。(还有一点注意,由于Unity本身原因,两个图集或模型重叠会闪烁,所以这里有个shader可以解决此问题 Overlay

4.然后设置凝视交互的物体和UI,这里以物体(cube)为例,UI设置与此操作一样,给需要操作的UI添加脚本VRGazeItem.cs 并且 要添加啊BoxCollider。

5.设置完成,运行工程带上VR 头盔测试下效果吧。
凝视物体效果:

凝视UI效果:

GazeController.cs 脚本源码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class GazeController : MonoBehaviour {
///
/// 准星容器.
///
public Canvas reticaleCanvas;
///
/// 准星图片.
///
public Image reticleImage;
///
/// 击中目标
///
private GameObject target;
///
/// 初始位置 
///
private Vector3 originPos;
///
/// 凝视圈初始缩放
///
private Vector3 originScale;
// 倒计时时间
private float countDownTime = 3f;
// 当前时间
private float nowTime =0f;
// Use this for initialization
void Start () {reticleImage.fillAmount = 0f;originPos = reticaleCanvas.transform.localPosition;originScale = reticaleCanvas.transform.localScale;
}// Update is called once per frame
void Update () {// 以相机位置向正前方发出一条射线Ray ray = new Ray (transform.position, transform.forward);// 接收射线碰到的物体RaycastHit hit;if (Physics.Raycast (ray, out hit, 100)) {reticaleCanvas.transform.position = hit.point;reticaleCanvas.transform.localScale = originScale * hit.distance;// 准星与击中的发线方向一致reticaleCanvas.transform.forward = hit.normal;if (hit.transform.gameObject != target) {if (target != null) {// 获取看中物体身上的凝视触发脚本VRGazeItem (需要凝视触发的要挂载此脚本)VRGazeItem oldItem = target.GetComponent ();if (oldItem) {// 视线移出触发oldItem.OnGazeOut ();}}// 视线初次进入的处理target = hit.transform.gameObject;VRGazeItem newItem = target.GetComponent ();if (newItem) {// 视线移入触发newItem.OnGazeIn ();}}// 视线在此停留else{nowTime += Time.deltaTime;if ((countDownTime - nowTime) > 0) {// 未达到激活条件reticleImage.fillAmount = nowTime/countDownTime;} else{// 达到激活条件VRGazeItem gazeFireItem = target.GetComponent ();if (gazeFireItem) {// 视线停留触发gazeFireItem.OnGazeFire (hit);}nowTime = 0f;}}} else // 没有击中物体{reticaleCanvas.transform.position = originPos;reticaleCanvas.transform.localScale = originScale;reticaleCanvas.transform.forward = Camera.main.transform.forward;nowTime = 0f;reticleImage.fillAmount = 0f;}
}

VRGazeItem.cs 脚本源码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;public class VRGazeItem : MonoBehaviour {////// 高亮材质///public Material hightlightMat;////// 默认材质///public Material normalMat;// Use this for initialization
void Start () {}// Update is called once per frame
void Update () {}
///
/// 视线移入触发
///
public void OnGazeIn()
{if (gameObject.tag == "GazeUI") {ExecuteEvents.Execute (gameObject,new PointerEventData (EventSystem.current),                                 ExecuteEvents.pointerEnterHandler);} else if (gameObject.tag == "GazeObj") {gameObject.GetComponent().material = hightlightMat;}
}
///
/// 视线移出触发
///
public void OnGazeOut()
{if (gameObject.tag == "GazeUI") {ExecuteEvents.Execute (gameObject,new PointerEventData (EventSystem.current), ExecuteEvents.pointerExitHandler);} else if (gameObject.tag == "GazeObj") {gameObject.GetComponent().material = normalMat;}
}
///
/// 视线激活触发
///
public void OnGazeFire(RaycastHit hit)
{if (gameObject.tag == "GazeUI"){Debug.Log("视线移入UI并现在停留在这里");}else if (gameObject.tag == "GazeObj"){Debug.Log("视线移入OBJ并现在停留在这里");
// 给看中的物体添加Rigibody,然后通过AddForce/AddForceAtPosition 添加施力点,1力的大小2施力的起始点gameObject.GetComponent().AddForceAtPosition(hit.point.normalized*100,hit.point);}}
}

shader Overlay 源码:

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'Shader "UI/Overlay"
{Properties{[PerRendererData] _MainTex ("Font Texture", 2D) = "white" {}_Color("Tint", Color) = (1,1,1,1)_StencilComp ("Stencil Comparison", Float) = 8_Stencil ("Stencil ID", Float) = 0_StencilOp ("Stencil Operation", Float) = 0_StencilWriteMask ("Stencil Write Mask", Float) = 255_StencilReadMask ("Stencil Read Mask", Float) = 255_ColorMask ("Color Mask", Float) = 15}SubShader{LOD 100Tags{"Queue" = "Transparent""IgnoreProjector" = "True""RenderType" = "Transparent""PreviewType"="Plane""CanUseSpriteAtlas" = "True"}Stencil{Ref [_Stencil]Comp [_StencilComp]Pass [_StencilOp] ReadMask [_StencilReadMask]WriteMask [_StencilWriteMask]}Cull OffLighting OffZWrite OffZTest AlwaysOffset -1, -1Blend SrcAlpha OneMinusSrcAlphaColorMask [_ColorMask]Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"#include "UnityUI.cginc"struct appdata_t{float4 vertex : POSITION;float2 texcoord : TEXCOORD0;float4 color : COLOR;};struct v2f{float4 vertex : SV_POSITION;half2 texcoord : TEXCOORD0;fixed4 color : COLOR;};sampler2D _MainTex;float4 _MainTex_ST;fixed4 _Color;fixed4 _TextureSampleAdd;v2f vert (appdata_t v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);o.color = v.color * _Color;#ifdef UNITY_HALF_TEXEL_OFFSETo.vertex.xy += (_ScreenParams.zw-1.0)*float2(-1,1);#endifreturn o;}fixed4 frag (v2f i) : SV_Target{fixed4 col = (tex2D(_MainTex, i.texcoord) + _TextureSampleAdd) * i.color;clip (col.a - 0.01);return col;}ENDCG}}
}

这篇关于VR凝视功能的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/737575

相关文章

Python使用FastAPI实现大文件分片上传与断点续传功能

《Python使用FastAPI实现大文件分片上传与断点续传功能》大文件直传常遇到超时、网络抖动失败、失败后只能重传的问题,分片上传+断点续传可以把大文件拆成若干小块逐个上传,并在中断后从已完成分片继... 目录一、接口设计二、服务端实现(FastAPI)2.1 运行环境2.2 目录结构建议2.3 serv

Debian 13升级后网络转发等功能异常怎么办? 并非错误而是管理机制变更

《Debian13升级后网络转发等功能异常怎么办?并非错误而是管理机制变更》很多朋友反馈,更新到Debian13后网络转发等功能异常,这并非BUG而是Debian13Trixie调整... 日前 Debian 13 Trixie 发布后已经有众多网友升级到新版本,只不过升级后发现某些功能存在异常,例如网络转

基于Java和FFmpeg实现视频压缩和剪辑功能

《基于Java和FFmpeg实现视频压缩和剪辑功能》在视频处理开发中,压缩和剪辑是常见的需求,本文将介绍如何使用Java结合FFmpeg实现视频压缩和剪辑功能,同时去除数据库操作,仅专注于视频处理,需... 目录引言1. 环境准备1.1 项目依赖1.2 安装 FFmpeg2. 视频压缩功能实现2.1 主要功

使用Python实现无损放大图片功能

《使用Python实现无损放大图片功能》本文介绍了如何使用Python的Pillow库进行无损图片放大,区分了JPEG和PNG格式在放大过程中的特点,并给出了示例代码,JPEG格式可能受压缩影响,需先... 目录一、什么是无损放大?二、实现方法步骤1:读取图片步骤2:无损放大图片步骤3:保存图片三、示php

深度解析Python yfinance的核心功能和高级用法

《深度解析Pythonyfinance的核心功能和高级用法》yfinance是一个功能强大且易于使用的Python库,用于从YahooFinance获取金融数据,本教程将深入探讨yfinance的核... 目录yfinance 深度解析教程 (python)1. 简介与安装1.1 什么是 yfinance?

Python脚本轻松实现检测麦克风功能

《Python脚本轻松实现检测麦克风功能》在进行音频处理或开发需要使用麦克风的应用程序时,确保麦克风功能正常是非常重要的,本文将介绍一个简单的Python脚本,能够帮助我们检测本地麦克风的功能,需要的... 目录轻松检测麦克风功能脚本介绍一、python环境准备二、代码解析三、使用方法四、知识扩展轻松检测麦

Java实现TXT文件导入功能的详细步骤

《Java实现TXT文件导入功能的详细步骤》在实际开发中,很多应用场景需要将用户上传的TXT文件进行解析,并将文件中的数据导入到数据库或其他存储系统中,本文将演示如何用Java实现一个基本的TXT文件... 目录前言1. 项目需求分析2. 示例文件格式3. 实现步骤3.1. 准备数据库(假设使用 mysql

Springboot项目登录校验功能实现

《Springboot项目登录校验功能实现》本文介绍了Web登录校验的重要性,对比了Cookie、Session和JWT三种会话技术,分析其优缺点,并讲解了过滤器与拦截器的统一拦截方案,推荐使用JWT... 目录引言一、登录校验的基本概念二、HTTP协议的无状态性三、会话跟android踪技术1. Cook

基于Spring Boot 的小区人脸识别与出入记录管理系统功能

《基于SpringBoot的小区人脸识别与出入记录管理系统功能》文章介绍基于SpringBoot框架与百度AI人脸识别API的小区出入管理系统,实现自动识别、记录及查询功能,涵盖技术选型、数据模型... 目录系统功能概述技术栈选择核心依赖配置数据模型设计出入记录实体类出入记录查询表单出入记录 VO 类(用于

Qt中实现多线程导出数据功能的四种方式小结

《Qt中实现多线程导出数据功能的四种方式小结》在以往的项目开发中,在很多地方用到了多线程,本文将记录下在Qt开发中用到的多线程技术实现方法,以导出指定范围的数字到txt文件为例,展示多线程不同的实现方... 目录前言导出文件的示例工具类QThreadQObject的moveToThread方法实现多线程QC