1. 總覽
ARCore 是一個平台,可讓您在 Android 平台上建構擴增實境應用程式。擴增圖片可讓你建立 AR 應用程式,藉此辨識現實世界中預先註冊的 2D 圖片,並將虛擬內容錨定在這些圖片上方。
本程式碼研究室將引導您修改現有的 ARCore 範例應用程式,以納入要移動或固定的擴增圖片。
建構項目
在這個程式碼研究室中,您將使用現有的 ARCore 範例應用程式進行建構。完成程式碼研究室後,您的應用程式將能:
- 偵測圖片目標,並在目標上連接虛擬迷宮
- 只要移動到攝影機視角的移動目標,即可進行追蹤
這是你第一次製作 ARCore 應用程式嗎?
您打算在本程式碼研究室中編寫程式碼範例,或單純想閱讀這些網頁嗎?
課程內容
- 如何在 Java 中使用 ARCore 中的擴增圖片
- 如何測量 ARCore 辨識圖片的能力
- 如何在圖片中附加虛擬內容並追蹤其動作
必要條件
您需要使用特定的硬體和軟體,才能完成這個程式碼研究室。
硬體需求
- 使用 USB 傳輸線連接至開發機器的 ARCore 支援裝置
軟體需求
- ARCore APK 1.9.0 以上版本。這個 APK 通常會透過 Play 商店自動安裝在裝置上
- 搭載 Android Studio (3.1 以上版本) 的開發機器
- 網際網路存取權,因為在開發期間需下載程式庫
一切準備就緒後,開始吧!
2. 設定開發環境
下載 SDK
請先從 GitHub 下載最新的 ARCore Android SDK。將其解壓縮到您想要的位置。在本程式碼研究室中,最早的 SDK 版本為 1.18.1。這個資料夾稱為 arcore-android-sdk-x.xx.x
,確切值會是您使用的 SDK 版本。
啟動 Android Studio,然後按一下「Open an existing Android Studio project」。
前往這個解壓縮資料夾:
arcore-android-sdk-x.xx.x/samples/augmented_image_java
按一下「開啟」。
等待 Android Studio 完成專案同步處理作業。如果 Android Studio 沒有必要元件,可能會失敗,並顯示 Install missing platform and sync project
訊息。按照操作說明修正問題。
執行範例應用程式
建立可運作的 ARCore 應用程式專案後,讓我們開始執行測試。
將 ARCore 裝置連線至開發機器,然後依序使用選單 [Run] >執行「app」,在裝置上執行偵錯版本。在提示中選擇要用來執行的裝置,請選擇已連結的裝置,然後按一下「OK」。
這個範例專案使用 targetSdkVersion 28
。如果您有 Failed to find Build Tools revision 28.0.3
等建構錯誤,請按照 Android Studio 中所述的操作說明,下載並安裝必要的 Android Build Tools 版本。
如果一切順利,範例應用程式就會在裝置上啟動,並提示你允許擴增圖像拍攝相片和影片的權限。輕觸「允許」即可授予權限。
使用範例圖片進行測試
設定好開發環境後,您現在可以提供應用程式檢視的映像檔,藉此測試應用程式。
返回 Android Studio,在「Project」視窗中前往「app」>「」資產,然後按兩下檔案 default.jpg
將其開啟。
將裝置的相機鏡頭對準螢幕上的地球圖像,然後按照指示將您要掃描的影像對準十字記號。
圖片頁框會重疊在圖片上,如下所示:
接著,我們會微幅改進範例應用程式。
3. 在 2D 圖片上顯示迷宮模型
您可以在「擴增圖片」上方顯示 3D 模型,開始體驗擴增圖片功能。
下載 3D 模型
在本程式碼研究室中,我們會使用「Circle Maze - Green」,並依據 CC-BY 3.0 授權取得授權。我已將這個 3D 模型的副本儲存在本程式碼研究室的 GitHub 存放區中,可以在這裡取得。
請按照下列步驟下載模型並加進 Android Studio。
- 前往本程式碼研究室的 GitHub 存放區 (third_party 目錄)。
- 按一下「GreenMaze_obj.zip」GreenMaze_obj.zip,然後點選「下載」GreenMaze_obj.zip按鈕。
這會下載名為 GreenMaze_obj.zip
的檔案。
- 在 Android Studio 中,於 app > 下方建立
green-maze
目錄資源 >模型 - 解壓縮
GreenMaze_obj.zip
,並將內容複製到這個位置:arcore-android-sdk-x.xx.x/samples/augmented_image_java/app/src/main/assets/models/green-maze
- 在 Android Studio 中,前往「app」(應用程式) > 資源 >模型 >綠迷宮。
這個資料夾中應有兩個檔案:GreenMaze.obj
和 GreenMaze.mtl
。
轉譯迷宮模型
如要在現有 2D 圖像上方顯示 GreenMaze.obj
3D 模型,請按照下列步驟操作。
在 AugmentedImageRenderer.java
中,新增名為 mazeRenderer
的成員變數,以算繪迷宮模型。由於迷宮應附加至圖片,因此將 mazeRenderer
放入 AugmentedImageRenderer
類別會很合理。
AugmentedImageRenderer.java
// Add a member variable to hold the maze model.
private final ObjectRenderer mazeRenderer = new ObjectRenderer();
在 createOnGlThread()
函式中載入 GreenMaze.obj
。為求簡單,請使用與紋理相同的影格紋理。
AugmentedImageRenderer.java
// Replace the definition of the createOnGlThread() function with the
// following code, which loads GreenMaze.obj.
public void createOnGlThread(Context context) throws IOException {
mazeRenderer.createOnGlThread(
context, "models/green-maze/GreenMaze.obj", "models/frame_base.png");
mazeRenderer.setMaterialProperties(0.0f, 3.5f, 1.0f, 6.0f);
}
將 draw()
函式的定義替換為下列內容。這會將迷宮的大小調整為偵測到的圖片大小,並在螢幕上顯示。
AugmentedImageRenderer.java
// Adjust size of detected image and render it on-screen
public void draw(
float[] viewMatrix,
float[] projectionMatrix,
AugmentedImage augmentedImage,
Anchor centerAnchor,
float[] colorCorrectionRgba) {
float[] tintColor =
convertHexToColor(TINT_COLORS_HEX[augmentedImage.getIndex() % TINT_COLORS_HEX.length]);
final float mazeEdgeSize = 492.65f; // Magic number of maze size
final float maxImageEdgeSize = Math.max(augmentedImage.getExtentX(), augmentedImage.getExtentZ()); // Get largest detected image edge size
Pose anchorPose = centerAnchor.getPose();
float mazeScaleFactor = maxImageEdgeSize / mazeEdgeSize; // scale to set Maze to image size
float[] modelMatrix = new float[16];
// OpenGL Matrix operation is in the order: Scale, rotation and Translation
// So the manual adjustment is after scale
// The 251.3f and 129.0f is magic number from the maze obj file
// You mustWe need to do this adjustment because the maze obj file
// is not centered around origin. Normally when you
// work with your own model, you don't have this problem.
Pose mazeModelLocalOffset = Pose.makeTranslation(
-251.3f * mazeScaleFactor,
0.0f,
129.0f * mazeScaleFactor);
anchorPose.compose(mazeModelLocalOffset).toMatrix(modelMatrix, 0);
mazeRenderer.updateModelMatrix(modelMatrix, mazeScaleFactor, mazeScaleFactor/10.0f, mazeScaleFactor); // This line relies on a change in ObjectRenderer.updateModelMatrix later in this codelab.
mazeRenderer.draw(viewMatrix, projectionMatrix, colorCorrectionRgba, tintColor);
}
現在,迷宮應該會顯示在地球的 default.jpg
圖片上方。
注意:由於您並不完全控制這個 3D 模型範例,因此上述程式碼會使用一些「魔法」數字。迷宮模型的尺寸為 492.65 x 120 x 492.65,中間為 (251.3、60、-129.0)。頂點的範圍X、Y 和 Z 座標值分別為 [5.02、497.67]、[0、120] 和 [-375.17、117.25]。因此,迷宮模型的比例必須是 image_size / 492.65
。之所以導入 mazeModelLocalOffset
,是因為迷宮的 3D 模型未以原點 (0, 0, 0) 為中心。
迷宮的牆壁仍然太高,無法印在相片上方。建立能不均勻縮放 X、Y、Z 的輔助函式 updateModelMatrix()
,將迷宮的高度調整為 0.1。請注意,您應保留現有的 updateModelMatrix(float[] modelMatrix, float scaleFactor)
,並將函式超載 updateModelMatrix(float[] modelMatrix, float scaleFactorX, float scaleFactorY, float scaleFactorZ)
新增為新函式。
common/rendering/ObjectRenderer.java
// Scale X, Y, Z coordinates unevenly
public void updateModelMatrix(float[] modelMatrix, float scaleFactorX, float scaleFactorY, float scaleFactorZ) {
float[] scaleMatrix = new float[16];
Matrix.setIdentityM(scaleMatrix, 0);
scaleMatrix[0] = scaleFactorX;
scaleMatrix[5] = scaleFactorY;
scaleMatrix[10] = scaleFactorZ;
Matrix.multiplyMM(this.modelMatrix, 0, modelMatrix, 0, scaleMatrix, 0);
}
執行程式碼。迷宮現在應該完全符合圖片的上方。
4. 把 Andy 加入迷宮
現在您已擁有迷宮,可以新增角色並在其中移動。使用 ARCore Android SDK 內含的 andy.obj
檔案。請保留圖片框架紋理做為紋理,因為它看起來與圖片上方算繪的綠色迷宮不同。
在 AugmentedImageRenderer.java
中,新增私人 ObjectRenderer
以轉譯 Andy。
AugmentedImageRenderer.java
// Render for Andy
private final ObjectRenderer andyRenderer = new ObjectRenderer();
接下來,在 createOnGlThread()
的結尾初始化 andyRenderer
。
AugmentedImageRenderer.java
public void createOnGlThread(Context context) throws IOException {
// Initialize andyRenderer
andyRenderer.createOnGlThread(
context, "models/andy.obj", "models/andy.png");
andyRenderer.setMaterialProperties(0.0f, 3.5f, 1.0f, 6.0f);
}
最後,在 draw()
函式結尾的迷宮上方算繪 Andy。
AugmentedImageRenderer.java
public void draw(
float[] viewMatrix,
float[] projectionMatrix,
AugmentedImage augmentedImage,
Anchor centerAnchor,
float[] colorCorrectionRgba) {
// Render Andy, standing on top of the maze
Pose andyModelLocalOffset = Pose.makeTranslation(
0.0f,
0.1f,
0.0f);
anchorPose.compose(andyModelLocalOffset).toMatrix(modelMatrix, 0);
andyRenderer.updateModelMatrix(modelMatrix, 0.05f); // 0.05f is a Magic number to scale
andyRenderer.draw(viewMatrix, projectionMatrix, colorCorrectionRgba, tintColor);
}
執行程式碼。您應該會看到安迪站在迷宮上方。
決定目標圖片品質
ARCore 需要使用視覺功能才能辨識圖片。由於品質差異,部分圖片可能不容易辨識。
您可以使用「arcoreimg
」這項指令列工具,決定圖片對 ARCore 的辨識度。這樣會輸出介於 0 到 100 之間的數字,100 是最容易辨識的數字。
,直接在 Google Cloud 控制台實際操作。範例如下:
arcore-android-sdk-x.xx.x/tools/arcoreimg/macos$
$ ./arcoreimg eval-img --input_image_path=/Users/username/maze.jpg
100
maze.jpg
的值為 100,因此 ARCore 可以輕鬆辨識。
5. 選手:讓安迪在迷宮展開行動
最後,您可以加入一些程式碼,在迷宮中動起來。例如使用開放原始碼物理引擎 jBullet 來處理物理模擬。即使跳過這個部分也完全沒有問題。
下載「PhysicsController.java
」,並新增至目錄中的專案
arcore-android-sdk-x.xx.x/samples/augmented_image_java/app/src/main/java/com/google/ar/core/examples/java/augmentedimage/
在 Android Studio 中,將 GreenMaze.obj 新增至「專案資產」目錄,以便在執行階段載入。從應用程式複製 GreenMaze.obj
>資產 >模型 >綠迷到應用程式 >assets:
在應用程式的 build.gradle
檔案中新增下列依附元件。
app/build.gradle
// jbullet library
implementation 'cz.advel.jbullet:jbullet:20101010-1'
定義變數 andyPose
以儲存 Andy 目前姿勢的位置。
AugmentedImageRenderer.java
// Create a new pose for the Andy
private Pose andyPose = Pose.IDENTITY;
修改 AugmentedImageRenderer.java
,使用新的 andyPose
變數轉譯 Andy。
AugmentedImageRenderer.java
public void draw(
float[] viewMatrix,
float[] projectionMatrix,
AugmentedImage augmentedImage,
Anchor centerAnchor,
float[] colorCorrectionRgba) {
// Use these code to replace previous code for rendering the Andy object
//
// Adjust the Andy's rendering position
// The Andy's pose is at the maze's vertex's coordinate
Pose andyPoseInImageSpace = Pose.makeTranslation(
andyPose.tx() * mazeScaleFactor,
andyPose.ty() * mazeScaleFactor,
andyPose.tz() * mazeScaleFactor);
anchorPose.compose(andyPoseInImageSpace).toMatrix(modelMatrix, 0);
andyRenderer.updateModelMatrix(modelMatrix, 0.05f);
andyRenderer.draw(viewMatrix, projectionMatrix, colorCorrectionRgba, tintColor);
}
新增公用程式函式 updateAndyPose()
,以接收 Andy 姿勢更新。
AugmentedImageRenderer.java
// Receive Andy pose updates
public void updateAndyPose(Pose pose) {
andyPose = pose;
}
在 AugmentedImageActivity.java
中,建立使用 JBullet 物理引擎的 PhysicsController
物件,藉此管理所有物理相關函式。
AugmentedImageActivity.java
import com.google.ar.core.Pose;
// Declare the PhysicsController object
private PhysicsController physicsController;
在物理引擎中,我們其實使用硬球來呈現安迪的姿勢,並利用球體的姿勢更新安迪的姿勢。呼叫 PhysicsController
,即可在應用程式辨識出圖片時更新物理行為。運用真實世界的重力在迷宮中移動球,就能像在現實世界中一樣移動球。
AugmentedImageActivity.java
// Update the case clause for TRACKING to call PhysicsController
// whenever the app recognizes an image
private void drawAugmentedImages(
...
case TRACKING:
// Switch to UI Thread to update View
this.runOnUiThread(
new Runnable() {
@Override
public void run() {
fitToScanView.setVisibility(View.GONE);
}
});
// Create a new anchor for newly found images
if (!augmentedImageMap.containsKey(augmentedImage.getIndex())) {
Anchor centerPoseAnchor = augmentedImage.createAnchor(augmentedImage.getCenterPose());
augmentedImageMap.put(
augmentedImage.getIndex(), Pair.create(augmentedImage, centerPoseAnchor));
physicsController = new PhysicsController(this);
} else {
Pose ballPose = physicsController.getBallPose();
augmentedImageRenderer.updateAndyPose(ballPose);
// Use real world gravity, (0, -10, 0), as gravity
// Convert to Physics world coordinate(maze mesh has to be static)
// Use the converted coordinate as a force to move the ball
Pose worldGravityPose = Pose.makeTranslation(0, -10f, 0);
Pose mazeGravityPose = augmentedImage.getCenterPose().inverse().compose(worldGravityPose);
float mazeGravity[] = mazeGravityPose.getTranslation();
physicsController.applyGravityToBall(mazeGravity);
physicsController.updatePhysics();
}
break;
執行應用程式。現在,您傾斜圖片時,應該就能如實地移動圖片。
下方範例使用了另一支手機來顯示圖片,也可以使用任何對您來說方便的東西,例如平板電腦、印刷本書籍的封面,或只附在平面上列印的紙張。
大功告成!祝你玩得開心,小安度過迷宮。提示:將目標圖片上下顛倒時,更容易找出離開事件。
6. 恭喜
恭喜,您已經完成本程式碼研究室,因此獲得以下成果:
- 建構並執行 ARCore AugmentedImage Java 範例。
- 更新範例,以適當比例在圖片上顯示迷宮模型。
- 運用圖片姿勢做一些有趣的事。
如要參考完整程式碼,請在這裡下載。