一、概述:

在使用Unity实现VR中在黑板上写字(初级篇)中的最后留下了一些有待完善的地方,首先完善画笔穿透画板的问题;

在之前使用画笔会出现这种情况:

可以看到画笔是穿透了画板,这样在VR中会给用户很差的体验,而且因为代码的原因会造成画的过程中中断,所以这个问题必须解决;

解决后的使用情况:

可以看到现在不会穿透了,而且画起来不会有中断,其实我的手的位置已经穿到画板后面了;

实现这个功能,其实有很多种方法,但是最终觉得参照The Lab里实现的方法比较好————用一个Plane类型解决;

二、知识点

Plane这个类中有两个方法:

1.public bool GetSide(Vector3 inPt);判断一个点在Plane的哪一侧

  Plane把一个空间分成了两部分,当一个点在Plane的normal(法线)指向的一侧的时候,这个值返回True,否则返回False;

2.public float GetDistanceToPoint(Vector3 inPt);判断一个点距离平面的距离,这个值是带符号的,当点在平面的正面的时候,返回正值,否则返回负值;

利用这两个方法可以判断出笔尖是不是穿透了画板;

三、代码原理

笔尖穿透了多少距离,我们就补多少回去,以俯视的视角,想像这个情况

根据上图,可以等到笔尖穿透的距离,从笔尖的位置减去这个距离,则刚好可以让笔尖处于平面上;

因为用的是VRTK插件,这个插件集成了很好的物理交互功能,比如抓起东西;VRTK中写了不少抓起物体的机制:

1.VRTK_ChildOfControllerGrabAttach

2.VRTK_ClimbableGrabAttach

3.VRTK_CustomJointGrabAttach

4.VRTK_FixedJointGrabAttach

5.VRTK_RotatorTrackGrabAttach

6.VRTK_SpringJointGrabAttach

7.VRTK_TrackObjectGrabAttach

对于穿透这种情况,没有一种是比较合适的,因此需要自己扩展一种抓附机制;上面的抓附机制都是直接或者间接继承自VRTK_BaseGrabAttach的,因为定义一个VRTK_InteractableObject的抓起方式的字段就是VRTK_BaseGrabAttach类型;

所以综上,需要扩展一个VRTK_BaseGrabAttach类型的抓附机制,并且Board类有了一些改变,需要增加一个UnityEngine.Plane类型的字段,以及封装一些函数;

四、代码实现

首先Board类增加一个Plane类型的字段

internal Plane boardPlane;

然后初始化这个字段

   private void Start(){//初始化Plane,让它的法线是这个画板的forward向量,并且法线通过画板的中心位置,由此确定一个平面boardPlane = new Plane(transform.forward, transform.position);     ......    }

最后增加核心的方法

/// <summary>/// 判断笔尖是在画板的正面还是背面/// </summary>/// <param name="point">笔尖的位置</param>/// <returns>true 在正面;false 在背面</returns>public bool GetSideOfBoardPlane(Vector3 point){return boardPlane.GetSide(point);}/// <summary>/// 笔尖与平面的距离/// </summary>/// <param name="point">笔尖的位置</param>/// <returns>当在正面的时候返回正值,当在背面的时候返回负值</returns>public float GetDistanceFromBoardPlane(Vector3 point){return boardPlane.GetDistanceToPoint(point);}/// <summary>/// 矫正后的笔尖应该在的位置/// </summary>/// <param name="point">笔尖的位置</param>/// <returns>矫正后的笔尖位置</returns>public Vector3 ProjectPointOnBoardPlane(Vector3 point){float d = -Vector3.Dot(boardPlane.normal, point - transform.position);return point + boardPlane.normal * d;}

然后扩展一个抓附机制

using VRTK.GrabAttachMechanics;
using UnityEngine;public class PainterGrabAttach : VRTK_BaseGrabAttach
{[Header("Painter Options")][SerializeField]private Transform tips;//笔尖private static Board board;//画板#region 重写的父类方法protected override void Initialise(){//初始化父类的一些字段,这些字段只是标识这个抓附机制的作用tracked = false;kinematic = false;climbable = false;//初始化自定义的属性if (precisionGrab)//最好不要用精确抓取,因为这样很有可能会让笔处于一个不合理的位置,这样使用的时候,会很变扭(比如必须手腕旋转一个角度,笔才是正的)
        {Debug.LogError("PrecisionGrab cant't be true in case of PainterGrabAttach Mechanic");}board = FindObjectOfType<Board>();}public override bool StartGrab(GameObject grabbingObject, GameObject givenGrabbedObject, Rigidbody givenControllerAttachPoint){if (base.StartGrab(grabbingObject, givenGrabbedObject, givenControllerAttachPoint)){SnapObjectToGrabToController(givenGrabbedObject);grabbedObjectScript.IsKinematic = true;return true;}return false;}public override void StopGrab(bool applyGrabbingObjectVelocity){ReleaseObject(applyGrabbingObjectVelocity);base.StopGrab(applyGrabbingObjectVelocity);}public override void ProcessFixedUpdate(){if (grabbedObject)//只有抓住物体后,grabbedObject才不会
        {grabbedObject.transform.rotation = controllerAttachPoint.transform.rotation * Quaternion.Euler(grabbedSnapHandle.transform.localEulerAngles);grabbedObject.transform.position = controllerAttachPoint.transform.position - (grabbedSnapHandle.transform.position - grabbedObject.transform.position);float distance = board.GetDistanceFromBoardPlane(tips.position);//笔尖距离平面的距离bool isPositiveOfBoardPlane = board.GetSideOfBoardPlane(tips.position);//笔尖是不是在笔尖的正面Vector3 direction = grabbedObject.transform.position - tips.position;//笔尖位置指向笔的位置的差向量//当笔尖穿透的时候,需要矫正笔的位置 if (isPositiveOfBoardPlane || distance > 0.0001f){Vector3 pos = board.ProjectPointOnBoardPlane(tips.position);grabbedObject.transform.position = pos - board.boardPlane.normal * 0.001f + direction;//pos是笔尖的位置,而不是笔的位置,加上direction后才是笔的位置
            }}}#endregion//让手柄抓住物体private void SnapObjectToGrabToController(GameObject obj){if (!precisionGrab){SetSnappedObjectPosition(obj);}}//设置物体和手柄连接的位置 private void SetSnappedObjectPosition(GameObject obj){if (grabbedSnapHandle == null){obj.transform.position = controllerAttachPoint.transform.position;}else{//设置旋转,controllerAttachPoint是手柄上的一个与物体的连接点obj.transform.rotation = controllerAttachPoint.transform.rotation * Quaternion.Euler(grabbedSnapHandle.transform.localEulerAngles);//因为grabbedSnapHandle和obj.transform之间可能不是同一个点,所以为了让手柄抓的位置是grabbedSnapHandle,需要减去括号中代表的向量obj.transform.position = controllerAttachPoint.transform.position - (grabbedSnapHandle.transform.position - obj.transform.position);}}}

五、场景中的设置

1.笔尖的位置还是要设置好

笔尖的位置要设置在笔芯的尖端,snapPoint的位置和旋转,决定了手柄抓住笔时的位置和旋转;

2.其它需要注意的一些设置

转自:http://www.cnblogs.com/marsir/p/8435240.html

使用Unity实现VR中在黑板上写字(升级篇)(一)-----解决画笔穿透画板的问题相关推荐

  1. linux ftp 登录慢,linux中vsftpd登录,上传下载文件慢解决办法linux操作系统 -电脑资料...

    vsftpd登录慢主要是nameserver #定义DNS服务器的IP地址没有设置了,这样我们只要设置或更新一下nameserver即可解决了, 在使用vsftpd的过程中,一直以来都有一个问题就是在 ...

  2. unity之vr中自动行走

    思路: ps:这里的vrSDK是googleVR. 1)获取摄像机<*1>的方向: transform.TransformDirection (Vector3.forward); 2) 让 ...

  3. java中ftp文件上传和中文乱码解决

    前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家.点击跳转到教程. 前几天 有个需求就是上传文件的时候,本地存一份,其他服务器也保存一份,于是就研究了一下,功能只实现了 ...

  4. kindeditor 在jsp中,无法上传本地图片的解决

    1.在myeclipse中新建项目,使kindeditor 的除了本地图片之外的其他功能正常使用.(具体过程网络上很多,google一把) 2.kindeditor.js这个文件在图片的本地上传的地方 ...

  5. 基于Unity的VR迷宫游戏项目技术分享

    一.项目重述 项目重述如下: 在移动端设计一个可参与的创作平台,结合计算机视觉相关技术,获取物理空间中的迷宫设计图: 将移动端获得的迷宫数据转换为三维虚拟场景,并在VR端呈现: 开发基于Unity 3 ...

  6. unity的vr场景怎么做_如何通过Unity快速创建1:1VR场景 不到一小时就可完成制作 - VR之家...

    如何通过Unity快速创建1:1 VR场景?日前,开发者Casland在medium上分享了他是如何通过Unity在VR中快速创建1:1 VR场景物理空间.只需不到一小时的时间就可以完成制作,而且还十 ...

  7. 深度解读 | VR中的See-Through技术

    近年来,虚拟现实(VR)行业迎来了爆发式增长,其消费级别的量产产品,目前已做到近千万级别的年销量.与此同时,VR行业不论是上游基础硬件还是下游软件生态都在迅速发展. 增强现实(AR)行业因其应用场景更 ...

  8. pureftpd mysql 失败_pureftpd传输速度慢与传送文件失败问题以及不能上传文件/目录的解决办法...

    pureftpd其实是一款不错文件上传功能了,但是如果说我们开了主动模式之后你会发现它传输速度慢与传送文件失败这些问题了,下面我来给各位介绍一个解决办法. pureftpd本身传输文件和反映速度可以, ...

  9. python怎么在图片上写字_python如何实现内容写在图片上

    本文实例为大家分享了python将内容写在图片上的具体代码,供大家参考,具体内容如下 # -*- coding: utf-8 -*- # Created on 2018/3/20 import bas ...

最新文章

  1. LeetCode 所有题目总结
  2. Javascript变量的注意要点
  3. node 之 ... 扩展运算符报错
  4. 自学python需要买书吗-学习python需要有编程基础吗
  5. ajax、offset
  6. java calendar类_2020 年,你还在使用 Java 中的 SimpleDateFormat 吗?
  7. Python练习 | 初识Python、数据类型、基本语句
  8. C语言中的数据类型在VB中的申明
  9. tftp服务器连接开发板下载内核提示:retry count exceeded; starting again
  10. 浅谈HR谈薪水的技巧
  11. svn php改客户端密码_记录VisualSVNServer配置在线密码修改功能
  12. 最优化学习笔记(十)——对偶线性规划
  13. python面向对象属性_Python面向对象属性
  14. 用arp-scan扫描局域网IP地址
  15. iOS 相册图片选择器
  16. 【爬虫】根据月份从地理空间数据云上爬取遥感影像信息
  17. 计算机表格增加,怎样在表格中新增一行和上排一样格式的表格。
  18. 8、Map存储世界杯信息相关操作
  19. 前端学习日记3-如何设置网页背景图片
  20. python实现文本审核_百度AI文本审核API使用说明

热门文章

  1. eBay信用评价体系全解析
  2. 淘票票sign----js(5: 继续淘票票--sign 生成完成)
  3. 做网站如何选择利于优化的服务器
  4. commvault oracle备份,Commvault Oracle备份常用命令
  5. WordCount单词统计笔记
  6. 数据治理体系解决方案(附PDF全文)
  7. ava使用MyEclipse构建webService简单案例
  8. centos开启防火墙端口
  9. vscode html tab键补全插件_打造舒适的 VS Code 开发环境
  10. 华摄氏度和摄氏度的转换 华摄氏度转化摄氏度 使用带运算的宏定义