OpenGL / GLSL: In Cube Map rendern?


13

Ich versuche herauszufinden, wie ich meine Szene auf eine Würfelkarte rendern kann. Ich war ein bisschen dabei und dachte, ich würde euch um Hilfe bitten. Ich bin neu in OpenGL und benutze zum ersten Mal einen FBO.

Ich habe derzeit ein funktionierendes Beispiel für die Verwendung einer Cubemap-BMP-Datei, und der SamplerCube-Beispieltyp im Fragment-Shader ist an GL_TEXTURE1 angehängt. Ich ändere den Shader-Code überhaupt nicht. Ich ändere nur die Tatsache, dass ich nicht die Funktion aufrufe, mit der die Cubemap-BMP-Datei geladen wurde, und versuche, den folgenden Code zum Rendern in eine Cubemap zu verwenden.

Sie können unten sehen, dass ich die Textur auch wieder an GL_TEXTURE1 anhänge. Dies ist so, wenn ich die Uniform setze:

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

es kann in meinem Fragment Shader über darauf zugreifen uniform samplerCube Cubemap.

Ich rufe die folgende Funktion wie folgt auf:

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

Jetzt merke ich in der Zeichenschleife unten, dass ich die Blickrichtung nicht ändere, um auf die + x, -x, + y, -y, + z, -z-Achse zu schauen. Ich wollte wirklich nur, dass etwas zuerst funktioniert, bevor ich das umsetzte. Ich dachte, ich sollte zumindest etwas auf meinem Objekt so sehen, wie der Code jetzt ist.

Ich sehe nichts, nur glattes Schwarz. Ich habe meinen Hintergrund weiß gemacht, trotzdem ist das Objekt schwarz. Ich habe die Beleuchtung und das Kolorieren entfernt, um nur die Cubemap-Textur und immer noch Schwarz abzutasten.

Ich denke, das Problem könnten die Formattypen sein, wenn ich die Textur GL_RGB8, GL_RGBA einstelle, aber ich habe es auch versucht:

GL_RGBA, GL_RGBA GL_RGB, GL_RGB

Ich dachte, dies wäre Standard, da wir eine Textur rendern, die an einen Framebuffer angehängt ist, aber ich habe verschiedene Beispiele gesehen, die unterschiedliche Enum-Werte verwenden.

Ich habe auch versucht, die Cube-Map-Textur in jedem Draw-Aufruf zu binden, für den ich die Cube-Map verwenden möchte:

glBindTexture(GL_TEXTURE_CUBE_MAP, cubeMapTexture);

Außerdem erstelle ich keinen Tiefenpuffer für den FBO, den ich in den meisten Beispielen gesehen habe, weil ich nur den Farbpuffer für meine Cube-Map haben möchte. Ich habe tatsächlich eine hinzugefügt, um zu sehen, ob dies das Problem ist, und trotzdem die gleichen Ergebnisse erzielt. Ich hätte das verfälschen können, als ich es versuchte.

Jede Hilfe, die mich in die richtige Richtung lenken kann, wäre dankbar.

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;
    }

Haben Sie getestet, ob Ihre drawSpheresFunktion tatsächlich etwas Sichtbares zeichnet? Zeichnet die Funktion tatsächlich etwas? Was passiert, wenn Sie drawSpheresden Framebuffer löschen?
Nicol Bolas

Ja. Ich mache zwei Pässe. Einer im obigen Code, tatsächlich 6 Aufrufe oben. Dann rufe ich drawSpheres beim Rendern auf Framebuffer 0 auf und es wird angezeigt.
Joey Green

Außerdem habe ich meinen Hintergrund auf Weiß gesetzt. Würde die weiße Farbe nicht zumindest in der Textur auftauchen?
Joey Green

Funktioniert Ihr Code für einen normalen FBO? So wie ich es verstehe, sollte eine Würfelkarte nur aus sechs Texturen bestehen, und Sie müssten jede einzeln rendern.
Jari Komppa,

Antworten:


10

Nun, ich kann nicht garantieren, dass dies Ihnen helfen wird, herauszufinden, was los ist. Sie haben einfach nicht genügend Informationen veröffentlicht, um bestimmte Fehler aufzuspüren. Obwohl ich eines von Ihnen sehr schnell korrigieren kann:

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);
}

Dies wird nur drawSpheres fünfmal anrufen . Ich vermute, Sie wollten es 6 Mal anrufen.

Aber ich kann eine funktionierende Antwort posten . Beachten Sie, dass dieser Code so konzipiert ist, dass er zusammen mit meiner Tutorial-Reihe ausgeführt wird , sodass er auf Code verweist, der nicht vorhanden ist. Aber das sind hauptsächlich Dinge wie das Erstellen von Maschen und so weiter; nichts wirklich wichtiges.

Hier sind die wichtigsten Punkte. Die Shader für das Hauptkugelobjekt.

Vertex-Shader:

#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;
}

Fragment-Shader:

#version 330

in vec3 modelSpaceNormal;

uniform samplerCube cubeTexture;

out vec4 outputColor;

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

Die Erstellung der Cubemap-Textur, die als Renderziel verwendet wird:

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);
}

Ich fülle die Textur tatsächlich mit Daten (anstatt NULL an glTexImage2D zu übergeben) als Debugging-Hilfe. Dies stellt sicher, dass alles funktioniert hat, bevor die Textur als Renderziel verwendet wurde.

Beachten Sie außerdem, dass ich BASE_LEVEL und MAX_LEVEL bereitstelle. Ich mache das immer mit meinen Texturen direkt nach der Erstellung. Es ist nur eine gute Angewohnheit, da OpenGL manchmal wählerisch in Bezug auf die Vollständigkeit der Textur und die Mipmap-Pyramide sein kann. Anstatt mich an die Regeln zu erinnern, habe ich sie religiös auf die richtigen Werte gesetzt.

Hier ist die Hauptzeichnungsfunktion:

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();
}

Dies DrawFacebezieht sich auf das Zeichnen der gegebenen Fläche der Cubemap. Das wird wie folgt umgesetzt:

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);
    }
}

Diese Funktion verweist auf eine Reihe globaler Tabellen, die ich verwende, um jedem Gesicht eine eigene Hintergrundfarbe und eine eigene Kugelfarbe zu geben und die Kugel (im Kameraraum) für dieses Gesicht richtig zu positionieren.

Die hervorstechenden Punkte für DrawFacesind diese.

In der Regel setze ich diesen Zustand , es sei denn, ich weiß genau, dass dieser Zustand eingestellt ist. Ich stelle das Ansichtsfenster bei jedem Anruf ein DrawFace. Ich stelle jedes Mal die Projektionsmatrix ein. Die sind überflüssig; Ich hätte sie wieder displayvor die DrawFaceaufrufende Schleife setzen können , genauso wie ich es mit dem aktuellen FBO und dem Tiefenrenderbuffer tue.

Ich lösche aber auch die Puffer, die für jedes Gesicht unterschiedlich sind (da jedes Gesicht eine andere Farbe hat).

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.