Multiple objects Glsl

Viewed 64

I have some problems using Glsl while I'm searching to drawing two object independently. When I search to see the result of my code, the object considered by the compiler is the first texture while the texture is the second.Additionally, I don't understand how I can set the initial position of the object in independent way using the same shaders. This is my code:

var program;
var gl;
var shaderDir; 
var baseDir;
var missileModel;
var pigModel;
var missileStr = 'model/R73-Ready.obj';
var missileTexture = 'model/R73 Texture.png';
var modelStr = 'model/mount.obj';
var modelTexture = 'model/ground_grass_3264_4062_Small.jpg';


function main() {
    
    var lastUpdateTime = (new Date).getTime();
    
    var Rx = 0.0;
    var Ry = 0.0;
    var Rz = 0.0;
    var S  = 0.5;

    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);

    
    //Here we extract the position of the vertices, the normals, the indices, and the uv coordinates
    var missileVertices = missileModel.vertices;
    var missileNormals = missileModel.vertexNormals;
    var missileIndices = missileModel.indices;
    var missileTexCoords = missileModel.textures;
    
    var pigVertices = pigModel.vertices;
    var pigNormals = pigModel.vertexNormals;
    var pigIndices = pigModel.indices;
    var pigTexCoords = pigModel.textures;
    //###################################################################################
   
    var  positionAttributeLocation = gl.getAttribLocation(program, "a_position");  
    var uvAttributeLocation = gl.getAttribLocation(program, "a_uv");  
    var matrixLocation = gl.getUniformLocation(program, "matrix");  
    var textLocation = gl.getUniformLocation(program, "u_texture");

    var perspectiveMatrix = utils.MakePerspective(120, gl.canvas.width/gl.canvas.height, 0.1, 100.0);
    var viewMatrix = utils.MakeView(0, 0.0, 3.0, 0.0, 0.0);
    
    //drawing land
    var vao = gl.createVertexArray();
    gl.bindVertexArray(vao);

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

    var uvBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, uvBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(pigTexCoords), gl.STATIC_DRAW);
    gl.enableVertexAttribArray(uvAttributeLocation);
    gl.vertexAttribPointer(uvAttributeLocation, 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(pigIndices), gl.STATIC_DRAW); 

    var texture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, texture);

    var image = new Image();
    image.src = baseDir+modelTexture;
    image.onload= function() {
    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);
    };
    
    
   //drawing the missile
    
    var missile = gl.createVertexArray();
    gl.bindVertexArray(missile);

    var misspositionBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, misspositionBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(missileVertices), gl.STATIC_DRAW);
    gl.enableVertexAttribArray(positionAttributeLocation);
    gl.vertexAttribPointer(positionAttributeLocation, 3, gl.FLOAT, false, 0, 0);

    var missileuvBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, missileuvBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(missileTexCoords), gl.STATIC_DRAW);
    gl.enableVertexAttribArray(uvAttributeLocation);
    gl.vertexAttribPointer(uvAttributeLocation, 2, gl.FLOAT, false, 0, 0);

    var missindexBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, missindexBuffer);
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(missileIndices), gl.STATIC_DRAW); 

    var misstexture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, misstexture);

    var missimage = new Image();
    missimage.src = baseDir+missileTexture;
    missimage.onload= function() {
    gl.bindTexture(gl.TEXTURE_2D, misstexture);
              gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, missimage);
              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);
    };
    
    
    drawScene();
    
    function animate(){
    var currentTime = (new Date).getTime();
   if(lastUpdateTime != null){
      //var deltaC = 0; //(30 * (currentTime - lastUpdateTime)) / 1000.0;
      Rx = 90;
      Ry = 90;
      Rz = 90;    
    }
    worldMatrix = utils.MakeWorld(0.0, 0.0, 0.0, Rx, Ry, Rz, S);
    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);

    var viewWorldMatrix = utils.multiplyMatrices(viewMatrix, worldMatrix);
    var projectionMatrix = utils.multiplyMatrices(perspectiveMatrix, viewWorldMatrix);

    gl.uniformMatrix4fv(matrixLocation, gl.FALSE, utils.transposeMatrix(projectionMatrix));

    gl.activeTexture(gl.TEXTURE0);
    gl.uniform1i(textLocation, misstexture);

    gl.bindVertexArray(missile);
    gl.drawElements(gl.TRIANGLES, missileIndices.length, gl.UNSIGNED_SHORT, 0 );
        
    gl.activeTexture(gl.TEXTURE0);
    gl.uniform1i(textLocation, texture);

    gl.bindVertexArray(vao);
    gl.drawElements(gl.TRIANGLES, pigIndices.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]);
      program = utils.createProgram(gl, vertexShader, fragmentShader); 

    });
    gl.useProgram(program);
    
    //###################################################################################
    //This loads the obj model in the pigModel variable
    var pigObjStr = await utils.get_objstr(baseDir+ missileStr);
    missileModel = new OBJ.Mesh(pigObjStr);
   
    var pigObjStr1 = await utils.get_objstr(baseDir+ modelStr);
    pigModel = new OBJ.Mesh(pigObjStr1);

    main();
}

window.onload = init;

2 Answers

bindTexture binds a named texture to a texturing target and the current texture unit. The current texture unit is set by activeTexture.
The texture unit is the binding point between the named texture object and the texture sampler uniform. The sampler uniform has to be set by the texture unit, rather than the texture object name.


You have to assign the texture unit (index) to the texture sampler uniform, and you have to bind the texture to the texture unit before drawing the object:

gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, misstexture);
gl.uniform1i(textLocation, 0); // 0 because 'misstexture' is bound to texture unit 0  

gl.bindVertexArray(missile);
gl.drawElements(gl.TRIANGLES, missileIndices.length, gl.UNSIGNED_SHORT, 0);
        
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.uniform1i(textLocation, 0);  // 0 because 'texture' is bound to texture unit 0

gl.bindVertexArray(vao);
gl.drawElements(gl.TRIANGLES, pigIndices.length, gl.UNSIGNED_SHORT, 0);

Of course it is possible to bind the textures to different texture units:

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

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

and to set the texture sampler uniform before drawing the object

gl.uniform1i(textLocation, 0); // 0 because 'misstexture' is bound to texture unit 0 
gl.bindVertexArray(missile);
gl.drawElements(gl.TRIANGLES, missileIndices.length, gl.UNSIGNED_SHORT, 0);

gl.uniform1i(textLocation, 1);  // 1 because 'texture' is bound to texture unit 1
gl.bindVertexArray(vao);
gl.drawElements(gl.TRIANGLES, pigIndices.length, gl.UNSIGNED_SHORT, 0);

As @Rabbid76 pointed out your calls to gl.uniform1i for textures are wrong. You need to pass in a texture unit index, not a WebGLTexture

As for positions you generally set the position of an object when rendering by passing in a matrix to the shader as a uniform

for each object
  set vertex array
  gl.useProgram(whateverProgramThisObjectNeeds)
  bind textures to texture units
  set uniforms to tell shader which texture units you bound the textures to
  set uniforms for material settings (colors, etc..)
  set uniforms for matrices (projection, view, model)
  gl.drawArrays or gl.drawElements

you don't generally hard code positions into shaders. Setting "initial" positions is not part of WebGL. WebGL just draws points, lines, and triangles. Positions of objects are part of your code. Store them in an array, an map, a tree, a scene graph, a gameobject, something you makeup and then loop through the ones you want to draw, setting some uniforms to draw them in the correct places.

Related