【发布时间】:2015-09-20 12:54:05
【问题描述】:
我正在用三个 js 开发一个项目。我正在尝试将 2D 坐标投影到世界上的球体上。
当我将函数绑定到 mousedown 事件时,以下代码可以完美运行:
function project(point){
var x = 2 * (point[0] - width/2) / width;
var y = 2 * (point[1] - height/2) / height;
var l = new THREE.Vector3(x, y, 0.5);
l.unproject(camera);
l.sub(camera.position).normalize(); // ray / direction of click on world coordinates
// Below is code for Ray Sphere Intersection (I'm certain this works)
var omc = camera.position.clone().sub(sphere.position);
var ldomc = l.dot(omc);
var d = -ldomc - Math.sqrt(ldomc*ldomc - omc.lengthSq() + radius*radius);
if (d == d){ // if there was an intersection
return camera.position.clone().add(l.multiplyScalar(d));
}
return null; // If no intersection was found
}
但是,当我尝试在以下代码中使用上述函数时,该函数仅返回 null(没有找到交集)。
get_random_point(scale){ // scale is the projected radius (in pixels) of the sphere
while (true){ // continue until a point works
var a = Math.random();
var b = Math.sqrt(Math.random());
var x = width/2 + scale * b * Math.cos(2 * Math.PI * a);
var y = height/2 + scale * b * Math.sin(2 * Math.PI * a);
if (width > x && x >= 0 && height > y && y >= 0){
var projp = project([x,y]);
if (projp != null){
return toSpherical(projp); // Return spherical coordinates of point
}
}
}
}
上述代码在每个动画循环中被调用约 100 次,以在球体表面上选取一个相机可见的随机点。
仅在移动相机后才会出现此问题。 我使用鼠标控制相机使其绕球体旋转。
发生这种情况时,我设法将项目内声明的所有变量转储到 javascript 控制台。然后我在不同的选项卡中用相同的相机位姿和点测试了项目功能,发现计算的光线不正确。
以下是相机控制功能:
d3.select("body").on("mousedown", function(event){
m0 = d3.mouse(this);
});
d3.select("body").on("mousemove", function(event){
if (m0 != null){
var m1 = d3.mouse(this);
var mv = [m1[0] - m0[0], m1[1] - m0[1]];
theta -= mv[0]*0.25/180.0*Math.PI;
phi += mv[1]*0.25/180.0*Math.PI*camera.up.y;
if (phi > Math.PI/2){ phi = Math.PI - phi; camera.up.y *= -1; theta += Math.PI}
if (-Math.PI/2 > phi){ phi = -Math.PI -phi; camera.up.y *= -1; theta += Math.PI}
while (theta >= 2 * Math.PI){ theta -= 2 * Math.PI; }
while ( 0 > theta){ theta += 2 * Math.PI; }
camera.position.x = r * Math.sin(theta) * Math.cos(phi);
camera.position.y = r * Math.sin(phi);
camera.position.z = r * Math.cos(theta) * Math.cos(phi);
camera.lookAt(new THREE.Vector3(0, 0, 0));
m0 = m1;
}
});
d3.select("body").on("mouseup", function(event){
m0 = null;
}).on("mouseleave", function(event){ m0 = null; });
function Zoom(event){
var movement;
if (event.wheelDelta){
movement = event.wheelDelta/120; // wheelDelta is in increments of 120
} else {
movement = event.deltaY/-3; // DeltaY is in increments of 3;
}
r -= 0.05 * movement;
if (0.9 > r){
r = 0.9;
} else if (r > 2.5){
r = 2.5;
}
camera.position.x = r * Math.sin(theta) * Math.cos(phi);
camera.position.y = r * Math.sin(phi);
camera.position.z = r * Math.cos(theta) * Math.cos(phi);
camera.lookAt(new THREE.Vector3(0, 0, 0));
}
我似乎无法弄清楚为什么项目函数在不从动画循环中调用时会适用于相同的点和相机姿势。
我的猜测是相机在鼠标运动回调期间被修改,但相机的矩阵之一没有更新,导致 Three.Vector3.unproject() 函数没有提供所需的输出。
编辑:我能够通过在渲染调用之后直接移动动画来解决这个问题。这让我几乎可以肯定,没有更新相机矩阵是个问题。我知道如何更新相机投影矩阵。如何强制相机的矩阵世界更新?
【问题讨论】:
-
我无法为您调试代码,但请尝试在您修改相机位置后立即调用
camera.updateMatrixWorld()。此外,在紧密循环中,请避免使用new和clone()。改为使用copy()方法创建一个实例并重用它。 -
您好,感谢您的回复。我会尝试 updateMatrixWorld 方法。关于不要在紧密循环中使用 new/clone() 的好建议。我应该避免重复创建新对象实例的额外成本。
标签: javascript three.js projection