2016-06-28 145 views
1

我正在使用SurfaceView通過GLES將相機預覽呈現到屏幕。渲染之前是否可以在下面的方法中裁剪紋理?我想裁剪一個16:9紋理在屏幕上顯示爲4:3。在繪製之前裁剪GLES紋理

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

回答

0

好吧,我堅信這是裁剪紋理的正確方法,但它能做到我所需要的。我只是將負值設置爲視口的起始座標,並根據我需要的輸出調整分辨率:

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.... 
} 
1

只要改變你的紋理座標(來接你希望出現在屏幕上的),和你的頂點座標(決定在哪裏在屏幕上繪製)。