【问题标题】:Crop GLES texture before drawing在绘图前裁剪 GLES 纹理
【发布时间】:2016-06-28 14:36:00
【问题描述】:

我正在使用 SurfaceView 通过 GLES 将相机预览呈现到屏幕上。是否可以在渲染之前用下面的方法裁剪纹理?我想裁剪 16:9 的纹理以在屏幕上显示为 4:3。

public void drawFrame(int width, int height, float sourceAspectRatio, float targetAspectRatio, boolean flipHorizontally, boolean flipVertically) {

    //Aspect ratio correction. Source Aspect ratio is taken from Camera.Parameters.getPictureSize()
    //assuming that value is the native resolution of the camera. Sometimes the native camera aspect ratio
    //doesn't match the display's aspect ratio.
    float scaleX, scaleY;
    if (sourceAspectRatio >= targetAspectRatio) {
        scaleX = sourceAspectRatio/targetAspectRatio;
        scaleY = 1;
    } else {
        scaleX = 1;
        scaleY = targetAspectRatio/sourceAspectRatio;
    }

    if (flipHorizontally) scaleX = -scaleX;
    if (flipVertically) scaleY = -scaleY;

    checkGlError("onDrawFrame start");
    mSurfaceTexture.getTransformMatrix(mSTMatrix);

    GLES20.glViewport(0,0,width,height);

    GLES20.glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

    GLES20.glUseProgram(mProgram);
    checkGlError("glUseProgram");

    /**
     * Explanation of double binding: http://stackoverflow.com/questions/20386515/glsurfaceview-framerate-issues-on-nexus-5
     *
     * I was able to replicate the behavior, and my GL wizard office-mate figured out the problem.
     * Basically, one of the EGL contexts isn't noticing that the texture contents have changed, so it keeps rendering older data.
     * We think it's getting occasional updates because it has a set of buffers that it cycles through,
     * so eventually it re-uses the buffer you're looking at.
     * I was able to fix the problem in my code by updating the texture renderer class, changing this:
     *
     * GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTextureID)
     *
     * to this
     *
     * GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
     * GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTextureID);
     *
     * The un-bind and re-bind causes the driver to pick up the right buffer.
     */
    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
    GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
    GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTextureID);

    mTriangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
    GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
    checkGlError("glVertexAttribPointer maPosition");
    GLES20.glEnableVertexAttribArray(maPositionHandle);
    checkGlError("glEnableVertexAttribArray maPositionHandle");

    mTriangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
    GLES20.glVertexAttribPointer(maTextureHandle, 2, GLES20.GL_FLOAT, false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
    checkGlError("glVertexAttribPointer maTextureHandle");
    GLES20.glEnableVertexAttribArray(maTextureHandle);
    checkGlError("glEnableVertexAttribArray maTextureHandle");
    Matrix.setIdentityM(mMVPMatrix, 0);
    mMVPMatrix[0] = scaleX;
    mMVPMatrix[5] = scaleY;
    GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
    GLES20.glUniformMatrix4fv(muSTMatrixHandle, 1, false, mSTMatrix, 0);

    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
    checkGlError("glDrawArrays");

    GLES20.glDisableVertexAttribArray(maTextureHandle);
    GLES20.glDisableVertexAttribArray(maPositionHandle);
    GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
    GLES20.glUseProgram(0);
}

【问题讨论】:

    标签: android opengl-es surfaceview


    【解决方案1】:

    好的,我确信这是裁剪纹理的正确方法,但它可以满足我的需要。我只是将视口的起始坐标设置为负值,并根据我需要的输出调整分辨率:

    public void drawFrame(int sourceWidth, int sourceHeight, int targetWidth, int targetHeight, boolean flipHorizontally, boolean flipVertically) {
    
        int offsetX = 0, offsetY = 0;
        float scaleX = 1, scaleY = 1;
        if (flipHorizontally) scaleX = -scaleX;
        if (flipVertically) scaleY = -scaleY;
    
        float sourceAspectRatio = (float) sourceWidth / sourceHeight;
        float targetAspectRatio = (float) targetWidth / targetHeight;
    
        //Pull the image off the screen if needed, based on the aspect ratio diff.
        if (sourceAspectRatio > targetAspectRatio) {
            int scaledTargetWidth = (int) (targetHeight * sourceAspectRatio);
            offsetX = (scaledTargetWidth - targetWidth) / 2;
            offsetX = -offsetX;
            targetWidth = scaledTargetWidth;
        } else if (sourceAspectRatio < targetAspectRatio) {
            int scaledTargetHeight = (int) (targetWidth / sourceAspectRatio);
            offsetY = (scaledTargetHeight - targetHeight) / 2;
            offsetY = -offsetY;
            targetHeight = scaledTargetHeight;
        }
    
        checkGlError("onDrawFrame start");
        mSurfaceTexture.getTransformMatrix(mSTMatrix);
    
        GLES20.glViewport(offsetX,offsetY,targetWidth,targetHeight);
    
        //TODO....
    }
    

    【讨论】:

    • 这很有帮助,谢谢!
    【解决方案2】:

    只需更改您的纹理坐标(以选择您希望在屏幕上显示的内容)和您的顶点坐标(以决定您在屏幕上绘制的位置)。

    【讨论】:

      猜你喜欢
      • 2014-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-08
      • 2015-03-17
      • 1970-01-01
      • 2020-09-27
      • 2013-01-13
      相关资源
      最近更新 更多