Depth Test

By default, WebGL draws objects in the order in which they are specified inside the buffer objects. This means that the objects behind that are supposed to be blocked by the objects in front may appear in the front instead. To correctly display the foreground and background objects, the DEPTH_TEST capability has to be enabled.

However, even with the capability enabled, hidden surface removal may fail when the objects are extremely close to one another. The phenomenon, known as Z-fighting, causes the object to appear unnatural. Z-fighting occurs because of the limited precision of the depth buffer. To resolve the problem, WebGL provides a feature known as 'polygon offset'.

WebGL hidden surface removal uses a left-handed clip coordinate system. This means that objects with smaller z values appear in front of objects with bigger z values.

If 'polygon_offset' is not enabled, the red triangle will cover the smaller green triangle entirely, even though the smaller green triangle is located just in front of the red triangle.
RESETRUNFULL
<!DOCTYPE html><html>
<head>
<script src="/shared/webgl-library.js"></script>
<script>
var VS_SOURCE=`
   attribute vec4 p;
   attribute vec4 c;
   varying vec4 c2;
   void main(){
      c2=c;
      gl_Position = p; 
      gl_PointSize=20.0;
   }`;
var FS_SOURCE=`
   precision mediump float;
   varying vec4 c2;
   void main(){
      gl_FragColor=c2;
   }`;
var gl, m, mL;function start(){
   var canvas = document.getElementById("myCanvas");
   gl = canvas.getContext("webgl");
   initShaders(gl, VS_SOURCE, FS_SOURCE);
   var points=new Array();
   var vc= new Float32Array([ 0.0,-0.5,0.0,  1.0, 0.0, 0.0,
                             -0.5, 0.5,0.0,  1.0, 0.0, 0.0,
                              0.5, 0.5,0.0,  1.0, 0.0, 0.0,
                     0.0,-0.4,-0.000000001,  0.0, 1.0, 0.0,
                    -0.4, 0.4,-0.000000001,  0.0, 1.0, 0.0,
                     0.4, 0.4,-0.000000001,  0.0, 1.0, 0.0]);
   var ESIZE=vc.BYTES_PER_ELEMENT;
   var b=gl.createBuffer();
   gl.bindBuffer(gl.ARRAY_BUFFER, b);
   gl.bufferData(gl.ARRAY_BUFFER, vc, gl.STATIC_DRAW);
   pL=gl.getAttribLocation(gl.program, 'p');
   gl.vertexAttribPointer(pL, 3, gl.FLOAT, false, ESIZE*6, 0);
   gl.enableVertexAttribArray(pL);
   cL=gl.getAttribLocation(gl.program, 'c');
   gl.vertexAttribPointer(cL, 3, gl.FLOAT, false, ESIZE*6, ESIZE*3);
   gl.enableVertexAttribArray(cL);
   gl.enable(gl.DEPTH_TEST);
   gl.enable(gl.POLYGON_OFFSET_FILL);
   gl.clearColor(0.0, 0.0, 0.0, 1.0);
   gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
   gl.drawArrays(gl.TRIANGLES, 0, 3);
   gl.polygonOffset(-1.0, -1.0);
   gl.drawArrays(gl.TRIANGLES, 3, 3);
}
</script>
</head>
<body onload="start()">
   <canvas id="myCanvas" width="500" height="500"></canvas>
</body>
</html>

polygonOffset(factor, units) specifies the offset to be added to the depth values, where offset = m * factor + r * units, with m representing the change in depth relative to the screen area of the polygon, and r representing the smallest difference between two depth values the hardware can distinguish. 'polygon offset' is also useful for rendering hidden-line images, for applying decals to surfaces, and for rendering solids with highlighted edges.

depthRange(near,far) specifies the mapping of depth values from normalized device coordinates to window coordinates. Window coordinate depth values in the depth buffer range from 0 to 1, which is also the default range. Values for 'near' and 'far' are clamped to the range [0,1].