Three.js - 推开然后在“鼠标移动”上恢复元素位置
Posted
技术标签:
【中文标题】Three.js - 推开然后在“鼠标移动”上恢复元素位置【英文标题】:Three.js - Push away and then restore elements position on "mouse move" 【发布时间】:2016-06-29 13:35:24 【问题描述】:大家好,我正在Three.js
开发一个项目,用户可以在其中hover
镶嵌面,并且每个网格在与不可见的球体相交时都应该被推开,当它在外面时回到原来的位置从它的区域。我使用this 和this example 作为参考,但我被卡住了,因为我不知道如何使它在Three.js
中工作。
在我的代码中,我可以hover
网格的每个面,使其变为红色并在鼠标消失后恢复其原始颜色。但我不能对这个职位做类似的事情。这是我认为问题所在的代码部分:
if (intersects.length > 0)
// if the closest object intersected is not the currently stored intersection object
if (intersects[0].object != INTERSECTED)
// Restore previous intersection objects (if they exist) to their original color
if (INTERSECTED)
INTERSECTED.face.color.setHex(INTERSECTED.currentHex);
// Intersected elements
INTERSECTED = intersects[0];
var intGeometry = INTERSECTED.object.geometry;
var intFace = INTERSECTED.face;
// Difference between intersected faces and geometry
INTERSECTED.currentHex = intFace.color.getHex();
intFace.color.setHex(0xc0392b);
intGeometry.colorsNeedUpdate = true;
// Identify the vertices of each face
var intVertices = intGeometry.vertices;
var v1 = intVertices[intFace.a],
v2 = intVertices[intFace.a],
v3 = intVertices[intFace.a];
// Calculate the centroid of the selected face
var intPosition = new THREE.Vector3();
intPosition.x = (v1.x + v2.x + v3.x) / 3;
intPosition.y = (v1.y + v2.y + v3.y) / 3;
intPosition.z = (v1.z + v2.z + v3.z) / 3;
console.log(intPosition);
通过console.log()
我可以看到人脸及其位置都被正确识别,但是球体没有正确跟踪鼠标,我需要位置方面的帮助。这是带有完整代码的JSFiddle。
【问题讨论】:
要让球体跟随鼠标,您需要将屏幕坐标转换为threejs的世界位置。 Check this link 。并更新fiddle here,更改代码从第 375 行开始。 谢谢你!这是another question问题的一部分,我问过,如果你愿意,你可以在那里发布答案并获得奖励。 【参考方案1】:您遇到的问题是您尝试使用ray.intersectObjects
的targetList
是不是 THREE.Mesh
实例。
因此,当您尝试访问 intersectedFace.acc
时会抛出错误
【讨论】:
我已经编辑了这个问题,也许你可以再试试看。谢谢!【参考方案2】:您没有将某些东西分配回您的几何体。大意:
intVertices[intFace.a].copy( intPosition );
intVertices[intFace.b].copy( intPosition );
intVertices[intFace.c].copy( intPosition );
intGeometry.verticesNeedUpdate = true;
intGeometry.normalsNeedUpdate = true;
【讨论】:
帅哥!但是我应该如何存储和重置位置?因为现在hover
上的每个区块都消失了。
我猜你需要另一个数组/缓冲区来保存你的顶点的state
这是一种可能性,我认为实现这一点的方法是每当与鼠标的距离低于球体半径时,将tessellated face
的质心推出。然后当它出来时,将它送回原来的位置。你怎么看?
为什么使用质心(这是额外的计算)而不是顶点本身?【参考方案3】:
这是一个关于这个主题的小测试: https://jsfiddle.net/77xvepp7/
它还不能正常工作,我将相机移动了一点,以便可以看到这个想法。
基本思想是从曲面中选择一个顶点作为“基点”,它可以是曲面的中心,就像您在示例中所做的那样,并保持该点作为参考点以移动所有其他点三角形的数量相同。如果不保存原始值,那么下一轮可能会有无效值,三角形会随机移动。
然后你计算鼠标到“基点”的距离,遍历所有顶点并将它们移动到基点的方向一些量。如果距离大于某个定义的量,则从顶点恢复原始值。
您可能会尝试使用顶点着色器来做到这一点,但问题是当鼠标在表面上时,每个顶点都会朝相反的方向移动,并且鼠标下方的三角形会缩放以填充空隙。选择一个点作为“基点”可以解决这个问题。
// Modify the geometry
var geometry = backgroundMesh.geometry;
for ( var i = 0, il = geometry.faces.length; i < il; i ++ )
var face = geometry.faces[ i ];
if ( face instanceof THREE.Face3 )
var a = geometry.vertices[face.a];
var b = geometry.vertices[face.b];
var c = geometry.vertices[face.c];
var vList = [a,b,c];
// The trick is to save the original face positions
if(!a.origXSet)
a.origX = a.x;
a.origY = a.y;
a.origZ = a.z;
a.origXSet = true;
var vect = a;
var dx = (vect.origX - pos.x),
dy = (vect.origY - pos.y),
dz = (vect.origZ - pos.z);
// distance to the mouse
var dist = Math.sqrt( dx*dx + dy*dy);
// magic constant, react if distance smaller than 4
if(dist < 4)
vList.forEach(function(v)
if(!v.origXSet)
v.origX = v.x;
v.origY = v.y;
v.origZ = v.z;
v.origXSet = true;
var len = Math.sqrt(dx*dx + dy*dy + dz*dz);
if(len==0) return;
var ndx = dx / len,
ndy = dy / len,
ndz = dz / len;
v.x = v.origX + ndx * 2; // move 2 pixels
v.y = v.origY + ndy * 2;
v.z = v.origZ + ndz * 2;
);
else
// otherwise, reset coordinates
vList.forEach(function(v)
if(v.origXSet)
v.x = v.origX;
v.y = v.origY;
v.z = v.origZ;
);
geometry.verticesNeedUpdate = true;
geometry.normalsNeedUpdate = true;
主要问题是:鼠标指针在世界坐标中的位置计算不正确。现在我没有精力考虑如何纠正这个问题,但决定发布这个答案,以便您可以继续。
【讨论】:
以上是关于Three.js - 推开然后在“鼠标移动”上恢复元素位置的主要内容,如果未能解决你的问题,请参考以下文章
如何通过鼠标移动事件获取相机位置并在three.js中转换为屏幕坐标? [关闭]
在鼠标移动中创建涂抹/液化效果,使用webgl连续动画回原始状态