Alireza Peer
Alireza Peer

Reputation: 908

OpenGL- Render to texture- whole rendered scene

I implemented FBO on my OpenGL Game. and Im rendering what is rendered to screen to a texture, the problem is that rendering to texture starts from lower left corner. look:

what is rendered to Default Frame Buffer:

enter image description here

what is rendered to texture attached to FBO:

enter image description here

But Where i want to be Rendered to Texture is:

enter image description here

i have calculated the Hypothetical Rectangle (red Dots) positions. But I dont Know how to exactly render that area,

how can i do this? here is the renderer Calass (the FBO operation is done in onDrawFrame function):

public class CurlRenderer implements GLSurfaceView.Renderer {

// Constant for requesting right page rect.
public static final int PAGE = 1;
// Set to true for checking quickly how perspective projection looks.
private static final boolean USE_PERSPECTIVE_PROJECTION = false;
// Background fill color.
private int mBackgroundColor;
// Curl meshes used for static and dynamic rendering.
private CurlMesh mCurlMesh;
private RectF mMargins = new RectF();
private CurlRenderer.Observer mObserver;
// Page rectangles.
private RectF mPageRect;
// View mode.
// Screen size.
private int mViewportWidth, mViewportHeight;
// Rect for render area.
private RectF mViewRect = new RectF();
private boolean first = true;
int[] fb, renderTex; 
int texW = 300; 
int texH = 256; 
IntBuffer texBuffer;
int[] buf = new int[texW * texH];
GL11ExtensionPack gl11ep ;
/**
 * Basic constructor.
 */
public CurlRenderer(CurlRenderer.Observer observer) {
    mObserver = observer;
    mCurlMesh = new CurlMesh(0);
    mPageRect = new RectF();
}

/**
 * Adds CurlMesh to this renderer.
 */
public synchronized void addCurlMesh(CurlMesh mesh) {
    mCurlMesh = mesh;
}

/**
 * Returns rect reserved for left or right page. Value page should be
 * PAGE_LEFT or PAGE_RIGHT.
 */
public RectF getPageRect(int page) {
        if (page == PAGE) {
        return mPageRect;
    }
    return null;
}
public void setup(GL10 gl){
    fb = new int[1];
    renderTex = new int[1];
    // generate
    ((GL11ExtensionPack)gl).glGenFramebuffersOES(1, fb, 0); 
    gl.glEnable(GL10.GL_TEXTURE_2D);
    gl.glGenTextures(1, renderTex, 0);// generate texture
    gl.glBindTexture(GL10.GL_TEXTURE_2D, renderTex[0]);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);
   // texBuffer = ByteBuffer.allocateDirect(buf.length*4).order(ByteOrder.nativeOrder()).asIntBuffer();
   // gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE,GL10.GL_MODULATE);
    gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGBA, texW, texH, 0, GL10.GL_RGBA, GL10.GL_UNSIGNED_SHORT_4_4_4_4, null);
    gl.glDisable(GL10.GL_TEXTURE_2D);
}
boolean RenderStart(GL10 gl){
    // Bind the framebuffer
    ((GL11ExtensionPack)gl).glBindFramebufferOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES, fb[0]);

    // specify texture as color attachment
    ((GL11ExtensionPack)gl).glFramebufferTexture2DOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES, GL11ExtensionPack.GL_COLOR_ATTACHMENT0_OES, GL10.GL_TEXTURE_2D, renderTex[0], 0);


    int error = gl.glGetError();
    if (error != GL10.GL_NO_ERROR) {
        Log.d("err", "Background Load GLError: " + error+"      ");
    }
    int status = ((GL11ExtensionPack)gl).glCheckFramebufferStatusOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES);
    if (status != GL11ExtensionPack.GL_FRAMEBUFFER_COMPLETE_OES)
    {
        Log.d("err", "Background Load GLError: " + status+"      ");;
        return true;
    }
    gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
    return true;
}
void RenderEnd(GL10 gl){
    ((GL11ExtensionPack)gl).glBindFramebufferOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES, 0);

    gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

    gl.glEnable(GL10.GL_TEXTURE_2D);
    gl.glBindTexture(GL10.GL_TEXTURE_2D, renderTex[0]);
    gl.glColor4f(1,1,1,1);
    gl.glDisable(GL10.GL_TEXTURE_2D);
}

@Override
public synchronized void onDrawFrame(GL10 gl) {
    if(first){
    int h = GLES20.glGetError();
    this.setup(gl);
    if(h!=0){
        Log.d("ERROR", "ERROR Happend"+h+"");
    }
    first = false;
    }
    mObserver.onDrawFrame();
    //glClearColor miad rangi ke maa entekhaab kardim ro tooye carde Graphic register mikone
    gl.glClearColor(Color.red(mBackgroundColor) / 255f,
            Color.green(mBackgroundColor) / 255f,
            Color.blue(mBackgroundColor) / 255f,
            Color.alpha(mBackgroundColor) / 255f);
    //glClear miad oon rangi ke bala register karde boodim ro dige az buffer paak mikone
    gl.glClear(GL10.GL_COLOR_BUFFER_BIT);

    //miad matris ro be MabdaEsh barmigardoone, ke bAd baraye glRotate va glTranslate moshkeli ijaad nashe
    //chon maa asle jaabejaa kardan hamoon baraye safhe, baste be makaane avalieye
    // kaaghazemoon hast, na oon makani ke dar haale hazer gharaar dare
    gl.glLoadIdentity();

    if (USE_PERSPECTIVE_PROJECTION) {
        gl.glTranslatef(0, 0, -6f);
    }


    RenderStart(gl);
    mCurlMesh.onDrawFrame(gl);
    RenderEnd(gl);
    mCurlMesh.onDrawFrame(gl);

}

@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
    gl.glViewport(0, 0, width, height);
    mViewportWidth = width;
    mViewportHeight = height;

    float ratio = (float) width / height;
    mViewRect.top = 1.0f;
    mViewRect.bottom = -1.0f;
    mViewRect.left = -ratio;
    mViewRect.right = ratio;
    updatePageRects();

    gl.glMatrixMode(GL10.GL_PROJECTION);
    gl.glLoadIdentity();
    if (USE_PERSPECTIVE_PROJECTION) {
        GLU.gluPerspective(gl, 20f, (float) width / height, .1f, 100f);
    } else {
        GLU.gluOrtho2D(gl, mViewRect.left, mViewRect.right,
                mViewRect.bottom, mViewRect.top);
    }

    gl.glMatrixMode(GL10.GL_MODELVIEW);
    gl.glLoadIdentity();
}

@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
//  mCurlMesh.setup(gl);
    gl.glClearColor(0f, 0f, 0f, 1f);
    gl.glShadeModel(GL10.GL_SMOOTH);
    gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
    gl.glHint(GL10.GL_LINE_SMOOTH_HINT, GL10.GL_NICEST);
    //gl.glHint(GL10.GL_POLYGON_SMOOTH_HINT, GL10.GL_NICEST);
    gl.glEnable(GL10.GL_LINE_SMOOTH);
    gl.glDisable(GL10.GL_DEPTH_TEST);
    gl.glDisable(GL10.GL_CULL_FACE);
}


/**
 * Change background/clear color.
 */
public void setBackgroundColor(int color) {
    mBackgroundColor = color;
}

/**
 * Set margins or padding. Note: margins are proportional. Meaning a value
 * of .1f will produce a 10% margin.
 */
public synchronized void setMargins(float left, float top, float right,
        float bottom) {
    mMargins.left = left;
    mMargins.top = top;
    mMargins.right = right;
    mMargins.bottom = bottom;
    updatePageRects();
}
/**
 * Translates screen coordinates into view coordinates.
 * mokhtassate ye noghte (masalan pointer Position) roye safhe ro, be moAdele mokhtasaatesh
 * rooye CurlView Tabdil mikene
 */
public void translate(PointF pt) {
    pt.x = mViewRect.left + (mViewRect.width() * pt.x / mViewportWidth);
    pt.y = mViewRect.top - (-mViewRect.height() * pt.y / mViewportHeight);
}

/**
 * Recalculates page rectangles.
 */
private void updatePageRects() {
    if (mViewRect.width() == 0 || mViewRect.height() == 0) {
        return;
    }
    /**
     * @ TODO inja daghighan hamnoon kaari ke mikham, yAni size dadan be Page ro anjaam mide
     * mpageRect... khode meshe  va mViewRect view E layout
     */
        mPageRect.set(mViewRect);
        mPageRect.left += mViewRect.width() * mMargins.left;
        mPageRect.right -= mViewRect.width() * mMargins.right;
        mPageRect.top += mViewRect.height() * mMargins.top;
        mPageRect.bottom -= mViewRect.height() * mMargins.bottom;

        int bitmapW = (int) ((mPageRect.width() * mViewportWidth) / mViewRect.width());
        int bitmapH = (int) ((mPageRect.height() * mViewportHeight) / mViewRect.height());
        mObserver.onPageSizeChanged(bitmapW, bitmapH);

}

/**
 * Observer for waiting render engine/state updates.
 */
public interface Observer {
    /**
     * Called from onDrawFrame called before rendering is started. This is
     * intended to be used for animation purposes.
     */
    public void onDrawFrame();

    /**
     * Called once page size is changed. Width and height tell the page size
     * in pixels making it possible to update textures accordingly.
     */
    public void onPageSizeChanged(int width, int height);

     }
} 

Upvotes: 2

Views: 405

Answers (1)

Sung
Sung

Reputation: 1066

First of all, you should understand a basic rendering pipeline. In which, there is a clipping coordinate after multiplying a projection matrix. When you call gluOrtho2D() which is the projection matrix, you cut the object by yourself.

In short, RTT (render to texture) is just a texture rendered to a render target (FBO), and you draw the chopped triangle at the FBO so you have the cut texture that you don't want to get.

To draw a object in the box is after multiplying projection and after w-divide step, all x,y, range must be between [-1,1]. If it is hard to calculate for you, don't multiply the projection matrix and make sure all x,y and z values are in the range [-1,1], and W must be 1  

Upvotes: 1

Related Questions