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);
这是本书对此代码如何工作的解释:
The prevIoUs code listens to the mousedown event on the renderer’s canvas.
得到它,我们通过使用renderer.domElement找到渲染器正在使用的domElement.然后我们用addEventListner绑定一个事件监听器,并指定我们要监听mousedown.单击鼠标时,我们启动匿名函数并将eventvariable传递给函数.
Then,
it creates a new Vector3 instance with the mouse’s coordinates on the screen
relative to the center of the canvas as a percent of the canvas width.
什么?我得到了我们如何使用新的THREE.Vector3创建一个新实例,并且我得到了Vector3所采用的三个参数是它的x,y和z坐标,但这就是我理解完全彻底崩溃的地方.
首先,我在这里做一个假设,但是为了绘制一个矢量,你必须在空间中需要两个点来投射?如果你只给它一套坐标,它怎么知道投射的方向?我的猜测是你实际上使用Raycaster来绘制“矢量”……
现在我们传递给Vector3的参数…我得到z是0因为我们只对我们点击屏幕的地方感兴趣.我们可以向上或向下,向左或向右,但不能进入或退出屏幕,因此我们将其设置为零.现在让我们来解决x:
renderer.devicePixelRatio * (event.pageX - this.offsetLeft) / this.width * 2 - 1,
我们得到了设备的PixelRatio,按照我们沿x轴点击的位置,除以渲染器的domElement宽度,将其除以2并取走一个.
如果你没有得到什么,你需要说出你的所作所为,这样人们才能最好地帮助你.所以当我说:我觉得这样的傻瓜时:
>我不明白为什么我们甚至需要像素比率我不明白为什么我们按照我们点击x的位置
>我不明白为什么我们把它除以宽度
>我完全不明白为什么我们需要时间到2并带走1.时间乘2,带走1.那真的可能是大象的时间,带走花生,它会有同样的意义.
我甚至更少:
-renderer.devicePixelRatio * (event.pageY - this.offsetTop) / this.height * 2 + 1,
为什么我们现在随机使用-devicePixelRatio?为什么现在决定加一个而不是一个?
That vector is then un-projected (from 2D into 3D space) relative to the camera.
什么?
Once we have the point in 3D space representing the mouse’s location,
we draw a line to it using the Raycaster. The two arguments that it
receives are the starting point and the direction to the ending point.
好的,我明白了,这就是我上面提到的.我们如何需要两点来绘制“矢量”.在三次谈话中,一个向量似乎被称为“raycaster”.
然而,我们作为论点传达它的两点并没有多大意义.如果我们传入相机的位置和矢量的位置并从这两点中绘制投影,我会得到它,实际上我们正在使用camera.position作为第一点,但是
vector.sub(camera.position).normalize()
我们为什么要减去camera.position?我们为什么要正常化?为什么这本无用的书不想解释什么?
We get the direction by subtracting the mouse and camera positions and
then normalizing the result,which divides each dimension by the
length of the vector to scale it so that no dimension has a value
greater than 1.
什么?我不是懒惰,不是过去的一句话在这里有意义.
Finally,we use the ray to check which objects are located in the
given direction (that is,under the mouse) with the intersectObjects
method. OBJECTS is an array of objects (generally meshes) to check; be
sure to change it appropriately for your code. An array of objects
that are behind the mouse are returned and sorted by distance,so the
first result is the object that was clicked. Each object in the
intersects array has an object,point,face,and distance property.
Respectively,the values of these properties are the clicked object
(generally a Mesh),a Vector3 instance representing the clicked
location in space,the Face3 instance at the clicked location,and the
distance from the camera to the clicked point.
我明白了.我们抓住矢量通过的所有对象,将它们按距离顺序放入数组并记录第一个,即最近的一个:
console.log(intersects[0]);
老实说,你认为我应该放弃三个吗?我的意思是,我肯定已经掌握了它,我理解它的所有编程方面,创建新实例,使用数据对象,如数组,使用匿名函数和传入变量,但每当我点击数学我似乎痛苦地停下来.
或者这真的很难吗?你觉得这很棘手吗?这本书并不觉得有必要详细解释,other answers也没有,好像这些东西对大多数人来说都是正常的.我觉得自己像个白痴.我应该放弃吗?我想创造3D游戏.我真的,非常想,但我被创造整个世界的诗意所吸引.不是数学.如果我说我没有发现数学困难,我会撒谎.
解决方法
让我们回顾一下vector的原始声明:
var vector = new THREE.Vector3( renderer.devicePixelRatio * (event.pageX - this.offsetLeft) / this.width * 2 - 1,0 );
> renderer.devicePixelRatio与虚拟站点像素的比率/
真实设备像素
> event.pageX和.pageY是mouseX,mouseY
>这个上下文是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表示顶部,此高度为底部)
因此,您可以获得向量的以下参数:
renderer.devicePixelRatio * (event.pageX - this.offsetLeft) / this.width * 2 - 1,0
现在,对于下一位,几个术语:
>归一化矢量意味着将其简化为小于1的x,y和z分量.为此,您只需将矢量的x,y和z分量除以矢量的大小即可.它似乎毫无用处,但它很重要,因为它在鼠标向量的方向上创建了一个单位向量(幅度= 1)!
> Raycaster通过画布中生成的3D景观投射矢量.它的构造函数是THREE.Raycaster(原点,方向)
考虑到这些术语,我可以解释为什么我们这样做:vector.sub(camera.position).normalize().首先,我们得到描述从鼠标位置矢量到相机位置矢量的距离的矢量vector.sub(camera.position).然后,我们将其标准化以使其成为方向向量(同样,幅度= 1).这样,我们就可以在鼠标位置的方向上将摄像机从摄像机投射到3D空间!此操作允许我们通过比较对象位置和光线矢量来找出鼠标下的任何对象.
我希望这有帮助.如果您还有其他问题,请随时发表评论,我会尽快回答.
哦,不要让数学劝阻你. THREE.js本质上是一门数学繁重的语言,因为你在3D空间中操纵物体,但经验将帮助你克服这些理解障碍.我会继续学习并回答Stack Overflow的问题.培养数学能力可能需要一些时间,但如果你不尝试,你就不会学习!