Search code examples
javascriptgraphicswebgltextures

Apply different textures to different object in a scene


I'm triyng to simply add two different objects in a scene with their own textures. However, while the objects are correctly drawn, it happens that the second texture is applied to both the objects and clearly is not what I'm looking for.

I'm trying to generalise the code as much as I can but since now I still don't get a solution.

var programs = new Array();
var gl;
var shaderDir;
var baseDir;
var boatModel;
var rockModel;



var modelStr = Array();
var modelTexture = Array();

modelStr[0] = 'Assets/Boat/Boat.obj';
modelStr[1] = 'Assets/Rocks/Rock1/rock1.obj';

modelTexture[0] = 'Assets/Boat/textures/boat_diffuse.bmp';
modelTexture[1] = 'Assets/Rocks/Rock1/textures/rock_low_Base_Color.png';

function main() {

  utils.resizeCanvasToDisplaySize(gl.canvas);
  gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
  gl.clearColor(0.85, 1.0, 0.85, 1.0);
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  gl.enable(gl.DEPTH_TEST);

  var lastUpdateTime = (new Date).getTime();

  var Rx_rock = 0.0;
  var Ry_rock = 0.0;
  var Rz_rock = 0.0;
  var S_rock = 1.0 / 10;
  var x_rock = 5.0;
  var y_rock = 0.0;
  var z_rock = 0.0;

  var Rx_boat = 90.0;
  var Ry_boat = 45.0;
  var Rz_boat = 0.0;
  var y_boat = 0.0;
  var z_boat = 0.0;
  var x_boat = -2;
  var S_boat = 1.0 / 300.0;

  utils.resizeCanvasToDisplaySize(gl.canvas);

  var objectVertices = Array();
  var objectNormals = Array();
  var objectIndices = Array();
  var objectTexCoords = Array();

  objectVertices[0] = boatModel.vertices;
  objectNormals[0] = boatModel.vertexNormals;
  objectIndices[0] = boatModel.indices;
  objectTexCoords[0] = boatModel.textures;

  objectVertices[1] = rockModel.vertices;
  objectNormals[1] = rockModel.vertexNormals;
  objectIndices[1] = rockModel.indices;
  objectTexCoords[1] = rockModel.textures;





  var positionAttributeLocation = new Array();
  var uvAttributeLocation = new Array();
  var matrixLocation = new Array();
  var textLocation = new Array();

  positionAttributeLocation[0] = gl.getAttribLocation(programs[0], "a_position");
  uvAttributeLocation[0] = gl.getAttribLocation(programs[0], "a_uv");
  matrixLocation[0] = gl.getUniformLocation(programs[0], "matrix");
  textLocation[0] = gl.getUniformLocation(programs[0], "u_texture");

  positionAttributeLocation[1] = gl.getAttribLocation(programs[1], "a_position");
  uvAttributeLocation[1] = gl.getAttribLocation(programs[1], "a_uv");
  matrixLocation[1] = gl.getUniformLocation(programs[1], "matrix");
  textLocation[1] = gl.getUniformLocation(programs[1], "u_texture");

  objectWorldMatrix = new Array();

  objectWorldMatrix[0] = utils.MakeWorld(x_boat, y_boat, z_boat, Rx_boat, Ry_boat, Rz_boat, S_boat);
  objectWorldMatrix[1] = utils.MakeWorld(x_rock, y_rock, z_rock, Rx_rock, Ry_rock, Rz_rock, S_rock);

  var perspectiveMatrix = utils.MakePerspective(90, gl.canvas.width / gl.canvas.height, 0.1, 100.0);
  var viewMatrix = utils.MakeView(0.0, 0.0, 3.0, 0.0, 0.0);
  var vaos = new Array();




  for (i = 0; i < 2; i++) {
    vaos[i] = gl.createVertexArray();
    gl.bindVertexArray(vaos[i]);

    var positionBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(objectVertices[i]), gl.STATIC_DRAW);
    gl.enableVertexAttribArray(positionAttributeLocation[i]);
    gl.vertexAttribPointer(positionAttributeLocation[i], 3, gl.FLOAT, false, 0, 0);

    var uvBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, uvBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(objectTexCoords[i]), gl.STATIC_DRAW);
    gl.enableVertexAttribArray(uvAttributeLocation[i]);
    gl.vertexAttribPointer(uvAttributeLocation[i], 2, gl.FLOAT, false, 0, 0);

    var indexBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(objectIndices[i]), gl.STATIC_DRAW);









    var texture = gl.createTexture();

    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, texture);

    image = new Image();
    image.crossOrigin = "anonymous";
    image.src = baseDir + modelTexture[i];

    image.onload = function () {

      gl.activeTexture(gl.TEXTURE0)
      gl.bindTexture(gl.TEXTURE_2D, texture);
      gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
      gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
      gl.generateMipmap(gl.TEXTURE_2D);
    };
  }



  /* --------------------------------------DRAW SCENE-----------------------------------*/
  drawScene();

  function animate() {
    var currentTime = (new Date).getTime();
    if (lastUpdateTime != null) {
      console.log(currentTime - lastUpdateTime);
      var deltaC = (30 * (currentTime - lastUpdateTime)) / 1000.0;
      Ry_boat += deltaC;
      Ry_boat -= deltaC;
      Rz_boat += deltaC;
    }

    y_boat = y_boat + 0.01;
    z_boat = z_boat - 0.01;

    objectWorldMatrix[0] = utils.MakeWorld(0.0, y_boat, z_boat, Rx_boat, Ry_boat, Rz_boat, S_boat);


    lastUpdateTime = currentTime;
  }

  function drawScene() {
    // animate();

    utils.resizeCanvasToDisplaySize(gl.canvas);
    gl.clearColor(0.85, 0.85, 0.85, 1.0);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);



    for (i = 0; i < 2; i++) {
      gl.useProgram(programs[i]);
      var viewWorldMatrix = utils.multiplyMatrices(viewMatrix, objectWorldMatrix[i]);
      var projectionMatrix = utils.multiplyMatrices(perspectiveMatrix, viewWorldMatrix);
      gl.uniformMatrix4fv(matrixLocation[i], gl.FALSE, utils.transposeMatrix(projectionMatrix));


      gl.activeTexture(gl.TEXTURE0);
      gl.bindTexture(gl.TEXTURE_2D, texture);
      gl.uniform1i(textLocation[i], texture);



      gl.bindVertexArray(vaos[i]);
      gl.drawElements(gl.TRIANGLES, objectIndices[i].length, gl.UNSIGNED_SHORT, 0);

    }


    window.requestAnimationFrame(drawScene);
  }


}

async function init() {

  var path = window.location.pathname;
  var page = path.split("/").pop();
  baseDir = window.location.href.replace(page, '');
  shaderDir = baseDir + "shaders/";

  var canvas = document.getElementById("c");
  gl = canvas.getContext("webgl2");
  if (!gl) {
    document.write("GL context not opened");
    return;
  }

  await utils.loadFiles([shaderDir + 'vs.glsl', shaderDir + 'fs.glsl'], function (shaderText) {
    var vertexShader = utils.createShader(gl, gl.VERTEX_SHADER, shaderText[0]);
    var fragmentShader = utils.createShader(gl, gl.FRAGMENT_SHADER, shaderText[1]);
    programs[0] = utils.createProgram(gl, vertexShader, fragmentShader);

  });

  await utils.loadFiles([shaderDir + 'vs.glsl', shaderDir + 'fs.glsl'], function (shaderText) {
    var vertexShader = utils.createShader(gl, gl.VERTEX_SHADER, shaderText[0]);
    var fragmentShader = utils.createShader(gl, gl.FRAGMENT_SHADER, shaderText[1]);
    programs[1] = utils.createProgram(gl, vertexShader, fragmentShader);

  });


  //###################################################################################
  //This loads the obj model in the boatModel variable
  var boatObjStr = await utils.get_objstr(baseDir + modelStr[0]);
  boatModel = new OBJ.Mesh(boatObjStr);
  //###################################################################################

  //###################################################################################
  //This loads the obj model in the boatModel variable
  var rockObjStr = await utils.get_objstr(baseDir + modelStr[1]);
  rockModel = new OBJ.Mesh(rockObjStr);
  //###################################################################################

  main();
}

window.onload = init;


Solution

  • I see this code

    var texture = gl.createTexture();
    
    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, texture);
    
    image = new Image();
    image.crossOrigin = "anonymous";
    image.src = baseDir + modelTexture[i];
    
    image.onload = function () {
    
      gl.activeTexture(gl.TEXTURE0)
      gl.bindTexture(gl.TEXTURE_2D, texture);
      gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
      gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
      gl.generateMipmap(gl.TEXTURE_2D);
    };    
    

    Is called twice but there is only 1 variable texture. Maybe you meant to make textures = [] and change this to

    texture[i] = gl.createTexture();
    
    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, texture[i]);
    
    image = new Image();
    image.crossOrigin = "anonymous";
    image.src = baseDir + modelTexture[i];
    
    image.onload = function (texture, image) {
      return function() {
        gl.activeTexture(gl.TEXTURE0)
        gl.bindTexture(gl.TEXTURE_2D, texture);
        gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
        gl.generateMipmap(gl.TEXTURE_2D);
      };
    }(texture[i], image);
    

    Note the change to the callback as we need to "close" over texture and image so they'll be available in the callback.

    And change your rendering code to

      gl.activeTexture(gl.TEXTURE0);
      gl.bindTexture(gl.TEXTURE_2D, texture[i]);
      gl.uniform1i(textLocation[i], texture[i]);