Tutorial: Difference between revisions
Line 5: | Line 5: | ||
WebGL is built on top of the HTML5 <code><canvas></code> element. As for a 2D canvas, you start out by getting a <code>WebGLRenderingContext</code> with a call to the <code>getContext()</code> method of the <code><canvas></code> element, passing the string "experimental-webgl". (This string is temporary and will eventually change to "webgl".) The returned object has a set of functions very similar to OpenGL ES 2.0. | WebGL is built on top of the HTML5 <code><canvas></code> element. As for a 2D canvas, you start out by getting a <code>WebGLRenderingContext</code> with a call to the <code>getContext()</code> method of the <code><canvas></code> element, passing the string "experimental-webgl". (This string is temporary and will eventually change to "webgl".) The returned object has a set of functions very similar to OpenGL ES 2.0. | ||
sup guys, is hitler jajaja | |||
==Initializing the Engine== | ==Initializing the Engine== |
Revision as of 19:10, 2 October 2013
HEIL
Creating the Context
WebGL is built on top of the HTML5 <canvas>
element. As for a 2D canvas, you start out by getting a WebGLRenderingContext
with a call to the getContext()
method of the <canvas>
element, passing the string "experimental-webgl". (This string is temporary and will eventually change to "webgl".) The returned object has a set of functions very similar to OpenGL ES 2.0.
sup guys, is hitler jajaja
Initializing the Engine
The next step is to get WebGL up and running. The init()
function uses the webgl-debug.js utility library:
function init()
{
// Initialize
var gl = initWebGL("example");
if (!gl) {
return;
}
g.program = simpleSetup(
gl, "vshader", "fshader",
[ "vNormal", "vColor", "vPosition"], [ 0, 0, 0, 1 ], 10000);
// Set some uniform variables for the shaders
gl.uniform3f(gl.getUniformLocation(g.program, "lightDir"), 0, 0, 1);
gl.uniform1i(gl.getUniformLocation(g.program, "sampler2d"), 0);
// Create a box. with the BufferObjects containing the arrays
// for vertices, normals, texture coords, and indices.
g.box = makeBox(gl);
// Load an image to use. Returns a WebGLTexture object
spiritTexture = loadImageTexture(gl, "resources/spirit.jpg");
// Create some matrices to use later and save their locations in the shaders
g.mvMatrix = new J3DIMatrix4();
g.u_normalMatrixLoc = gl.getUniformLocation(g.program, "u_normalMatrix");
g.normalMatrix = new J3DIMatrix4();
g.u_modelViewProjMatrixLoc = gl.getUniformLocation(g.program, "u_modelViewProjMatrix");
g.mvpMatrix = new J3DIMatrix4();
// Enable all of the vertex attribute arrays.
gl.enableVertexAttribArray(0);
gl.enableVertexAttribArray(1);
gl.enableVertexAttribArray(2);
// Set up all the vertex attributes for vertices, normals and texCoords
gl.bindBuffer(gl.ARRAY_BUFFER, g.box.vertexObject);
gl.vertexAttribPointer(2, 3, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, g.box.normalObject);
gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, g.box.texCoordObject);
gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 0, 0);
// Bind the index array
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, g.box.indexObject);
return gl;
}
The simpleSetup()
utility function takes the following parameters:
gl
- The WebGL context
"vshader", "fshader",
- Ids of the vertex and fragment shaders
"vNormal", "vColor", "vPosition"
- Vertex shader attribute names used by the shaders.
[ 0, 0, 0, 1 ], 10000)
- Clear color and depth values
This initialization loads the shaders and attaches them to a GLSL program, which is how you define the interface to your shaders. You pass uniform parameters to a shader for values that don't change and vertex attributes for things that do change, like vertices. Most of this is taken care of in the utility library, but you can pass additional values here, as with the lightDir
and sampler2d
uniforms. This code also tells WebGL to use the arrays the makeBox()
function sets up containing the vertices, normals, and texture coordinates.
Setting Up the Viewport
Before you can render, you have to tell the canvas how to map the objects from modeling space to screen space. Initially, an object's geometry is described in modeling coordinates, local coordinates that describe the shape itself. These coordinates are transformed into other types of coordinates as follows:
MODELING COORDINATES ->> WORLD COORDINATES ->> VIEW COORDINATES ->> VIEWPORT COORDINATES
- World coordinates are the global coordinate system that takes into account all objects in the scene.
- View coordinates are the coordinate system that incorporates a virtual camera's view of the scene.
- Viewport coordinates are the coordinate system that describes the camera projection for the scene (for example, orthographic or perspective) and fits the projected scene into screen space. This projection takes the scene from a 3D to a 2D projection so that it can be displayed on the screen. The textured spinning box example uses a perspective projection, which will make closer objects look larger than further ones, just as in the real world.
A transformation matrix is used to perform the calculations from one coordinate system to the next. In this example, the transformation from modeling to world to view coordinates is performed by the model-view matrix, which combines two transformations into one matrix. The perspective matrix, pMatrix
, performs the transformation from view coordinates to viewport coordinates. This perspective matrix is created in the reshape()
function and saved for use later at the end of the transformation pipeline, where it transforms view coordinates to viewport coordinates.
The reshape()
function uses the matrix function utility library (J3DIMath.js):
function reshape(gl)
{
// if the display size of the canvas has changed
// change the size we render at to match.
var canvas = document.getElementById('example');
if (canvas.clientWidth == canvas.width && canvas.clientHeight == canvas.height) {
return;
}
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
// Set the viewport and projection matrix for the scene
gl.viewport(0, 0, canvas.clientWidth, canvas.clientHeight);
g.perspectiveMatrix = new J3DIMatrix4();
g.perspectiveMatrix.lookat(0, 0, 7, 0, 0, 0, 0, 1, 0);
g.perspectiveMatrix.perspective(30, canvas.clientWidth / canvas.clientHeight, 1, 10000);
}
Drawing the Box
Now you're all set up and you can finally draw your box. Most of the hard work is done, but you still have to tell the box to spin, and to do that you define a model-view matrix, which transforms modeling coordinates to view coordinates. This transformation tells the box where and at what angle you want it to appear. Then you multiply the model-view matrix by the perspective matrix that was saved earlier to complete the transformation all the way from modeling coordinates to viewport coordinates. Note that the order of transformations is significant (that is, matrix multiplication is not commutative). You can also turn the model-view matrix into a normal matrix so it can be used to compute the proper lighting on the box:
function drawPicture(gl)
{
//Make sure the canvas is sized correctly.
reshape(gl);
// Clear the canvas
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// Make a model/view matrix.
g.mvMatrix.makeIdentity();
g.mvMatrix.rotate(20, 1, 0, 0);
g.mvMatrix.rotate(currentAngle, 0, 1, 0);
// Construct the normal matrix from the model-view matrix and pass it in
g.normalMatrix.load(g.mvMatrix);
g.normalMatrix.invert();
g.normalMatrix.transpose();
g.normalMatrix.setUniform(gl, g.u_normalMatrixLoc, false);
// Construct the model-view * projection matrix and pass it in
g.mvpMatrix.load(g.perspectiveMatrix);
g.mvpMatrix.multiply(g.mvMatrix);
g.mvpMatrix.setUniform(gl, g.u_modelViewProjMatrixLoc, false);
// Bind the texture to use
gl.bindTexture(gl.TEXTURE_2D, spiritTexture);
// Draw the cube
gl.drawElements(gl.TRIANGLES, g.box.numIndices, gl.UNSIGNED_BYTE, 0);
// Show the framerate
framerate.snapshot();
currentAngle += incAngle;
if (currentAngle > 360) {
currentAngle -= 360;
}
}
Finally, you simply add a JavaScript call to requestAnimationFrame to keep changing the angle and rendering the box in its new position—and you have a spinning box!
What's Next?
For a nontextured version of the spinning cube, see the Spinning Box example. Also see the Demo Repository for more WebGL samples.
Khronos WebGL Spinning Box Tutorial is licensed under a Creative Commons Attribution 3.0 Unported License.