Jump to content

[1.8] [OpenGL] Using a Framebuffer breaks further rendering


Rene8888

Recommended Posts

Hello!

 

I put together my own FrameBuffer helper class. I want to use it to render shapes to a side if a block.

 

Framebuffer Helper class:

Note that not all methods are yes implemented!

 

 

package at.renehollander.advancedmanager.client.util;

import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import org.lwjgl.opengl.EXTFramebufferObject;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL14;

import java.nio.ByteBuffer;

public class FrameBufferObject {

    private int width;
    private int height;
    private boolean depth;

    private int fboId;
    private int texId;
    private int depId;

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

    public void initialize() {
        this.texId = GL11.glGenTextures();
        GL11.glBindTexture(GL11.GL_TEXTURE_2D, this.getTexId());
        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
        GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, this.getWidth(), this.getHeight(), 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, (ByteBuffer) null);
        this.fboId = EXTFramebufferObject.glGenFramebuffersEXT();
        EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, this.getFboId());
        EXTFramebufferObject.glFramebufferTexture2DEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT, GL11.GL_TEXTURE_2D, this.getTexId(), 0);
        if (this.isDepth()) {
            this.depId = EXTFramebufferObject.glGenRenderbuffersEXT();
            EXTFramebufferObject.glBindRenderbufferEXT(EXTFramebufferObject.GL_RENDERBUFFER_EXT, this.getDepId());
            EXTFramebufferObject.glRenderbufferStorageEXT(EXTFramebufferObject.GL_RENDERBUFFER_EXT, GL14.GL_DEPTH_COMPONENT24, this.getWidth(), this.getHeight());
            EXTFramebufferObject.glFramebufferRenderbufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, EXTFramebufferObject.GL_DEPTH_ATTACHMENT_EXT, EXTFramebufferObject.GL_RENDERBUFFER_EXT, this.getDepId());
        }
        int status = EXTFramebufferObject.glCheckFramebufferStatusEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT);
        if (status != EXTFramebufferObject.GL_FRAMEBUFFER_COMPLETE_EXT) {
            throw new RuntimeException("fbo config not supported");
        }
        EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, 0);
        if (this.isDepth())
            EXTFramebufferObject.glBindRenderbufferEXT(EXTFramebufferObject.GL_RENDERBUFFER_EXT, 0);
    }

    public void destroy() {

    }

    public void bindFrameBuffer() {
        GlStateManager.pushMatrix();
        GlStateManager.pushAttrib();
        EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, this.getFboId());
        if (this.isDepth())
            EXTFramebufferObject.glBindRenderbufferEXT(EXTFramebufferObject.GL_RENDERBUFFER_EXT, this.getDepId());
        GL11.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        GL11.glClearDepth(1.0f);
        GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
        GL11.glViewport(0, 0, this.getWidth(), this.getHeight());
        GL11.glMatrixMode(GL11.GL_PROJECTION);
        GL11.glLoadIdentity();
        GL11.glOrtho(0.0, this.getWidth(), 0.0, this.getHeight(), -1.0, 1.0);
        GL11.glMatrixMode(GL11.GL_MODELVIEW);
        GL11.glLoadIdentity();
        GL11.glDisable(GL11.GL_TEXTURE_2D);
    }

    public void unbindFrameBuffer() {
        EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, 0);
        if (this.isDepth())
            EXTFramebufferObject.glBindRenderbufferEXT(EXTFramebufferObject.GL_RENDERBUFFER_EXT, 0);
        GL11.glViewport(0, 0, Minecraft.getMinecraft().displayWidth, Minecraft.getMinecraft().displayHeight);
        GL11.glEnable(GL11.GL_TEXTURE_2D);
        GlStateManager.popMatrix();
        GlStateManager.popAttrib();
    }

    public void bindTexture() {

    }

    public void unbindTexture() {

    }

    public int getWidth() {
        return width;
    }

    public int getHeight() {
        return height;
    }

    public boolean isDepth() {
        return depth;
    }

    public int getFboId() {
        return fboId;
    }

    public int getTexId() {
        return texId;
    }

    public int getDepId() {
        return depId;
    }

}

 

 

Usage:

I use the FBO in a TileEntitySpecialRenderer to draw to it. After the fbo.unbindFrameBuffer() further rendering is completely broken. I think something is not reset correctly, but I don't know what causes the issue.

 

 

fbo.bindFrameBuffer();
setColor(0, 170, 255);
fillRect(0, 0, 50, 50);
setColor(255, 0, 0);
fillCircle(150, 150, 150);
fbo.unbindFrameBuffer();

 

 

I can assure you that my custom 2D rendering calls are working fine. I tried them by directly rendering to the side of the block. I also don't know if something is actually rendered to the FBO because if I want to apply the texture afterwards rendering is messed up.

 

The rendering gets broken in the following way:

  • Water doesn't get rendered while looking at the block
  • Item in hand and hand are not rendered while looking at the block
  • Block outline is not rendered while looking at the block
  • A black band appears on horizon (whole time)

 

Here are some screenshots to visualize the issue:

The block to get rendered is the light shadow in front of the Dispenser to the left of the hole.

 

System Information:

Minecraft 1.8

Forge Version: 11.14.1.1402

Operating System: Debian 8 with Gnome 3 and official Nvidia Drivers

Link to comment
Share on other sites

HI

 

YOu are messing with a pile of the OpenGL settings and not saving/restoring them properly.

 

What's the reason you can't just use the vanilla frame buffer helper?

 

This class is a working example of how you can render to a framebuffer object

https://github.com/TheGreyGhost/SpeedyTools/blob/master/src/main/java/speedytools/clientside/selections/SelectionBlockTextures.java

start from the updateTextures() method...

 

-TGG

  • Thanks 1
Link to comment
Share on other sites

Hi!

 

Thanks for your reply and your great blog about Minecraft architecture and informations!

 

I tried using the vanilla Framebuffer helper, but that lead to the exact same issues as with my own try. I tried making my own helper hoping to find the issue.

 

I will look into your example tomorrow!

Link to comment
Share on other sites

I tried it again with the Minecraft Framebuffer class and with the code in your example. Further rendering still gets broken after I try to render to the Framebuffer.

 

This is how I use it:

 

 

Framebuffer frameBuffer = null;
        try {
            GL11.glPushAttrib(GL11.GL_ENABLE_BIT);
            GL11.glMatrixMode(GL11.GL_MODELVIEW);
            GL11.glPushMatrix();
            GL11.glMatrixMode(GL11.GL_PROJECTION);
            GL11.glPushMatrix();

            // setup modelview matrix
            GL11.glMatrixMode(GL11.GL_MODELVIEW);
            GL11.glLoadIdentity();
            GL11.glMatrixMode(GL11.GL_PROJECTION);
            GL11.glLoadIdentity();

            GL11.glOrtho(0.0D, 1.0, 1.0, 0.0, -10.0, 10.0);
            GL11.glEnable(GL11.GL_CULL_FACE);
            GL11.glEnable(GL11.GL_DEPTH_TEST);
            GL11.glDisable(GL11.GL_LIGHTING);
            GL11.glDisable(GL11.GL_BLEND);
            GL11.glAlphaFunc(GL11.GL_GREATER, 0.1F);

            frameBuffer = new Framebuffer(300, 300, true);

            frameBuffer.setFramebufferColor(0.0F, 0.0F, 0.0F, 0.0F);
            frameBuffer.framebufferClear();
            frameBuffer.bindFramebuffer(true);

            setColor(0, 170, 255);
            fillRect(0, 0, 50, 50);
            setColor(255, 0, 0);
            fillCircle(150, 150, 150);

            frameBuffer.unbindFramebuffer();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (frameBuffer != null) {
                frameBuffer.deleteFramebuffer();
            }
            GL11.glMatrixMode(GL11.GL_PROJECTION);
            GL11.glPopMatrix();
            GL11.glMatrixMode(GL11.GL_MODELVIEW);
            GL11.glPopMatrix();
            GL11.glPopAttrib();
        }

 

 

Link to comment
Share on other sites

Hi

 

>Thanks for your reply and your great blog about Minecraft architecture and informations!

 

No worries, you're welcome :)

 

Strange symptoms.  I don't know, to be honest.  Some thoughts:

1) You don't need to call unbindFrameBuffer, it is called in deleteFramebuffer() already

2) Do the symptoms remain if you bind the buffer then unbind again immediately without rendering to it?  i.e. perhaps your setColor etc methods are doing something strange - try to narrow it down?

3) If you are changing settings in your setColor , fillCircle etc using the GlStateManager, it caches the settings but doesn't dirty the cache properly, so vanilla can sometimes change the settings through GLStateManager but OpenGL doesn't see it.  Solution is to use GL11 calls directly instead of GLstateManager

4) Some rendering settings are not saved by glPushAttrib(GL_ENABLE_BIT).  Check out the OpenGL docs to see other settings.

You could try doing your setColor, fillRect etc using the Tessellator and worldRenderer - starting simple and building up more complicated.

 

-TGG

 

 

Link to comment
Share on other sites

I finally fixed it! By using the following command I found out, that in the render loop we don't render to framebuffer object 0, but a diffrent one.

GL11.glGetInteger(EXTFramebufferObject.GL_FRAMEBUFFER_BINDING_EXT);

Now before I create the framebuffer or bind it get the "default" id that in need to switch back to when I am finished. This fixes the issue.

 

Now i just have to figure out why the drawn texture is not working as expected... :D

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.