PDA

View Full Version : Z values output from shader are inverted.



chrisvarns
12-15-2010, 10:27 AM
I'm having trouble with z buffering, in my application it seems that the z values of fragments coming out of the vertex shader are the wrong way around, and this is effectively causing the scene to draw the 'wrong' way around, with fragments further away drawing over the top of fragments closer.

Below is my vertex shader:



attribute vec4 vPosition;
attribute vec4 vColor;
attribute vec4 vTexture;
uniform mat4 u_modelMatrix;
uniform mat4 u_projectionMatrix;
uniform mat4 u_textureMatrix;
varying vec2 a_texCord;
varying vec4 aColor;
void main()
{
vec4 transformCord = u_textureMatrix * vTexture;"
gl_Position = u_projectionMatrix * u_modelMatrix * vPosition;
aColor = vColor;
a_texCord = transformCord.xy;
}


I simply added the line: gl_Position.z = -gl_Position.z; and this inverts the z values and causes the scene to draw properly. This however, is only fixing the symptom, and as DepthFunc is set to LEQUAL i guess the problem can only be in the projection/modelview matrix? Anyone have any ideas on how to flip the z axis in either of these to produce the same result as flipping it here? The maths is a little confusing and nothing i try in either the projection or model view matrix solve the issue. Is this the only place to really fix the problem?

SteveBaker
12-15-2010, 06:52 PM
I agree that it's most likely to be your projection matrix...but it's hard to guess what you've done wrong without seeing the code.

This is what I use (JavaScript...for WebGL):



this.perspective = function ( fovY, aspect, near, far )
{
var t = Math.tan ( fovY / 360.0 * Math.PI ) * near ;
var b = -t ;
var r = t * aspect ;
var l = -r ;
var dX = r - l ;
var dY = t - b ;
var dZ = far - near ;
if ( near <= 0 || far <= 0 || dX <= 0 || dY <= 0 || dZ <= 0 ) return ;
this.m[1] = this.m[2] = this.m[ 3] = this.m[ 4] = this.m[ 6] =
this.m[7] = this.m[12] = this.m[13] = this.m[15] = 0 ;
this.m[ 0] = 2 * near / dX ;
this.m[ 5] = 2 * near / dY ;
this.m[ 8] = (r + l) / dX ;
this.m[ 9] = (t + b) / dY ;
this.m[10] = -(near + far) / dZ ;
this.m[11] = -1 ;
this.m[14] = -2 * near * far / dZ ;
}

chrisvarns
12-16-2010, 06:39 AM
Ok so a bit of background, I'm porting from GL 1.5 with extensions, to GLES 2.0, and the projection matrix I'm using in GLES2 works perfectly with the programmable pipe in GL 1.5 (as that's where it originated), all i've changed is doubles to floats as GLES2 only supports floats. I assumed maths was just maths, and it would work fine, but there's possibly a difference in how Z is dealt with between the 2 API's, and i need to flip the Z in the matrix(?).

Below is the code used to work out the projection matrix:


static void R_SetupProjectionMatrix(const refdef_t *rd, mat4x4_t m)
{
#ifndef GLES2 //if OGL
GLdouble xMin, xMax, yMin, yMax, zNear, zFar;
#else
GLfloat xMin, xMax, yMin, yMax, zNear, zFar;
#endif

if (ri.params & RP_SHADOWMAPVIEW)
// do not alter the farclip distance for shadow map views
;
else if (rd->rdflags & RDF_NOWORLDMODEL)
ri.farClip = 2048;
else
ri.farClip = R_FarClip();

zNear = Z_NEAR;
zFar = ri.farClip;

yMax = zNear * tan(rd->fov_y * M_PI / 360.0);
yMin = -yMax;

xMax = zNear * tan(rd->fov_x * M_PI / 360.0);
xMin = -xMax;

xMin += -(2 * glState.cameraSeparation) / zNear;
xMax += -(2 * glState.cameraSeparation) / zNear;

m[0] = (2.0 * zNear) / (xMax - xMin);
m[1] = 0.0f;
m[2] = 0.0f;
m[3] = 0.0f;
m[4] = 0.0f;
m[5] = (2.0 * zNear) / (yMax - yMin);
m[6] = 0.0f;
m[7] = 0.0f;
m[8] = (xMax + xMin) / (xMax - xMin);
m[9] = (yMax + yMin) / (yMax - yMin);
m[10] = -(zFar + zNear) / (zFar - zNear);
m[11] = -1.0f;
m[12] = 0.0f;
m[13] = 0.0f;
m[14] = -(2.0 * zFar * zNear) / (zFar - zNear);
m[15] = 0.0f;
}


Here are the values output for the matrix (apologies, the forum strips my formatting). I've interpreted the matrix as being in COLUMN major order, so if this is wrong just swap element 11 and 14 (i actually did this in the code at one point, but it just made the player really small.):


3.7320509 0 0 0
0 2.48803401 0 0
0 0 -1.00391388 -8.01565552
0 0 -1 0


Incase this doesn't give you enough info, and you want the various input values, here they are:



zNear = 4
zFar = 2048 (in the player setup menu where I'm currently testing, the RDF_NOWORLDMODEL flag is set)

fov_x = 30
fov_y = 43.7927361
M_PI defined as 3.14159265358979323846
cameraSeparation = 0
therefore....
yMax = 1.6076951
yMin = -1.6076951
xMax = 1.07179677
xMin = -1.07179677


The fov values are specifically to do with the player model being rendered in this case.
I can give the Model View matrix also if this is needed. It looks to me as if your code and mine are... pretty much exactly the same. Perhaps the problem isnt here?

SteveBaker
12-16-2010, 06:38 PM
Well, I guess I'm out of ideas. I'm pretty sure there is no difference in the orientation of matrices and such between OpenGL and OpenGLES - that would be just crazy.

(Although there **IS** a difference between OpenGL/OpenGLES and Direct3D...the range of Z goes 0..1 on one and -1..1 on the other (I have temporarily forgotten which is which!)...that produces some interesting oddities when you feed a projection designed for one into the other).