Skip to content Skip to sidebar Skip to footer

How To Use Multiple Textures On A Cube In Webgl?

This is my source code. It still doesnt work. I want to put 6 different pictures on the 6 sides of a cube, which is animated. Please help :)

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 and IndexBuffer and CoordBuffer as local variables in initBuffers but then used them in drawScene.

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?"