I am trying to program an input mechanism wherein the player is standing inside -- but not necessarily at the center -- of a sphere whose interior is populated with video-textured quads. By clicking and dragging, the player may reposition those quads along the interior surface of the sphere. Note that there is no actual geometry for the sphere, rather it is implied by the plastering of video-textured quads all over its interior.
I tried so many ways to get the quads to move correctly... rotating about the sphere origin in objectspace, cameraspace, donkeyspace...
My current approach is to do classic ray-sphere intersection based on where the player clicked. I will then snap the selected video-textured quad to that position.
Now, I know the origin and radius of the sphere and I should be able to figure out the origin and direction of the ray using this approach:
http://antongerdelan.net/opengl/raycasting.html
For collision, I am using the ray-sphere intersection code from Peter Shirley's "Ray Tracing in a Weekend" (not online)
My results are off though -- I am getting hits but not where I expect -- and I don't know where I am going wrong.
Hunches as to my mistakes:
1. Anton's comments about not needing to unproject might be biting me... I have no idea why to use 0.5 for z...
2. Maybe I should just build the ray myself without unprojecting -- I can use the camera FOV and near plane distance to build a ray per-pixel.
3. I probably am mixing up my spaces... moving the camera seems to change my results.
4. What sort of values should I be seeing for cameraspace clicks? I expected huge x and y values but they seem to be constrained to [-1...1].
5. Detecting ray-sphere intersection is different if you are inside the sphere (I am testing with an external sphere first)
Thanks for any help! I feel like this should be raycasting 101!!!
P.S. I am using threejs
P.P.S. But I would like to understand this problem in a library-agnostic manner
// via anton
var screen_x = event.touches[0].clientX;
var screen_y = event.touches[0].clientY;
var ndc_x = screen_x / window.innerWidth;
var ndc_y = screen_y / window.innerHeight;
ndc_x = (2.0 * ndc_x) - 1.0;
ndc_y = (2.0 * ndc_y) - 1.0;;
ndc_y *= -1.0;
var clipspace_x = ndc_x;
var clipspace_y = ndc_y;
var clipspace_z = -1.0;
var clipspace_pos = new THREE.Vector4(clipspace_x, clipspace_y, clipspace_z, 0.0);
clipspace_pos.applyMatrix4(this.main_camera.matrixWorldInverse);
clipspace_pos.z = -1.0;
clipspace_pos.w = 0.0;
var cameraspace_pos = clipspace_pos.clone();
cameraspace_pos.normalize();
var sphere_center = new THREE.Vector3(0, 0, -40);
var sphere_radius = 10.0;
var ray_origin = new THREE.Vector3(0, 0, 0);
var ray_direction = cameraspace_pos.clone();
// via peter shirley
var center_to_origin = ray_origin.clone();
center_to_origin.sub(sphere_center);
var a = ray_direction.clone().dot(ray_direction);
var b = 2.0 * center_to_origin.clone().dot(ray_direction);;
var c = center_to_origin.clone().dot(center_to_origin) - (sphere_radius * sphere_radius);
var discriminant = b*b - 4*a*c;
if (discriminant >= 0.0) console.log('********************** YOU HIT ME ****************************');