Z position in Camera/View Space

edited January 2014 in GLSL / Shaders

I am new to shaders and trying to create a shader that highlights a particular plane of pixels on the z axis. I have done a bunch of poking around the web for an accurate representation of the world or eye space so that I can input the z value from the Processing sketch to the shader and then highlight that plane. But my calculations seem off.

It is my impression that the eye space is relative to the camera position so that that if the cameraZ is set to 300, the eye position of an object on the z axis at 0 should be 300 (or maybe -300), but my calculations seem to be off.

I suspect I am not calculating the eye space correctly but I haven't seen an answer that makes the adjustments.

My object is always at the origin (in world space/ processing) and I move the camera to see what different values look like. By moving the mouse I can scrub the selected zPlane in the shader. When the highlighted region is centered on the hexagon and it "blinks" the hole shape when facing the camera I believe that should be the zPlane of the origin, but my results are as follows:

zPlane: 254.5  camZ: 311.76917  near: 31.176916  far: 3117.6917
zPlane: 204.0  camZ: 261.76917  near: 26.176916  far: 2617.6917
zPlane: 152.5  camZ: 211.76917  near: 21.176916  far: 2117.6917
zPlane: 102.0  camZ: 161.76917  near: 16.176916  far: 1617.6917
zPlane: 50.0  camZ: 111.769165  near: 11.176916  far: 1117.6917

It is my impression that the zPlane and camZ should be equal when the hexagon is blinking but as you can see they aren't. I have included my calculations of the default processing clipping planes as well. My suspicion is that it has something to do with that.

Any help or direction would be great. Thanks.

Here is my processing sketch:

PShape shape;
PShader shader;
float zPlane, cameraZ, nearZ, farZ;
color bgColor;

void setup() {
  zPlane = 500.0;
  cameraZ = 500;

  size(640, 360, P3D);
  colorMode(HSB, 1.0);
  bgColor = color(0.0, 1.0, 0.5, 1.0);
  shader = loadShader("frag.glsl", "vert.glsl");

  shape = createShape();
  shape.setFill( color(1.0, 0.0, 0.0, 1.0) );
  //shape.setStroke( false);
  shape.beginShape();
  for(float i = 0; i < 6; i++) {
    shape.vertex( sin(i * TAU / 6) * 50, cos(i * TAU / 6) * 50, 0 );
  }    
  shape.endShape(CLOSE);
  shader.set("zPlane", zPlane);
  //hint(DISABLE_DEPTH_MASK);
  //shader(shader, LINES);
  cameraZ = (height/2.0) / tan(PI*60.0/360.0);
  nearZ = cameraZ / 10.0;
      farZ = cameraZ * 10.0;
      println( cameraZ + ", " + nearZ + ", " + farZ);
    }

void draw() {
  zPlane = map( (float) mouseX, 0.0, width, 0.0, width/2.0);

  shader.set("zPlane", zPlane);
  shader(shader);
  background( bgColor );

  camera(width/2.0, height/2.0, cameraZ, width/2.0, height/2.0, 0, 0, 1, 0);
  //camera(width/2.0, height/2.0, cameraZ, width/2.0, height/2.0, 0, 0, 1, 0);
  translate(width/2, height/2,  0);
  rotateY( TAU * frameCount / 120 );
  shape( shape );
}

void mouseReleased() {
  println( "plane: " + zPlane + "  cam: " + cameraZ + "  near: " + nearZ + "  far: " + farZ);

  cameraZ = cameraZ - 50;
  nearZ = cameraZ / 10.0;
  farZ = cameraZ * 10.0;
}

My Vertex shader:

#define PROCESSING_COLOR_SHADER

uniform mat4 transform;   //transform --> gl_ModelViewProjectionMatrix

attribute vec4 vertex;    //vertex -----> gl_Vertex
attribute vec4 color;     //color ------> gl_Color

varying vec4 vertColor;
varying vec4 position_in_view_space;
varying float zCoord;

void main() {
  gl_Position = transform * vertex; 
  vertColor = color;
  zCoord = (gl_ProjectionMatrixInverse * gl_Position).z;
}

My Fragment shader:

#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif

varying vec4 vertColor;
varying float zCoord;

uniform float zPlane;

void main() {
  float dist = distance(position_in_view_space, vec4( 0.0, 0.0, 0.0, 1.0) );

  if( zCoord > zPlane - 2.0 && zCoord < zPlane + 2.0) {
    gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0); //If zCoord to zPlane make it green
  } else {
    gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0); //Otherwise make it blue
  }
}

Answers

  • Ok... so after some detective work I answered my own question. I am still a little shaky on why this is so and how in my search to answer this question no one else uses this formula but here is what I found.

    depth = 1.0 / gl_FragCoord.w;
    

    This line in the fragment shader give the depth in world units of the fragment. This seems really useful to me and I would think others but I haven't seen much said about it on any forums. If people have insight on to what this is I would love to know.

    I mostly figured out by using the line:

        printProjection();
        printCamera();
    

    I then multiplied these matrix by hand with the origin vector (0, 0, 0, 1). This should give the same results as:

    gl_ModelViewProjectionMatrix * gl_Position;
    

    Looking at the resulting vector I noticed the value for z I was getting matched the value I had in the experiment ( not the correct world coordinate) but the value for w was my camera position.

    What I can't figure out is that...

    gl_ModelViewMatrix * glPosition
    

    ...should have a value for z of -depth, but it doesn't (at least in my tests).

    Anyways this solves my problem, but if others have insight into the details of this, I would love to know.

  • from the opengl docs, gl_FragCoord.z is the actual depth value of the fragment:

    http://www.opengl.org/sdk/docs/manglsl/xhtml/gl_FragCoord.xml

    In a previous thread, http://forum.processing.org/two/discussion/comment/8300#Comment_8300, it was mentioned gl_FragCoord.z / gl_FragCoord.w as the fragment depth, but that should be wrong then... anyways, I'm not 100% sure at this time.

    This tutorial on opengl transformations http://www.songho.ca/opengl/gl_transform.html might be useful to understand the underlying math.

  • gl_FragCoord.z holds the non linear depth, dividing it by gl_FragCoord.w gives you the linear depth.

    But remember: As gl_FragCoords are screen space coords the resulting linear depth will also be in screen space. ;)

  • Thanks both of you! I'll take a look at the transformations tutorial.

Sign In or Register to comment.