I can't find any documentation of different behavior, so this is just a sanity check that I'm not doing anything wrong...
I've created some helper functions in GLSL to output float/vec/mat comparisons as a color:
note: pretty sure there aren't any errors here, just including it so you know exactly what I'm doing...
//returns true or false if floats are eq (within some epsillon)
bool feq(float a, float b)
{
float c = a-b;
return (c > -0.05 && c < 0.05);
}
returns true or false if vecs are eq
bool veq(vec4 a, vec4 b)
{
return
(
feq(a.x, b.x) &&
feq(a.y, b.y) &&
feq(a.z, b.z) &&
feq(a.w, b.w) &&
true
);
}
//returns color indicating where first diff lies between vecs
//white for "no diff"
vec4 cveq(vec4 a, vec4 b)
{
if(!feq(a.x, b.x)) return vec4(1.,0.,0.,1.);
else if(!feq(a.y, b.y)) return vec4(0.,1.,0.,1.);
else if(!feq(a.z, b.z)) return vec4(0.,0.,1.,1.);
else if(!feq(a.w, b.w)) return vec4(1.,1.,0.,1.);
else return vec4(1.,1.,1.,1.);
}
//returns true or false if mats are eq
bool meq(mat4 a, mat4 b)
{
return
(
veq(a[0],b[0]) &&
veq(a[1],b[1]) &&
veq(a[2],b[2]) &&
veq(a[3],b[3]) &&
true
);
}
//returns color indicating where first diff lies between mats
//white means "no diff"
vec4 cmeq(mat4 a, mat4 b)
{
if(!veq(a[0],b[0])) return vec4(1.,0.,0.,1.);
else if(!veq(a[1],b[1])) return vec4(0.,1.,0.,1.);
else if(!veq(a[2],b[2])) return vec4(0.,0.,1.,1.);
else if(!veq(a[3],b[3])) return vec4(1.,1.,0.,1.);
else return vec4(1.,1.,1.,1.);
}
So I have a model mat, a view mat, and a proj mat. I'm rendering a rectangle on screen (that is correctly projected/transformed...), and setting its color based on how well each steps of the calculations match with my on-cpu-calculated equivalents.
uniform mat4 model_mat;
uniform mat4 view_mat;
uniform mat4 proj_mat;
attribute vec4 position;
varying vec4 var_color;
void main()
{
//this code works (at least visually)- the rect is transformed as expected
vec4 model_pos = model_mat * position;
gl_Position = proj_mat * view_mat * model_pos;
//this is the test code that does the same as above, but tests its results against CPU calculated equivalents
mat4 m;
//test proj
//compares the passed in uniform 'proj_mat' against a hardcoded rep of 'proj_mat' as printf'd by the CPU
m[0] = vec4(1.542351,0.000000,0.000000,0.000000);
m[1] = vec4(0.000000,1.542351,0.000000,0.000000);
m[2] = vec4(0.000000,0.000000,-1.020202,-1.000000);
m[3] = vec4(0.000000,0.000000,-2.020202,0.000000);
var_color = cmeq(proj_mat,m); //THIS PASSES (the rect is white)
//view
//compares the passed in uniform 'view_mat' against a hardcoded rep of 'view_mat' as printf'd by the CPU
m[0] = vec4(1.000000,0.000000,-0.000000,0.000000);
m[1] = vec4(-0.000000,0.894427,0.447214,0.000000);
m[2] = vec4(0.000000,-0.447214,0.894427,0.000000);
m[3] = vec4(-0.000000,-0.000000,-22.360680,1.000000);
var_color = cmeq(view_mat,m); //THIS PASSES (the rect is white)
//projview
mat4 pv = proj_mat*view_mat;
//proj_mat*view_mat
//compares the result of GPU computed proj*view against a hardcoded rep of proj*view **<- NOTE ORDER** as printf'd by the CPU
m[0] = vec4(1.542351,0.000000,0.000000,0.000000);
m[1] = vec4(0.000000,1.379521,-0.689760,0.000000);
m[2] = vec4(0.000000,-0.456248,-0.912496,20.792208);
m[3] = vec4(0.000000,-0.447214,-0.894427,22.360680);
var_color = cmeq(pv,m); //THIS FAILS (the rect is green)
//view_mat*proj_mat
//compares the result of GPU computed proj*view against a hardcoded rep of view*proj **<- NOTE ORDER** as printf'd by the CPU
m[0] = vec4(1.542351,0.000000,0.000000,0.000000);
m[1] = vec4(0.000000,1.379521,0.456248,0.903462);
m[2] = vec4(0.000000,0.689760,21.448183,-1.806924);
m[3] = vec4(0.000000,0.000000,-1.000000,0.000000);
var_color = cmeq(pv,m); //THIS FAILS (the rect is green)
//view_mat_t*proj_mat_t
//compares the result of GPU computed proj*view against a hardcoded rep of view_t*proj_t **<- '_t' = transpose, also note order** as printf'd by the CPU
m[0] = vec4(1.542351,0.000000,0.000000,0.000000);
m[1] = vec4(0.000000,1.379521,-0.456248,-0.447214);
m[2] = vec4(0.000000,-0.689760,-0.912496,-0.894427);
m[3] = vec4(0.000000,0.000000,20.792208,22.360680);
var_color = cmeq(pv,m); //THIS PASSES (the rect is white)
}
And here are my CPU vector/matrix calcs (matrices are col-order [m.x is first column, not first row]):
fv4 matmulfv4(fm4 m, fv4 v)
{
return fv4
{ m.x[0]*v.x+m.y[0]*v.y+m.z[0]*v.z+m.w[0]*v.w,
m.x[1]*v.x+m.y[1]*v.y+m.z[1]*v.z+m.w[1]*v.w,
m.x[2]*v.x+m.y[2]*v.y+m.z[2]*v.z+m.w[2]*v.w,
m.x[3]*v.x+m.y[3]*v.y+m.z[3]*v.z+m.w[3]*v.w };
}
fm4 mulfm4(fm4 a, fm4 b)
{
return fm4
{ { a.x[0]*b.x[0]+a.y[0]*b.x[1]+a.z[0]*b.x[2]+a.w[0]*b.x[3], a.x[0]*b.y[0]+a.y[0]*b.y[1]+a.z[0]*b.y[2]+a.w[0]*b.y[3], a.x[0]*b.z[0]+a.y[0]*b.z[1]+a.z[0]*b.z[2]+a.w[0]*b.z[3], a.x[0]*b.w[0]+a.y[0]*b.w[1]+a.z[0]*b.w[2]+a.w[0]*b.w[3] },
{ a.x[1]*b.x[0]+a.y[1]*b.x[1]+a.z[1]*b.x[2]+a.w[1]*b.x[3], a.x[1]*b.y[0]+a.y[1]*b.y[1]+a.z[1]*b.y[2]+a.w[1]*b.y[3], a.x[1]*b.z[0]+a.y[1]*b.z[1]+a.z[1]*b.z[2]+a.w[1]*b.z[3], a.x[1]*b.w[0]+a.y[1]*b.w[1]+a.z[1]*b.w[2]+a.w[1]*b.w[3] },
{ a.x[2]*b.x[0]+a.y[2]*b.x[1]+a.z[2]*b.x[2]+a.w[2]*b.x[3], a.x[2]*b.y[0]+a.y[2]*b.y[1]+a.z[2]*b.y[2]+a.w[2]*b.y[3], a.x[2]*b.z[0]+a.y[2]*b.z[1]+a.z[2]*b.z[2]+a.w[2]*b.z[3], a.x[2]*b.w[0]+a.y[2]*b.w[1]+a.z[2]*b.w[2]+a.w[2]*b.w[3] },
{ a.x[3]*b.x[0]+a.y[3]*b.x[1]+a.z[3]*b.x[2]+a.w[3]*b.x[3], a.x[3]*b.y[0]+a.y[3]*b.y[1]+a.z[3]*b.y[2]+a.w[3]*b.y[3], a.x[3]*b.z[0]+a.y[3]*b.z[1]+a.z[3]*b.z[2]+a.w[3]*b.z[3], a.x[3]*b.w[0]+a.y[3]*b.w[1]+a.z[3]*b.w[2]+a.w[3]*b.w[3] } };
}
A key thing to notice is that the view_mat_t * proj_mat_t on the CPU matched the proj_mat * view_mat on the GPU. Does anyone know why? I've done tests on matrices on the CPU and compared them to results of online matrix multipliers, and they seem correct...
I know that the GPU does things between vert shader and frag shader (I think it like, divides gl_Position by gl_Position.w or something?)... is there something else I'm not taking into account going on here in just the vert shader? Is something being auto-transposed at some point?