先說下題外話哈,最近做了個領取電商平臺優惠券的小程序,掃碼支持下哈~
離屏渲染
之前已經將相機的預覽數據已經輸出到opengl的紋理上,渲染的時候,opengl直接將紋理渲染到了屏幕。
但是,如果想要對該紋理進一步處理,就不能直接渲染到屏幕,而是應該先渲染到屏幕外的緩衝區(FrameBuffer)處理完後再渲染到屏幕。渲染到緩衝區的操作就是離屏渲染。
離屏渲染的目的是更改渲染目標(屏幕->緩衝區),主要步驟如下:
- 準備離屏渲染所需要的 FrameBuffer 和 紋理對象
- 切換渲染目標(屏幕->緩衝區)
- 執行渲染(和之前一樣,執行onDrawFrame方法進行繪製)
- 重置渲染目標(緩衝區->屏幕)
關鍵代碼如下:
//準備離屏渲染所需要的 FrameBuffer 和 紋理對象
public void genFrameBufferAndTexture() {
glGenFramebuffers(frameBuffer.length, frameBuffer, 0);
glGenTextures(frameTexture.length, frameTexture, 0);
}
//切換渲染目標(屏幕->緩衝區)
public void bindFrameBufferAndTexture() {
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer[0]);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, frameTexture[0], 0);
}
//重置渲染目標(緩衝區->屏幕)
public void unBindFrameBuffer() {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
拍照
無論中間經過離屏渲染做了多少處理,最後都會切換渲染到屏幕,不渲染到屏幕看不到,也就沒法預覽。
拍照是再預覽的基礎上,再點擊拍照的一瞬間將最後一個渲染環節切換到FrameBuffer,然後通過 glReadPixels
方法將顯存中的數據回傳到內存中保存到本地,最後再將渲染切換回屏幕繼續預覽。
需要注意的是在屏幕預覽時y軸正方向是向下的,所以保存到本地的時候需要在y軸上做一次反轉。
關鍵代碼如下:
if (isTakingPhoto()) {
ByteBuffer exportBuffer = ByteBuffer.allocate(width * height * 4);
bindFrameBufferAndTexture();
colorFilter.setMatrix(MatrixUtil.flip(matrix, false, true));
colorFilter.onDraw();
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, exportBuffer);
savePhoto(exportBuffer);
unBindFrameBuffer();
setTakingPhoto(false);
colorFilter.setMatrix(MatrixUtil.flip(matrix, false, true));
} else {
colorFilter.onDraw();
}
前後相機切換
這個比較簡單,需要注意的就是前置/後置攝像頭默認的旋轉角度不同預覽的時候需要進行旋轉校正。
//後置相機,順時針旋轉90度
public static final float[] textureCoordCameraBack = {
1.0f, 1.0f,
0.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f
};
//前置相機,逆時針旋轉90度
public static final float[] textureCoordCameraFront = {
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f
};
另外一個需要注意的就是前置相機的鏡像問題,通過矩陣進行設置
if (this.useFront != useFront) {
this.useFront = useFront;
cameraFilter.setUseFront(useFront);
matrix = MatrixUtil.flip(matrix, true, false);
}