Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Layered rendering to CUBEMAP using geometry shader

Tags:

opengl

glsl

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

like image 663
Michael IV Avatar asked Oct 15 '15 18:10

Michael IV


1 Answers

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.

like image 97
Nicol Bolas Avatar answered Nov 13 '22 17:11

Nicol Bolas