8
votes

I am trying to render to all 6 faces of cubemap with a single drawcall.The GL cubemap is attached to an offscreen frame buffer object.The result I am getting is only the face number zero is affected by both frame buffer clear color and the fragment shader output.The goal is to use geometry shader which is invoked 6 times (once per face),then the gl_InstanceID is assigned to built-in gl_Layer.Fragment shader stage would read gl_Layer value and shade the raster based on in.It is expected that all 6 faced will be painted with a unique color that depends on gl_Layer value.

For the tests to see that I am getting correct gl_layer value I'm trying to render the layer id into the alpha channel of the texture by the following fragment shader:

#version 430  

// Ouput data
layout(location = 0) out vec4 color;

in int gl_Layer;

void main(){
    color  = vec4(0.5,0.5,0.5,float(gl_Layer)/255.0);
}

The vertex shader basically do nothing:

#version 430  

in vec3 position;


void main(){
     gl_Position = vec4(position, 1.0);
}

and the geometry shader executes 6 times, render a unit square (covers the whole viewport) and sets gl_Layer according to gl_InvocationID:

#version 430  

layout(triangles, invocations = 6) in;
layout(triangle_strip, max_vertices = 4) out;

out int gl_Layer;

void main() 
{     
    const vec2 vert_data[4] = vec2[]( vec2(-1.0, 1.0), vec2(-1.0, -1.0), vec2(1.0, 1.0), vec2(1.0, -1.0) );

    for(int i=0; i<4; i++)
    {
        gl_Layer = gl_InvocationID;
        gl_Position = vec4(vert_data[i].xy,0,1);
        EmitVertex();
    }

    EndPrimitive();
}

and finally, this is how I set the texture and the framebuffer:

    glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &fbtextures_count);
    // how many textures to create? depends on complexity of your effects.
    glActiveTexture(GL_TEXTURE0);
    glGenFramebuffers(1, &framebuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
    glGenTextures(1, &fbcubetexture);
    GLenum target = GL_TEXTURE_CUBE_MAP;

    // initializing color maps
    glBindTexture(target, fbcubetexture);
    glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);


    initData(255,255, 255);
    for (int i = 0; i < 6; i++)
    { 
        glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGBA8, cube_s, cube_s, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
    }

    glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, fbcubetexture, 0);

    GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0 };
    glDrawBuffers(1, drawBuffers); 
    glReadBuffer(GL_COLOR_ATTACHMENT0);
    glDrawBuffer(GL_COLOR_ATTACHMENT0);
    glBindFramebuffer(GL_FRAMEBUFFER, 0); 

I am reading the faces colors on the client with:

 for (int i = 0; i < 6; i++)
 { 
    glGetTexImage(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGBA,GL_UNSIGNED_BYTE, data); 
 }

The result I get for GL_TEXTURE_CUBE_MAP_POSITIVE_X, is correct. but the rest of the face stay with the same first initialized value.I also debugged using NVIDIA NSIGHT where the whole cubemap texture is seen with only one face painted.

I read tens of examples which show how to use gl_Layer id for multi-target rendering through geometry shader but all of them do it differently.

For example,it is not clear if it is enough to attach cubemap texture to a single render target of FBO,or each face must be attached to a different render target?

Should glFramebufferTexture be used to bind the attachments or glFramebufferTexture2D ?

When cubemap is attached to the framebuffer is glClearColor supposed to clear all the faces to some color or just the first one?

What do I miss here?Anyone can show how to do it the right way?

System specs:

GPU:NVIDIA GeForce 960 GTX Windows7 64bit MSVC120

1
As far as I know glTexImage2D() is used for uploading/writing texture data not for downloading/reading it. To read texture data you should use glGetTexImage(). The rest of the code looks ok. Just ensure that before offscreen drawing you bind correct FBO (glBindFramebuffer()), and then set up glViewport(0, 0, cube_s, cube_s) then perform draw.Shot
Oops,that's a type.That's in reality was glGetTexImage()Michael IV
oh, i have same problem now. you solve this problem?? I use nsight, i can see only 1 face draw, and other 5 is black.Redwings

1 Answers

1
votes

I can't prove this is the problem. But it is certainly one problem:

for(int i=0; i<4; i++)

You said that your GS takes triangles as inputs. Well, those only have three vertices, not 4. So your triangle strip will have a bad vertex in it.

When looping over items in a GS, it's always safer to do this:

for(int i = 0; i < gl_in.length(); i++)

That way, if you change the input primitive type, your length automatically gets updated.