OpenGL ES erzeugt einen Schabloneneffekt mit Textur

10

Umgebung

Dies ist die Umgebung, in der ich arbeite:

  • OpenGL ES 2.0
  • iPhone Simulator & iPhone 4
  • iMac 27 "mit NVIDIA GeForce GTX 680MX 2048 MB

Hoffentlich hilft das.

Das Problem

Ich habe aus mehreren Quellen und mehreren Websites, einschließlich Stackoverflow, hoch und niedrig gesucht, aber keinen funktionierenden Schabloneneffekt erzielt.

Was ich habe ist folgendes:

Einrichtung der Schablonenszene

Das schwarze 'S'-Ding ist kein Polygon, sondern eine Textur, die auf ein Rechteck-Quad gezeichnet wird, das dieselbe Breite und Höhe wie das Hintergrundbild hat.

Ich versuche einen Schabloneneffekt zu erzielen, bei dem der Hintergrund und der kleine gelbe Kerl nur sichtbar sein sollten, wenn er sich innerhalb dieser schwarzen S-Textur befindet.

In meinem Fragment-Shader habe ich Folgendes:

varying lowp vec4 destinationColor;

varying lowp vec2 TexCoordOut;
uniform sampler2D Texture;
uniform highp float TexScale;

void main()
{
    highp vec4 color = texture2D(Texture, TexCoordOut);

    if(color.a == 0.0)
    {
        discard;
    }

    gl_FragColor = color;
}

Für meinen Setup Depth Stencil Buffer habe ich ihn folgendermaßen eingerichtet:

-(void)setupDepthStencilBuffer
{
    GLint width;
    GLint height;

    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width);
    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height);

    glGenBuffers(1, &depthStencilBuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, depthStencilBuffer);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, width, height);
    //glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_COMPONENT24_OES, width, height);

    NSLog(@"depthStencilBuffer = %d", depthStencilBuffer);
}

Laut Apples Dokumentation (die meiner Meinung nach veraltet ist):

http://developer.apple.com/library/ios/#documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/WorkingwithEAGLContexts/WorkingwithEAGLContexts.html#//apple_ref/doc/uid/TP40008793-CH103-S1

Beachten Sie, dass einige Dinge wie die GL_RGBA-Enumeration nicht vorhanden sind, als ich versucht habe, sie in Xcode einzugeben (ich denke, Apple muss sie entfernt und veraltet gemacht haben).

Ich habe auch versucht, wie Apple den sogenannten "Tiefen- / Schablonen" -Puffer im obigen Link definiert, aber es gab den gleichen Fehler unten.

Der Code, den ich oben habe, ist, wie Sie einen Schablonenpuffer erstellen würden.

In meiner setupFrameBuffer () -Methode hänge ich es folgendermaßen an:

-(void)setupFrameBuffer
{
    GLuint frameBuffer;

    glGenBuffers(1, &frameBuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRenderBuffer);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthStencilBuffer);

    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);

    if(status != GL_FRAMEBUFFER_COMPLETE)
    {
        NSLog(@"failed to make complete framebuffer object %x", status);
    }
}

Der Fehler, den ich beim Anhängen wie oben gezeigt erhalten habe, ist:

Fehler beim Erstellen des vollständigen Framebuffer-Objekts 8cd6

Für meine Rendermethode habe ich Folgendes:

-(void)render:(CADisplayLink *)displayLink
{
    glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);



    glClearStencil(0);
    glEnable(GL_STENCIL_TEST);

    // ----------------------------------------
    // Don't write to color or depth buffer
    // ----------------------------------------
    glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
    glDepthMask(GL_FALSE);

    glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);

    // ----------------------------------------
    // First set the alpha test so that
    // fragments greather than threshold
    // will pass thus will set nonzero
    // bits masked by 1 in stencil
    // ----------------------------------------
    glStencilFunc(GL_ALWAYS, 1, 1);

    // ----------------------------------------------------------------
    // Drawing our stencil
    // ----------------------------------------------------------------

    glBindBuffer(GL_ARRAY_BUFFER, bgVBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bgIBO);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, stencilTexture);
    glUniform1i(textureUniform, 0);

    glVertexAttribPointer(positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
    glVertexAttribPointer(colorSlot, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void *)(sizeof(GLfloat) * 3));
    glVertexAttribPointer(texCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void *)(sizeof(GLfloat) * 7));

    glDrawElements(GL_TRIANGLE_FAN, sizeof(bgIndices)/sizeof(bgIndices[0]), GL_UNSIGNED_BYTE, 0);

    /*
    // -----------------------------------------
    // Second pass of the fragments less
    // or equal than the threshold will pass
    // thus will set zero bits masked by 1
    // in stencil
    // -----------------------------------------
    glStencilFunc(GL_ALWAYS, 0, 1);

    glBindBuffer(GL_ARRAY_BUFFER, bgVBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bgIBO);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, stencilTexture);
    glUniform1i(textureUniform, 0);

    glVertexAttribPointer(positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
    glVertexAttribPointer(colorSlot, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void *)(sizeof(GLfloat) * 3));
    glVertexAttribPointer(texCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void *)(sizeof(GLfloat) * 7));

    glDrawElements(GL_TRIANGLE_STRIP, sizeof(bgIndices)/sizeof(bgIndices[0]), GL_UNSIGNED_BYTE, 0);
    */


    // ---------------------------------------------------
    // RE-ENABLING THE COLOR AND DEPTH MASK AGAIN
    // TO DRAW REST OF THE SCENE AFTER STENCIL
    // ---------------------------------------------------
    glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
    glDepthMask(GL_TRUE);




    Mat4 frustrumMatrix = [CameraMatrix createOrthographicMatrixUsingLeft:-(self.bounds.size.width / 2.0)
                                                                       Right:(self.bounds.size.width / 2.0)
                                                                      Bottom:-(self.bounds.size.height / 2.0)
                                                                         Top:(self.bounds.size.height / 2.0)
                                                                        Near:-1.0f
                                                                         Far:1.0f];

    glUniformMatrix4fv(projectionUniform, 1, 0, frustrumMatrix.matrix);

    glViewport(0, 0, self.bounds.size.width * self.contentScaleFactor, self.bounds.size.height * self.contentScaleFactor);

    // ----------------------------------------------------------------
    // Drawing our background first
    // ----------------------------------------------------------------

    glBindBuffer(GL_ARRAY_BUFFER, bgVBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bgIBO);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, bgTexture);
    glUniform1i(textureUniform, 0);

    glVertexAttribPointer(positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
    glVertexAttribPointer(colorSlot, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void *)(sizeof(GLfloat) * 3));
    glVertexAttribPointer(texCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void *)(sizeof(GLfloat) * 7));

    glDrawElements(GL_TRIANGLE_FAN, sizeof(bgIndices)/sizeof(bgIndices[0]), GL_UNSIGNED_BYTE, 0);



    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);


    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, floorTexture);
    glUniform1i(textureUniform, 0);


    glVertexAttribPointer(positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
    glVertexAttribPointer(colorSlot, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void *)(sizeof(GLfloat) * 3));

    glVertexAttribPointer(texCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void *)(sizeof(GLfloat) * 7));

    glDrawElements(GL_TRIANGLE_FAN, sizeof(Indices)/sizeof(Indices[0]), GL_UNSIGNED_BYTE, 0);

    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_BLEND);

    [context presentRenderbuffer:GL_RENDERBUFFER];
}

Das Ergebnis ist offensichtlich ein rosa Bildschirm, was bedeutet, dass mein Setup falsch ist:

Geben Sie hier die Bildbeschreibung ein

Kann jemand bitte etwas Licht ins Dunkel bringen?

Zhang
quelle
Keine Ahnung, wie man das genaue Problem löst, aber warum nicht einfach die "Schablonentextur" beim Zeichnen des kleinen gelben Mannes verwenden und verwerfen, wenn der Texelwert nicht übereinstimmt?
Jari Komppa
Die Schablone dient nicht zum Maskieren des kleinen Mannes, sondern zum Erkennen von Gelände, auf dem der kleine Kerl steht (nicht das Hintergrundbild, das Sie oben sehen). Denken Sie an das Wurmspiel, Sie haben den Hintergrund und dann das Gelände in der Mitte, das von einer Schablone verdeckt wird, um sowohl das Gelände zu löschen als auch Kollisionen für die Spieler auf dem Bildschirm (den kleinen gelben Kerl) zu erkennen.
Zhang

Antworten:

7

Die Lösung

Hölle ja !!!

Ich bin jetzt ein glücklicher Kerl! : D.

OK, ich schaffe es endlich, Stencil mit Textur zum Laufen zu bringen :)

(Außerdem haben wir auf dem Weg eine Reihe von Dingen gelernt, z. B. können wir color.alpha überprüfen und Discard verwenden, um transparente Pixel zu entfernen, und der Trick glBlend (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) ist veraltet.)

Das erste, was mir auffiel, war, die Namen für meinen Schablonenpuffer falsch zu generieren.

Im obigen Quellcode in meiner Frage hatte ich Folgendes eingegeben:

glGenBuffers(1, &depthStencilBuffer);

Das sollte wirklich sein:

glGenRenderbuffers(1, &depthStencilBuffer);

d'oh!

Zweitens habe ich die wichtige zweite glStencilFunc () auskommentiert, die aufgerufen werden musste:

glStencilFunc(GL_ALWAYS, 1, 1);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);

// draw black 'S' textured quad here

. . .

// -----------------------------------
// I WAS MISSING THIS IMPORTANT LINE
// -----------------------------------
glStencilFunc(GL_ALWAYS, 0, 1);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

/* draw the rest of the scene here (the background and yellow guy) */

Das Endergebnis:

Geben Sie hier die Bildbeschreibung ein

Ich hoffe, das hilft allen anderen, die diese coole Schablone mit einer Texturfunktion ausprobieren: D.

Ich habe auch eine Reihe anderer Quellcodes geändert, aber diese beiden waren die Hauptänderungen, die dazu geführt haben, dass es funktioniert.

Einige hilfreiche Änderungen haben mir auch beim Debuggen des Problems geholfen:

  • Ich habe festgestellt, dass ich meinem Framebuffer keinen Tiefenpuffer hinzufügen muss, damit er funktioniert
  • Ich muss auch GL_DEPTH_BUFFER_BIT nicht löschen
  • Ich habe die setupFrameBuffer () -Methode mit den zusätzlichen if-else-Bedingungen dahingehend geändert, dass ich deutlich auf mögliche Fehler hingewiesen werde.

Die neue Methode setupFrameBuffer ():

-(void)setupFrameBuffer
{
    GLuint frameBuffer;

    glGenBuffers(1, &frameBuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRenderBuffer);
    //glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthStencilBuffer);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthStencilBuffer);

    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);

    if(status == GL_FRAMEBUFFER_COMPLETE)
    {
        NSLog(@"framebuffer complete");
        //NSLog(@"failed to make complete framebuffer object %x", status);
    }
    else if(status == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT)
    {
        NSLog(@"incomplete framebuffer attachments");
    }
    else if(status == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT)
    {
        NSLog(@"incomplete missing framebuffer attachments");
    }
    else if(status == GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS)
    {
        NSLog(@"incomplete framebuffer attachments dimensions");
    }
    else if(status == GL_FRAMEBUFFER_UNSUPPORTED)
    {
        NSLog(@"combination of internal formats used by attachments in thef ramebuffer results in a nonrednerable target");
    }
}
Zhang
quelle