Are you using the right amount of vertices/triangles/whatever when doing the draw call?
THAT WAS IT! Thank you very much, can't believe I didn't consider that.
Not Telling
tempvar hasn't added any contacts yet.
14 February 2013 - 06:42 PM
Are you using the right amount of vertices/triangles/whatever when doing the draw call?
THAT WAS IT! Thank you very much, can't believe I didn't consider that.
14 February 2013 - 05:46 AM
Tried GL_DYNAMIC_DRAW but no change.
03 January 2013 - 12:02 PM
Well, err ... forgotten that OpenGL uses a camera that looks along the negative z axis. So although the (unnormalized) forward vector is
forward := target - pos
it doesn't point in the same direction as rowZ from the matrix, because rowZ is (per definition) along the positive z axis.
Also
rowY = crossProd(&rowX, &rowZ); // new rowY
should probably better be
rowY = crossProd(&rowZ, &rowX); // new rowY
to match the other cross-product.
With a little bit of clean-up, what's about the hopefully-now-considering-all-caveats-solution:
Matrix4x4 createView( Vector3* pos, Vector3* target, Vector3* up ) { Matrix4x4 cameraMat; Matrix4x4 view; Vector3 vX; Vector3 vY; Vector3 vZ; // computing vZ as the unit vector to look along vZ = sub(pos, target); normalise(&vZ); // computing vX being orthogonal on the plane of up and vZ; considering // its place in the ortho-normal basis later, this means up x vZ vX = crossProd(up, &vZ); normalise(&vX); // computing vY being orthogonal on the plane of vZ and vX; considering // its place in the ortho-normal basis later, this means vZ x vX vY = crossProd(&vZ, &vX); normalise(&vY); // building basis ... setColv(&cameraMat, 0, &vX, 0.0f); setColv(&cameraMat, 1, &vY, 0.0f); setColv(&cameraMat, 2, &vZ, 0.0f); // ... and injecting position setColv(&cameraMat, 3, pos, 1.0f); // inverting camera matrix to yield in the view matrix view = inverseMat4(&cameraMat); return view; }
Please notice that looking along the negative axis also has an implication on the code when pressing W a.k.a. "go forward". In fact, you need to go in direction of the negative 3 column vector then.
Hey, thank you for your reply. Sorry it took me a couple days to get back to you.
I managed to get it working, but not exactly 100% how you've shown me.
Matrix4x4 createView(Camera* cam)
{
Matrix4x4 cameraMat;
Matrix4x4 view;
Vector3 rowZ;
Vector3 row4 = { cam->pos.x, cam->pos.y, cam->pos.z };
Vector3 rowX;
Vector3 rowY;
Vector3 target;
target = addVec(&cam->pos, &cam->dir);
rowZ = sub(&target, &cam->pos);
normalise(&rowZ);
setEqual(&rowY, &cam->up);
rowX = crossProd(&rowY, &rowZ);
normalise(&rowX);
rowY = crossProd(&rowZ, &rowX);
normalise(&rowY);
setRowv(&cameraMat, 0, &rowX, 0.0f);
setRowv(&cameraMat, 1, &rowY, 0.0f);
setRowv(&cameraMat, 2, &rowZ, 0.0f);
setRowv(&cameraMat, 3, &row4, 1.0f);
view = inverseMat4(&cameraMat); // has to be inverse for camera transformations
return view;
}
I've changed a couple things such as passing in the camera and accessing the data from that, just easier. I was still getting weird results using setColv function, so I fixed up the setRowv function and that is what has made it work for me (not entirely sure why because setColv should be working anyway).
void setRowv( Matrix4x4* m, int rowNum, Vector3* v, float w )
{
int index1 = (0 * 4) + rowNum;
int index2 = (1 * 4) + rowNum;
int index3 = (2 * 4) + rowNum;
int index4 = (3 * 4) + rowNum;
m->m.m1[index1] = v->x;
m->m.m1[index2] = v->y;
m->m.m1[index3] = v->z;
m->m.m1[index4] = w;
}
Also I found out that changing the cam->up vector was actually causing weird rotations. But as long as I calculate the rowX as the cross product of the up vector (0, 1, 0) it works. If the up vector is set to the new rowY it gets messed up and I seem to experience some roll when moving the camera around.
Thank you for your help and explanations, I've think this should be ok from here, feel free to chime in if you notice why its working like this ![]()
02 January 2013 - 07:30 AM
First I have to apologize that I've made a mistake. The correct computation for column-major indices is
index := col * 4 + row
so that e.g. col == 1 skips the first 4 elements (i.e. column vector 0) and addresses m1[4] up to m1[7] (i.e. the 2nd column) in dependence on row.
The second problem is with the order of inverseMat4 and setting the position vector. The position is an inherent part of the transformation. As such the camera matrix is a composition of
M := T * R
and its inverse is
M-1 = ( T * R )-1 = R-1 * T-1
Your current computation gives
T * R-1
what is obviously different in 2 ways: The translation is not inverted, and the translation is applies on the wrong side.
So please invoke inverseMat4 as last step after setting all 4 columns and just before returning the view matrix result.
Ah ok, makes sense.
I've made those changes and I can see my object again. It's rotating weirdly though as I look around the screen and if I translate the view changes and then after a second or so it disappears. Also my object is a terrain, but it looks like a flat plane currently which is oriented about the up axis, not on the XZ plane like before.
I'll post my changes but I'm sure they adhere to your critiques.
Matrix4x4 createView( Vector3* pos, Vector3* target, Vector3* up )
{
Matrix4x4 cameraMat;
Matrix4x4 view;
Vector3 rowZ;
Vector3 row4 = { pos->x, pos->y, pos->z };
Vector3 rowX;
Vector3 rowY;
setEqual(&rowY, up);
rowZ = sub(target, pos);
normalise(&rowZ);
rowX = crossProd(&rowY, &rowZ);
normalise(&rowX);
rowY = crossProd(&rowX, &rowZ); // new rowY
normalise(&rowY);
setColv(&cameraMat, 0, &rowX, 0.0f);
setColv(&cameraMat, 1, &rowY, 0.0f);
setColv(&cameraMat, 2, &rowZ, 0.0f);
setColv(&cameraMat, 3, &row4, 1.0f);
view = inverseMat4(&cameraMat); // has to be inverse for camera transformations
return view;
}I'm doing translations in my update loop before I call updateCam(&cam);
They are just simple changes to the camera position to moving in 6 directions, here's an example:
if (glfwGetKey('A'))
{
addVec3f(&cam.pos, 0.5f, 0.0f, 0.0f); cam.needUpdate = 1;
}
if (glfwGetKey('W'))
{
addVec3f(&cam.pos, 0.0f, 0.0f, 0.5f); cam.needUpdate = 1;
}
void addVec3f( Vector3* vec, float x, float y, float z )
{
vec->x += x;
vec->y += y;
vec->z += z;
}
02 January 2013 - 03:15 AM
1. Thanks, I will rename it to "target"Okay.
2. I guess so3. Because i'm using C I can't overload operators.No problem. And the implementation of sub(...) works as expected.4. It should be fine, here's the code:The implementation is okay. However, the invocation is still questionable. Remember that the cross-product is not commutative, because
a x b = - ( b x a )
Hence the wrong order will yield in the reverse direction vector. IMHO you need to compute forward vector cross up vector to yield in the side vector, but you compute up vector cross forward vector and yield in the negative side vector. Please check this.5. A little further down in the function I call setEqual which initialises the left parameter to the right parameter; In this cals rowY gets set to the up vector.Nonetheless, what happens "a little further down" doesn't interest the code above. Normalizing a vector means to keep its direction and ensure a length of 1. Now rowY is [0,0,0] at the moment of normalization, and hence has no non-vanishing direction and cannot be enlarged to have a length of 1. So normalize(&rowY) must die with an error like "division by zero". That is the point I made.6. I'll need to change this because my rowX is currently the cross of up and rowZ.Not sure if I understand you answer here, so I explain in detail what I mean. The orientation matrix you want to compute has the requirement that each row/column has a length of 1 and each pair of them is orthogonal. Your forward vector and up vectors are not necessarily orthogonal when createView is invoked, but the cross product of those 2 vectors will be orthogonal to both. So after the first cross product only 2 of the 3 required orthogonalities are guaranteed. Hence you need to compute a second cross-product to guarantee that the up vector is orthogonal to the other vectors, too. In summary:
side := forward x up
new_up := side x forward7. I think I might be treating rows as columns because opengl is column-major.First, "column-major" is a term that describes how the elements of the 2D matrix construct are arranged linearly in 1D memory. That is not the topic I meant, although you have to consider it in your routines, of course.
What I meant is whether you use column-vectors, so that you do a matrix vector product like so
p' := M * p
or else row-vectors, so that you compute the same matrix vector product like so
q' := q * N
because there is a mathematical correspondence named the "transpose"
p := qt
M := Nt
between them. Looking at a pure orientation matrix gives
Rt = R-1
so that confusing row and column vectors gives the inverse rotation. Confusing them when dealing with the position sub-matrix is even worse.
When you're using column-vectors (what is usual in OpenGL) then side, up, forward, and location vectors have to be set as columns of the matrix.
Now coming to column-major (what is also usual in OpenGL): Make sure that the linear index is computed as
index = row * 4 + column
and it should work.8. Brain exploded! So it should just be called the view matrix then?Yes, it is the view matrix.
Ok I've revised my view matrix function and the setRowv function.
Matrix4x4 createView( Vector3* pos, Vector3* target, Vector3* up )
{
Matrix4x4 cameraMat;
Matrix4x4 view;
Vector3 rowZ;
Vector3 row4 = { pos->x, pos->y, pos->z };
Vector3 rowX;
Vector3 rowY;
setEqual(&rowY, up);
rowZ = sub(target, pos);
normalise(&rowZ);
rowX = crossProd(up, &rowZ);
normalise(&rowX);
rowY = crossProd(&rowX, &rowZ); // new rowY
normalise(&rowY);
setRowv(&cameraMat, 0, &rowX, 0.0f);
setRowv(&cameraMat, 1, &rowY, 0.0f);
setRowv(&cameraMat, 2, &rowZ, 0.0f);
view = inverseMat4(&cameraMat); // has to be inverse for camera transformations
setRowv(&cameraMat, 3, &row4, 1.0f);
return view;
}
I set the position row after I calculate the inverse so that the inverse part will only be calculated for the rotation correct?
setRowv function is now this:
void setRowv( Matrix4x4* m, int rowNum, Vector3* v, float w )
{
int index = rowNum * 4 + 0;
m->m.m1[index] = v->x;
m->m.m1[++index] = v->y;
m->m.m1[++index] = v->z;
m->m.m1[++index] = w;
}
I can see some geometry now but it doesn't resemble anything like I had before. At least before I could see what the object was and it was just translating incorrectly.
Find content