how to compute vector projection matrix

Started by
5 comments, last by soconne 18 years, 2 months ago
I'm trying to create a matrix that projects one vector onto another. I already know to accomplish this you do: v' = (v*n)n where v is your original vector and n is the direction you wish to project to. But after projection, I need v' to be the same length as v, which does not happen doing normal projection. I already know how to build the matrix which does the above, but how do you build a matrix that also preserves vector length after the transformation? I want to be able to orient an object on terrain so that it's y-axis points in the direction of the surface normals.
Author Freeworld3Dhttp://www.freeworld3d.org
Advertisement
Is there any particular reason you can't just normalize the vectors?
You need a rotation matrix R that would rotate v such that R*v would "point" to the same direction as n.

You could construct such a matrix by creating a rotation quaternion and then converting the quaternion to rotation matrix.

Another way is to use Rodrigues' rotation formula, and construct the matrix directly:

R = I + sin(a)*[w] + (1-cos(a))*[w]2,

where:
I - Identity matrix
a - Angle between v and n ( ex: ArcCos( Dot(v, n) ) )
w - Normalize( Cross( v, n ) )
[w] - The cross matrix such that for any vector u: [w]*u = Cross( w, u ).

If both v and u are normalized, the process can be seriously optimized:

R = I + [w] + b*[w]2,

where:
w - Cross( v, n )
b - 1/(1 + Dot( v, n ))


I can already construct a matrix that performs the rotation of v to n. What I need is a matrix that preserves the length of v AFTER the rotation.

Plus it does not matter if v and n are already normalized. The projection of v onto n does NOT have a length of 1.
Author Freeworld3Dhttp://www.freeworld3d.org
Quote:Original post by oconnellseanm
I can already construct a matrix that performs the rotation of v to n. What I need is a matrix that preserves the length of v AFTER the rotation.
A properly constructed rotation matrix does preserve the length of the vector it operates on, so this shouldn't even be an issue. Are you sure you're building the rotation matrix correctly? If you're not sure, you could post the code for us to look at...
Here's my code:

void normalize(float *n){	float mag = sqrt(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]);	n[0] /= mag;	n[1] /= mag;	n[2] /= mag;}float mag(float *n){	return sqrt(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]);}int _tmain(int argc, _TCHAR* argv[]){ 	float v[] = {1, 0, 0};	float n[] = {1, 1, 0};	float m[9];	normalize(n);	m[0] = n[0]*n[0];	m[1] = n[1];		m[2] = n[2];	m[3] = n[0];		m[4] = n[1]*n[1];	m[5] = n[2];	m[6] = n[0];		m[7] = n[1];		m[8] = n[2]*n[2];	float v0[3];		v0[0] = m[0]*v[0] + m[3]*v[1] + m[6]*v[2];	v0[1] = m[1]*v[0] + m[4]*v[1] + m[7]*v[2];	v0[2] = m[2]*v[0] + m[5]*v[1] + m[8]*v[2];	printf("After transform: v={%f,%f,%f}  l=%f\n", v0[0], v0[1], v0[2], mag(v0));		normalize(v0);	printf("Rescale: v={%f,%f,%f}  l=%f\n", v0[0], v0[1], v0[2], mag(v0));	return 0;}



I basically given my direction vector n I construct the rotation matrix like so:

    m = [  nx*nx    ny        nz     ]        [  nx       ny*ny     nz     ]        [  nx       ny        nz*nz  ]
Author Freeworld3Dhttp://www.freeworld3d.org
Okay, I figured it out. I was WAY OFF on how to calculate this correctly. Here's the actualy correct solution.

	Vector3 v(1, 0, 0);	Vector3 n(1, 1, 0);	n.normalize();	Vector3 axis = crossProduct(v, n);	axis.normalize();	float theta = angle(v, n);	Matrix4 mat;	mat.identity();	mat.setupRotate(axis, theta);	Vector3 v0 = v * mat;	printf("new v = [%f %f %f]\n", v0.x, v0.y, v0.z);


So basically what I finally realized is that you just take the cross product of your vector v and n, then find the angle between the two vectors..........then simply rotate theta radians around the cross product vector. That's it.
Author Freeworld3Dhttp://www.freeworld3d.org

This topic is closed to new replies.

Advertisement