Opengl帧缓冲渲染看起来很奇怪

时间:2014-05-08 16:44:13

标签: java opengl framebuffer tile

原始问题:

我在OpenGL中制作了一个使用磁贴绘制地图的2D游戏。目前,每个瓷砖都是在四边形上单独绘制的。平铺渲染的代码是:

@Override
public void render() {
    if (parentTileSet.getTexture() == null)
        return;

    float alpha = parentLayer.getOpacity();
    if (alpha < 0)
        alpha = 0;
    glColor4f(1.0f, 1.0f, 1.0f, alpha); //Set alpha to parent layer's alpha

    parentTileSet.getTexture().bind(); //Bind texture

    float bx = parentTileSet.getTileWidth() / 2; //Half the width
    float by = parentTileSet.getTileHeight() / 2; //Half the height
    float x = getX(), y = getY();
    float z = 0f;

    glPushMatrix(); //Save the current view matrix
    glTranslatef(x, y, 0f); //Translate to the tile's position

    glRotatef(rotate, 0f, 0f, 1f); //Rotate the tile if it has a rotation
    if ((flipType & 1) > 0) //Are we flipping horizontally?
        glScalef(-1f, 1f, 1f);
    if ((flipType & 2) > 0) //Are we flipping vertically?
        glScalef(1f, -1f, 1f);

    //Draw the tile
    glBegin(GL_QUADS);
    glTexCoord2f(tex_cords.bottom_left.x, tex_cords.bottom_left.y); //bottom left
    glVertex3f(-bx, -by, z);
    glTexCoord2f(tex_cords.bottom_right.x, tex_cords.bottom_right.y); //bottom right
    glVertex3f(bx, -by, z);
    glTexCoord2f(tex_cords.top_right.x, tex_cords.top_right.y); //top right
    glVertex3f(bx, by, z);
    glTexCoord2f(tex_cords.top_left.x, tex_cords.top_left.y); //top left
    glVertex3f(-bx, by, z);
    glEnd();
    glPopMatrix(); //Reload the view matrix to original state
    parentTileSet.getTexture().unbind(); //Unbind the texture

}

结果如下: http://i.stack.imgur.com/maIXk.jpg

哪个好。然而,FPS可能会更好,当地图变得更加详细时,这尤其成为一个问题。 (FPS降至约20)。

我的理想解决方案:

由于瓷砖永远不会改变位置或动画,如果我将所有瓷砖渲染到纹理一次,然后只绘制纹理,那么性能会提高!

所以,我使用以下类创建了一个帧缓冲区:

public class Framebuffer implements Drawable {
private int fID, tID;

protected int width, height;

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

public void generate() {
    fID = glGenFramebuffers();
    tID = glGenTextures();

    glBindFramebuffer(GL_FRAMEBUFFER, fID);
    glBindTexture(GL_TEXTURE_2D, tID);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_INT, (ByteBuffer) null);

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tID, 0);

    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
        throw new RuntimeException("Framebuffer configuration error.");
    glBindTexture(GL_TEXTURE_2D, 0);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

public void begin() {
    glPushMatrix();
    glPushAttrib(GL_VIEWPORT_BIT);
    glBindFramebuffer(GL_FRAMEBUFFER, fID);
    glViewport(0, 0, width, height);
}

public void end() {
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glPopMatrix();
    glPopAttrib();
}

@Override
public void render() {
    float x = 0f;
    float y = 0f;
    float z = 0f;
    float bx = (this.width)/2f;
    float by = (this.height)/2f;

    glPushMatrix();

    glBindTexture(GL_TEXTURE_2D, tID);
    glBegin(GL_QUADS);
    glTexCoord2f(0f, 0f); //bottom left
    glVertex3f(x - bx, y - by, z);
    glTexCoord2f(1f, 0f); //bottom right
    glVertex3f(x + bx, y - by, z);
    glTexCoord2f(1f, 1f); //top right
    glVertex3f(x + bx, y + by, z);
    glTexCoord2f(0f, 1f); //top left
    glVertex3f(x - bx, y + by, z);
    glEnd();
    glBindTexture(GL_TEXTURE_2D, 0);

    glPopMatrix();
}

然后使用以下代码生成帧缓冲区,并将贴图渲染到纹理:

System.out.println("Attempting to generate frame buffer..");

                    try {
                        Framebuffer frame = new Framebuffer(tiledData.getPixelWidth(), tiledData.getPixelHeight());
                        frame.generate();
                        frame.begin();
                        glScalef(0.5f, 0.5f, 1f); //The game is scaled up by 2, so I'm just unscalling here.
                        Iterator<Drawable> drawableIterator = getSortedDrawables();
                        while (drawableIterator.hasNext()) {
                            Drawable d = drawableIterator.next();
                            if (d instanceof TileObject) {
                                TileObject t = (TileObject)d;
                                if (t.isGroundLayer() && !t.isParallaxLayer() && !t.isAnimated()) {
                                    t.render(); //This render method is the one from above
                                    drawableIterator.remove();
                                }
                            }
                        }
                        frame.end();
                        System.out.println("Success!");
                        addDrawable(frame);
                    } catch (RuntimeException e) {
                        System.out.println("Framebuffers are not supported!");
                    }

然而,输出是这样的:

http://puu.sh/8Eemy.jpg

这不是我预期会发生的事情。我尝试缩放它,移动它,以及各种各样的东西,但我永远无法完全正确。

我的问题

我做错了什么?还有另一种方法可以解决这个问题吗?我错过了什么吗?

更新

感谢您的评论,我已经让它正确呈现!

我将framebuffer类改为:

private int fID, tID;

protected int width, height;

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

public void generate() {
    fID = glGenFramebuffers();
    tID = glGenTextures();

    glBindFramebuffer(GL_FRAMEBUFFER, fID);
    glBindTexture(GL_TEXTURE_2D, tID);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_INT, (ByteBuffer) null);

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tID, 0);

    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
        throw new RuntimeException("Framebuffer configuration error.");
    glBindTexture(GL_TEXTURE_2D, 0);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

public void begin() {
    glBindFramebuffer(GL_FRAMEBUFFER, fID);

    glPushAttrib(GL_VIEWPORT_BIT);
    glViewport(0, 0, width, height);

    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();
    glOrtho(0, width, 0, height, -1, 1);

    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glLoadIdentity();
}

public void end() {
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    glMatrixMode(GL_PROJECTION);
    glPopMatrix();

    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();

    glPopAttrib();
}

@Override
public void render() {
    float x = this.width / 2f;
    float y = this.height / 2f;
    float z = 0f;
    float bx = (this.width)/2f;
    float by = (this.height)/2f;

    glPushMatrix();

    glBindTexture(GL_TEXTURE_2D, tID);
    glBegin(GL_QUADS);
    glTexCoord2f(0f, 0f); //bottom left
    glVertex3f(x - bx, y - by, z);
    glTexCoord2f(1f, 0f); //bottom right
    glVertex3f(x + bx, y - by, z);
    glTexCoord2f(1f, 1f); //top right
    glVertex3f(x + bx, y + by, z);
    glTexCoord2f(0f, 1f); //top left
    glVertex3f(x - bx, y + by, z);
    glEnd();
    glBindTexture(GL_TEXTURE_2D, 0);

    glPopMatrix();
}

这里的兴趣点是begin()和end()方法,我在其中设置一个新的投影矩阵并保存旧的投影矩阵,然后在end()方法中恢复它。

0 个答案:

没有答案