anon755
anon755

Reputation: 11

How to get a second shader in webGL to work?

I have set up two shaders in my program to use for different objects in the code. The shaders individually have been tested and work, so the issue lies with the webgl code. Here's what I have in the initial shading code.

    var vertexShader = this.getShader("VertexShader2");

    this.shaderProgram = gl.createProgram();
    gl.attachShader(this.shaderProgram, vertexShader);
    gl.attachShader(this.shaderProgram, fragmentShader);
    gl.linkProgram(this.shaderProgram);

    if(!gl.getProgramParameter(this.shaderProgram, gl.LINK_STATUS)){
        console.log("unable to init shader program");
    }

    gl.useProgram(GC.canvas.shaderProgram);

    GC.vertexPositionAttribute = gl.getAttribLocation(this.shaderProgram, "vPos");
    gl.enableVertexAttribArray(GC.vertexPositionAttribute);

    GC.barycentricAttribute = gl.getAttribLocation(this.shaderProgram, "bary");
    gl.enableVertexAttribArray(GC.barycentricAttribute);

    GC.normalAttribute = gl.getAttribLocation(this.shaderProgram, "norm");
    gl.enableVertexAttribArray(GC.normalAttribute);

    var fragmentShader2 = this.getShader("FragmentShader1");
    var vertexShader2 = this.getShader("VertexShader1");

    this.shaderProgram2 = gl.createProgram();
    gl.attachShader(this.shaderProgram2, vertexShader2);
    gl.attachShader(this.shaderProgram2, fragmentShader2);
    gl.linkProgram(this.shaderProgram2);

    if(!gl.getProgramParameter(this.shaderProgram2, gl.LINK_STATUS)){
        console.log("unable to init shader program 2");
    }




    GC.shaderProgram = this.shaderProgram;
    GC.shaderProgram2 = this.shaderProgram2;

And in a separate function to initialize the shaders...

    gl.useProgram(GC.canvas.shaderProgram2);
    GC.vertexPositionAttribute2 = gl.getAttribLocation(GC.shaderProgram2, "vPos");
    gl.enableVertexAttribArray(GC.vertexPositionAttribute2);

    GC.barycentricAttribute2 = gl.getAttribLocation(GC.shaderProgram2, "bary");
    gl.enableVertexAttribArray(GC.barycentricAttribute2);

    GC.textureCoordAttribute = gl.getAttribLocation(GC.shaderProgram2, "aTextureCoord");
    gl.enableVertexAttribArray(GC.textureCoordAttribute);

    GC.vert_tangPtr = gl.getAttribLocation(GC.shaderProgram2, "vert_tang");
    gl.enableVertexAttribArray(GC.vert_tangPtr);

    GC.vert_bitangPtr = gl.getAttribLocation(GC.shaderProgram2, "vert_bitang");
    gl.enableVertexAttribArray(GC.vert_bitangPtr);

    GC.vert_uvPtr = gl.getAttribLocation(GC.shaderProgram2, "vert_uv");
    gl.enableVertexAttribArray(GC.vert_uvPtr); 
}

And the webgl code later to switch the shader and set up the object.

    gl.useProgram(GC.shaderProgram2);
    setupShader2();
    mvTranslate([(m1.minX+m1.maxX)/2.0,(m1.minY+m1.maxY)/2.0,(m1.minZ+m1.maxZ)/2.0],GC);

    mvMultMatrix(camera.Transform,GC);//multiply by the transformation

    //translate back to original origin
    mvTranslate([-(m1.minX+m1.maxX)/2.0,-(m1.minY+m1.maxY)/2.0,-(m1.minZ+m1.maxZ)/2.0],GC);
    //---------

    //passes modelview and projection matrices to the vertex shader
    setMatrixUniforms(GC);

    GC.norm_mtx = GC.mvMatrix;
    GC.norm_mtx = GC.norm_mtx.inverse();
    GC.norm_mtx = GC.norm_mtx.transpose();

    var pnormal = gl.getUniformLocation(GC.shaderProgram2, "norm_mtx");
    gl.uniformMatrix4fv(pnormal, false, new Float32Array(GC.norm_mtx.flatten()));


    //pass the vertex buffer to the shader
    gl.bindBuffer(gl.ARRAY_BUFFER, m1.vertexBuffer);
    gl.vertexAttribPointer(GC.vertexPositionAttribute2, 3, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(GC.vertexPositionAttribute2);

    //pass the barycentric coords to the shader for edge detection
    gl.bindBuffer(gl.ARRAY_BUFFER, GC.barycentricBuffer);
    gl.vertexAttribPointer(GC.barycentricAttribute2, 3, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(GC.barycentricAttribute2);

    gl.bindBuffer(gl.ARRAY_BUFFER, GC.textureCoordBuffer);
    gl.vertexAttribPointer(GC.textureCoordAttribute, 2, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(GC.vtextureCoordAttribute);

    gl.bindBuffer(gl.ARRAY_BUFFER, GC.vert_tang);
    gl.vertexAttribPointer(GC.vert_tangPtr, 3, gl.FLOAT, false, 0, 0);

    gl.bindBuffer(gl.ARRAY_BUFFER, GC.vert_bitang);
    gl.vertexAttribPointer(GC.vert_bitangPtr, 3, gl.FLOAT, false, 0, 0);

    gl.bindBuffer(gl.ARRAY_BUFFER, GC.vert_uv);
    gl.vertexAttribPointer(GC.vert_uvPtr, 2, gl.FLOAT, false, 0, 0);

    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, GC.tex_norm);
    var uni = gl.getUniformLocation(GC.shaderProgram2, "tex_norm");
    gl.uniform1i(uni, 0);

    gl.activeTexture(gl.TEXTURE1);
    gl.bindTexture(gl.TEXTURE_2D, GC.tex_diffuse);
    uni = gl.getUniformLocation(GC.shaderProgram2, "tex_diffuse");
    gl.uniform1i(uni, 1);

    gl.activeTexture(gl.TEXTURE2);
    gl.bindTexture(gl.TEXTURE_2D, GC.tex_depth);
    uni = gl.getUniformLocation(GC.shaderProgram2, "tex_depth");
    gl.uniform1i(uni, 2);

    gl.uniform1i(GC.uSampler, 0);

    var scale = 0.01 * 1.0;
    uni = gl.getUniformLocation(GC.shaderProgram2, "depth_scale");
    gl.uniform1f(uni, scale);

    var steps = 1.0;
    uni = gl.getUniformLocation(GC.shaderProgram2, "num_layers");
    gl.uniform1f(uni, steps);

    var show_tex = true;
    uni = gl. getUniformLocation(GC.shaderProgram2, "show_tex");
    gl.uniform1i(uni, show_tex);
    //draw everything
    gl.drawArrays(gl.TRIANGLES,0,m1.indices.length);

Please take a look and help-it's currently not showing any object past the first.

Upvotes: 1

Views: 84

Answers (1)

YGilk1
YGilk1

Reputation: 464

In the code you shared, I see different things missing. You link a program and use another one to get vertex attributes locations

gl.linkProgram(this.shaderProgram);

// ...

gl.useProgram(GC.canvas.shaderProgram);

You get the vertex attributes for the second program in your separate function, but we don't know when it's called. I think it would have been easier to read and understand if you had created 2 functions to initialize each program

function setProgram()
{
    fragmentShader = this.getShader("VertexShader2");
    vertexShader = this.getShader("VertexShader2");

    this.shaderProgram = gl.createProgram();
    gl.attachShader(this.shaderProgram, vertexShader);
    gl.attachShader(this.shaderProgram, fragmentShader);
    gl.linkProgram(this.shaderProgram);

    if(!gl.getProgramParameter(this.shaderProgram, gl.LINK_STATUS)){
        console.log("unable to init shader program");
    }

    gl.useProgram(this.shaderProgram);

    GC.vertexPositionAttribute = gl.getAttribLocation(this.shaderProgram, "vPos");
    gl.enableVertexAttribArray(GC.vertexPositionAttribute);

    GC.barycentricAttribute = gl.getAttribLocation(this.shaderProgram, "bary");
    gl.enableVertexAttribArray(GC.barycentricAttribute);

    GC.normalAttribute = gl.getAttribLocation(this.shaderProgram, "norm");
    gl.enableVertexAttribArray(GC.normalAttribute);

    GC.shaderProgram = this.shaderProgram;
}

function setProgram2()
{
    var fragmentShader2 = this.getShader("FragmentShader1");
    var vertexShader2 = this.getShader("VertexShader1");

    this.shaderProgram2 = gl.createProgram();
    gl.attachShader(this.shaderProgram2, vertexShader2);
    gl.attachShader(this.shaderProgram2, fragmentShader2);
    gl.linkProgram(this.shaderProgram2);

    if(!gl.getProgramParameter(this.shaderProgram2, gl.LINK_STATUS)){
        console.log("unable to init shader program 2");
    }

    gl.useProgram(this.shaderProgram2);

    GC.vertexPositionAttribute2 = gl.getAttribLocation(GC.shaderProgram2, "vPos");
    gl.enableVertexAttribArray(GC.vertexPositionAttribute2);

    GC.barycentricAttribute2 = gl.getAttribLocation(GC.shaderProgram2, "bary");
    gl.enableVertexAttribArray(GC.barycentricAttribute2);

    GC.textureCoordAttribute = gl.getAttribLocation(GC.shaderProgram2, "aTextureCoord");
    gl.enableVertexAttribArray(GC.textureCoordAttribute);

    GC.vert_tangPtr = gl.getAttribLocation(GC.shaderProgram2, "vert_tang");
    gl.enableVertexAttribArray(GC.vert_tangPtr);

    GC.vert_bitangPtr = gl.getAttribLocation(GC.shaderProgram2, "vert_bitang");
    gl.enableVertexAttribArray(GC.vert_bitangPtr);

    GC.vert_uvPtr = gl.getAttribLocation(GC.shaderProgram2, "vert_uv");
    gl.enableVertexAttribArray(GC.vert_uvPtr); 

    GC.shaderProgram2 = this.shaderProgram2;
}

And I don't see where you use the second program in the animation loop.

Remember WebGL is kind of a state machine. Everything that is set up when you call draw function is used. You can split the code in 2 parts: what should be executed at init time and once the animation loop is running.

At init time You need to setup your objects geometry and create the programs

  • create buffers
  • feed them with data
  • create programs and for each: get uniform and vertex attribute locations
function init()
{
    // for each buffer, create, bind and set data
    gl.createBuffer(...)
    gl.bindBuffer(gl.ARRAY_BUFFER, ...)
    gl.bufferData(...)

    // Do the same with every buffer

    // for each program, create, compile and validate shaders, create the program, attach shaders, link and validate
    var program = createProgram()

    // Use the program
    gl.useProgram(program)

    // Get vertex attribute locations
    gl.getAttribLocation(...)

    // Get uniform locations
    gl.getUniformLocation(...)

    // Do the same with every program
}

In the animation loop, you need to set the current state before drawing each mesh in a same frame:

  • set state requirements (enable/disable stuff)
  • bind buffers (ARRAY and ELEMENT_ARRAY if you use indexed geometry)
  • bind textures
  • use a program (it must be linked and validated)
  • retrieve vertex attributes locations, specify their layout and enable them
  • set uniform values (matrices in your case)

If something is missing, it will be used from the previous state. That can explain why you don't see your objects.

function renderObject()
{
    // State requirements (if needed)
    gl.enable(...)
    gl.disable(...)

    // Bind textures
    gl.bindTexture(gl.TEXTURE_2D, ...) // repeat this for each texture your program needs

    // Using program
    gl.useProgram(program) // this enable the program you need for the draw

    // Bind buffers
    gl.bindBuffer(gl.ARRAY_BUFFER, ...) // repeat this for each buffer your program needs
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ...)

    // Specify attributes layout (use stored locations)
    gl.vertexAttribPointer(...)

    // Enable vertex attributes
    gl.enableVertexAttribArray(...)

    // Set uniform values (use stored locations)
    gl.uniform1234fv(...)

    // And finally draw your mesh
    gl.drawArrays(...)

    // Clear what you won't need anymore (bind things to null, disable...)
    gl.disableVertexAttribArray(...)
}

Upvotes: 1

Related Questions