Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 3 of 3

Thread: Problem multi-texturing my water quad.

  1. #1
    Intern Contributor
    Join Date
    Sep 2016
    Posts
    71

    Problem multi-texturing my water quad.

    I’m attempting to make water using color, depth frame buffers and a quad. When I bind the frame buffer’s color texture, I actually see the tex rendered on the quad, but once I try binding TEXTURE1 (refraction), I get the following warning:



    I understand what the warning is telling me, but I'm not sure at what point I'm making this mistake, or even if this is what's going on. This only happens as soon as I try binding TEXTURE1, so for now I comment those two lines out, and just bind TEXTURE0 and my scene is rendered properly. But I'd love to bind the second texture (TEXTURE1) too



    I’m almost sure this is due to my lack of multi-texturing knowledge, I just started reading on it, so I’m suspecting there’s something I’m doing wrong. The idea is to obviously reflect the scene on to the reflection sampler2D, and mix it with the refraction sampler2D which will show what’s “under the water” with depth.

    I don’t think it’s my shader code because I’m including all the attributes and uniforms, and I’m getting 0 shader compiler errors. Let me show what I’m doing so far, hopefully it’s not too much code. I’ve condensed, and by the way thank you for reading.

    This is how I’m drawing the quad water on every frame:

    Code :
    /* DRAW */
    var shader = this.shader;
    shader.bind();
    gl.bindTexture(gl.TEXTURE_2D, null);
     
    // Vertex Postion
    gl.bindBuffer(gl.ARRAY_BUFFER, this.vboVertex);
    gl.vertexAttribPointer(this.vertexAttrib, 3, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(this.vertexAttrib);
    gl.bindBuffer(gl.ARRAY_BUFFER, null);
     
    // Normals
    gl.bindBuffer(gl.ARRAY_BUFFER, this.vboNormal);
    gl.vertexAttribPointer(this.normalsAttrib, 3, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(this.normalsAttrib);
    gl.bindBuffer(gl.ARRAY_BUFFER, null);
     
    // Indices
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.vboIndices);
     
     
    gl.uniform1i(this.reflection, 0);
    gl.uniform1i(this.refraction, 1);
     
    // Texture
    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, this.reflectionColorTexture);
     
    gl.activeTexture(gl.TEXTURE1);
    gl.bindTexture(gl.TEXTURE_2D, this.refractionColorTexture);
     
    gl.bindBuffer(gl.ARRAY_BUFFER, this.vboTex);
    gl.vertexAttribPointer(this.texAttrib, 2, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(this.texAttrib);
     
    // Uniforms
    gl.uniformMatrix4fv(this.mvp, false, mvp);
    gl.uniformMatrix4fv(this.model, false, model);
    gl.uniformMatrix4fv(this.view, false, view);
    gl.uniformMatrix4fv(this.normMat, false, normMat);  
     
    gl.drawElements(gl.TRIANGLES, this.numIndices, gl.UNSIGNED_SHORT, 0);

    This is how I initialize the water quad before rendering (only runs once):

    Code :
    depthExt = gl.getExtension("WEBGL_depth_texture");
    if (!depthExt) { throw "Ahh"; }
     
    let mesh    = Forge.Model.plane(3, 3, 1);
    this.width  = size;
    this.height = size;
    this.shader = shader;
    /*
    MESH!
    */
    // Vertex 
    this.vboVertex = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, this.vboVertex);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(mesh.vertex.coords), gl.STATIC_DRAW);
    gl.bindBuffer(gl.ARRAY_BUFFER, null);
    this.vertexPosAttrib = gl.getAttribLocation(shader.program, "a_position");
    // Normal
    this.vboNormal = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, this.vboNormal);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(mesh.normals.coords), gl.STATIC_DRAW);
    gl.bindBuffer(gl.ARRAY_BUFFER, null);	
    this.normalsAttrib 	= gl.getAttribLocation(shader.program, "a_normals");
    // Indices
    this.vboIndices = gl.createBuffer();
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.vboIndices);
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(mesh.indices.coords), gl.STATIC_DRAW);
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);		
    this.numIndices = mesh.indices.coords.length;	
    // Tex
    this.vboTex = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, this.vboTex);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(mesh.texture.coords), gl.STATIC_DRAW);
    gl.bindBuffer(gl.ARRAY_BUFFER, null);
    this.texAttrib = gl.getAttribLocation(shader.program, "a_texCoords");
     
    // Uniforms
    this.mvp 		= gl.getUniformLocation(shader.program, "mvp");
    this.model 		= gl.getUniformLocation(shader.program, "model");
    this.view 		= gl.getUniformLocation(shader.program, "view");
    this.normMat 	= gl.getUniformLocation(shader.program, "normMat"); 
     
    /*
      WATER REFLECTION FRAME BUFFER
    */
    this.reflectionFrameBuffer = gl.createFramebuffer();
    gl.bindFramebuffer(gl.FRAMEBUFFER, this.reflectionFrameBuffer);
     
    // Color Texture
    this.reflectionColorTexture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, this.reflectionColorTexture);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.reflectionColorTexture, 0);
    gl.bindTexture(gl.TEXTURE_2D, null);
     
    // Depth Buffer Attachment
    this.reflectionDepthBuffer = gl.createRenderbuffer();
    gl.bindRenderbuffer(gl.RENDERBUFFER, this.reflectionDepthBuffer);
    gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, this.width, this.height);
    gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, this.depthBuffer);
     
    // Unbind
    gl.bindRenderbuffer(gl.RENDERBUFFER, null);
    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
     
     
    /*
      WATER REFRACTION FRAME BUFFER
    */
    this.refractionFrameBuffer = gl.createFramebuffer();
    gl.bindFramebuffer(gl.FRAMEBUFFER, this.refractionFrameBuffer);
     
    // Color Texture
    this.refractionColorTexture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, this.refractionColorTexture);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.refractionColorTexture, 0);
    gl.bindTexture(gl.TEXTURE_2D, null);
     
    // Depth Buffer Attachment
    this.refractionDepthTexture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, this.refractionDepthTexture);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, size, size, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_SHORT, null);
    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, this.refractionDepthTexture, 0);
     
    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    gl.bindTexture(gl.TEXTURE_2D, null);
     
    if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) { throw "oh no"; }
     
    // Reflection and Refraction Uniform
    this.reflection = gl.getUniformLocation(shader.program, "reflection");
    this.refraction = gl.getUniformLocation(shader.program, "refraction");
    // Unbind
    gl.bindFramebuffer(gl.FRAMEBUFFER, null);

    and this how I render the water quad after I’ve drawn the scene two previous times, one for the reflection texture, the other for refraction:
    Code :
     
    /*
        Render Function!
    */
    {
        frameBuffer.bindReflection();
        clear();
     
        drawScene(objs, numObjs);
        frameBuffer.unbind();
     
     
        frameBuffer.bindRefraction();
        clear();
     
        drawScene(objs, numObjs);
        frameBuffer.unbind();
    }
     
    projection = Mathf.perspective(currentCam.fov, Forge.app.aspect, currentCam.near, currentCam.far);
    clear();
     
    water.draw(projection, view);	
    finalDrawScene(objs, numObjs);

    Oh and almost forgot to include the bind and unbind functions, although they're quite straight forward:

    Code :
        bindReflection = function () {
            gl.bindFramebuffer(gl.FRAMEBUFFER, this.reflectionFrameBuffer);
            gl.viewport(0, 0, this.width, this.height);
        };
     
        bindRefraction = function () {
            gl.bindFramebuffer(gl.FRAMEBUFFER, this.refractionFrameBuffer);
            gl.viewport(0, 0, this.width, this.height);
        };
     
        unbind = function () {
            gl.bindFramebuffer(gl.FRAMEBUFFER, null);
            gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
        };
    Last edited by hashbrown; 06-10-2017 at 12:28 PM.

  2. #2
    Member Regular Contributor
    Join Date
    May 2016
    Posts
    419
    from what the "warnings" say, i guess that you try to read and write from the same texture, afaik thats not allowed. the warnings also say that there isnt a texture bountd at unit 0, so before you gl.bindtexture(...), call gl.activetexture(GL.texture0 + 0/* 0 being the unit */), by the way its sufficient to do that once and let'em bound there

    remember: when you call gl.bindtexture(blabla, 0), you unbind the texture at the current "texture unit", just to make sure that textures ae in place you can bind them each again to their respective unit once you've initialized them:

    init texture 1
    init texture 2
    init texture 3
    init texture ...

    /* bind to unit */
    gl.activetexture(GL.texture0 + 1)
    glBindtexture(blabla, texture1);

    gl.activetexture(GL.texture0 + 2)
    glBindtexture(blabla, texture2);

    gl.activetexture(GL.texture0 + 3)
    glBindtexture(blabla, texture3);

    ...

    /* reset marker */
    gl.activetexture(GL.texture0)
    Last edited by john_connor; 06-10-2017 at 12:39 PM.

  3. #3
    Intern Contributor
    Join Date
    Sep 2016
    Posts
    71
    Quote Originally Posted by john_connor View Post
    from what the "warnings" say, i guess that you try to read and write from the same texture, afaik thats not allowed. the warnings also say that there isnt a texture bountd at unit 0, so before you gl.bindtexture(...), call gl.activetexture(GL.texture0 + 0/* 0 being the unit */), by the way its sufficient to do that once and let'em bound there

    remember: when you call gl.bindtexture(blabla, 0), you unbind the texture at the current "texture unit", just to make sure that textures ae in place you can bind them each again to their respective unit once you've initialized them:

    init texture 1
    init texture 2
    init texture 3
    init texture ...

    /* bind to unit */
    gl.activetexture(GL.texture0 + 1)
    glBindtexture(blabla, texture1);

    gl.activetexture(GL.texture0 + 2)
    glBindtexture(blabla, texture2);

    gl.activetexture(GL.texture0 + 3)
    glBindtexture(blabla, texture3);

    ...

    /* reset marker */
    gl.activetexture(GL.texture0)

    John, amazing. Now I understand how multi-texturing works, and I tried several sites. but your explanation did it. Oh and the problem I mostly had was that I was missing the reset marker. As soon as I read that part of your code, I added it and now it's working. Thanks again.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •