GLES: объект FrameBuffer, показывающий странные изображения

В настоящее время я пытаюсь заставить работать FBO в моей игре с помощью Android Studio.

Мне уже удалось настроить FBO и нарисовать заполненный белый прямоугольник (64x64px) к нему.

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

Снимок странных изображений, которые производит FBO
Снимок странных изображений, которые производит FBO



Я не знаю, почему не отображается мой сплошной цветной прямоугольник, и почему в чате Whatsapp есть изображение профиля, которое не предназначено для этого.

Вот как я инициализирую свой объект FrameBuffer:

private void initFrameBuffer() {

    int[] temp = new int[1];

    //Create a texture object and bind it. This will be the color buffer.
    glGenTextures(1, temp, 0);
    colorTexture = temp[0];

    glBindTexture(GL_TEXTURE_2D, colorTexture);

    //Set parameters. We're probably using non-power-of-two (NPOT) dimensions,
    //so some values may not be available for use!
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    //Create a texture storage:
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, null);

    //Create framebuffer object and bind it.
    glGenBuffers(1, temp, 0);
    frameBufferID = temp[0];
    glBindFramebuffer(GL_FRAMEBUFFER, frameBufferID);

    //Create a depth buffer and bind it.
    glGenRenderbuffers(1, temp, 0);
    depthBuffer = temp[0];

    glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);

    //Allocate storage for the depth buffer.
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);

    //Attach the depth buffer and the texture (color buffer) to the framebuffer object.
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
            GL_TEXTURE_2D, colorTexture, 0);

    //Check if GL ES is happy with all this ... :)
    int status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    if (status != GL_FRAMEBUFFER_COMPLETE) {
        throw new RuntimeException("Framebuffer not complete! StatusID: " + status);
    }

    //Switch back to the default framebuffer.
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

Как я рисую весь пейзаж:

@Override
public void draw() {
    GLES20.glBindFramebuffer(GL_FRAMEBUFFER, frameBufferObject.getID());
        Graphics.setColor(new Color(255, 255, 255));
        Graphics.fillRect(0, 0, 64, 64);
    GLES20.glBindFramebuffer(GL_FRAMEBUFFER, 0);

    Graphics.drawFrameBuffer(frameBufferObject, 0, 0, frameBufferObject.getWidth(), frameBufferObject.getHeight());
}

И последнее, но не менее важное: вот как я рисую цветной буфер FBO на экране, используя простую шейдерную программу:

public static void drawFrameBuffer(FrameBufferObject frameBufferObject, int x, int y, int w, int h) {

    ImageMesh mesh = new ImageMesh(generateMesh(x, y, w, h));

    imageShader.start();

    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, frameBufferObject.getColorTexture());
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);

    //Enable generic vertex attribute array
    GLES20.glEnableVertexAttribArray(imageShader.positionHandle);

    //Prepare triangle coordinate data
    GLES20.glVertexAttribPointer(imageShader.positionHandle, 3, GLES20.GL_FLOAT, false, 0, mesh.baseMesh.vertexBuffer);

    //Enable generic vertex attribute array
    GLES20.glEnableVertexAttribArray(imageShader.texCoordLocation);

    //Prepare the textureCoordinates
    GLES20.glVertexAttribPointer(imageShader.texCoordLocation, 2, GLES20.GL_FLOAT, false, 0, mesh.uvBuffer);

    //Apply the projection and view transformation
    GLES20.glUniformMatrix4fv(imageShader.mtrxHandle, 1, false, Renderer.getUMVPMatrix(), 0);

    //Set the sampler texture unit to 0
    GLES20.glUniform1i(imageShader.samplerLoc, 0);

    //Draw the triangles
    GLES20.glDrawElements(GLES20.GL_TRIANGLES, mesh.baseMesh.indices.length, GLES20.GL_UNSIGNED_SHORT, mesh.baseMesh.drawListBuffer);

    //Disable vertex arrays
    GLES20.glDisableVertexAttribArray(imageShader.positionHandle);
    GLES20.glDisableVertexAttribArray(imageShader.texCoordLocation);

    //Unbind the texture
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);

    imageShader.stop();
}

Уровень API Android, который я использую, равен 22. Кроме того, созданный мной FBO точно соответствует размеру экрана, который составляет 720x1280px.

Эта проблема была потрачена впустую целый день, и я понятия не имею, что может быть причиной этой проблемы!

Я очень благодарен за любую помощь! <3

1 ответ

Решение

Через несколько часов мне наконец удалось заставить это работать хотя!

Основной причиной ошибки было то, что я не правильно настроил свой FBO, что привело к получению этого глючного изображения.

Поэтому я посмотрел учебник по OpenGL от ThinMatrix на Youtube, и он смог вытащить меня из этой плохой ситуации.:)

Вот мой обновленный объектный код FrameBuffer:

public class FrameBufferObject {

private int width;
private int height;

private int frameBufferID;
private int texture;
private int depthTexture;
private int depthBuffer;

private Matrices.MatrixKit previousMatrixKit;

public FrameBufferObject(int width, int height) {
    this.width = width;
    this.height = height;

    initFrameBuffer();
}

private void initFrameBuffer() {

    frameBufferID = createFrameBuffer();
    texture = createTextureAttachment();
    depthTexture = createDepthTextureAttachment(width, height);
    depthBuffer = createDepthBufferAttachment();

    int status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    if (status != GL_FRAMEBUFFER_COMPLETE) {
        Logger.error("Framebuffer not Complete! STATUS: " + status + "\nWidth: " + width + "\nHeight: " + height);
    }

    glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

private int createFrameBuffer() {
    int[] ids = new int[1];
    glGenFramebuffers(1, ids, 0);
    int frameBufferID = ids[0];
    glBindFramebuffer(GL_FRAMEBUFFER, frameBufferID);

    int[] buffers = new int[] {GL_COLOR_ATTACHMENT0};

    GLES30.glDrawBuffers(1, buffers, 0);
    return frameBufferID;
}

private int createTextureAttachment() {
    int[] ids = new int[1];
    glGenTextures(1, ids, 0);
    int colorTexture = ids[0];

    glBindTexture(GL_TEXTURE_2D, colorTexture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, null);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0);
    return colorTexture;
}

private int createDepthTextureAttachment(int width, int height) {
    int[] ids = new int[1];
    glGenTextures(1, ids, 0);
    int depthTextureID = ids[0];

    glBindTexture(GL_TEXTURE_2D, depthTextureID);
    //glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, null);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, null);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTextureID, 0);
    return depthTextureID;
}

private int createDepthBufferAttachment() {
    int[] ids = new int[1];
    glGenBuffers(1, ids, 0);
    int depthBuffer = ids[0];

    glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);
    return depthBuffer;
}

public int getColorTexture() {
    return this.texture;
}

public void bindFrameBuffer() {
    glBindTexture(GL_TEXTURE_2D, 0); //just make sure the texture isn't bound
    glBindFramebuffer(GL_FRAMEBUFFER, frameBufferID);
    glViewport(0, 0, width, height);

    previousMatrixKit = Renderer.getMatrices();
    Renderer.setMatrixKit(Matrices.createMatrixKit(width, height));
}

public void unbindFrameBuffer() {
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glViewport(0, 0, previousMatrixKit.width, previousMatrixKit.height);

    Renderer.setMatrixKit(previousMatrixKit);
}

public int getWidth() {
    return this.width;
}

public int getHeight() {
    return this.height;
}

public int getID() {
    return this.frameBufferID;
}
}
Другие вопросы по тегам