I am trying to get the distance of each pixel drawn to the canvas in the vertex shader. The vertex shader code is as follows:
attribute vec4 modelVertexPosition;
// cameraMatrix is strictly used as a ref to the camera's position in this case
// and does not contribute to the screen projection position calculation
uniform mat4 cameraMatrix;
uniform mat4 projectionMatrix;
uniform mat4 modelMatrix;
varying float cameraDistance;
void main(void) {
// calc world position of vertex
vec4 vertexPosition = modelMatrix * modelVertexPosition;
// calc frustum position of vertex
vec4 projVertexPosition = projectionMatrix * vertexPosition;
gl_Position = projVertexPosition;
// set cameraDistance varying for fragment shader
cameraDistance = distance(cameraMatrix[3].xyz, (modelMatrix * scaledModelVertexPosition).xyz);
}
This works fine for all points strictly on the vertices of the triangles being drawn, but it's clear glsl is interpolating the distances of points inside the triangles linearly relative to their vertices. It's usually not a big issue, but it's especially noticeable when the camera is closer to the middle of the triangle than the vertices.
To demonstrate this issue, I set the fragment shader to set the brightness of the shape as a function of the distance of that point from the camera, the darker the closer. I set a situation that exposes the flaws in the method of implementation show below:
So this begs the question, is there a way to get the position of each pixels distance from the camera?
The distance of a fragment from the camera is related to its depth in the depth buffer. You can calculate depth in the fragment shader as follows:
float depth = gl_Position.z / gl_Position.w;
The depth of visible fragments varies from 0 to 1, with 0 being on the near clip plane and 1 being on the far clip plane. You can calculate the distance from the camera with this formula:
depth = (1/camera_distance - 1/near)/(1/far - 1/near)
Note that depth and camera distance are not linearly related. Instead, depth is linearly related to 1/camera_distance. OpenGL etc define "depth" using the reciprocal of camera distance so hardware can do linear interpolation of "depth" across triangles in screen space to quickly determine which triangle is visible at each pixel in perspective views.