PDA

View Full Version : Help getting perpendicular angle of point on sphere



mrbendel
09-06-2012, 11:09 AM
Hey Guys,

I'm trying to figure out the rotation of an object placed around a sphere. Here is the sphere with the objects unrotated:

https://dl.dropbox.com/u/5257679/sphere_unrotated.png

I can get the Y rotation by just setting y rotation to -pi2 * xProgress + pi*0.5, seen here:

https://dl.dropbox.com/u/5257679/sphere.png

But I can't figure out the X rotation and I think the way I'm going about this is flawed. If I apply what I did for Y to X I get:

https://dl.dropbox.com/u/5257679/sphere_wrong.png

The center of the sphere is just 0,0,0, so the projected vector to the surface of the sphere is just the position where each face is placed (x,y,z).

Any ideas?

Thanks! -andy

Coconut
09-06-2012, 04:59 PM
Try changing the order of rotation. For example, instead of X then Y, rotate Y then X.

Dark Photon
09-06-2012, 05:27 PM
Hey Guys,
I'm trying to figure out the rotation of an object placed around a sphere. ...

I can get the Y rotation by just setting y rotation to -pi2 * xProgress + pi*0.5...
But I can't figure out the X rotation

Not sure I completely get the jist of your question, but sounds like you just want to orient a quad tangent to a sphere at a specific point on the sphere. To do so you just need MODELING transform which positions the quad on the sphere. This MODELING transform is just a frame of reference (3 orthonormal vectors [UVW] and an origin offset).

Building this transform with vector math is often much simpler than using trig and euler angles. You know your origin offset -- it's the point on the sphere where you want your quad to touch. Your "W" vector is a vector from the center of the sphere to the point. Assuming the sphere center is 0,0,0, just normalize the position vector on the sphere. Then to get the "U" orthonormal vector, pick some generally up vector (e.g. a vector through the north pole -- say, 0,0,1), cross it with the W vector, and normalize the result. Then cross W and U to get V.

Stuff those 3 orthonormal vector (U,V,W) and the origin offset into a matrix, and you're done. No trig or euler angles required.

mrbendel
09-07-2012, 07:26 AM
Thanks for the help!

I'm trying to follow –*I'm sorry If i'm a bit slow. I think I have the W, U, V being calculated correctly, I'm just not sure what you mean by the last step - stuffing them into a matrix. Also I have to apologize in advance, I'm writing all this for webgl (javascript) so I'm using the THREEjs library. I hope the library code is clear enough. Here is what I have so far:

var x = this.vertexArray[i].x;
var y = this.vertexArray[i].y;
var z = this.vertexArray[i].z;

var cube = new THREE.CubeGeometry(20, 20, 1);
var tmp = new THREE.Mesh(new THREE.CubeGeometry(20, 20, 1));

var w = new THREE.Vector3(x,y,z);

var u = new THREE.Vector3(0,0,1);
u = u.crossSelf(w);

var v = new THREE.Vector3(0,0,0)
var v = v.cross(w,u);

var mat = new THREE.Matrix4(
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0
);

// User UVW to rotate somehow?

mat.translate(new THREE.Vector3(x*this.worldScale,
y*this.worldScale,
z*this.worldScale));

tmp.geometry.applyMatrix( mat );



Now I know my 3D math isn't the greatest, so I'm not sure what to do to make the rotations work...

Thanks,
Andy

mrbendel
09-07-2012, 10:08 AM
I got my original method working! Here's the code that ended up working right:

var mat = new THREE.Matrix4(
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0
);

mat.translate(new THREE.Vector3(x*this.worldScale,
y*this.worldScale,
z*this.worldScale));


var rotationY = (i%this.resX/this.resX) * -Math.PI*2 + (Math.PI*0.5);
var rotationX = (Math.floor(i/this.resY)/this.resY) * -Math.PI + (Math.PI*0.5);

mat.rotateY(rotationY);
mat.rotateX(rotationX);

tmp.geometry.applyMatrix( mat );

Dark Photon
09-08-2012, 06:51 PM
Glad you got an approach working. You may not care about the other method then. But just in case you're curious...


var w = new THREE.Vector3(x,y,z);
Ok, now subtract the center of the sphere from that, and normalize the result. So you have a unit vector pointing from the center of the sphere to the point on the sphere. That is:



w = normalize( (x,y,z) - center );



var u = new THREE.Vector3(0,0,1);
u = u.crossSelf(w);
var v = new THREE.Vector3(0,0,0)
var v = v.cross(w,u);

Not sure what "crossSelf does, but you want:



v = normalize( cross( w, (0,0,1) ) ); (assuming a right handed coordinate system).
u = cross( v,w );



I'm just not sure what you mean by the last step - stuffing them into a matrix.

Stuff them in the upper-left 3x3 of your 4x4 matrix, like this:



u_x u_y u_z 0
v_x v_y v_z 0
w_x w_y w_z 0
0 0 0 1


As you can see, if you premultiply this by a vector (1,0,0), you get "u". If you premultiply this by a vector (0,1,0), you get "v". Similarly for (0,0,1) -> w. You've just built a basis change matrix (i.e. the rotation matrix), without having to mess with any trig!


Now slam (x,y,z) in the last column (your translation), and you're done!

By the way, the one bit of error checking you'll want to add to the above is if "cross( w, (0,0,1) )" is (0,0,0) (i.e. the length is 0), then w and (0,0,1) are colinear. -- in this case just chose another arbitrary "up vector". If (0,0,1) points toward the north pole of your sphere, you'd only do this for points that are exactly on the north or south poles.

mrbendel
09-10-2012, 06:51 AM
Thanks for the detailed help – I'll give this a go and see if I can get it working.

/andy