# The Industry's Foundation for High Performance Graphics

1. ## MVP functions

Hi,
I'm very new to OpenGL and for various reasons I'm rolling my own functions to calculate the various parts of my MVP matrix (described here). Anyway the code based off of them doesn't work (naturally...) and i would greatly appreciate if someone with a few minutes could take a look at them and check whether they're at fault, since I can't find a good way to isolate them from the rest of the code, so can't tell where the error is.
Angus
Code :
```void perspective(float fovy, float aspect, float zNear, float zFar, float result[4][4])
{
float f=1/tanf(fovy/2);

result[0][0]=f/aspect;
result[0][1]=0;
result[0][2]=0;
result[0][3]=0;
result[1][0]=0;
result[1][1]=f;
result[1][2]=0;
result[1][3]=0;
result[2][0]=0;
result[2][1]=0;
result[2][2]=(zFar+zNear)/(zNear-zFar);
result[2][3]=(2*zNear*zFar)/(zNear-zFar);
result[3][0]=0;
result[3][1]=0;
result[3][2]=-1;
result[3][3]=0;
}

void crossproduct(float a[4], float b[4], float result[4]);

void lookat(float eyeX, float eyeY, float eyeZ, float centreX, float centreY, float centreZ, float upX, float upY, float upZ, float result[4][4])
{
float f[4] = {centreX-eyeX, centreY-eyeY, centreZ-eyeZ, 1};
float u[4] = {upX, upY, upZ, 1};
float s[4];
float temp[4][4];
float temp2[4][4];
normalise(f);
normalise(u);

crossproduct(f, u, s);
crossproduct(s, f, u);

temp[0][0]=s[0];
temp[0][1]=s[1];
temp[0][2]=s[2];
temp[0][3]=0;
temp[1][0]=u[0];
temp[1][1]=u[1];
temp[1][2]=u[2];
temp[1][3]=0;
temp[2][0]=-f[0];
temp[2][1]=-f[1];
temp[2][2]=-f[2];
temp[2][3]=0;
temp[3][0]=0;
temp[3][1]=0;
temp[3][2]=0;
temp[3][3]=1;

translate(temp2, -eyeX, -eyeY, -eyeZ);
multmatrix(temp, temp2, result);
}

void crossproduct(float a[4], float b[4], float result[4])
{
result[0] = (a[1]*b[2]) - (a[2] * b[1]);
result[1] = (a[2]*b[0]) - (a[0] * b[2]);
result[2] = (a[0]*b[1]) - (a[1] * b[0]);
result[3] = 1;
}

void multmatrix(float a[4][4], float b[4][4], float result[4][4])
{
int i;
int j;
int k;
float total;

for(i=0;i<4;i++)
for(j=0;j<4;j++)
{
total=0;
for(k=0;k<4;k++)
total+=a[i][k]*b[k][j];
result[i][j]=total;
}

}

void translate(float result[4][4], float x, float y, float z)
{
result[0][0]=1;
result[0][1]=0;
result[0][2]=0;
result[0][3]=x;
result[1][0]=0;
result[1][1]=1;
result[1][2]=0;
result[1][3]=y;
result[2][0]=0;
result[2][1]=0;
result[2][2]=1;
result[2][3]=z;
result[3][0]=0;
result[3][1]=0;
result[3][2]=0;
result[3][3]=1;
}```

2. ## Re: MVP functions

I've only looked at your translate.
OpenGL expects matrices stored in float arrays to be column major, i.e. the first index is the column and the second is the row - your translate matrix are transposed.

3. ## Re: MVP functions

Thanks, don't know why I didn't think to check which way matrices should be. Will change that and see if it at all improves things.
Angus

4. ## Re: MVP functions

Yeah, an easy way to deal with this given that C/C++ is row-major order and OpenGL is column-major is: Just do row-major like C/C++ wants, and flip the transform order.

That is, instead of doing "P*V*M * v_obj = v_clip" like OpenGL wants, do this "v_obj * M*V*P = v_clip". In practice this means you use the transposes of the matrices, and you composite them in the opposite order. Then you can blissfully care less that OpenGL uses column major order.

6. ## Re: MVP functions

Tried flipping round the order of the transformations just now which didn't help. I'll do a full proper check of the entire piece of code tomorrow/over the next week, mainly worried about these bits of code as I've no real way to check they're working.
Just as a matter of interest, is there any good reason to keep the C code using row major matrices? I just did it because it seems intuitive and I hadn't checked properly but you seem to imply there's a good reason one might want to do that.

7. ## Re: MVP functions

is there any good reason to keep the C code using row major matrices?
No, not really. It's all purely conventional; just put the columns where you put the rows now. Your matrix multiplication functions will all work exactly the same.

8. ## Re: MVP functions

Originally Posted by Mjiig
is there any good reason to keep the C code using row major matrices?
Yes. Then you never have to do transposes to pass matrices to OpenGL. Further, you end up with matrix translate and basis vectors being in rows of the matrix rather than column which is more efficient to access. And you can just forget the whole column major issue on the C/C++ side.

9. ## Re: MVP functions

Further, you end up with matrix translate and basis vectors being in rows of the matrix rather than column which is more efficient to access.
I think you're conflating certain terms, which is why we give conflicting advice that is in fact the same. The major storage order of a matrix does not change how the basis vectors are stored. It simply changes the order of storage of the data.

What you're talking about is combing row-major storage with row vectors. That is, you're transposing the matrix into a row-based matrix, and then storing that row-based matrix in a row-major array.

This results in identical data to storing a column-based matrix in a column-major array. That's why transposing isn't necessary; because you've transposed the data at storage time.

A more detailed discussion of the issue can be found on this Stack Exchange answer.

10. ## Re: MVP functions

Originally Posted by Alfonse Reinheart
What you're talking about is combing row-major storage with row vectors....This results in identical data to storing a column-based matrix in a column-major array. That's why transposing isn't necessary; because you've transposed the data at storage time.
Exactly. You're right. We're talking about the same thing. Thanks for clarifying that.

#### Posting Permissions

• You may not post new threads
• You may not post replies
• You may not post attachments
• You may not edit your posts
•