Unity由“鼠标点不准物体”引发的Camera的相关思考

2023-12-07 11:30

本文主要是介绍Unity由“鼠标点不准物体”引发的Camera的相关思考,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

问题        

        前段一个同事在使用Unity开发时遇到一个奇怪的问题,使用左键点击发射射线的方式选择物体,总是选不准,尤其是小的物体,鼠标点击到物体上,有时能选上,有时选不上,偶尔点击到物体旁边反而能选上,于是他让我帮看看咋回事。我第一个想法是也许代码写的有问题吧,但我仔细检查了同事写的代码,规规矩矩,完全没问题。

        就类似下面这种:

if (Input.GetMouseButtonDown(0))
{Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);RaycastHit hit;if (Physics.Raycast(ray, out hit, 500)){Debug.Log(hit.transform.name);}
}

        我一时也是有点儿发懵,但是当我检查他的摄像机设置时,发现他把摄像机的近剪切平面距离设置的很小,是0.01,同事说是为了避免距离近的物体看不到,只能设置到最小,本来想设置为0,但是Unity不允许,最小就只能是0.01了。好吧,反正我也找不到问题所在,咱不妨把这个值先设置为默认值0.3,排除是这个引发问题的可能吧。结果不可思议的事情发生了,再次运行,马上就能够精确点击了。

为啥(一)

        问题是解决了,但是为什么呢?

        先看看这行代码:

Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

        很多时候,这几乎就是Unity的标准写法,一直以来,我都没有深入的研究过,我一直以为这个ray是从摄像机的位置发射出来,也就是ray.origin这个值应该和摄像机的位置是重叠的,但是,当我把ray.origin打印出来(代码如下)的时候,我发现,这个这值位于摄像机的近剪切平面上,并不和摄像机位置重叠!!!

Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
Debug.Log(ray.origin);

        但是,这和近剪切距离的值有什么关系呢?

        因为我们会发现,近剪切平面的长宽和近剪切距离是等比关系,如果近剪切距离小,那么意味着近剪切平面的长宽也变得很小,对于

Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

这样的代码来说,射线的 ray.origin这个值的位置取决于鼠标在屏幕上的位置映射到近剪切平面的结果,而近剪切平面的长宽越大,越容易获得一个精确的值(这个也实在是没办法的事情,Unity的位置精度是float嘛,而这种精度也不单单是Unity如此,大部分游戏引擎都如此,据说使用Double精度的位置对显卡渲染速度影响很大,同时动力学计算也有问题,当然了,听说而已,没亲身研究过)。

        所以我们可以认为,如果近剪切距离是0.3的话,其精度是近剪切距离0.01的30倍,嗯,好像应该可以这么认为吧。

为啥(二)

        但是为什么射线的起始点不是和摄像机位置重叠,偏偏要放在近剪切平面上呢?仔细想想,好像也很好理解,摄像机只会渲染其视锥体内的物体,不会渲染摄像机所在位置和近剪切平面之间的物体,如果射线的出发点和摄像机重叠,那么就可以点击到摄像机所在位置和近剪切平面之间的物体,而这个物体用户根本看不到!Unity当然不应该让这种事情发生,于是把射线的位置放在了近剪切平面上就成了解决这个问题的绝佳方法!!

为啥啊

        到此为止,我以为一切都在掌握之中,于是我认为,远剪切平面之外的物体也点击不了,不管你在Physics.Raycast方法中把射线发射距离设置为多远!

        然后我把Physics.Raycast方法中的maxDistance设置为2000,因为摄像机默认的远剪切距离为1000,如果我把一个物体放置在远剪切平面之外,那么一定是即渲染不了,也点击不到。然而经过测试,发现并非如此,远剪切平面之外的物体只要在射线发射的maxDistance距离之内,就能够被点击到,哈哈哈哈,为啥啊......

这篇关于Unity由“鼠标点不准物体”引发的Camera的相关思考的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

JavaScript Array.from及其相关用法详解(示例演示)

《JavaScriptArray.from及其相关用法详解(示例演示)》Array.from方法是ES6引入的一个静态方法,用于从类数组对象或可迭代对象创建一个新的数组实例,本文将详细介绍Array... 目录一、Array.from 方法概述1. 方法介绍2. 示例演示二、结合实际场景的使用1. 初始化二

CSS模拟 html 的 title 属性(鼠标悬浮显示提示文字效果)

《CSS模拟html的title属性(鼠标悬浮显示提示文字效果)》:本文主要介绍了如何使用CSS模拟HTML的title属性,通过鼠标悬浮显示提示文字效果,通过设置`.tipBox`和`.tipBox.tipContent`的样式,实现了提示内容的隐藏和显示,详细内容请阅读本文,希望能对你有所帮助... 效

Redis的Zset类型及相关命令详细讲解

《Redis的Zset类型及相关命令详细讲解》:本文主要介绍Redis的Zset类型及相关命令的相关资料,有序集合Zset是一种Redis数据结构,它类似于集合Set,但每个元素都有一个关联的分数... 目录Zset简介ZADDZCARDZCOUNTZRANGEZREVRANGEZRANGEBYSCOREZ

关于rpc长连接与短连接的思考记录

《关于rpc长连接与短连接的思考记录》文章总结了RPC项目中长连接和短连接的处理方式,包括RPC和HTTP的长连接与短连接的区别、TCP的保活机制、客户端与服务器的连接模式及其利弊分析,文章强调了在实... 目录rpc项目中的长连接与短连接的思考什么是rpc项目中的长连接和短连接与tcp和http的长连接短

Linux使用fdisk进行磁盘的相关操作

《Linux使用fdisk进行磁盘的相关操作》fdisk命令是Linux中用于管理磁盘分区的强大文本实用程序,这篇文章主要为大家详细介绍了如何使用fdisk进行磁盘的相关操作,需要的可以了解下... 目录简介基本语法示例用法列出所有分区查看指定磁盘的区分管理指定的磁盘进入交互式模式创建一个新的分区删除一个存

关于Maven生命周期相关命令演示

《关于Maven生命周期相关命令演示》Maven的生命周期分为Clean、Default和Site三个主要阶段,每个阶段包含多个关键步骤,如清理、编译、测试、打包等,通过执行相应的Maven命令,可以... 目录1. Maven 生命周期概述1.1 Clean Lifecycle1.2 Default Li

numpy求解线性代数相关问题

《numpy求解线性代数相关问题》本文主要介绍了numpy求解线性代数相关问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 在numpy中有numpy.array类型和numpy.mat类型,前者是数组类型,后者是矩阵类型。数组

使用C#如何创建人名或其他物体随机分组

《使用C#如何创建人名或其他物体随机分组》文章描述了一个随机分配人员到多个团队的代码示例,包括将人员列表随机化并根据组数分配到不同组,最后按组号排序显示结果... 目录C#创建人名或其他物体随机分组此示例使用以下代码将人员分配到组代码首先将lstPeople ListBox总结C#创建人名或其他物体随机分组

Redis的Hash类型及相关命令小结

《Redis的Hash类型及相关命令小结》edisHash是一种数据结构,用于存储字段和值的映射关系,本文就来介绍一下Redis的Hash类型及相关命令小结,具有一定的参考价值,感兴趣的可以了解一下... 目录HSETHGETHEXISTSHDELHKEYSHVALSHGETALLHMGETHLENHSET

python中的与时间相关的模块应用场景分析

《python中的与时间相关的模块应用场景分析》本文介绍了Python中与时间相关的几个重要模块:`time`、`datetime`、`calendar`、`timeit`、`pytz`和`dateu... 目录1. time 模块2. datetime 模块3. calendar 模块4. timeit