OpenGL / GLSL: eseguire il rendering sulla mappa del cubo?


13

Sto cercando di capire come rendere la mia scena su una mappa cubica. Sono stato bloccato su questo per un po 'e ho pensato che avrei chiesto aiuto a voi ragazzi. Sono nuovo di OpenGL e questa è la prima volta che utilizzo un FBO.

Attualmente ho un esempio funzionante di utilizzo di un file bmp cubemap e il tipo di campione samplerCube nello shader di frammento è collegato a GL_TEXTURE1. Non sto cambiando affatto il codice shader. Sto solo cambiando il fatto che non chiamerò la funzione che stava caricando il file bmp di cubemap e provando a usare il codice seguente per eseguire il rendering su una cubemap.

Di seguito puoi vedere che allego di nuovo anche la trama a GL_TEXTURE1. Questo è così quando ho impostato l'uniforme:

glUniform1i(getUniLoc(myProg, "Cubemap"), 1);

può accedervi nel mio shader di frammenti tramite uniform samplerCube Cubemap.

Sto chiamando la seguente funzione in questo modo:

cubeMapTexture = renderToCubeMap(150, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);

Ora, mi rendo conto nel ciclo di disegno qui sotto che non sto cambiando la direzione della vista per guardare in basso l'asse + x, -x, + y, -y, + z, -z. Volevo davvero vedere qualcosa che funzionasse prima di implementarlo. Ho pensato che avrei dovuto almeno vedere qualcosa sul mio oggetto come è ora il codice.

Non vedo nulla, solo nero. Ho reso il mio sfondo bianco ancora l'oggetto è nero. Ho rimosso l'illuminazione e la colorazione per campionare solo la trama della mappa cubica e ancora nera.

Sto pensando che il problema potrebbe essere il tipo di formato durante l'impostazione della mia trama che è GL_RGB8, GL_RGBA ma ho anche provato:

GL_RGBA, GL_RGBA GL_RGB, GL_RGB

Ho pensato che sarebbe stato standard dato che stiamo eseguendo il rendering su una trama collegata a un framebuffer, ma ho visto diversi esempi che usano valori enum differenti.

Ho anche provato a legare la trama della mappa cubo in ogni chiamata di disegno che voglio usare la mappa cubo:

glBindTexture(GL_TEXTURE_CUBE_MAP, cubeMapTexture);

Inoltre, non sto creando un buffer di profondità per l'FBO che ho visto nella maggior parte degli esempi, perché desidero solo il buffer di colore per la mia mappa del cubo. In realtà ne ho aggiunto uno per vedere se quello era il problema e ho comunque ottenuto gli stessi risultati. Potrei rovinare tutto quando ho provato.

Qualsiasi aiuto che possa indicarmi la giusta direzione sarebbe apprezzato.

GLuint renderToCubeMap(int size, GLenum InternalFormat, GLenum Format, GLenum Type)
    {

    // color cube map
    GLuint textureObject;
    int face;
    GLenum status;

    //glEnable(GL_TEXTURE_2D);
    glActiveTexture(GL_TEXTURE1);
    glGenTextures(1, &textureObject);
    glBindTexture(GL_TEXTURE_CUBE_MAP, textureObject);
    glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);

    for (face = 0; face < 6; face++) {
        glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, InternalFormat, size, size, 0, Format, Type, NULL);
    }

    // framebuffer object
    glGenFramebuffers(1, &fbo);
    glBindFramebuffer(GL_FRAMEBUFFER, fbo);

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X, textureObject, 0);

    status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    printf("%d\"\n", status);
        printf("%d\n", GL_FRAMEBUFFER_COMPLETE);

    glViewport(0,0,size, size);

    for (face = 1; face < 6; face++) {

        drawSpheres();
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, textureObject, 0);

    }

     //Bind 0, which means render to back buffer, as a result, fb is unbound
       glBindFramebuffer(GL_FRAMEBUFFER, 0);

       return textureObject;
    }

Hai testato per vedere che la tua drawSpheresfunzione disegna effettivamente qualcosa di visibile? La funzione disegna davvero qualcosa? Cosa succede se cambi drawSpheresper cancellare il framebuffer?
Nicol Bolas,

Sì. Sto facendo due passaggi. Uno nel codice sopra, in realtà 6 chiamate sopra. Quindi sto chiamando drawSpheres durante il rendering su framebuffer 0 e viene visualizzato.
Joey Green,

Inoltre, ho impostato il mio sfondo su bianco. Il colore bianco non si presenta almeno nella trama?
Joey Green,

Il tuo codice funziona bene per un normale FBO? Per come la capisco, una mappa cubica dovrebbe essere solo di sei trame e dovresti renderizzarla separatamente.
Jari Komppa,

Risposte:


10

Bene, non posso garantire che questo ti aiuterà a capire cosa sta succedendo. Semplicemente non hai pubblicato abbastanza informazioni su ciò che stai facendo per rintracciare eventuali errori particolari. Anche se posso correggere una cosa del tuo molto velocemente:

glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X, textureObject, 0);

...

for (face = 1; face < 6; face++) {
    drawSpheres();
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, textureObject, 0);
}

Questo chiamerà solo drawSpheres cinque volte. Immagino che volessi chiamarlo 6 volte.

Ma posso pubblicare una risposta funzionante. Nota che questo codice è progettato per essere eseguito insieme alla mia serie di tutorial , quindi fa riferimento a codice che non è presente. Ma questo è principalmente cose come la creazione di maglie e così via; niente di veramente importante.

Ecco i punti salienti. Gli shader per l'oggetto sfera principale.

Shader vertice:

#version 330

layout(std140) uniform;

layout(location = 0) in vec4 position;
layout(location = 2) in vec3 normal;

out vec3 modelSpaceNormal;

uniform Projection
{
    mat4 cameraToClipMatrix;
};

uniform mat4 modelToCameraMatrix;

void main()
{
    gl_Position = cameraToClipMatrix * (modelToCameraMatrix * position);
    modelSpaceNormal = normal;
}

Shader di frammenti:

#version 330

in vec3 modelSpaceNormal;

uniform samplerCube cubeTexture;

out vec4 outputColor;

void main()
{
    outputColor = texture(cubeTexture, modelSpaceNormal);
//  outputColor = vec4(normalize(modelSpaceNormal), 1.0);
}

La creazione della texture cubemap che verrà utilizzata come destinazione di rendering:

void CreateCubeTexture()
{
    glGenTextures(1, &g_cubeTexture);
    glBindTexture(GL_TEXTURE_CUBE_MAP, g_cubeTexture);

    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, 0);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    std::vector<GLubyte> testData(CUBE_TEXTURE_SIZE * CUBE_TEXTURE_SIZE * 256, 128);
    std::vector<GLubyte> xData(CUBE_TEXTURE_SIZE * CUBE_TEXTURE_SIZE * 256, 255);

    for(int loop = 0; loop < 6; ++loop)
    {
        if(loop)
        {
            glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + loop, 0, GL_RGBA8,
                CUBE_TEXTURE_SIZE, CUBE_TEXTURE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, &testData[0]);
        }
        else
        {
            glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + loop, 0, GL_RGBA8,
                CUBE_TEXTURE_SIZE, CUBE_TEXTURE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, &xData[0]);
        }
    }

    glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
}

In realtà riempio la trama di dati (piuttosto che passare NULL a glTexImage2D) come aiuto per il debug. Assicura che tutto funzionasse prima di iniziare a utilizzare la trama come destinazione del rendering.

Inoltre, nota che fornisco un BASE_LEVEL e MAX_LEVEL. Lo faccio sempre con le mie trame immediatamente dopo la creazione. È solo una buona abitudine, poiché a volte OpenGL può essere esigente in merito alla completezza delle trame e alla piramide mipmap. Piuttosto che ricordare le regole, le ho semplicemente impostate sui valori corretti religiosamente.

Ecco la principale funzione di disegno:

void display()
{
    //Draw the cubemap.
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, g_framebuffer);
    glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, g_depthbuffer);

    for(int loop = 0; loop < 6; ++loop)
        DrawFace(loop);

    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);

    //Draw the main scene.
    //The projection matrix is in a uniform buffer.
    ProjectionBlock projData;
    projData.cameraToClipMatrix = glm::perspective(90.0f,
        (g_viewportSize.x / (float)g_viewportSize.y), g_fzNear, g_fzFar);

    glBindBuffer(GL_UNIFORM_BUFFER, g_projectionUniformBuffer);
    glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(ProjectionBlock), &projData);
    glBindBuffer(GL_UNIFORM_BUFFER, 0);

    glViewport(0, 0, (GLsizei)g_viewportSize.x, (GLsizei)g_viewportSize.y);

    glClearColor(0.75f, 0.75f, 1.0f, 1.0f);
    glClearDepth(1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glutil::MatrixStack modelMatrix;
    modelMatrix.ApplyMatrix(g_viewPole.CalcMatrix());

    if(g_pSphere)
    {
        glutil::PushStack push(modelMatrix);

        glUseProgram(g_progMain.theProgram);
        glUniformMatrix4fv(g_progMain.modelToCameraMatrixUnif, 1, GL_FALSE,
            glm::value_ptr(modelMatrix.Top()));

        glActiveTexture(GL_TEXTURE0 + g_cubeTexUnit);
        glBindTexture(GL_TEXTURE_CUBE_MAP, g_cubeTexture);

        g_pSphere->Render("lit");

        glBindTexture(GL_TEXTURE_CUBE_MAP, 0);

        glUseProgram(0);
    }

    glutPostRedisplay();
    glutSwapBuffers();
}

Questo fa riferimento a DrawFace, che disegna la faccia data della cubemap. Questo è implementato come segue:

void DrawFace(int iFace)
{
    glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
        GL_TEXTURE_CUBE_MAP_POSITIVE_X + iFace, g_cubeTexture, 0);

    GLenum status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
    if(status != GL_FRAMEBUFFER_COMPLETE)
        printf("Status error: %08x\n", status);

    //The projection matrix is in a uniform buffer.
    ProjectionBlock projData;
    projData.cameraToClipMatrix = glm::perspective(90.0f, 1.0f, g_fzNear, g_fzFar);

    glBindBuffer(GL_UNIFORM_BUFFER, g_projectionUniformBuffer);
    glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(ProjectionBlock), &projData);
    glBindBuffer(GL_UNIFORM_BUFFER, 0);

    glViewport(0, 0, (GLsizei)CUBE_TEXTURE_SIZE, (GLsizei)CUBE_TEXTURE_SIZE);

    const glm::vec4 &faceColor = g_faceColors[iFace];
    glClearColor(faceColor.x, faceColor.y, faceColor.z, faceColor.w);
    glClearDepth(1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    if(g_pSphere)
    {
        glutil::MatrixStack modelMatrix;
        modelMatrix.Translate(g_faceSphereLocs[iFace]);

        glUseProgram(g_progUnlit.theProgram);
        glUniformMatrix4fv(g_progUnlit.modelToCameraMatrixUnif, 1, GL_FALSE,
            glm::value_ptr(modelMatrix.Top()));

        const glm::vec4 &sphereColor = g_faceSphereColors[iFace];
        glUniform4fv(g_progUnlit.objectColorUnif, 1, glm::value_ptr(sphereColor));

        glActiveTexture(GL_TEXTURE0 + g_cubeTexUnit);
        glBindTexture(GL_TEXTURE_CUBE_MAP, g_cubeTexture);

        g_pSphere->Render("flat");

        glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
        glUseProgram(0);
    }
}

Questa funzione fa riferimento a una serie di tabelle globali che uso per dare a ciascuna faccia un colore di sfondo distinto, un colore di sfera distinto e per posizionare la sfera (nello spazio della fotocamera) correttamente per quella faccia.

I punti salienti per DrawFacequesti sono questi.

Come regola generale, a meno che non abbia la certezza che lo stato è impostato, ho impostato quello stato. Ho impostato il riquadro di visualizzazione ogni volta che chiamo DrawFace. Ho impostato la matrice di proiezione ogni volta. Quelli sono superflui; Avrei potuto ripristinarli displayprima del loop che chiama DrawFace, proprio come faccio con l'attuale FBO e renderbuffer di profondità.

Ma pulisco anche i buffer, che è diverso per ogni faccia (poiché ogni faccia ha un colore diverso).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.