1. ภาพรวม
ARCore เป็นแพลตฟอร์มสำหรับสร้างแอป Augmented Reality บน Android รูปภาพเสริมช่วยให้คุณสร้างแอป AR ที่จดจำรูปภาพ 2 มิติที่ลงทะเบียนไว้ล่วงหน้าในโลกแห่งความจริงและยึดเนื้อหาเสมือนไว้ด้านบนได้
Codelab นี้จะแนะนําให้คุณแก้ไขแอปตัวอย่าง ARCore ที่มีอยู่เพื่อรวมรูปภาพเสริมที่เคลื่อนไหวหรือคงที่
สิ่งที่คุณจะสร้าง
ใน Codelab นี้ คุณจะได้สร้างแอปตัวอย่าง ARCore ที่มีอยู่แล้ว เมื่อสิ้นสุด Codelab แอปของคุณจะทำสิ่งต่อไปนี้ได้
- ตรวจจับเป้าหมายรูปภาพและติดเขาวงกตเสมือนบนเป้าหมาย
- ติดตามเป้าหมายที่เคลื่อนไหวตราบใดที่เป้าหมายนั้นอยู่ในมุมมองของกล้อง

นี่เป็นครั้งแรกที่คุณสร้างแอป ARCore ใช่ไหม
คุณวางแผนที่จะเขียนโค้ดตัวอย่างใน Codelab นี้หรือเพียงต้องการอ่านหน้าเหล่านี้
สิ่งที่คุณจะได้เรียนรู้
- วิธีใช้รูปภาพเสริมใน ARCore ใน Java
- วิธีวัดความสามารถของรูปภาพที่ ARCore จะจดจำได้
- วิธีแนบเนื้อหาเสมือนจริงในรูปภาพและติดตามการเคลื่อนไหวของเนื้อหา
ข้อกำหนดเบื้องต้น
คุณต้องมีฮาร์ดแวร์และซอฟต์แวร์ที่เฉพาะเจาะจงเพื่อทำ Codelab นี้ให้เสร็จสมบูรณ์
ข้อกำหนดเกี่ยวกับฮาร์ดแวร์
- อุปกรณ์ที่รองรับ ARCore ซึ่งเชื่อมต่อผ่านสาย USB กับคอมพิวเตอร์สำหรับการพัฒนาซอฟต์แวร์
ข้อกำหนดของซอฟต์แวร์
- ARCore APK 1.9.0 ขึ้นไป โดยปกติแล้ว ระบบจะติดตั้ง APK นี้ในอุปกรณ์โดยอัตโนมัติผ่าน Play Store
- เครื่องพัฒนาที่มี Android Studio (v3.1 ขึ้นไป)
- สิทธิ์เข้าถึงอินเทอร์เน็ต เนื่องจากคุณจะต้องดาวน์โหลดไลบรารีระหว่างการพัฒนา
เมื่อเตรียมทุกอย่างพร้อมแล้ว ก็มาเริ่มกันเลย
2. ตั้งค่าสภาพแวดล้อมในการพัฒนา
ดาวน์โหลด SDK
เราจะเริ่มต้นด้วยการดาวน์โหลด ARCore Android SDK เวอร์ชันล่าสุดจาก GitHub คลายซิปไปยังตำแหน่งที่ต้องการ สำหรับ Codelab นี้ SDK เวอร์ชันที่เก่าที่สุดคือ 1.18.1 ระบบจะอ้างอิงโฟลเดอร์เป็น arcore-android-sdk-x.xx.x โดยค่าที่แน่นอนจะเป็นเวอร์ชันของ SDK ที่คุณใช้
เปิด Android Studio แล้วคลิกเปิดโปรเจ็กต์ Android Studio ที่มีอยู่

ไปที่โฟลเดอร์ที่แตกไฟล์แล้วนี้
arcore-android-sdk-x.xx.x/samples/augmented_image_java
คลิกเปิด
รอให้ Android Studio ซิงค์โปรเจ็กต์เสร็จ หาก Android Studio ไม่มีคอมโพเนนต์ที่จำเป็น อาจเกิดข้อผิดพลาดพร้อมข้อความ Install missing platform and sync project ทำตามวิธีการเพื่อแก้ไขปัญหา
เรียกใช้แอปตัวอย่าง
ตอนนี้คุณมีโปรเจ็กต์แอป ARCore ที่ใช้งานได้แล้ว มาลองทดสอบกัน
เชื่อมต่ออุปกรณ์ ARCore กับคอมพิวเตอร์สำหรับการพัฒนาซอฟต์แวร์ แล้วใช้เมนูเรียกใช้ > เรียกใช้ "แอป" เพื่อเรียกใช้เวอร์ชันแก้ไขข้อบกพร่องในอุปกรณ์ ในกล่องโต้ตอบที่แจ้งให้คุณเลือกอุปกรณ์ที่จะใช้ ให้เลือกอุปกรณ์ที่เชื่อมต่อแล้วคลิกตกลง


โปรเจ็กต์ตัวอย่างนี้ใช้ targetSdkVersion 28 หากคุณมีข้อผิดพลาดในการสร้าง เช่น Failed to find Build Tools revision 28.0.3 ให้ทำตามวิธีการที่อธิบายไว้ใน Android Studio เพื่อดาวน์โหลดและติดตั้งเครื่องมือสร้าง Android เวอร์ชันที่จำเป็น
หากทุกอย่างเป็นไปด้วยดี แอปตัวอย่างจะเปิดขึ้นในอุปกรณ์และแจ้งให้คุณขอสิทธิ์เพื่ออนุญาตให้รูปภาพเสริมถ่ายภาพและวิดีโอ แตะอนุญาตเพื่อให้สิทธิ์
ทดสอบด้วยรูปภาพตัวอย่าง
เมื่อตั้งค่าสภาพแวดล้อมการพัฒนาแล้ว คุณจะทดสอบแอปได้โดยให้แอปดูรูปภาพ
กลับไปที่ Android Studio ในหน้าต่างโปรเจ็กต์ ให้ไปที่ app > assets แล้วดับเบิลคลิกไฟล์ default.jpg เพื่อเปิด

เล็งกล้องของอุปกรณ์ไปที่รูปภาพโลกบนหน้าจอ แล้วทำตามวิธีการเพื่อให้รูปภาพที่คุณกำลังสแกนพอดีกับกากบาท
กรอบรูปภาพจะซ้อนทับอยู่ด้านบนของรูปภาพ ดังนี้

จากนั้นเราจะปรับปรุงแอปตัวอย่างเล็กน้อย
3. แสดงโมเดลเขาวงกตบนรูปภาพ 2 มิติ
คุณเริ่มเล่นกับรูปภาพเสริมได้โดยการแสดงโมเดล 3 มิติบนรูปภาพ
ดาวน์โหลดโมเดล 3 มิติ
สำหรับโค้ดแล็บนี้ เราจะใช้ "Circle Maze - Green" โดย Evol ซึ่งได้รับอนุญาตภายใต้ CC-BY 3.0 ฉันเก็บสำเนาโมเดล 3 มิตินี้ไว้ในที่เก็บ GitHub ของ Codelab นี้ ซึ่งคุณดูได้ที่นี่
ทำตามขั้นตอนต่อไปนี้เพื่อดาวน์โหลดโมเดลและรวมไว้ใน Android Studio
- ไปที่ที่เก็บ GitHub ของ Codelab นี้ ซึ่งก็คือไดเรกทอรี third_party
- คลิก GreenMaze_obj.zip แล้วคลิกปุ่มดาวน์โหลด
ซึ่งจะดาวน์โหลดไฟล์ชื่อ GreenMaze_obj.zip
- ใน Android Studio ให้สร้างไดเรกทอรี
green-mazeภายใต้ app > assets > models - คลายซิป
GreenMaze_obj.zipและคัดลอกเนื้อหาไปยังตำแหน่งนี้arcore-android-sdk-x.xx.x/samples/augmented_image_java/app/src/main/assets/models/green-maze - ใน Android Studio ให้ไปที่ app > assets > models > green-maze
โฟลเดอร์นี้ควรมีไฟล์ 2 ไฟล์ ได้แก่ GreenMaze.obj และ GreenMaze.mtl

แสดงผลโมเดลเขาวงกต
ทำตามขั้นตอนต่อไปนี้เพื่อแสดงGreenMaze.objโมเดล 3 มิติบนรูปภาพ 2 มิติที่มีอยู่
ใน 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โลก
หมายเหตุ: เนื่องจากคุณไม่มีสิทธิ์ควบคุมโมเดล 3 มิติตัวอย่างนี้อย่างเต็มที่ โค้ดด้านบนจึงใช้ตัวเลข "มหัศจรรย์" บางตัว ขนาดของโมเดลเขาวงกตคือ 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 เนื่องจากโมเดล 3 มิติของเขาวงกตไม่ได้อยู่ตรงกลางที่จุดเริ่มต้น (0, 0, 0)
กำแพงเขาวงกตยังสูงเกินไปที่จะวางไว้ด้านบนของรูปภาพ สร้างฟังก์ชันตัวช่วย updateModelMatrix() ที่ปรับขนาด X, Y, Z ไม่เท่ากันเพื่อปรับความสูงของเขาวงกตขึ้น 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.obj ที่รวมอยู่ใน ARCore Android SDK คงพื้นผิวของกรอบรูปภาพไว้ตามเดิม เนื่องจากพื้นผิวของกรอบรูปภาพจะแตกต่างจากเขาวงกตสีเขียวที่แสดงบนรูปภาพ
ใน AugmentedImageRenderer.java ให้เพิ่มObjectRendererส่วนตัวเพื่อแสดงผล Andy
AugmentedImageRenderer.java
// Render for Andy
private final ObjectRenderer andyRenderer = new ObjectRenderer();
จากนั้นเริ่มต้น andyRenderer ที่ส่วนท้ายของ createOnGlThread()
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() ฟังก์ชัน
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 คือการจดจำที่ง่ายที่สุด
ตัวอย่างเช่น
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 จาก app > assets > models > green-maze ไปยัง app > assets
เพิ่มทรัพยากร Dependency ต่อไปนี้ลงในไฟล์ build.gradle ของแอป
app/build.gradle
// jbullet library
implementation 'cz.advel.jbullet:jbullet:20101010-1'
กำหนดตัวแปร andyPose เพื่อจัดเก็บตำแหน่งของท่าทางปัจจุบันของแอนดี้
AugmentedImageRenderer.java
// Create a new pose for the Andy
private Pose andyPose = Pose.IDENTITY;
แก้ไข AugmentedImageRenderer.java เพื่อแสดงผล Andy โดยใช้ตัวแปร andyPose ใหม่
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() เพื่อรับข้อมูลอัปเดตท่าทางของแอนดี้
AugmentedImageRenderer.java
// Receive Andy pose updates
public void updateAndyPose(Pose pose) {
andyPose = pose;
}
ใน AugmentedImageActivity.java ให้สร้างออบเจ็กต์ PhysicsController ที่ใช้เอนจินฟิสิกส์ JBullet เพื่อจัดการฟังก์ชันทั้งหมดที่เกี่ยวข้องกับฟิสิกส์
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;
เรียกใช้แอป ตอนนี้ Andy ควรเคลื่อนไหวอย่างสมจริงเมื่อคุณเอียงรูปภาพ
ตัวอย่างด้านล่างใช้โทรศัพท์อีกเครื่องเพื่อแสดงรูปภาพ คุณสามารถใช้อุปกรณ์ใดก็ได้ที่สะดวก เช่น แท็บเล็ต ปกหนังสือฉบับพิมพ์ หรือกระดาษที่พิมพ์ออกมาแล้วติดไว้บนวัตถุแบน

เท่านี้ก็เรียบร้อย สนุกกับการพยายามพาแอนดี้ผ่านเขาวงกต เคล็ดลับ: การถือภาพเป้าหมายกลับหัวจะช่วยให้คุณหาทางออกได้ง่ายขึ้น
6. ขอแสดงความยินดี
ขอแสดงความยินดี คุณได้ทำ Codelab นี้จนจบแล้ว และได้ทำสิ่งต่อไปนี้
- สร้างและเรียกใช้ตัวอย่าง AugmentedImage Java ของ ARCore
- อัปเดตตัวอย่างเพื่อแสดงโมเดลเขาวงกตในรูปภาพที่สเกลที่เหมาะสม
- ใช้ท่าทางของรูปภาพเพื่อทำอะไรสนุกๆ
หากต้องการดูรหัสที่สมบูรณ์ คุณสามารถดาวน์โหลดได้ที่นี่