我正在努力完成这本书,我想我做得很好,但是我已经找到了一些我并没有真正得到的东西.
以下是如何在单击的3D空间中登录控制台和对象的方法:
renderer.domElement.addEventListener('mousedown', function(event) {
var vector = new THREE.Vector3(
renderer.devicePixelRatio * (event.pageX - this.offsetLeft) / this.width * 2 - 1,
-renderer.devicePixelRatio * (event.pageY - this.offsetTop) / this.height * 2 + 1,
0
);
projector.unprojectVector(vector, camera);
var raycaster = new THREE.Raycaster(
camera.position,
vector.sub(camera.position).normalize()
);
var intersects = raycaster.intersectObjects(OBJECTS);
if (intersects.length) {
console.log(intersects[0]);
}
}, false);
Run Code Online (Sandbox Code Playgroud)
这是本书对此代码如何工作的解释:
前面的代码在渲染器的画布上侦听mousedown事件.
得到它,我们通过使用找到渲染器正在使用的domElement renderer.domElement
.然后我们用它绑定一个事件监听器addEventListner
,并指定我们想要监听一个mousedown
.单击鼠标时,我们启动匿名函数并将event
变量传递给函数.
然后,它创建一个新的Vector3实例,屏幕上的鼠标坐标相对于画布中心的百分比为画布宽度的百分比.
什么?我得到了我们如何创建一个新实例new THREE.Vector3
,我得到的三个参数Vector3
是它的x, y and z
坐标,但这就是我的理解完全彻底崩溃的地方.
首先,我在这里做一个假设,但是为了绘制一个矢量,你必须在空间中需要两个点来投射?如果你只给它一套坐标,它怎么知道投射的方向?我的猜测是你实际用它Raycaster
来绘制"矢量"......
现在我们传递的论点Vector3
......我得到的z
是0.因为我们只对我们点击屏幕的地方感兴趣.我们可以向上或向下,向左或向右单击,但不能进入或退出屏幕,因此我们将其设置为零.现在让我们来解决x:
renderer.devicePixelRatio * (event.pageX - this.offsetLeft) / this.width * 2 - 1,
Run Code Online (Sandbox Code Playgroud)
我们得到了设备的PixelRatio,按照我们沿x轴点击的位置,除以渲染器的domElement宽度,将其除以2并取走一个.
如果你没有得到什么,你需要说出你得到的东西,这样人们才能最好地帮助你.所以当我说:我觉得这样的傻瓜时:
我变得y
更少了:
-renderer.devicePixelRatio * (event.pageY - this.offsetTop) / this.height * 2 + 1,
Run Code Online (Sandbox Code Playgroud)
为什么我们现在随机使用-
devicePixelRatio?为什么现在决定add
一个而不是minus
一个?
然后,该矢量相对于相机未投影(从2D到3D空间).
什么?
一旦我们在3D空间中有一个代表鼠标位置的点,我们就使用Raycaster为它绘制一条线.它收到的两个参数是起点和结束点的方向.
好的,我明白了,这就是我上面提到的.我们如何需要两点来绘制"矢量".在三次谈话中,一个向量似乎被称为"raycaster".
但是,我们作为论点传递给它的两点并没有多大意义.如果我们传入相机position
和矢量position
并从这两点中绘制投影,我会得到它,实际上我们使用的camera.position
是第一点,但是
vector.sub(camera.position).normalize()
Run Code Online (Sandbox Code Playgroud)
我们为什么要减去camera.position?我们为什么要正常化?为什么这本无用的书不想解释什么?
我们通过减去鼠标和摄像机位置来获得方向,然后对结果进行标准化,该结果将每个维度除以向量的长度以对其进行缩放,以使任何维度的值都不大于1.
什么?我不是懒惰,过去没有一句话by
在这里有意义.
最后,我们使用ray通过intersectObjects方法检查哪些对象位于给定方向(即鼠标下).OBJECTS是要检查的对象数组(通常是网格); 请务必为您的代码更改它.返回鼠标后面的对象数组并按距离排序,因此第一个结果是单击的对象.intersects数组中的每个对象都有一个object,point,face和distance属性.这些属性的值分别是单击的对象(通常是网格),表示空间中单击位置的Vector3实例,单击位置处的Face3实例以及从相机到单击点的距离.
我明白了.我们抓住矢量通过的所有对象,将它们按距离顺序放入数组并记录第一个,即最近的一个:
console.log(intersects[0]);
Run Code Online (Sandbox Code Playgroud)
老实说,你认为我应该放弃三个吗?我的意思是,我肯定已经掌握了它,我理解它的所有编程方面,创建新实例,使用数据对象,如数组,使用匿名函数和传入变量,但每当我点击数学我似乎痛苦地停下来.
或者这真的很难吗?你觉得这很棘手吗?只是这本书并不觉得有必要详细解释,也没有其他 答案,好像这些东西对大多数人来说都是正常的.我觉得自己像个白痴.我应该放弃吗?我想制作3D游戏.我真的非常想要,但我被创造一个整个世界的诗意所吸引.不是数学.如果我说我没有发现数学困难,我会撒谎.
Eva*_*man 13
我理解你的麻烦,我来帮忙.您似乎有一个主要问题:对矢量执行哪些操作以准备点击检测?
让我们回顾一下原始声明vector
:
var vector = new THREE.Vector3(
renderer.devicePixelRatio * (event.pageX - this.offsetLeft) / this.width * 2 - 1,
-renderer.devicePixelRatio * (event.pageY - this.offsetTop) / this.height * 2 + 1,
0
);
Run Code Online (Sandbox Code Playgroud)
renderer.devicePixelRatio
涉及虚拟站点像素/真实设备像素的比率event.pageX
并且.pageY
是mouseX,mouseYthis
上下文renderer.domElement
,所以.width, .height, .offsetLeft/Right
涉及到的1
似乎是计算的校正"神奇"数字(为了尽可能在视觉上精确)我们不关心z值,THREE会为我们处理.X和Y是我们最关心的问题.让我们推导出来:
event.pageX - this.offsetLeft
this.width
来得到mouseX占屏幕宽度的百分比renderer.devicePixelRatio
从设备像素转换为站点像素2
,但它可能与用户有视网膜显示器的假设有关(如果这是错误的话,有人可以随意纠正我).1
再次,魔术可以解决可能只是偏移误差的问题y
,我们将整个表达式乘以-1
补偿倒置坐标系(0是顶部,this.height
是底部)因此,您可以获得向量的以下参数:
renderer.devicePixelRatio * (event.pageX - this.offsetLeft) / this.width * 2 - 1,
-renderer.devicePixelRatio * (event.pageY - this.offsetTop) / this.height * 2 + 1,
0
Run Code Online (Sandbox Code Playgroud)
现在,对于下一位,几个术语:
THREE.Raycaster( origin, direction )
考虑到这些条款,我可以解释为什么我们这样做:vector.sub(camera.position).normalize()
.首先,我们得到描述从鼠标位置矢量到相机位置矢量的距离的矢量vector.sub(camera.position)
.然后,我们将其标准化以使其成为direction
矢量(同样,幅度= 1).这样,我们就可以在鼠标位置的方向上将摄像机从摄像机投射到3D空间!此操作允许我们通过比较对象位置和光线矢量来找出鼠标下的任何对象.
我希望这有帮助.如果您还有其他问题,请随时发表评论,我会尽快回答.
哦,不要让数学劝阻你.THREE.js
本质上是一门数学繁重的语言,因为你在3D空间中操纵物体,但经验将帮助你克服这些理解障碍.我会继续学习并回答Stack Overflow的问题.培养数学能力可能需要一些时间,但如果你不尝试,你就不会学习!