2
\$\begingroup\$

I am currently developing a deferred renderer for my game engine and I have to output multiple textures from my shader to my GBuffer. I have been struggling with getting multiple outputs from the fragment shader. I am using OpenGL 3.3. My Frame Buffer class allows for multiple color buffers by binding multiple textures and receiving inputs from GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, etc... GL_COLOR_ATTACHMENT0 works but using any different color attachment yields an empty texture. I have looked at many examples but cannot find what is wrong with my code. Any thoughts as to why this setup may not be working would be very helpful.

Frame Buffer Creation Code:

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL12.*;
import static org.lwjgl.opengl.GL14.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*;


import java.nio.IntBuffer;
import java.util.ArrayList;



public class RenderPass {

private int framebufferID;
private int[] texIDs = new int[16];
private Texture[] tex = new Texture[16];
private int depthTextureID;
private int  colorTextureID;
private int depthRenderBufferID;
private int width;
private int height;

private Texture depth_texture;
private Texture color_texture;

private ArrayList<Integer> renderLayers = new ArrayList<Integer>();
 ArrayList<Integer> buffers = new ArrayList<Integer>();
IntBuffer drawBuffers;

public RenderPass(int width, int height){

    this(width, height, new ArrayList<Integer>());

}

public RenderPass(int width, int height, ArrayList<Integer> renderLayers){

    this.width = width;
    this.height = height;
    this.renderLayers = renderLayers;


    System.out.println("FBO is supported!!!");

    framebufferID = glGenFramebuffers();
    colorTextureID = glGenTextures();
    depthTextureID = glGenTextures();
    depthRenderBufferID = glGenRenderbuffers();     

    glBindFramebuffer(GL_FRAMEBUFFER, framebufferID);
    framebufferID = glGenFramebuffers();                                         // create a new framebuffer
    //colorTextureID = glGenTextures();                                               // and a new texture used as a color buffer
    depthRenderBufferID = glGenRenderbuffers();                                  // And finally a new depthbuffer

    glBindFramebuffer(GL_FRAMEBUFFER, framebufferID);                        // switch to the new framebuffer

 addTexture(0,false);

    // initialize depth renderbuffer
    glBindRenderbuffer(GL_RENDERBUFFER, depthRenderBufferID);                // bind the depth renderbuffer
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height); // get the data space for it
    glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_RENDERBUFFER, depthRenderBufferID); // bind it to the renderbuffer

    glBindTexture(GL_TEXTURE_2D, depthTextureID);                                   // Bind the depthbuffer texture
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);               // make it linear filterd

    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 0,GL_DEPTH_COMPONENT, GL_FLOAT, (java.nio.ByteBuffer) null);  // Create the texture data
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);


    glFramebufferTexture2D(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_TEXTURE_2D, depthTextureID, 0); // attach it to the framebuffer

    glBindFramebuffer(GL_FRAMEBUFFER, 0);                                    // Swithch back to normal framebuffer rendering

}    
public void addTexture(int index, boolean isFloatingPoint){
    texIDs[index] = glGenTextures();
    if(!buffers.contains(index))buffers.add(GL_COLOR_ATTACHMENT0+index);
    glBindFramebuffer(GL_FRAMEBUFFER, framebufferID);
    System.out.println(buffers);
    glBindTexture(GL_TEXTURE_2D,texIDs[index]);   
      glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);               // make it linear filterd
       if(isFloatingPoint) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0,GL_RGBA, GL_FLOAT, (java.nio.ByteBuffer) null);
       else glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0,GL_RGBA, GL_INT, (java.nio.ByteBuffer) null);  // Create the texture data
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
        glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0+index,GL_TEXTURE_2D, texIDs[index], 0); // attach it to the framebuffer

    drawBuffers = Util.createFlippedBuffer(Util.toIntArray(buffers.toArray(new Integer[buffers.size()])));

}

public void begin(){
    glBindTexture(GL_TEXTURE_2D, 0); 
    glBindFramebuffer(GL_FRAMEBUFFER, framebufferID); 
    glDrawBuffers(drawBuffers);
    if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
        System.err.println("OOPS SOMETHING IS WRONG WITH YOUR FRAMEBUFFER");

    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);   

}

public void end(){
    color_texture = new Texture(colorTextureID);
    for(int i = 0; i<texIDs.length;i++){
        if(texIDs[i]!= 0)tex[i]= new Texture(texIDs[i]);
        //tex[i]= new Texture(texIDs[i]);
    }
    depth_texture = new Texture(depthTextureID);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  

}


public void addRenderLayer(int layerIndex){

    renderLayers.add(layerIndex);

}

public ArrayList<Integer> getRenderLayers() {
    return renderLayers;
}

public void setRenderLayers(ArrayList<Integer> renderLayers) {
    this.renderLayers = renderLayers;
}

public Texture[] getTextures(){
    return tex;
}
public Texture getDepthTexture(){
    return depth_texture;
}

public Texture getColor_texture() {
    return color_texture;
}

public void setColor_texture(Texture color_texture) {
    this.color_texture = color_texture;
}

}`

Vertex Shader Code:

#version 330
layout (location = 0) in vec3 position;
layout (location = 1) in vec2 texCoord;
layout (location = 2) in vec3 normal;
layout (location = 3) in vec3 vertColor;
layout (location = 4) in vec3 tangent;
layout (location = 5) in int materialIndex;

out vec2 texCoord0;
out vec3 normal0;
out mat3 tangentToWorld;
out vec3 worldPos0;
out vec3 vertColor0;
flat out int materialIndex0;

uniform mat4 transform;
uniform mat4 transformProjected;

void main()
{   
    gl_Position = transformProjected * vec4(position, 1.0);
    texCoord0 = texCoord;
    normal0 = (transform * vec4(normal, 0.0)).xyz;
    //worldPos0 = (transform * vec4(position, 1)).xyz;
    vertColor0 = vertColor;
    materialIndex0 = materialIndex;
    vec3 binormal = cross(tangent,normal);
    mat3 tangentToWorld;
    tangentToWorld[0] = tangent;
    tangentToWorld[1] = binormal;
    tangentToWorld[2] = normal;
}

Fragment Shader Code:

#version 330

const int MAX_MATERIALS=16;

in vec2 texCoord0;
in vec3 normal0;
in vec3 worldPos0;
in vec3 vertColor0;
flat in int materialIndex0;
in mat3 tangentToWorld;

layout (location = 0) out vec4 colorSI;
layout (location = 1) out vec4 normalSE;
//layout (location = 2) out vec4 specularColorAO;
layout (location = 2) out vec4 EmissionAOMat;

uniform sampler2D Diffuse;
uniform sampler2D Normal;
uniform sampler2D Specular;
uniform sampler2D AO;
uniform sampler2D Emission;

void main()
{   
    colorSI = vec4(1,1,0,1);
    normalSE = vec4(1,0,1,1);

    vec4 diffuseTexture = texture2D(Diffuse, texCoord0.xy);
    if(diffuseTexture.xyz != vec3(0)){
    colorSI.xyz = vec3(diffuseTexture.xyz*vertColor0);
    }
    vec4 normalTexture = texture2D(Normal, texCoord0.xy);
    if(normalTexture.xyz != vec3(0)){
        normalSE.xyz = normalTexture.xyz*tangentToWorld;
    }
    vec4 specTexture = texture2D(Specular, texCoord0.xy);
    if(specTexture.xyz != vec3(0)){
        colorSI.a = specTexture.r;
        normalSE.a = specTexture.g;
    }
    vec4 AOTexture = texture2D(AO, texCoord0.xy);
    vec4 emissionTexture = texture2D(Emission, texCoord0.xy);

    EmissionAOMat = vec4(emissionTexture.r, AOTexture.r,materialIndex0,0);
    normalSE.a = 1;

}

Mesh Draw Code:

public void drawAdvanced(){

        //if(mat.getTexture() != null)
        //  mat.getTexture().bind();

        glEnableVertexAttribArray(0);
        glEnableVertexAttribArray(1);
        glEnableVertexAttribArray(2);
        glEnableVertexAttribArray(3);
        glEnableVertexAttribArray(4);
        glEnableVertexAttribArray(5);

        glBindBuffer(GL_ARRAY_BUFFER, vbo);
        glVertexAttribPointer(0, 3, GL_FLOAT, false, Vertex.SIZE * 4, 0);
        glVertexAttribPointer(1, 2, GL_FLOAT, false, Vertex.SIZE * 4, 12);
        glVertexAttribPointer(2, 3, GL_FLOAT, false, Vertex.SIZE * 4, 20);
        glVertexAttribPointer(3, 3, GL_FLOAT, false, Vertex.SIZE * 4, 32);
        glVertexAttribPointer(4, 3, GL_FLOAT, false, Vertex.SIZE * 4, 44);
        glVertexAttribPointer(5, 1, GL_INT, false, Vertex.SIZE * 4, 56);

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
        glDrawElements(GL_TRIANGLES, size, GL_UNSIGNED_INT, 0);

        glDisableVertexAttribArray(0);
        glDisableVertexAttribArray(1);
        glDisableVertexAttribArray(2);
        glDisableVertexAttribArray(3);
        glDisableVertexAttribArray(4);
        glDisableVertexAttribArray(5);
        //if(mat.getTexture() != null)
        //  mat.getTexture().unbind();
    }

GBuffer Code:

import static org.lwjgl.opengl.EXTFramebufferObject.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL12.GL_CLAMP_TO_EDGE;
import static org.lwjgl.opengl.GL14.*;
import static org.lwjgl.opengl.GL30.*;

import java.util.ArrayList;

import com.epicmstudios.openworldengine.core.FlatRenderer;
import com.epicmstudios.openworldengine.core.Mesh;
import com.epicmstudios.openworldengine.core.MeshRenderer;
import com.epicmstudios.openworldengine.core.RenderPass;
import com.epicmstudios.openworldengine.core.Texture;


public class GBuffer {

    private static RenderPass gBufferPass = new RenderPass(1280, 720);
    private static GBufferShader gBufferShader = GBufferShader.getInstance();

    public static RenderPass getGBufferPass() {
        return gBufferPass;
    }
    public static void setGBufferPass(RenderPass gBufferPass) {
        GBuffer.gBufferPass = gBufferPass;
    }

    public static void setUpTextures(){
        gBufferPass.addTexture(1, true);
        gBufferPass.addTexture(2, false);
        //for(int i = 2; i<4;i++)gBufferPass.addTexture(i, false);
    }

    public static void bind(Mesh mesh){
        gBufferPass.begin();
        gBufferShader.bind();
        gBufferShader.updateUniforms(mesh);
    }

    public static void unbind(){
        gBufferShader.unbind();
        gBufferPass.end();
    }

    public static void updateUniforms(Mesh mesh){
        gBufferShader.updateUniforms(mesh);
    }

    public static Texture getColorSI(){
        return gBufferPass.getTextures()[0];
    }
    public static Texture getNormalSE(){
        return gBufferPass.getTextures()[1];
    }
    public static Texture getEmissionAOMat(){
        return gBufferPass.getTextures()[2];
    }
    public static Texture[] getTextures(){
        return gBufferPass.getTextures();
    }

}

GBuffer Shader Class Code

import static org.lwjgl.opengl.GL13.*;


import com.epicmstudios.openworldengine.core.Matrix4f;
import com.epicmstudios.openworldengine.core.Mesh;
import com.epicmstudios.openworldengine.core.ResourceGetter;
import com.epicmstudios.openworldengine.core.Shader;



public class GBufferShader extends Shader {

    public static final GBufferShader instance = new GBufferShader();

    public static GBufferShader getInstance(){

        return instance;

    }
    private GBufferShader() {
        super();

        addVertexShader(ResourceGetter.loadShader("GBuffer.vert"));
        addFragmentShader(ResourceGetter.loadShader("GBuffer.frag"));
        compileShader();
        //addUniform("transform");
        addUniform("transformProjected");
        addUniform("Diffuse");
        addUniform("Normal");
        addUniform("Specular");
        addUniform("AO");
        addUniform("Emission");
    }
    public void updateUniforms(Mesh mesh){

        //setUniformM4f("transform", mesh.getTransform().getTransformation());
        setUniformM4f("transformProjected", mesh.getTransform().getProjectedTransformation());
        setUniformi("Diffuse",0);
        setUniformi("Normal",1);
        setUniformi("Specular",2);
        setUniformi("AO",3);
        setUniformi("Emission",4);
        glActiveTexture(GL_TEXTURE0);
        if(mesh.getDiffuseTexture()!=null)mesh.getDiffuseTexture().bind();
        glActiveTexture(GL_TEXTURE1);
        if(mesh.getNormalTexture()!=null)mesh.getNormalTexture().bind();
        glActiveTexture(GL_TEXTURE2);
        if(mesh.getSpecularTexture()!=null)mesh.getSpecularTexture().bind();
        glActiveTexture(GL_TEXTURE3);
        if(mesh.getAOTexture()!=null)mesh.getAOTexture().bind();
        glActiveTexture(GL_TEXTURE4);
        if(mesh.getEmissionTexture()!=null)mesh.getEmissionTexture().bind();
    }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.