當相機預覽分辨率設置爲1280*720,但是GLSurfaceView設置爲正方形會如何?很明顯畫面會被拉伸導致變形,在想一下如果設置GLSurfaceView爲全屏,但目前市場上的手機有很多種不同的分辨率,尤其是全面屏、摺疊屏屏,這些手機並不是常見的16:9的手機,因此我們需要適配這些不同分辨率的手機。
有的同學可能可能會想根據不同分辨率的手機而設置不同的預覽尺寸,是否可以呢?答案是 NO,因爲camera的預覽尺寸是需要硬件支持的,比如:camera支持640*480、1280*720,我們只能設置支持的分辨率,在項目中可以通過如下方式獲取camera支持的預覽尺寸:
val mCamera = Camera.open(i) val parameters = mCamera.parameters val supportSizeList = parameters.supportedPreviewSizes
既然相機的預覽尺寸無法隨便設置,那如何適配不同分辨率的手機呢?
視頻適配和相機適配有一些不同,視頻適配的最終效果是視頻畫面顯示完全,保證不拉伸的前提下會出現黑色區域,而相機的適配最終的效果是保證不拉伸而且不能出現黑色區域,因此我們需要裁剪紋理(相機畫面)來實現適配。
假設相機預覽尺寸是比率3/4(640*480),渲染窗口比率是9/16,正常不拉伸的效果如下:
底下的淺紅色表示渲染窗口,上面的淺藍色表示相機預覽畫面,想要達到畫面不拉伸而且鋪滿渲染窗口需要放大相機預覽畫面,放大到如下效果:
將紋理等比放大,如上圖所示。因此我們只需要裁剪淺紅色區域的紋理並顯示就達到了適配的目的。
原理搞清楚了,接下來在相機預覽的基礎上進行修改,頂點shader修改如下:
attribute vec4 a_Position; attribute vec4 a_TexCoordinate; uniform mat4 mMatrix; uniform mat4 mTextureMatrix; varying vec4 v_TexCoord; void main() { v_TexCoord = mTextureMatrix * a_TexCoordinate; gl_Position = mMatrix * a_Position; }
增加mTextureMatrix紋理矩陣,mTextureMatrix作用在紋理座標上。
片段shader修改如下:
#extension GL_OES_EGL_image_external : require precision mediump float; uniform samplerExternalOES u_Texture; varying vec4 v_TexCoord; void main() { gl_FragColor = texture2D(u_Texture, v_TexCoord.xy); }
v_TexCoord類型由vec2變爲vec4,採樣的時候使用v_TexCoord.xy。
獲取mTextureMatrix紋理矩陣參數句柄,代碼如下:
override fun onSurfaceCreated(p0: GL10?, p1: EGLConfig?) { ... mTextureMatrixLoc = GLES20.glGetUniformLocation(mProgramHandle, "mTextureMatrix") ... }
通過矩陣裁剪紋理,代碼如下:
var mTextureMatrix = FloatArray(16) private var screenWidth = 0 private var screenHeight = 0 private var cameraWidth = 640 private var cameraHeight = 480 override fun onSurfaceChanged(p0: GL10?, width: Int, height: Int) { ... screenWidth = width screenHeight = height computeTextureMatrix() } private fun computeTextureMatrix() { val cameraRatio = cameraWidth / cameraHeight.toFloat() val screenRatio = screenWidth / screenHeight.toFloat() Matrix.setIdentityM(mTextureMatrix, 0) if (cameraRatio > screenRatio) { Matrix.scaleM(mTextureMatrix, 0, 1F, 1 - ((cameraRatio - screenRatio) / 2), 1F) } else if (cameraRatio < screenRatio) { Matrix.scaleM(mTextureMatrix, 0, 1 - ((screenRatio - cameraRatio) / 2), 1F, 1F) } }
繪製時設置mTextureMatrix紋理矩陣數據:
override fun onDrawFrame(p0: GL10?) { ... GLES20.glUniformMatrix4fv(mTextureMatrixLoc, 1, false, mTextureMatrix, 0) ... }
本文主體內容轉載自:https://zhuanlan.zhihu.com/p/107651857