Up Vector calculation for matrices

I’m trying figure out a problem with my ‘lookat’ matrix.

Let’s say I have +Z as a direction, but I need the +Y vector, without any other information. Does anyone have a solution?

Thanks in advance

It isn’t possible.

Knowing which way is forwards does not enable you to work which way is up.

So how should I handle this? I’m using a lookat matrix, and it needs a forward, and up vector. The forward is constantly varying…

Well, I’m not sure what you’re trying to achieve, but (0.0, 1.0, 0.0) would be a pretty good bet.

if you start in a known position, then just rotate this matrix in a similar way to how your camera rotates the world and it should automatically give you all vectors

You’ll have to clarify the question. If a matrix represents simply rotation+translation, then the columns (or rows depending on your chosen convention) represent how this transformation is related to its parent. So like the pictured matrix you can direct extract the “directions” of that local coordinate frame. (The dot product is a parallel projection operator). So if the parent is “world” and then this matrix’s x,y,z match some forward, up and right or left, again depending on the chosen convention. Say right handed and Z is up, X is right and Y is forward, then 0=right, 1=forward and 2=up…where the numbers are the row or column. Is this your question?

I’m trying to calculate a lookat matrix to render the scene from the light’s perspective with only given a direction and position. I have it all worked out except for the up vector. I could just make it so the Y value of vector Z doesn’t change, so the up vector remains (0, 1, 0), but that doesn’t solve my problem.

Okay you have a direction and a point. You don’t need to think about the point since that’s just the translation part. So the question becomes what do you want? You have a logically infinite number of choices to complete your basis so what’s important?

point + direction. … up ? not sure, i dont understand what you’re after :clue:

if you dont care how tilted your projection is, you could find the smalles component and cross the direction with a vector pointing into the smalles component :

vec3 axis                               = new vec3(1.0f, 0.0f, 0.0f); // assume x is smallest
if(dir.y < dir.x && dir.y < dir.z) axis = new vec3(0.0f, 1.0f, 0.0f);
if(dir.z < dir.x && dir.z < dir.y) axis = new vec3(0.0f, 0.0f, 1.0f);

vec3 up = normalize(cross(dir, axis));

with that …

mat4 lookat = new mat4(-side.x, -side.y, -side.z,  dot(side,pos),
                          up.x,    up.y,    up.z, -dot(up,pos),           
                        -dir.x,  -dir.y,  -dir.z,  dot(dir,pos),   
                          0.0f,    0.0f,    0.0f,  1.0f);

this would be row-major. need to transpose before sending to GL.
sign of the side might be + if you compute it to the other side.

vec3 side = cross(up,dir); // cross(dir,up)

What you do is assume that the camera isn’t going to be upside down and so “up” will be in the same direction as (0, 1, 0) (by which I mean (dot(up, (0, 1, 0)) > 0). So with that in mind you assume the up vector is (0, 1, 0), calculate the left vector then you have the left and forward vectors from which to calculate the actual up vector.

Pseudo code cos everyone loves a bit of pseudo code.


Matric calcMatrix(Vector forward) {
    Vector up = new Vector(0, 1, 0);
    Vector left = cross(up, forward); //I think it is that way round, might be the other way though. "i"s, "j"s and "k"s confuse me.
    up = cross(forward, left); //Ditto as above.
    left.normalize();
    up.normalize();
    return createOrthoBasisMatrix(left, up, forward); //Make the matrix. 
}

Like I said. There’s an infinite number of solutions. Until OP says what he wants…toss some out isn’t really useful. Or I’m not reading too good.

I’m looking for a solution to that I can’t render the scene from the light’s perspective, because I’m only given a direction and not and up-vector.

Okay, I tried this out with a vector of (0, 1, 0) or (0, -1, 0) and it returned (0, 0, 0) and (NaN, NaN, NaN) normalized (because of the division by zero). Pretty much everything else worked.

Yeah, sorry. Forgot to say you have to check for this unique case.

Only normalize a vector when the length isn’t one. That should fix this issue.

Setting the direction to a vector of (0.1, -1.0, 0.0) or (0.0, -1.0, 0.001) seems to work perfectly.

Thanks a bunch!

The issue is that when you cross two parallel vectors, you get a zero magnitude vector so if the forward vector is (0, 1, 0) or (0, -1, 0). Then you normalize a zero vector (giving NaN) or cross it to get another vector (giving another zero vector).

It’ll work until you have a forward vector of (0.1, -1, 0) or (0, -1, 0.001). If you are in a situation where your forward vector might be pointing straight up, better to do a check to make sure it doesn’t. One conditional is not going to be noticed.

Okay, works fine… Thanks!

Vector3f up = new Vector3f(0, 1, 0);
if(!direction.equals(new Vector3f(0.0f, 1.0f, 0.0f)) && !direction.equals(new Vector3f(0.0f, -1.0f, 0.0f))){
	Vector3f left = new Vector3f();
	left.cross(direction, up);
	up.cross(direction, left);
	left.normalize();
	up.normalize();
} else {
	up = new Vector3f(0, 0, 1);
}
Matrix4f out = ViewTransformComponent.lookat(position, direction, up);
out.mul(depthProjection);

Use the dot product as the test value vs. some threshold instead. The problem is in all approaching values.