Threejs Vector3 Unrpoject 相机
Threejs Vector3 Unrpoject Camera
我正在用 three-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() 函数无法提供所需的输出。
编辑:我能够通过在渲染调用之后直接移动动画来解决这个问题。这让我几乎可以肯定,没有更新相机矩阵是一个问题。我知道如何更新相机投影矩阵。如何强制更新相机的矩阵世界?
在 three.js 中,渲染器会在每个渲染循环中为您调用 camera.updateMatrixWorld()
。
如果您修改相机 position
、rotation
或 quaternion
,然后使用依赖于 camera.matrixWorld
的方法,并且如果该方法不更新 camera.matrixWorld
本身,您必须手动更新矩阵。
camera.updateMatrixWorld();
three.js r.71
我正在用 three-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() 函数无法提供所需的输出。
编辑:我能够通过在渲染调用之后直接移动动画来解决这个问题。这让我几乎可以肯定,没有更新相机矩阵是一个问题。我知道如何更新相机投影矩阵。如何强制更新相机的矩阵世界?
在 three.js 中,渲染器会在每个渲染循环中为您调用 camera.updateMatrixWorld()
。
如果您修改相机 position
、rotation
或 quaternion
,然后使用依赖于 camera.matrixWorld
的方法,并且如果该方法不更新 camera.matrixWorld
本身,您必须手动更新矩阵。
camera.updateMatrixWorld();
three.js r.71