# light as camera? for shadow maps

This topic is 4726 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

how to create a view matrix from the light-view? I have position and a direction vector but no up vector, I have tried many different things I have found about cameras and stuff like that but nothing that works.

##### Share on other sites
ha, i never thought of that. im planning on doing shadow mapping myself.
make the up vector 0,1,0
you got the front vector and cross it to get the right, have you tried that?
tell me if you have tried that yet.
anyway, ive got a question myself
can you orthogonally project to make the light a directional light?
would that work?

if you cant work it out look at the latest directx sdk, theres a shadow mapping
demo in it.

also, do you know if you can make soft shadow maps, cause thats what i really
would like.

my games bump mapped and if the shadows are soft the game will kick command and
conquer generals butt.

http://www.geocities.com/magnus_wootton/Building.jpg

##### Share on other sites
Since it doesn't really matter, just use some arbitrary vector for the up vector, like [0,1,0]. If the light's direction is nearly parallel to that vector (i.e. abs(L dot Up) > .707), then pick another vector that is perpendicular to it, like [1,0,0]. One of the two will work.

##### Share on other sites
Supposing that up is the vector (0, 1, 0) and target and eye are classic look at parameters:

    vector3 z(target-eye); //Get the z vector    z.Normalize();        vector3 x(up*z);   //crossing z and (0, 1, 0) to get x vector    x.Normalize();        vector3 y(z*x);  //crossing z and x and you get you correct up vector

That should be what you need.

##### Share on other sites
When I need an up vector for a light source that doesn't naturally have one I use this function to get some perpendicular vector (HLSL code):

float3 GetPerpendicular(float3 vec){	float3 absvec=abs(vec);		float3 result;		if (absvec.x<absvec.y)	{		if (absvec.x<absvec.z)		{	//x is smallest			result.x=0.0f;			result.y=vec.z;			result.z=-vec.y;		} else		{	//z is smallest			result.z=0.0f;			result.x=vec.y;			result.y=-vec.x;		}	}	else	{		if (absvec.y<absvec.z)		{	//y is smallest			result.y=0.0f;			result.x=vec.z;			result.z=-vec.x;		} else		{	//z is smallest			result.z=0.0f;			result.x=vec.y;			result.y=-vec.x;		}	}		return result;}

Just normalize and you are done.

##### Share on other sites
Quote:
 Original post by cignox1Supposing that up is the vector (0, 1, 0) and target and eye are classic look at parameters: vector3 z(target-eye); //Get the z vector z.Normalize(); vector3 x(up*z); //crossing z and (0, 1, 0) to get x vector x.Normalize(); vector3 y(z*x); //crossing z and x and you get you correct up vectorThat should be what you need.

I have tried that several times, but without any success.. at the moment I use the light as camera and render from it's view just so that I can make sure it is "looking" at the correct stuff, but it isn't I have made a small function that draws a line from the lights position and to it's "lookat" point and that works ok..

muhkuh: I'll try that one, maybe it works :)

##### Share on other sites
I don't know if you found a solution of your problem, but if not, then what do you need exactly? Perhaps I misunderstood you question: if you need the 'up' vector of your camera, then the code posted should work (it works for me). If you need the view-at matrix in order to be able to move and rotate it and to make it look at a specific point, you have to build the view-at matrix as always, and then invert it.
That is, if you want to make your light look at the (x y z) point, you have to build the lok-at matrix with the position of your light as the parameter 'eye', the point you want to look at as the at parameter and the (0,1,0) vector as the up (if you function does not calculate the actual up vector itself, you will need to do it) and then invert the resulting matrix.
Then you transform your light with this matrix.

##### Share on other sites
I would like to create a view matrix using only the eye and lookat target, by creating my own right and up vectors..

if I don't remember wrong the matrix looks something like this

m.identity();
m[0,0] = right.x; m[1,0] = up.x; m[2,0] = lookatdir.x;
m[0,1] = right.y; m[1,1] = up.y; m[2,1] = lookatdir.y;
m[0,2] = right.z; m[1,2] = up.z; m[2,2] = lookatdir.z;

then I multiply that matrix with a translation matrix like this

t.identity();
t.translate( -x, -y, -z );

result.identity();
result = m * t;

and then the result is the final modelview matrix. or have I missed something?

EDIT: the problem is when I have the light/camera at 0,30,0 lookat dir 0,-1,0 then the up can't be 0,1,0 and I can't get a working one either

##### Share on other sites
Ok, that's how I set up my look-at matrix. I use a left-handed coordinate system (that is x positive right, y positive up and z positive far from the screen) with a ROWxCOL matrix system, and you may need to modify it to fit yours systems:
void matrix::LookAt(vector3 &eye, vector3 &target, vector3 &up){    if(eye == target)     {        Identity();        return; //eye and target are the same    }        vector3 z(target-eye);    z.Normalize();        vector3 x(up*z);       x.Normalize();        vector3 y(z*x);        mat[0][0] = x.x;    mat[0][1] = x.y;    mat[0][2] = x.z;    mat[0][3] = -(x^eye);      mat[1][0] = y.x;    mat[1][1] = y.y;    mat[1][2] = y.z;    mat[1][3] = -(y^eye);     mat[2][0] = z.x;    mat[2][1] = z.y;    mat[2][2] = z.z;    mat[2][3] = -(z^eye);      mat[3][0] = 0;    mat[3][1] = 0;    mat[3][2] = 0;      mat[3][3] = 1;  }

You don't need to specify right vector and the up vector is always (0,1,0) (except if you want your camera to be reversed, but for a light it is not tha case). This function (that is pretty the same to the one in the DXSDK) takes your parameters and builds the three vectors it needs in order to set a local coordinate system realted to the camera (light in your case).
The following section of the function builds these three vectors
    vector3 z(target-eye);    z.Normalize();        vector3 x(up*z);       x.Normalize();        vector3 y(z*x);

When applied to a vector, the matrix transforms the original point in the new coordinate system (hope to be right, I'm new to this).
What you need to know are only position and the look-at point of your light.
For the use with an up and z vectors that coincide (or are too much paralel), you can try to add a check and use (1, 0, 0) instead, as JhonBolton said.

##### Share on other sites
what is the ^ for? mat[0][3] = -(x^eye); is that the dotproduct between x and eye?

EDIT: what is the difference between the right and lefthanded view matrices and ROWxCOL based vs. COLxROW based?

##### Share on other sites
Quote:
 what is the ^ for? mat[0][3] = -(x^eye); is that the dotproduct between x and eye?

Yes, I use this overloaded operator as dot product. I thought it would be pretty useful (and it is) but it seems to be not often used since everyone ask me what does it mean. It could be wrong using the ^ as the dot product (I don't remember precedece rules) but I don't care now...
There are differences between right-handed and left-handed coordinate systems. In general, left-handed system (as the one used by DX) have the positive values going into the screen, while in right-handed ones (OGL and many others) the positive side of the z axis come out from the screen.
You can find some useful informations about that with google.
With ROWxCOL I simply specify that the first index of my matrix indicates the ROW, while the second indicates the COLUMN. This different order changes the matrices I build (in fact to change from one to another you have to transpose your matrix).
I think that choosing the coordinate sytsem and the index-order is a matter of taste, but I have to specify it when I post the code...
Hope that this helps.

##### Share on other sites
still doesn't work as I want to, altough it works exactly the same as gluLookAt(...):

my lookat function
void cMatrix::CreateLookat( cVertex3f &eye, cVertex3f &target, cVertex3f &up ){        Identity();	cVertex3f z = eye - target;	z.Normalize();	cVertex3f x;	x.CrossProduct(up, z);	x.Normalize();	cVertex3f y;	y.CrossProduct( z, x );	y.Normalize();	cout << "X axis " << x << endl;	cout << "Y axis " << y << endl;	cout << "Z axis " << z << endl;	m[VAL(0,0)] = x.x; m[VAL(0,1)] = y.x; m[VAL(0,2)] = z.x;	m[VAL(1,0)] = x.y; m[VAL(1,1)] = y.y; m[VAL(1,2)] = z.y;	m[VAL(2,0)] = x.z; m[VAL(2,1)] = y.z; m[VAL(2,2)] = z.z;	m[VAL(3,0)] = -(x.DotProduct(eye));	m[VAL(3,1)] = -(y.DotProduct(eye));	m[VAL(3,2)] = -(z.DotProduct(eye));}

this is the matrix I get with eye(0,30,0) lookat(0,0,0) up(0,1,0):
0 0 0 0
0 0 1 0
0 0 0 0
0 0 -30 1

if I have the eye at 0,30,0 then the lookat dir should be 0,-1,0 and the up would be 0,0,-1 and right 0,0,1.. but all vectors except lookat gets 0,0,0

##### Share on other sites
Try to check if the (eye - target) vector is too much similar to your up vector. Replace the first part of your function with:
Identity();cVertex3f z = eye - target;z.Normalize();if((abs(z.x) < 0.0001) && ((abs(z.y) - 1.0) < 0.0001) && (abs(z.z) < 0.0001)) up = cVertex3f(0.0, 0.0, 1.0);

Put this just before

cVertex3f x;

Hope that this works. The idea is to check if the (eye - target) vector is near (0, 1, 0). If this is the case (and in your example it is (0, -1, 0) then you cannot have a perpendicular vector.

EDIT: I've just tried on my code and I had the same problem: with your camera position and look at point it doesn't work. But I added the check and now it runs.