Рендеринг пинг-понга между двумя FBO завершается неудачно после первого кадра. - PullRequest
4 голосов
/ 28 ноября 2011

Я пытаюсь создать два FBO и реализовать рендеринг пинг-понга.Но я получаю только первый кадр для правильной работы.Я пытаюсь смоделировать игру в жизнь, и после первого кадра я получаю только черный экран.Не могли бы вы помочь мне проверить это?Я потратил часы на эту проблему.

Редактировать

Возможно, я не очень четко описал.На самом деле, я хочу использовать textureB в качестве текстуры и визуализировать ее в textureA, затем использовать textureA для рендеринга на экран, а затем наоборот.

Edit Я вижу первый кадр,которая является текстурой.После прохождения фрагмента шейдер становится черным.Сначала я подозреваю, что фрагментный шейдер изменен таким образом, чтобы вернуть только черный цвет к белому и белый к черному.Он по-прежнему становится черным.

Настройка fbo и текстуры

glEnable(GL_TEXTURE_2D);
    glGenTextures(1, &textureA);
    glBindTexture(GL_TEXTURE_2D, textureA);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA,
                 GL_UNSIGNED_BYTE, NULL);

    glGenTextures(1, &textureB);
    glBindTexture(GL_TEXTURE_2D, textureB);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    data=(GLubyte*)malloc(256*256*4*sizeof(GLubyte));
    GLubyte val;
    for (int i = 0; i < 256 * 256 * 4; i+=4) {   
        if (rand()%10 ==1) 
            { val = 0; } 
        else 
            { val = 255; }
        data[i] = data[i+1] = data[i+2] = val;
        data[i+3] = 255;
    }
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);

    glGenFramebuffers(1, &fboA);
    glBindFramebuffer(GL_FRAMEBUFFER, fboA);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureA, 0);

    glGenFramebuffers(1, &fboB);
    glBindFramebuffer(GL_FRAMEBUFFER, fboB);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureB, 0);

Render Loop

if ([context API] == kEAGLRenderingAPIOpenGLES2) {


        if(counter%2==0)
        {
            glUseProgram(automateProg);
            glBindFramebuffer(GL_FRAMEBUFFER, fboA);
            glActiveTexture(GL_TEXTURE0);
            glBindTexture(GL_TEXTURE_2D, textureB);
            glUniform1i(AUTOMATE_TEXT, 0);
            glUniform1f(DU, 1.0/256);
            glUniform1f(DV, 1.0/256);
            // Update attribute values.
            glVertexAttribPointer(ATTRIB_VERTEX_2, 2, GL_FLOAT, 0, 0, squareVertices);
            glEnableVertexAttribArray(ATTRIB_VERTEX_2);

            glVertexAttribPointer(ATTRIB_TEXCOORD_2, 2, GL_FLOAT, GL_FALSE, 0, texCoord);    
            //glEnableVertexAttribArray(ATTRIB_TEXCOORD_2);
            glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
            if (![self validateProgram:automateProg]) {
                NSLog(@"Failed to validate program: %d", automateProg);
                return;
            }

            glBindFramebuffer(GL_FRAMEBUFFER, 0);
            glUseProgram(0);
        }
        else
        {
            glUseProgram(automateProg);            
            glBindFramebuffer(GL_FRAMEBUFFER, fboB);
            glActiveTexture(GL_TEXTURE0);
            glBindTexture(GL_TEXTURE_2D, textureA);
            glUniform1i(AUTOMATE_TEXT, 0);
            glUniform1f(DU, 1.0/256);
            glUniform1f(DV, 1.0/256);
            // Update attribute values.
            glVertexAttribPointer(ATTRIB_VERTEX_2, 2, GL_FLOAT, 0, 0, squareVertices);
            glEnableVertexAttribArray(ATTRIB_VERTEX_2);
            glVertexAttribPointer(ATTRIB_TEXCOORD_2, 2, GL_FLOAT, GL_FALSE, 0, texCoord); 
            //glEnableVertexAttribArray(ATTRIB_TEXCOORD_2);
            glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
            if (![self validateProgram:automateProg]) {
                NSLog(@"Failed to validate program: %d", automateProg);
                return;
            }

            glBindFramebuffer(GL_FRAMEBUFFER, 0);
            glUseProgram(0);
        }

        [(EAGLView *)self.view setFramebuffer];
        glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        if (counter % 2 == 0) {
            glUseProgram(normalProg);
            glActiveTexture(GL_TEXTURE0);
            glBindTexture(GL_TEXTURE_2D, textureB);
            glUniform1i(NORMAL_TEXT, 0);
            glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, squareVertices);
            glEnableVertexAttribArray(ATTRIB_VERTEX);
            glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, texCoord); 
            glEnableVertexAttribArray(ATTRIB_TEXCOORD);
            glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
            if (![self validateProgram:normalProg]) {
                NSLog(@"Failed to validate program: %d", normalProg);
                return;
            }
            glUseProgram(0);

        } else {
            glUseProgram(normalProg);
            glActiveTexture(GL_TEXTURE0);
            glBindTexture(GL_TEXTURE_2D, textureA);
            glUniform1i(NORMAL_TEXT, 0);
            glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, squareVertices);
            glEnableVertexAttribArray(ATTRIB_VERTEX);
            glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, texCoord); 
            glEnableVertexAttribArray(ATTRIB_TEXCOORD);
            glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
            if (![self validateProgram:normalProg]) {
                NSLog(@"Failed to validate program: %d", normalProg);
                return;
            }
            glUseProgram(0);
        }
        counter++;

[(EAGLView *)self.view presentFramebuffer];

Фрагмент шейдера

precision mediump float;
varying vec2 v_texCoord;
uniform sampler2D tex; //the input texture
uniform float du; //the width of the cells
uniform float dv; //the height of the cells
    void main() {
        int count = 0;

        vec4 C = texture2D( tex, v_texCoord );
        vec4 E = texture2D( tex, vec2(v_texCoord.x + du, v_texCoord.y) );
        vec4 N = texture2D( tex, vec2(v_texCoord.x, v_texCoord.y + dv) );
        vec4 W = texture2D( tex, vec2(v_texCoord.x - du, v_texCoord.y) );
        vec4 S = texture2D( tex, vec2(v_texCoord.x, v_texCoord.y - dv) );
        vec4 NE = texture2D( tex, vec2(v_texCoord.x + du, v_texCoord.y + dv) );
        vec4 NW = texture2D( tex, vec2(v_texCoord.x - du, v_texCoord.y + dv) );
        vec4 SE = texture2D( tex, vec2(v_texCoord.x + du, v_texCoord.y - dv) );
        vec4 SW = texture2D( tex, vec2(v_texCoord.x - du, v_texCoord.y - dv) );

        if (E.r == 1.0) { count++; }
        if (N.r == 1.0) { count++; }
        if (W.r == 1.0) { count++; }
        if (S.r == 1.0) { count++; }
        if (NE.r == 1.0) { count++; }
        if (NW.r == 1.0) { count++; }
        if (SE.r == 1.0) { count++; }
        if (SW.r == 1.0) { count++; }

        if ( (count == 2 || count == 3)) {
            gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); //cell lives...
        } else {
            gl_FragColor = vec4(0.0,0.0,0.0, 1.0); //cell dies...
        }
    }

Ответы [ 2 ]

1 голос
/ 29 ноября 2011

Правильно ли я понимаю ваш код, что вы хотите отобразить результат в текстуру в первом if-else -блоке и отразить этот результат на экране во втором if-else -блоке? Если это так, то похоже, что у вас есть ошибка в том, как вы организовали свой ввод и вывод для начала. Вот что происходит в вашем первом проходе (я сократил ваш код):

if(counter%2==0)
{
    glBindFramebuffer(GL_FRAMEBUFFER, fboA); // will render to textureA
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, textureB); // textureB is our input
} else {
    ...
}

if (counter % 2 == 0) {
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, textureB); // textureB still as input? not textureA?
} else {
    ...
}

... и вот что происходит во втором проходе:

if(counter%2==0)
{
    ...
} else {
    glBindFramebuffer(GL_FRAMEBUFFER, fboB); // will render to textureB
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, textureA); // textureA as input
}

if (counter % 2 == 0) {
    ...
} else {
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, textureA); // textureA as input again?
}

Причина, по которой вы видите что-то в первом кадре, заключается в том, что вы фактически визуализируете свои входные данные, а не результат первого прохода. И причина, по которой у вас во втором проходе черный экран, может заключаться в том, что ваш фрагментный шейдер работает неправильно. Судя по вашему шейдерному коду, ошибка в доступе к соседним текселям кажется наиболее вероятной причиной этого. Можете ли вы предоставить значения du и dv?

Также я не думаю, что использование только одного текстурного блока должно создавать проблемы, как Брэд указывал ранее. Хотя я не уверен в этом.

С другой стороны: для пинг-понга вы должны создать свои FBO в виде массива , чтобы сделать ваш код более читабельным.

EDIT:

Если у вас проблемы с настройкой формы du и dv с помощью glUniform1f(), попробуйте glUniform1i() (вам нужно использовать float() в вашем шейдере) или glUniform1fv(). Однажды у меня была такая же проблема с драйверами PowerVR GLES2, где эта функция ничего не делала и приводила к тому, что униформа была 0.0.

0 голосов
/ 28 ноября 2011

У вас есть две текстуры, с которыми вы хотели бы иметь дело, но я вижу, что здесь используется только одна текстура. Возможно, если вы привязали свою текстуру FBO к единице текстуры, используя код, подобный следующему:

glBindFramebuffer(GL_FRAMEBUFFER, fboA);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textureA);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureB);

или

glBindFramebuffer(GL_FRAMEBUFFER, fboB);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textureB);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureA);

перед рендерингом каждого кадра он будет правильно считывать одну текстуру, привязанную к блоку 0, и выводить через FBO в другую текстуру в блоке 1.

В качестве альтернативы, вы можете навсегда привязать одну текстуру к одному юниту, а другой - к другому юниту, и чередовать значения для униформы AUTOMATE_TEXT, чтобы указать, из какого юнита тянуть. Это было бы немного более эффективно, потому что это позволило бы избежать накладных расходов на связывание текстур при каждом рендеринге.

...