ARCore 现在支持电子防抖 (EIS),该技术有助于生成流畅的相机预览。EIS 采用陀螺仪观察手机的运动情况,并在相机纹理边界内应用补偿单应矩阵网格来达到防抖效果。EIS 仅在设备的纵向模式下受支持。1.39.0 版本的 ARCore 将支持所有屏幕方向。
查询 EIS 支持并启用 EIS
如需启用 EIS,请将会话配置为使用 ImageStabilizationMode.EIS
。如果设备不支持 EIS 功能,会导致 ARCore 抛出异常。
Java
if (!session.isImageStabilizationModeSupported(Config.ImageStabilizationMode.EIS)) { return; } Config config = session.getConfig(); config.setImageStabilizationMode(Config.ImageStabilizationMode.EIS); session.configure(config);
Kotlin
if (!session.isImageStabilizationModeSupported(Config.ImageStabilizationMode.EIS)) return session.configure( session.config.apply { imageStabilizationMode = Config.ImageStabilizationMode.EIS } )
转换坐标
开启 EIS 后,渲染程序在渲染相机背景时需要使用修改后的设备坐标和包含 EIS 补偿的匹配纹理坐标。如需获取 EIS 补偿坐标,请使用 Frame.transformCoordinates3d()
,使用 OPENGL_NORMALIZED_DEVICE_COORDINATES
作为输入,使用 EIS_NORMALIZED_DEVICE_COORDINATES
作为输出以获取 3D 设备坐标,使用 EIS_TEXTURE_NORMALIZED
作为输出来获取 3D 纹理坐标。目前,Frame.transformCoordinates3d()
唯一支持的输入坐标类型是 OPENGL_NORMALIZED_DEVICE_COORDINATES
。
Java
final FloatBuffer cameraTexCoords = ByteBuffer.allocateDirect(COORDS_BUFFER_SIZE_3D) .order(ByteOrder.nativeOrder()) .asFloatBuffer(); final FloatBuffer screenCoords = ByteBuffer.allocateDirect(COORDS_BUFFER_SIZE_3D) .order(ByteOrder.nativeOrder()) .asFloatBuffer(); final FloatBuffer NDC_QUAD_COORDS_BUFFER = ByteBuffer.allocateDirect(COORDS_BUFFER_SIZE_2D) .order(ByteOrder.nativeOrder()) .asFloatBuffer() .put( new float[] { /*0:*/ -1f, -1f, /*1:*/ +1f, -1f, /*2:*/ -1f, +1f, /*3:*/ +1f, +1f, }); final VertexBuffer screenCoordsVertexBuffer = new VertexBuffer(render, /* numberOfEntriesPerVertex= */ 3, null); final VertexBuffer cameraTexCoordsVertexBuffer = new VertexBuffer(render, /* numberOfEntriesPerVertex= */ 3, null); NDC_QUAD_COORDS_BUFFER.rewind(); frame.transformCoordinates3d( Coordinates2d.OPENGL_NORMALIZED_DEVICE_COORDINATES, NDC_QUAD_COORDS_BUFFER, Coordinates3d.EIS_NORMALIZED_DEVICE_COORDINATES, screenCoords); screenCoordsVertexBuffer.set(screenCoords); NDC_QUAD_COORDS_BUFFER.rewind(); frame.transformCoordinates3d( Coordinates2d.OPENGL_NORMALIZED_DEVICE_COORDINATES, NDC_QUAD_COORDS_BUFFER, Coordinates3d.EIS_TEXTURE_NORMALIZED, cameraTexCoords); cameraTexCoordsVertexBuffer.set(cameraTexCoords);
Kotlin
val COORDS_BUFFER_SIZE_2D = 2 * 4 * Float.SIZE_BYTES val COORDS_BUFFER_SIZE_3D = 3 * 4 * Float.SIZE_BYTES val cameraTexCoords = ByteBuffer.allocateDirect(COORDS_BUFFER_SIZE_3D) .order(ByteOrder.nativeOrder()) .asFloatBuffer() val screenCoords = ByteBuffer.allocateDirect(COORDS_BUFFER_SIZE_3D) .order(ByteOrder.nativeOrder()) .asFloatBuffer() val cameraTexCoordsVertexBuffer = VertexBuffer(render, /* numberOfEntriesPerVertex= */ 3, null) val screenCoordsVertexBuffer = VertexBuffer(render, /* numberOfEntriesPerVertex= */ 3, null) val NDC_QUAD_COORDS_BUFFER = ByteBuffer.allocateDirect(COORDS_BUFFER_SIZE_2D) .order(ByteOrder.nativeOrder()) .asFloatBuffer() .apply { put( floatArrayOf( /* 0: */ -1f, -1f, /* 1: */ +1f, -1f, /* 2: */ -1f, +1f, /* 3: */ +1f, +1f ) ) } NDC_QUAD_COORDS_BUFFER.rewind() frame.transformCoordinates3d( Coordinates2d.OPENGL_NORMALIZED_DEVICE_COORDINATES, NDC_QUAD_COORDS_BUFFER, Coordinates3d.EIS_NORMALIZED_DEVICE_COORDINATES, screenCoords ) screenCoordsVertexBuffer.set(screenCoords) NDC_QUAD_COORDS_BUFFER.rewind() frame.transformCoordinates3d( Coordinates2d.OPENGL_NORMALIZED_DEVICE_COORDINATES, NDC_QUAD_COORDS_BUFFER, Coordinates3d.EIS_TEXTURE_NORMALIZED, cameraTexCoords ) cameraTexCoordsVertexBuffer.set(cameraTexCoords)
当 EIS 处于关闭状态时,输出的 3D 坐标等同于对应的 2D 坐标,并将 z 值设为不产生任何变化。
修改着色器
计算的 3D 坐标应传递给背景渲染着色器。现在,顶点缓冲区为具有 EIS 的 3D:
layout(location = 0) in vec4 a_Position;
layout(location = 1) in vec3 a_CameraTexCoord;
out vec3 v_CameraTexCoord;
void main() {
gl_Position = a_Position;
v_CameraTexCoord = a_CameraTexCoord;
}
此外,fragment 着色器需要应用透视校正:
precision mediump float;
uniform samplerExternalOES u_CameraColorTexture;
in vec3 v_CameraTexCoord;
layout(location = 0) out vec4 o_FragColor;
void main() {
vec3 tc = (v_CameraTexCoord / v_CameraTexCoord.z);
o_FragColor = texture(u_CameraColorTexture, tc.xy);
}
如需了解详情,请参阅 hello_eis_kotlin 示例应用。