How To Use Multiple Textures On A Cube In Webgl?
Solution 1:
Did you even try to debug this? The code you pasted above does not run and gets JavaScript errors. in Chrome open the JavaScript console (Wrench->Tools->JavaScript Console). In Firefox (Firefox->Web Developer->Web Console)
Things that were wrong
Lots of globals used but are not actually global.
Declared
vertBuffer
andIndexBuffer
andCoordBuffer
as local variables ininitBuffers
but then used them indrawScene
.
That made it at least not get JavaScript errors.
Didn't setup the texture coords.
The code made a CoordBuffer but never uses it in an attribute. This caused GL errors ("attribs not setup correctly" in Chrome)
Fixing this made it stop getting GL errors. At that point I set the background color to green and I saw a spinning black cube which suggested the next problem was textures.
Not setting the textures up to handle no mips and non-power-of-2 textures.
If your textures are not power of 2 in each dimension you need to set the texture wrap to clamp.
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
Here's a working version using randomly colored canvases instead of images.
var gl;
functioninitGL(canvas) {
try {
gl = canvas.getContext("experimental-webgl");
gl.viewportWidth = canvas.width;
gl.viewportHeight = canvas.height;
} catch (e) {
}
if (!gl) {
alert("Could not initialise WebGL, sorry :-(");
}
}
functiongetShader(gl, id) {
var shaderScript = document.getElementById(id);
if (!shaderScript) {
returnnull;
}
str = shaderScript.text;
var shader;
if (shaderScript.type == "x-shader/x-fragment") {
shader = gl.createShader(gl.FRAGMENT_SHADER);
} elseif (shaderScript.type == "x-shader/x-vertex") {
shader = gl.createShader(gl.VERTEX_SHADER);
} else {
returnnull;
}
gl.shaderSource(shader, str);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert(gl.getShaderInfoLog(shader));
returnnull;
}
return shader;
}
var shaderProgram;
functioninitShaders() {
var fragmentShader = getShader(gl, "shader-fs");
var vertexShader = getShader(gl, "shader-vs");
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert("Could not initialise shaders");
}
gl.useProgram(shaderProgram);
// This is a bad code.// If the context is lsot shaderProgram will be null// and trying to assign a vertexPositionAttribute to null// will throw an exception.// better would be // shaderProgram = {};// shaderProgram.program = gl.createProgram();// shaderProgram.vertexPositionAtrribute = ...
shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord");
gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute);
shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler");
}
var texturen = newArray();
functioninitTexture(sFilename,texturen)
{
var anz = texturen.length;
texturen[anz] = gl.createTexture();
// this is a bad code. on context lost gl.createTexture() will return null and// an exception will be thrown when you try to attach .image to null// Better would be// texturen[anz] = {};// texturen[anz].texture = gl.createTexture();// texturen[anz].image = new Image();
texturen[anz].image = newImage();
texturen[anz].image.onload = function()
{
gl.bindTexture(gl.TEXTURE_2D, texturen[anz]);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
//gl.texImage2D (gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texturen[anz].image);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.bindTexture(gl.TEXTURE_2D, null);
}
//texturen[anz].image.src = sFilename;// Since I can't load cross domain I'll use a canvas to make texturesfunctionrnd() { returnMath.floor(Math.random() * 256); }
var c = document.createElement("canvas");
c.width = 64;
c.height = 64;
var ctx = c.getContext("2d");
ctx.fillStyle = "rgb(" + rnd() + "," + rnd() + "," + rnd() + ")";
ctx.fillRect(0, 0, 64, 64);
ctx.fillStyle = "rgb(" + rnd() + "," + rnd() + "," + rnd() + ")";
ctx.beginPath();
ctx.arc(32, 32, 30, 0, Math.PI * 2, false);
ctx.fill();
gl.bindTexture(gl.TEXTURE_2D, texturen[anz]);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, c);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
}
var mvMatrix = mat4.create();
var mvMatrixStack = [];
var pMatrix = mat4.create();
functionmvPushMatrix() {
var copy = mat4.create();
mat4.copy(copy, mvMatrix);
mvMatrixStack.push(copy);
}
functionmvPopMatrix() {
if (mvMatrixStack.length == 0) {
throw"Invalid popMatrix!";
}
mvMatrix = mvMatrixStack.pop();
}
functionsetMatrixUniforms() {
gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, pMatrix);
gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mvMatrix);
}
functiondegToRad(degrees) {
return degrees * Math.PI / 180;
}
functioninitBuffers() {
vertBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertBuffer);
var vertices = [
// Front face
-1.0, -1.0, 1.0,
1.0, -1.0, 1.0,
1.0, 1.0, 1.0,
-1.0, 1.0, 1.0,
// Back face
-1.0, -1.0, -1.0,
-1.0, 1.0, -1.0,
1.0, 1.0, -1.0,
1.0, -1.0, -1.0,
// Top face
-1.0, 1.0, -1.0,
-1.0, 1.0, 1.0,
1.0, 1.0, 1.0,
1.0, 1.0, -1.0,
// Bottom face
-1.0, -1.0, -1.0,
1.0, -1.0, -1.0,
1.0, -1.0, 1.0,
-1.0, -1.0, 1.0,
// Right face1.0, -1.0, -1.0,
1.0, 1.0, -1.0,
1.0, 1.0, 1.0,
1.0, -1.0, 1.0,
// Left face
-1.0, -1.0, -1.0,
-1.0, -1.0, 1.0,
-1.0, 1.0, 1.0,
-1.0, 1.0, -1.0,
];
gl.bufferData(gl.ARRAY_BUFFER, newFloat32Array(vertices), gl.STATIC_DRAW);
// This is bad code. See the above examples of bad code.// vertBuffer will be null on context lost and this code// will throw an exception.
vertBuffer.itemSize = 3;
vertBuffer.numItems = 24;
CoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,CoordBuffer);
var textureCoords = [
// Front face0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0,
// Back face1.0, 0.0,
1.0, 1.0,
0.0, 1.0,
0.0, 0.0,
// Top face0.0, 1.0,
0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
// Bottom face1.0, 1.0,
0.0, 1.0,
0.0, 0.0,
1.0, 0.0,
// Right face1.0, 0.0,
1.0, 1.0,
0.0, 1.0,
0.0, 0.0,
// Left face0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0,
];
gl.bufferData(gl.ARRAY_BUFFER, newFloat32Array(textureCoords), gl.STATIC_DRAW);
CoordBuffer.itemSize = 2;
CoordBuffer.numItems = 24;
IndexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, IndexBuffer);
varIndices = [
0, 1, 2, 0, 2, 3, // Front face4, 5, 6, 4, 6, 7, // Back face8, 9, 10, 8, 10, 11, // Top face12, 13, 14, 12, 14, 15, // Bottom face16, 17, 18, 16, 18, 19, // Right face20, 21, 22, 20, 22, 23// Left face
];
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, newUint16Array(Indices), gl.STATIC_DRAW);
IndexBuffer.itemSize = 1;
IndexBuffer.numItems = 36;
}
var xRot = 0;
var yRot = 0;
var zRot = 0;
functiondrawScene() {
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
mat4.perspective(pMatrix, 45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0);
mat4.identity(mvMatrix);
mat4.translate(mvMatrix, mvMatrix, [0.0, 0.0, -5.0]);
mat4.rotate(mvMatrix, mvMatrix, degToRad(xRot), [1, 0, 0]);
mat4.rotate(mvMatrix, mvMatrix, degToRad(yRot), [0, 1, 0]);
mat4.rotate(mvMatrix, mvMatrix, degToRad(zRot), [0, 0, 0]);
setMatrixUniforms();
gl.bindBuffer(gl.ARRAY_BUFFER, vertBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute,vertBuffer.itemSize,
gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, CoordBuffer);
gl.vertexAttribPointer(shaderProgram.textureCoordAttribute,CoordBuffer.itemSize,
gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, IndexBuffer);
// Draw face 0
gl.bindTexture(gl.TEXTURE_2D, texturen[0]);
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
// Draw face 1
gl.bindTexture(gl.TEXTURE_2D, texturen[1]);
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 12);
// Draw face 2
gl.bindTexture(gl.TEXTURE_2D, texturen[2]);
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 24);
// Draw face 3
gl.bindTexture(gl.TEXTURE_2D, texturen[3]);
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 36);
// Draw face 4
gl.bindTexture(gl.TEXTURE_2D, texturen[4]);
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 48);
// Draw face 5
gl.bindTexture(gl.TEXTURE_2D, texturen[5]);
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 60);
}
var lastTime = 0;
functionanimate() {
var timeNow = newDate().getTime();
if (lastTime != 0) {
var elapsed = timeNow - lastTime;
xRot += (90 * elapsed) / 1000.0;
yRot += (90 * elapsed) / 1000.0;
zRot += (90 * elapsed) / 1000.0;
}
lastTime = timeNow;
}
functiontick() {
requestAnimationFrame(tick);
drawScene();
animate();
}
functionwebGLStart() {
var canvas = document.getElementById("lesson05-canvas");
initGL(canvas);
initShaders();
initBuffers();
initTexture("Logo.png",texturen);
initTexture("le.png",texturen);
initTexture("Logo.png",texturen);
initTexture("le.png",texturen);
initTexture("Logo.png",texturen);
initTexture("le.png",texturen);
gl.clearColor(0.0, 1.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST);
tick();
}
webGLStart();
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.3.2/gl-matrix-min.js"></script><scriptid="shader-fs"type="x-shader/x-fragment">
precision mediump float;
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
voidmain(void) {
gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
}
</script><scriptid="shader-vs"type="x-shader/x-vertex">
attribute vec3 aVertexPosition;
attribute vec2 aTextureCoord;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
varying vec2 vTextureCoord;
voidmain(void) {
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
vTextureCoord = aTextureCoord;
}
</script><canvasid="lesson05-canvas"style="border: none;"width="500"height="500"></canvas>
Other problems: There's several places in the code where properties are assigned to WebGL objects. Examples
shaderProgram = gl.createProgram();
shaderProgram.textureCoordAttribute =
gl.getAttribLocation(shaderProgram, "aTextureCoord");
...
texturen[anz] = gl.createTexture();
texturen[anz].image = newImage();
texturen[anz].image.onload = function()
...
vertBuffer = gl.createBuffer();vertBuffer.itemSize = 3;
All of these will have to be refactored if you ever decide to handle context lost events since the gl.create???
functions will return null and attaching a property to null will cause an exception.
Better to do something more like this
shaderProgram = {};
shaderProgram.program = gl.createProgram();
shaderProgram.textureCoordAttribute =
gl.getAttribLocation(shaderProgram, "aTextureCoord");
...
texturen[anz] = {};
texturen[anz].texture = gl.createTexture();
texturen[anz].image = newImage();
texturen[anz].image.onload = function()
...
vertBuffer = {};vertBuffer.buffer = gl.createBuffer();vertBuffer.itemSize = 3;
Post a Comment for "How To Use Multiple Textures On A Cube In Webgl?"