I'm currently working on a project using three-js where I am attempting to project 2D coordinates onto a sphere within the virtual world.
The code snippet below functions perfectly when bound to the mousedown event:
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(); // represents ray or direction of click in world coordinates
// Code for Ray Sphere Intersection provided below (which is assumed to be correct)
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){ // indicates an intersection was found
return camera.position.clone().add(l.multiplyScalar(d));
}
return null; // No intersection found
}
However, upon trying to utilize this function in the following piece of code, the function consistently returned null (indicating no intersections were detected).
get_random_point(scale){ // scale denotes the projected radius (in pixels) of the sphere
while (true){ // keep iterating until a valid point is obtained
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 obtained point
}
}
}
}
This above code snippet is executed approximately 100 times each animation cycle to select a random visible point on the sphere's surface based on the camera view.
The issue arises once the camera position has been altered. The method I use to control the camera involves orbiting it around the sphere using the mouse.
At one point, I managed to output all variables declared inside the project function to the JavaScript console during such occurrences. Upon testing the same function with identical camera positioning and coordinates in another tab, I discovered that the calculated ray was inaccurate.
Following are the functions related to controlling the camera:
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 increments by 120 units
} else {
movement = event.deltaY/-3; // DeltaY increments by 3 units
}
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));
}
I have been unable to determine why the project function behaves differently when called from the animation loop compared to outside of it.
My assumption is that alterations to the camera during mouse movements may result in the insufficient update of the camera matrices, leading to discrepancies in the output of Three.Vector3.unproject() function.
UPDATE: The problem was resolved by rearranging the animation immediately after the render call. This strongly suggests that the issue stemmed from outdated camera matrices. While I understand how to update the camera projection matrix, I am unsure of how to enforce updating the camera's matrix world. Any guidance on this matter would be greatly appreciated.