small medium large xlarge

Hi,

I’m having difficulty with the second exercise in 12.7 on page 251 of the 2013 edition.

Here’s what I have so far:

``````/* Heightmap fragment shader */
precision mediump float;
varying vec3 v_Color;
float zValueLinear;

void main() {
zValueLinear = (1.0 - gl_FragCoord.z) * (100.0 - 0.1); // near - far
gl_FragColor = vec4((zValueLinear, zValueLinear, zValueLinear, 1.0);
}
``````

The results appear linear for the wrong range. On https://www.opengl.org/discussion_boards/showthread.php/164089-gl_FragCoord-z, one user suggested to use the following:

``````float Z = gl_ProjectionMatrix[3].z /
(gl_FragCoord.z
* -2.0
+  1.0
-  gl_ProjectionMatrix[2].z);
``````

If ProjectionMatrix is u_Matrix, how do I access the values referenced here?

Thanks!

Hi Robert,

Apologies for the delay, I wanted to test things out first before responding, and I haven’t had my head in the math for quite a while. :)

So, first to get access to the matrix, you can modify the program by adding the matrix as a uniform:

``````uniform mat4 u_ProjectionMatrix;
``````

Then you’d need to pass this in setUniforms:

``````public void setUniforms(float[] mvpMatrix, float[] projectionMatrix) {
glUniformMatrix4fv(uMvpMatrixLocation, 1, false, mvpMatrix, 0);
glUniformMatrix4fv(uProjectionMatrixLocation, 1, false, projectionMatrix, 0);
}
``````

Also taking care to add uProjectionMatrixLocation to the class and initializing it in the constructor. Then, you’d need to update the call to setUniforms:

``````heightmapProgram.setUniforms(modelViewProjectionMatrix, projectionMatrix);
``````

In testing though, this method with that shader code just resulted in a black screen for me. Here’s how to do it by just using the fragment shader:

``````precision mediump float;

varying vec3 v_Color;

highp float get_linear_z_from_z(highp float n, highp float f, highp float z) {
return (n * z) / ( f - z * (f - n));
}

void main()
{
float linear_z = get_linear_z_from_z(1.0, 100.0, gl_FragCoord.z);
gl_FragColor = vec4(linear_z, linear_z, linear_z, 1.0);
}
``````

This uses the near and far from the perspective projection to convert the non-linear z/w value back into a linear z value. When using a perspective projection, you can also use the w value directly:

``````precision mediump float;

varying vec3 v_Color;

float get_linear_w_from_w(float n, float f, float inverse_w) {
float w = 1.0 / inverse_w;
return (w - n) / (f - n);
}

void main()
{
float linear_distance = get_linear_w_from_w(1.0, 100.0, gl_FragCoord.w);
gl_FragColor = vec4(linear_distance, linear_distance, linear_distance, 1.0);
}
``````

gl_FragCoord.w stores 1/Wc (w in clip coordinates), so it’s inverted first and then scaled by the near and far values from the projection matrix; these could be passed in as uniforms to the shader rather than being hardcoded. So these are both from the thread that you mentioned; lots of good methods in there. :)

Hope this helps out! :)

You must be logged in to comment