Controller Overview - WebGL Textures & Vertices: Beginner's Guide (2015)

WebGL Textures & Vertices: Beginner's Guide (2015)

Controller Overview

The next few paragraphs provide an overview of the controller GLControl class. For readers new to WebGL the overview might seem confusing. Sections following Controller Details provide step by step instructions to each WebGL feature.

GLControl Constructor

The constructor for GLControl initializes everything needed for a WebGL program. Formal parameters in order include Float32Array aVert, Uint16Array aIdx, Array aE, and glDemo. The aVert parameter by default includes a Float32Array of interleaved vertices and texels. The aIdx parameter is a Uint16Array for use as an element array buffer. The aE parameter is an array of GLEntity. The glDemo parameter references the current project. glDemo is a class instance implemented for one of the book's examples.

The constructor assigns the aE parameter to the aEntity property, saving the array of GLEntity. The constructor assigns the glDemo parameter to the glDemo property. Many methods need references to the current project.

GLControl Initialization

The constructor for GLControl calls the following methods in order getGLContext(), getProgram(), getBuffers(), getImages(), and last setListeners().

Method getGLContext() obtains and saves a WebGLContext reference, to the instance variable gl. Method getProgram() prepares the program from a fragment and vertex shader. If the Web page doesn't declare a shader, then getProgram() uses the provided default shaders. The compiled and linked program is saved to the instance variable program. Method getBuffers() prepares an element array buffer from the Uint16Array of indices passed to the GLControl constructor. Method getBuffers() prepares a vertex buffer object from the Float32Array of vertices and texels passed to the GLControl constructor. Method getImages() calls the GLEntity method getImageVariables(), for each GLEntity maintained in the aEntity array. Method setListeners() assigns event listeners to buttons which play and stop the project's animation. Additionally setListeners() assigns a click event listener to the canvas, which renders one frame of the animation.

After all textures load, setProgramVariables() calls method animOne() to display one frame of the scene.

Don't feel overwhelmed with the preceding overview. Sections following Controller Details provide step by step instructions to each WebGL feature. See the GLControl source code.

Entity Overview

The next few paragraphs provide an overview of the entity GLEntity class. The section titled Entity Details provides a wealth of WebGL instruction regarding each feature. Readers new to WebGL might find the overview confusing. However sections following Entity Details, illuminate the concepts introduced in this brief overview.

GLEntity Constructor

The constructor for GLEntity initializes everything needed for a WebGLTexture and a matrix. The matrix allows display of each entity with transformation, such as position or rotation.

Constructor parameters in order include s and i. The s parameter represents either a String path to an image file or null. Not every entity needs an image file. The i parameter is an integer. The constructor assigns the i parameter to the idx property. The constructor assigns the s parameter to the sSrc property. During initialization, method getImageVariables() loads an image file from the sSrc file path. The idx property represents the texture unit for an entity.

GLEntity Structure

The GLEntity class includes instance variables sSrc, img, texture, uSampler, aTexCoord, idx, and matrix.

The String variable named sSrc, contains the path to an image file if one exists. GLEntity applies data from an image file to a texture. However GLEntity may apply procedurally generated color data to a texture, as well. The imgvariable maintains either an Image object, Uint8Array of color data, or null. The texture variable maintains a WebGLTexture generated from data in the img variable, when available. By default the controller requires at least one GLEntity with a valid WebGLTexture. Additional entities with null textures may process matrices or other data.

Every entity in the controller's list does not need a valid texture property. The list might contain one GLEntity with a texture and many GLEntity without a texture. The list might contain many GLEntity each with a unique texture.

The idx variable is an integer which uniquely represents one entity in the array of entities. The idx property has three uses. Associate GLEntity properties with a shader attribute, shader uniform, and a texture unit.

Use the idx property to associate a uniform with the GLEntity instance variable uSampler, and an attribute with the instance variable aTexCoord. The uSampler variable is the location of a uniform sampler2D from the fragment shader. The aTexCoord variable is the location of an attribute for processing texture coordinates, within the vertex shader. The idx property of a GLEntity reference works with the two shader variables. For example the GLEntity with an idxvalue of 0, references a sampler named u_sampler0 and an attribute named a_tex_coord0. The GLEntity with an idx value of 1, references a sampler named u_sampler1 and an attribute named a_tex_coord1. However, if shader variables beyond idx value 0 aren't available, then examples work fine without them. Example projects operate successfully if the list contains more than one entity, even if shaders declare just one u_sampler0 and one a_tex_coord0.

The GLEntity idx property also refers to the associated texture unit. For example when idx equals 1, and the entity maintains a texture, then the texture unit equals TEXTURE1. The following listing activates a texture unit, based on the entity's idx value.

gl.activeTexture

(

gl.TEXTURE0 + entity.idx

);

Activate GLEntity Texture Unit

Use the idx property to associate the uSampler property with the entity's texture unit. The following listing assigns the entity's sampler to a texture unit with the WebGL method uniformi(). Once assigned the entity's texture processes with the shader's sampler2D.

gl.uniform1i

(

entity.uSampler,

entity.idx

);

Listing 26: Assign GLEntity Sampler to Texture Unit

GLEntity Initialization

The controller calls GLEntity method getImageVariables(). Method getImageVariables() obtains variable locations from the shaders, and prepares to load any images. Method setImage() activates when images load asynchronously. However code may call method setImage() synchronously with procedurally generated color data. In that case, the texture initializes without waiting for a file download. Method setImage() completes texture initialization. After all textures have initialized, setImage() calls the controller method setProgramVariables() once.

It's necessary to call the controller's method setProgramVariables() after textures initialize. Method setProgramVariables() validates the program. Some browsers fail validation if shader variables associated with textures, haven't initialized.

Don't feel overwhelmed with the preceding overview. Sections following Entity Details provide step by step instructions to each WebGL feature. See the GLEntity source code.

Controller Details

This section discusses the controller's methods in order getGLContext(), getProgram(), getBuffers(), getImages(), and last setListeners(). Method getGLContext() obtains a WebGLContext. Method getProgram() compiles and links shader code. Method getBuffers() uploads buffers to the GPU. Method getImages() begins GLEntity initialization.

This section demonstrates how to use a long list of WebGL API methods including createProgram(), attachShader(WebGLProgram, WebGLShader), linkProgram(WebGLProgram), useProgram(WebGLProgram), createShader(type),shaderSource(WebGLShader, String), compileShader(WebGLShader), getShaderParameter(WebGLShader, COMPILE_STATUS), getShaderInfoLog(WebGLShader), getUniformLocation(WebGLProgram,String),uniformMatrix4fv(WebGLUniformLocation, Boolean, Float32Array), getAttribLocation(WebGLProgram, String), enableVertexAttribArray(Number), viewport(Number x,Number y,Number w,Number h), createBuffer(),bindBuffer(ARRAY_BUFFER, WebGLBuffer), bufferData(ARRAY_BUFFER, Float32Array, STATIC_DRAW), vertexAttribPointer(), uniformi(WebGLUniformLocation, Number), validateProgram(WebGLProgram),getProgramParameter(WebGLProgram, Number), getProgramInfoLog(WebGLProgram), deleteProgram(WebGLProgram), and drawElements(Number mode,Number count,Number type,Number offset). Projects include working examples, thorough comments, explanation, and diagrams, to clarify each step.

Obtain a WebGLContext

The controller constructor first calls method getGLContext(canvas). Method getGLContext(canvas) returns a reference to a WebGLContext, suitable for rendering to the canvas with WebGL. The controller saves a reference to theWebGLContext to the instance variable named gl. Every WebGL method, constant, and feature, requires a valid WebGLContext. If the browser doesn't support WebGL then getGLContext(canvas) displays an error message, and returns null.

First the GLControl constructor obtains a reference to the HTML5 canvas as follows.

var cv = document.getElementById('cv');

The constructor passes a reference to the HTML5 canvas to method getGLContext(canvas). If you've used the HTML5 2D context, then obtaining the 3D context may look familiar. In most cases canvas.getContext('webgl') returns a valid WebGLContext. However at this time, some browsers name the 3D context experimental-webgl, webkit-3d, or moz-webgl. Therefore getGLContext(canvas) iterates over a list of possible context names. After finding a valid WebGLContext, method getGLContext(canvas) breaks and returns the context.

If the WebGLContext is valid, then GLControl saves a reference to the property named gl. However if the value returned from getGLContext() is null, then code displays an error message and exits. The method viewError(String,controller) displays a message to an element on the current Web page. The following listing includes the entire source code for getGLContext(canvas).

getGLContext: function(canvas){

// Windows Phone 8.1

// default browser

// uses 'experimental-webgl'.

var a3D = ['webgl',

'experimental-webgl',

'webkit-3d',

'moz-webgl'

];

var glContext = null;

try {

// Iterate over our array.

for (var i = 0; i < a3D.length; i++) {

// Try to obtain a 3D context.

glContext = canvas.getContext(a3D[i]);

// If we found a context,

// then break out of the loop.

if (glContext != null) {

break;

}

}

}

// If there's an error,

// then display it.

catch(err) {

this.viewError(err,this);

}

// WebGLContext or null.

return glContext;

},

Listing 27: getGLContext(canvas)