ARCore kini mendukung Electronic Image Stabilization (EIS), yang membantu menghasilkan pratinjau kamera yang lancar. EIS mencapai stabilisasi dengan mengamati gerakan ponsel menggunakan giroskop dan menerapkan mesh homography kompensasi dalam batas tekstur kamera yang melawan guncangan kecil. EIS hanya didukung dalam orientasi potret perangkat. Semua orientasi akan didukung dalam rilis ARCore 1.39.0.
Membuat kueri untuk dukungan EIS dan mengaktifkan EIS
Untuk mengaktifkan EIS, konfigurasikan sesi Anda untuk menggunakan ImageStabilizationMode.EIS
. Jika perangkat tidak mendukung fitur EIS, pengecualian akan ditampilkan dari ARCore.
if (!session.isImageStabilizationModeSupported(Config.ImageStabilizationMode.EIS)) { return; } Config config = session.getConfig(); config.setImageStabilizationMode(Config.ImageStabilizationMode.EIS); session.configure(config);
if (!session.isImageStabilizationModeSupported(Config.ImageStabilizationMode.EIS)) return session.configure( session.config.apply { imageStabilizationMode = Config.ImageStabilizationMode.EIS } )
Mentransformasi koordinat
Jika EIS aktif, perender harus menggunakan koordinat perangkat yang dimodifikasi dan koordinat tekstur yang cocok yang menggabungkan kompensasi EIS saat merender latar belakang kamera. Untuk mendapatkan koordinat yang dikompensasi EIS, gunakan Frame.transformCoordinates3d()
, menggunakan OPENGL_NORMALIZED_DEVICE_COORDINATES
sebagai input dan EIS_NORMALIZED_DEVICE_COORDINATES
sebagai output untuk mendapatkan koordinat perangkat 3D dan EIS_TEXTURE_NORMALIZED
sebagai output untuk mendapatkan koordinat tekstur 3D. Untuk saat ini, satu-satunya jenis koordinat input yang didukung untuk Frame.transformCoordinates3d()
adalah OPENGL_NORMALIZED_DEVICE_COORDINATES
.
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);
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)
Jika EIS nonaktif, koordinat 3D output setara dengan koordinat 2D-nya, dengan nilai z disetel agar tidak menghasilkan perubahan.
Mengubah shader
Koordinat 3D yang dihitung harus diteruskan ke shader rendering latar belakang. Buffer vertex kini menjadi 3D dengan EIS:
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;
}
Selain itu, shader fragmen perlu menerapkan koreksi perspektif:
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);
}
Lihat aplikasi contoh hello_eis_kotlin untuk detail selengkapnya.