OpenGL-渲染到纹理 - 屏幕的特定区域

时间:2015-07-31 13:29:23

标签: android opengl-es

我在OpenGL游戏中实现了FBO。并且我渲染渲染到屏幕的纹理,问题是渲染到纹理从左下角开始。看:

呈现给默认帧缓冲区的内容:

enter image description here

渲染到附加到FBO的纹理的内容:

enter image description here

但我想要渲染到纹理的地方是:

enter image description here

我该怎么做?这里是渲染器Calass(FBO操作在onDrawFrame函数中完成):

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);

     }
} 

1 个答案:

答案 0 :(得分:3)

您缺少为FBO渲染设置视口。如果您只想在绘制到默认帧缓冲区时绘制几何体的相同部分,则可以使用纹理大小作为视口尺寸:

glViewport(0, 0, texW, texH);

当您完成FBO渲染后,不要忘记将视口设置回适当大小的视图/曲面,并再次开始渲染到默认的帧缓冲区。

要绘制几何图形的不同(子)部分,如草图所示,您有几个选项:

  • 使用模型视图转换来平移/缩放几何体。
  • 调整投影变换。
  • 调整视口。

使用其中任何一个的结果可能会略有不同,具体取决于渲染的内容和方式。特别是如果涉及照明或透视投影,并非所有选项都会给出完全相同的结果。在这种情况下,您必须决定您想要的行为。

更改其中一个转换可能是最标准的方法。但是,调整视口可以是一种优雅的替代方案,具体取决于您正在尝试实现的目标。

例如,只是粗略地根据草图猜测值,您可以使用:

glViewport(texW / 4, -texH / 4, texW / 2, texH);

这将视口矩形定义为与草图中的虚线橙色矩形大致匹配。您可能需要更多数学值来保持宽高比,但这显示了基本思想。