WebGL Game Development Tutorials

Clearing Screen (Color Buffer) to solid color (GL_COLOR_BUFFER_BIT)

We've already initialized the 3D canvas and talked a bit about theory behind the WebGL pipeline. I think it's a good time to actually do something physical on the screen.

This JavaScript WebGL demo switches the background color to a random RGB value every 1 second. It also loads a simple PLY model (see my How to load PLY models from blender into your WebGL program tutorial.) So just view the source code of this page or read on!

And that's what GL_COLOR_BUFFER_BIT is for. Use gl.clearColor(R, G, B, A); to set the refresh color and gl.clear(gl.COLOR_BUFFER_BIT); execute the screen clearing command.

The great thing about JavaScript's Math.random() function is that it already generates random values between 0.0 and 1.0, exactly what WebGL expects for R, G, B and A (alpha) values!

WebGL Clear Color with GL_COLOR_BUFFER_BIT

Let's use the very basic of GL commands on the newly created 3D canvas. We won't do much in this section other than familiarize ourselves with a few basic WebGL functions. If you've ever programmed in OpenGL before, they have synonymous names. Except in WebGL they stem from the main context object (in this example it is called gl) as its methods.

This example assumes that jQuery library is included providing $(document).ready function which executes at the time the page's DOM has finished downloading. But you can simply write this code at the bottom of your page just before closing </body> tag or execute these commands from <body onload = "here"> if you don't want to use jQuery.

jQuery is like the Swiss Army Knife for basic JavaScript programming. It's a library that some programmers don't like because it adds an extra HTTP request to your page. And you won't be using most of its functions or methods. But it is exceptionally great for determining when DOM is loaded, without worrying about cross-browser code.

For JavaScript Purists

Don't want to use jQuery? That's fine. You can use the following construct. Just rewrite the window's default onload function as follows. Remember that in JavaScript, thanks to a principle called hoisting functions don't have to be defined first in order to be used. And for this reason we can do something like this:

window.onload = InitializeWebGL;

function  InitializeWebGL() { /* Write your WebGL init code here */  }

jQuery does exactly the same thing, only using slightly different syntax.

Here is the jQuery example with actual WebGL initialization code:

// Execute this code only after DOM has finished loading completely

$(document).ready(function()

{

        var canvas = document.getElementById('gl');

        var gl = GetWebGLContext( canvas );

 

    if ( !gl ) {

        console.log('Failed to set up WebGL.');

    } else {

        // WebGL initialized!

        gl.clearColor(1.0, 0.0, 0.0, 1.0);

        gl.clear(gl.COLOR_BUFFER_BIT);

    }

});

If you supplied a buffer type that is not supported or does not exist, the result of your gl "clear" operation will produce the following error: INVALID_VALUE.

The function gl.clearColor accepts 4 parameters for the RGBA values. The RGB value in 0.0-1.0f format (where 0.0 = 0 and 1.0 = 255) for each one of the 3 color channels, followed by the fourth parameter specifying alpha value for translucency effect. In this case alpha was set to 255 to create a lush solid red color.

The color defined by clearColor is retained by the pipeline once it is set and you're not required to set it on every frame. It is changed only if clearColor function is used once again to reset it.

But it's the function gl.clear that is responsible for actually wiping the screen clean with the selected color. It takes gl.COLOR_BUFFER_BIT flag which says: clear the color component.

Basic Types of Memory Buffers

Color buffers are only one type of buffers in WebGL. And the flag COLOR_BUFFER_BIT represents simple [r, g, b] set. The other two flags are listed below.

COLOR_BUFFER_BIT

Only pixel color will be read / written

DEPTH_BUFFER_BIT

Operation will be performed on an off-screen depth buffer

STENCIL_BUFFER_BIT

Same as above, except for stencil buffer

Below is an example of how you would use functions that relate to setting the rest of the buffers. For example, note that clearDepth and clearStencil are used to specify Depth and Stencil buffers. These buffers must be first created, but we'll take a look at how that's done later in the book when it becomes necessary:

gl.clearColor( red, green, blue, alpha );        

gl.clearDepth( depth );

gl.clearStencil( stencil );

The DEPTH_BUFFER_BIT represents the depth buffer and it is used for determining the distance between the 3D fragment and the camera / eye position. The depth buffer stores only the Z coordinate in 3D space for each pixel rendered on screen starting from the position of the camera in the world. The depth buffer does not store X and Y coordinates.

As we continue rendering polygons on the screen the data in the depth buffer is then compared with pixels drawn in the same physical location on the screen (if any.)

If there is a pixel "A" rendered in that same spot on the screen, the new incoming pixel "B" which happens to occupy the same space is tested for whether it is farther away or closer to the camera than pixel "A".

This process continues until all pixels in the scene are processed. The 2D depth buffer is built for each pixel on the 2D screen. Depth buffers are also often passed to shaders for aiding calculation for creating various effects that require knowing distance between the currently processed fragment and the camera.

Whichever pixel is closer to the camera takes precedence and is picked to be the one that will be actually drawn on the screen. All other pixels "behind it" are discarded.

This improves shader performance because we no longer need to render every single pixel that will appear at some [x= y=] position in screen space. Just ones that are the closest to the camera. This avoids performance loss from fragment overdraw.

Ideally, we would want to draw our 3D world and models in it using an algorithm that draws objects from back to front, imitating how an artist would paint on a physical sheet of canvas. The painter first draws the background scene and objects that are far away. On top of that, the artist then proceeds to draw objects that are closer, overdrawing background items.

However, that sounds good only until you realize that some polygons that are translated and rotated to occupy exactly the same volume of space cannot be always drawn using this technique without losing visual integrity. It makes sense because, which object would you choose to draw first if they shared the same pixel coordinates in 3D space?

In fact, if two objects are drawn in a way where their pixels will share exactly the same 3D location your program can experience something referred to as Z-buffer fighting.

This is when the shader is struggling to decide which pixel out of the two should be shown at that location. Often this creates a pixel flickering effect, or long jagged-edge stripes of pixels seemingly flipping on and off following a will unknown to us as shown in the diagram below:

depthTestError.png

This happens not due to the fault in the depth algorithm itself but because of the fact that floating-point operations on the CPU have limitations. Unfortunately, there is not much we can do in this case. Good news is that in most cases, we don't really need to.

To avoid this artifact we usually want to avoid drawing objects occupying exactly the same place altogether. But this depth buffer technique is still critical in being used for accurately rasterizing polygons that overlap each other when they do not occupy the same space.

If we avoid the depth buffer test, some of your polygons may appear to be rendered in random order and intersect each other, creating severe visual artifacts.

As long as large majority of fragments occupy a unique location in the world coordinates, the z-buffer technique is more than efficient to eliminate all issues with polygon ordering.

For example, consider this geometric object consisting of several rectangles.

polygon-drawing-order.png

When z-buffer ordering technique is applied, the object is rendered accurately (left hand side). Without it, the polygon rendering order is obscure, and the model is inaccurately drawn. Note, however, to accurately correct this effect, WebGL's Z-buffer must be switched on with the following command:

gl.enable(gl.DEPTH_TEST);

Likewise, you can also disable the z-buffer depth test:

gl.disable(gl.DEPTH_TEST);

We'll deal with these cases in practice later on in the book. I just wanted to show you this now before we move on, in order to get an idea of how different types of off-screen buffers can be used in WebGL.

WebGL Book: A WebGL Tutorial Reference Book
WebGL Book - A WebGL Tutorial Reference Book

If tutorials on this site are not enough, or you simply like reading from a physical book or a digital device (Kindle, iPad, tablets, etc.) check out WebGL Book. Written by the author of tutorials on this site.

This book is a WebGL tutorial and a reference that guides the reader through the process of setting up and initializing WebGL, drawing 3D primitives and creating 3D computer games.

Preorder Here
© 2016-2018 Copyright WebGL Tutorials (webgltutorials.org)

All content and graphics on this website are the property of webgltutorials.org - please provide a back link when referencing on other sites.

Lyrics Haven: a song lyrics website, with clean printable lyrics react js tutorials react js elements react js components vue js tutorials angular js tutorials