Reputation: 4617
I've been following a couple of tutorials on html5rocks, and I managed to make a javascript program which displays ONE image on a canvas using webGL. I have posted the code I have for this below.
The problem is, it seems there is nobody out there who shows you how to draw more than ONE object in webGL. I've never worked directly with webGL before, so it's not very intuitive for me.
How can I modify this code to draw each object in the imageObjectArray
? (notice that now I'm just drawing imageObjectArray[0]
.
function render(canvas, contextGL, imageObjectArray) {
vertexShader = createShaderFromScriptElement(contextGL, "2d-vertex-shader");
fragmentShader = createShaderFromScriptElement(contextGL, "2d-fragment-shader");
program = createProgram(contextGL, [vertexShader, fragmentShader]);
contextGL.useProgram(program);
var positionLocation = contextGL.getAttribLocation(program, "a_position");
var texCoordLocation = contextGL.getAttribLocation(program, "a_texCoord");
var texCoordBuffer = contextGL.createBuffer();
contextGL.bindBuffer(contextGL.ARRAY_BUFFER, texCoordBuffer);
contextGL.enableVertexAttribArray(texCoordLocation);
contextGL.vertexAttribPointer(texCoordLocation, 2, contextGL.FLOAT, false, 0, 0);
setRectangle(contextGL, 0.0, 0.0, 1.0, 1.0);
var texture = contextGL.createTexture();
contextGL.bindTexture(contextGL.TEXTURE_2D, texture);
contextGL.texParameteri(contextGL.TEXTURE_2D, contextGL.TEXTURE_WRAP_S, contextGL.CLAMP_TO_EDGE);
contextGL.texParameteri(contextGL.TEXTURE_2D, contextGL.TEXTURE_WRAP_T, contextGL.CLAMP_TO_EDGE);
contextGL.texParameteri(contextGL.TEXTURE_2D, contextGL.TEXTURE_MIN_FILTER, contextGL.NEAREST);
contextGL.texParameteri(contextGL.TEXTURE_2D, contextGL.TEXTURE_MAG_FILTER, contextGL.NEAREST);
contextGL.texImage2D(contextGL.TEXTURE_2D, 0, contextGL.RGBA, contextGL.RGBA, contextGL.UNSIGNED_BYTE, imageObjectArray[0].displayObject.data);
var resolutionLocation = contextGL.getUniformLocation(program, "u_resolution");
contextGL.uniform2f(resolutionLocation, canvas.width, canvas.height);
var buffer = contextGL.createBuffer();
contextGL.bindBuffer(contextGL.ARRAY_BUFFER, buffer);
contextGL.enableVertexAttribArray(positionLocation);
contextGL.vertexAttribPointer(positionLocation, 2, contextGL.FLOAT, false, 0, 0);
setRectangle(contextGL, imageObjectArray[0].x, imageObjectArray[0].y, imageObjectArray[0].width, imageObjectArray[0].height);
// draw
contextGL.drawArrays(contextGL.TRIANGLES, 0, 6);
}
function setRectangle(gl, x, y, width, height) {
var x2 = x + width;
var y2 = y + height;
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(
[x, y,
x2, y,
x, y2,
x, y2,
x2, y,
x2, y2
]), gl.STATIC_DRAW);
}
My aim here is to work on a (very basic) 2d sprite game. Without the comfort of libraries. (except for maybe glMatrix.js)
[EDIT] My render function had an error in it, fixed.
Upvotes: 4
Views: 4013
Reputation: 3575
The following code does the following:
The above 5 steps only need to be run once.
vertexShader = createShaderFromScriptElement(contextGL, "2d-vertex-shader");
fragmentShader = createShaderFromScriptElement(contextGL, "2d-fragment-shader");
program = createProgram(contextGL, [vertexShader, fragmentShader]);
contextGL.useProgram(program);
var positionLocation = contextGL.getAttribLocation(program, "a_position");
var texCoordLocation = contextGL.getAttribLocation(program, "a_texCoord");
var texCoordBuffer = contextGL.createBuffer();
contextGL.bindBuffer(contextGL.ARRAY_BUFFER, texCoordBuffer);
contextGL.enableVertexAttribArray(texCoordLocation);
contextGL.vertexAttribPointer(texCoordLocation, 2, contextGL.FLOAT, false, 0, 0);
var texture = contextGL.createTexture();
contextGL.bindTexture(contextGL.TEXTURE_2D, texture);
contextGL.texParameteri(contextGL.TEXTURE_2D, contextGL.TEXTURE_WRAP_S, contextGL.CLAMP_TO_EDGE);
contextGL.texParameteri(contextGL.TEXTURE_2D, contextGL.TEXTURE_WRAP_T, contextGL.CLAMP_TO_EDGE);
contextGL.texParameteri(contextGL.TEXTURE_2D, contextGL.TEXTURE_MIN_FILTER, contextGL.NEAREST);
contextGL.texParameteri(contextGL.TEXTURE_2D, contextGL.TEXTURE_MAG_FILTER, contextGL.NEAREST);
setRectangle(contextGL, 0.0, 0.0, 1.0, 1.0);
The rest of the code must execute for each image you want to draw and it does the following:
contextGL.texImage2D(contextGL.TEXTURE_2D, 0, contextGL.RGBA, contextGL.RGBA,contextGL.UNSIGNED_BYTE, imageObjectArray[0].displayObject.data); var resolutionLocation = contextGL.getUniformLocation(program, "u_resolution"); contextGL.uniform2f(resolutionLocation, canvas.width, canvas.height); var buffer = contextGL.createBuffer(); contextGL.bindBuffer(contextGL.ARRAY_BUFFER, buffer); contextGL.enableVertexAttribArray(positionLocation); contextGL.vertexAttribPointer(positionLocation, 2, contextGL.FLOAT, false, 0, 0); setRectangle(contextGL, imageObjectArray[0].x, imageObjectArray[0].y, imageObjectArray[0].width, imageObjectArray[0].height); // draw contextGL.drawArrays(contextGL.TRIANGLES, 0, 6);
You need to split step 2 into separate steps. The first step, creating the vertex buffer for posistions, should only be executed once. The second step, filling the position of the image, needs to be executed for each image you want to draw.
I should say that my suggestions will not give the optimal implementation but it will get you drawing more than 1 image. To be optimal you should consider doing:
Upvotes: 5