1. Tổng quan
ARCore là nền tảng tạo các ứng dụng thực tế tăng cường trên Android. Hình ảnh tăng cường cho phép bạn tạo những ứng dụng thực tế tăng cường (AR) có khả năng nhận dạng hình ảnh 2D đã đăng ký trước trong thế giới thực và cố định nội dung ảo trên đó.
Lớp học lập trình này hướng dẫn bạn chỉnh sửa ứng dụng mẫu ARCore hiện có để tích hợp Hình ảnh tăng cường đang di chuyển hoặc cố định tại chỗ.
Sản phẩm bạn sẽ tạo ra
Trong lớp học lập trình này, bạn sẽ xây dựng dựa trên một ứng dụng mẫu ARCore có sẵn. Khi kết thúc lớp học lập trình, ứng dụng của bạn sẽ có thể:
- Phát hiện mục tiêu hình ảnh và đính kèm một mê cung ảo vào mục tiêu
- Theo dõi mục tiêu di chuyển miễn là mục tiêu đó nằm trong góc nhìn của camera
Đây có phải là lần đầu tiên bạn tạo ứng dụng ARCore?
Bạn dự định viết mã mẫu trong lớp học lập trình này hay chỉ muốn đọc các trang này?
Kiến thức bạn sẽ học được
- Cách sử dụng Hình ảnh tăng cường trong ARCore trong Java
- Cách đánh giá khả năng ARCore nhận dạng hình ảnh
- Cách đính kèm nội dung ảo vào hình ảnh và theo dõi chuyển động của hình ảnh đó
Điều kiện tiên quyết
Bạn cần có phần cứng và phần mềm cụ thể để hoàn tất lớp học lập trình này.
Yêu cầu về phần cứng
- Một thiết bị hỗ trợ ARCore được kết nối với máy phát triển qua cáp USB
Yêu cầu về phần mềm
- ARCore APK 1.9.0 trở lên. Tệp APK này thường được tự động cài đặt trên thiết bị thông qua Cửa hàng Play
- Máy phát triển có Android Studio (phiên bản 3.1 trở lên)
- Quyền truy cập Internet, vì bạn sẽ cần phải tải thư viện xuống trong quá trình phát triển
Giờ thì mọi thứ đã sẵn sàng. Hãy bắt đầu nào!
2. Thiết lập môi trường phát triển
Tải SDK xuống
Chúng ta sẽ bắt đầu bằng cách tải SDK ARCore Android mới nhất xuống từ GitHub. Giải nén tệp này đến vị trí bạn muốn. Đối với lớp học lập trình này, phiên bản SDK cũ nhất là 1.18.1. Thư mục này sẽ được gọi là arcore-android-sdk-x.xx.x
, giá trị chính xác sẽ là phiên bản SDK mà bạn sử dụng.
Chạy Android Studio rồi nhấp vào Open an existing Android Studio project (Mở một dự án hiện có trong Android Studio).
Chuyển đến thư mục đã giải nén này:
arcore-android-sdk-x.xx.x/samples/augmented_image_java
Nhấp vào Mở.
Chờ Android Studio hoàn tất quá trình đồng bộ hoá dự án. Nếu Android Studio không có các thành phần bắt buộc, thì có thể Android Studio sẽ không hiện thông báo Install missing platform and sync project
. Làm theo hướng dẫn để khắc phục sự cố.
Chạy ứng dụng mẫu
Bây giờ, bạn đã có một dự án ứng dụng ARCore đang hoạt động, hãy chạy thử dự án đó.
Kết nối thiết bị ARCore với máy phát triển và sử dụng trình đơn Run > (Chạy >) Chạy "app" (ứng dụng) để chạy phiên bản gỡ lỗi trên thiết bị. Trong hộp thoại nhắc bạn chọn thiết bị sẽ chạy, hãy chọn thiết bị được kết nối rồi nhấp vào OK.
Dự án mẫu này sử dụng targetSdkVersion 28
. Nếu bạn gặp lỗi bản dựng như Failed to find Build Tools revision 28.0.3
, hãy làm theo hướng dẫn được mô tả trong Android Studio để tải xuống và cài đặt phiên bản được yêu cầu của Công cụ xây dựng Android.
Nếu mọi thứ đều thành công, ứng dụng mẫu sẽ khởi chạy trên thiết bị và nhắc bạn cấp quyền cho phép Hình ảnh tăng cường chụp ảnh và quay video. Nhấn vào CHO PHÉP để cấp quyền.
Kiểm thử bằng hình ảnh mẫu
Giờ đây, khi đã thiết lập môi trường phát triển, bạn có thể kiểm thử ứng dụng bằng cách cung cấp hình ảnh để xem.
Quay lại Android Studio, trong cửa sổ Project (Dự án), chuyển đến app > nội dung rồi nhấp đúp vào tệp default.jpg
để mở tệp đó.
Hướng máy ảnh của thiết bị vào hình ảnh của Earth trên màn hình và làm theo hướng dẫn sao cho hình ảnh mà bạn đang quét khớp với hình chữ thập.
Một khung hình ảnh sẽ phủ lên trên hình ảnh, như sau:
Tiếp theo, chúng ta sẽ thực hiện những cải tiến nhỏ đối với ứng dụng mẫu.
3. Hiển thị mô hình mê cung trên Hình ảnh 2D
Bạn có thể bắt đầu phát bằng Hình ảnh tăng cường bằng cách cho thấy một mô hình 3D lên trên hình ảnh đó.
Tải mô hình 3D xuống
Đối với lớp học lập trình này, chúng ta sẽ sử dụng "Mê cung hình tròn – Xanh lục" bởi Evol và được cấp phép theo CC-BY 3.0. Tôi đã lưu trữ một bản sao của mô hình 3D này trong kho lưu trữ github của lớp học lập trình này. Bạn có thể tìm thấy bản sao đó tại đây.
Hãy làm theo các bước sau để tải mô hình xuống và thêm vào Android Studio.
- Chuyển đến kho lưu trữ GitHub của lớp học lập trình này, thư mục bên thứ ba.
- Nhấp vào GreenMaze_obj.zip rồi nhấp vào nút Download (Tải xuống).
Thao tác này sẽ tải một tệp có tên là GreenMaze_obj.zip
xuống.
- Trong Android Studio, hãy tạo thư mục
green-maze
trong app > thành phần > người mẫu - Giải nén
GreenMaze_obj.zip
rồi sao chép nội dung vào vị trí sau:arcore-android-sdk-x.xx.x/samples/augmented_image_java/app/src/main/assets/models/green-maze
- Trong Android Studio, hãy chuyển đến app > (ứng dụng) > thành phần > mô hình > mê cung xanh.
Phải có hai tệp trong thư mục này: GreenMaze.obj
và GreenMaze.mtl
.
Kết xuất mô hình mê cung
Làm theo các bước sau để hiển thị mô hình 3D GreenMaze.obj
ở đầu hình ảnh 2D hiện có.
Trong AugmentedImageRenderer.java
, hãy thêm một biến thành phần có tên là mazeRenderer
để kết xuất mô hình mê cung. Vì mê cung phải đính kèm vào hình ảnh, nên bạn nên đặt mazeRenderer
bên trong lớp AugmentedImageRenderer
.
AugmentedImageRenderer.java
// Add a member variable to hold the maze model.
private final ObjectRenderer mazeRenderer = new ObjectRenderer();
Trong hàm createOnGlThread()
, hãy tải GreenMaze.obj
. Để đơn giản, hãy sử dụng hoạ tiết khung giống như hoạ tiết của khung.
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);
}
Thay thế định nghĩa của hàm draw()
bằng nội dung sau. Thao tác này sẽ điều chỉnh kích thước của mê cung theo kích thước của hình ảnh phát hiện được và hiển thị hình ảnh trên màn hình.
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);
}
Bây giờ, mê cung sẽ hiển thị ở trên ảnh default.jpg
của Trái đất.
Lưu ý: Vì bạn không có toàn quyền kiểm soát đối với mô hình 3D mẫu này, mã ở trên sử dụng một vài "phép màu" số. Kích thước của mô hình mê cung là 492,65 x 120 x 492,65, với tâm là (251,3, 60, -129,0). Dải ô các đỉnh của nó Các giá trị toạ độ X, Y và Z lần lượt là [5,02, 497,67], [0, 120] và [-375,17, 117,25]. Do đó, tỷ lệ của mô hình mê cung cần phải là image_size / 492.65
. mazeModelLocalOffset
được giới thiệu vì mô hình 3D của mê cung không tập trung vào nguồn gốc (0, 0, 0).
Bức tường của mê cung vẫn quá cao nên không vừa với ảnh trên cùng. Tạo một hàm trợ giúp updateModelMatrix()
có thể điều chỉnh tỷ lệ X, Y, Z không đồng đều để tăng chiều cao của Mê cung thêm 0,1. Lưu ý: bạn sẽ giữ updateModelMatrix(float[] modelMatrix, float scaleFactor)
hiện có và thêm phương thức nạp chồng hàm updateModelMatrix(float[] modelMatrix, float scaleFactorX, float scaleFactorY, float scaleFactorZ)
làm hàm mới.
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);
}
Chạy mã. Lúc này, mê cung sẽ vừa khít phía trên hình ảnh.
4. Thêm An vào mê cung
Giờ bạn đã có một mê cung, hãy thêm một nhân vật để di chuyển xung quanh bên trong mê cung đó. Dùng tệp andy.obj
có trong SDK Android ARCore. Giữ hoạ tiết của khung hình ảnh làm hoạ tiết, vì nó trông khác với mê cung màu xanh lục được kết xuất ở trên cùng hình ảnh.
Trong AugmentedImageRenderer.java
, hãy thêm một ObjectRenderer
riêng tư để kết xuất An.
AugmentedImageRenderer.java
// Render for Andy
private final ObjectRenderer andyRenderer = new ObjectRenderer();
Tiếp theo, hãy khởi chạy andyRenderer
ở cuối 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);
}
Cuối cùng, hãy kết xuất Andrew đứng trên mê cung ở cuối hàm 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);
}
Chạy mã. Bạn sẽ thấy An đang đứng trên mê cung.
Xác định chất lượng ảnh mục tiêu
ARCore dựa vào các tính năng trực quan để nhận dạng hình ảnh. Do sự khác biệt về chất lượng, nên không phải hình ảnh nào cũng có thể dễ dàng nhận ra.
arcoreimg
là một công cụ dòng lệnh cho phép bạn xác định mức độ nhận dạng của hình ảnh đối với ARCore. Kết quả này cho ra một số từ 0 đến 100, trong đó 100 là số dễ nhận ra nhất.
của Google. Sau đây là một ví dụ:
arcore-android-sdk-x.xx.x/tools/arcoreimg/macos$
$ ./arcoreimg eval-img --input_image_path=/Users/username/maze.jpg
100
maze.jpg
có giá trị là 100 nên ARCore có thể dễ dàng nhận ra.
5. Không bắt buộc: Khiến An di chuyển trong mê cung
Cuối cùng, bạn có thể thêm mã để di chuyển trong mê cung. Ví dụ: sử dụng công cụ Physics nguồn mở jBullet để xử lý hoạt động mô phỏng thực tế. Bạn hoàn toàn có thể bỏ qua phần này.
Tải PhysicsController.java
xuống rồi thêm vào dự án của bạn trong thư mục
arcore-android-sdk-x.xx.x/samples/augmented_image_java/app/src/main/java/com/google/ar/core/examples/java/augmentedimage/
Trong Android Studio, hãy Thêm GreenMaze.obj vào thư mục project assets để có thể tải tệp này trong thời gian chạy. Sao chép GreenMaze.obj
từ ứng dụng > thành phần > mô hình > Green-maze thành app > tài sản.
Thêm các phần phụ thuộc sau đây vào tệp build.gradle
của ứng dụng.
app/build.gradle
// jbullet library
implementation 'cz.advel.jbullet:jbullet:20101010-1'
Xác định biến andyPose
để lưu trữ vị trí tư thế hiện tại của An.
AugmentedImageRenderer.java
// Create a new pose for the Andy
private Pose andyPose = Pose.IDENTITY;
Sửa đổi AugmentedImageRenderer.java
để kết xuất An bằng cách sử dụng biến andyPose
mới.
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);
}
Thêm một hàm số hiệu dụng mới là updateAndyPose()
để nhận thông tin cập nhật về tư thế của An.
AugmentedImageRenderer.java
// Receive Andy pose updates
public void updateAndyPose(Pose pose) {
andyPose = pose;
}
Trong AugmentedImageActivity.java
, hãy tạo một đối tượng PhysicsController
sử dụng công cụ vật lý JBullet để quản lý tất cả hàm liên quan đến vật lý.
AugmentedImageActivity.java
import com.google.ar.core.Pose;
// Declare the PhysicsController object
private PhysicsController physicsController;
Trong công cụ Vật lý, chúng ta sử dụng một quả bóng cứng để thể hiện An và cập nhật tư thế của An bằng tư thế quả bóng. Gọi PhysicsController
để cập nhật vật lý bất cứ khi nào ứng dụng nhận ra một hình ảnh. Để di chuyển quả bóng như thể trong thế giới thực, hãy áp dụng trọng lực trong thế giới thực để di chuyển quả bóng trong mê cung.
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;
Chạy ứng dụng. Bây giờ, An sẽ di chuyển xung quanh khi bạn nghiêng hình ảnh một cách thực tế.
Ví dụ dưới đây dùng một chiếc điện thoại khác để hiển thị hình ảnh, bạn có thể dùng bất kỳ thứ gì thuận tiện cho mình, chẳng hạn như máy tính bảng, bìa của một cuốn sách cứng hoặc chỉ một tờ giấy in gắn trên một vật phẳng.
Vậy là xong! Chúc bạn vui vẻ khi cố gắng đưa An qua mê cung. Gợi ý: Bạn sẽ dễ tìm thấy lối ra này hơn khi lật ngược hình ảnh mục tiêu.
6. Xin chúc mừng
Xin chúc mừng! Bạn đã kết thúc lớp học lập trình này và:
- Xây dựng và chạy mẫu AAcceleratedImage Java của ARCore.
- Đã cập nhật mẫu để hiển thị mô hình mê cung trên hình ảnh theo tỷ lệ thích hợp.
- Sử dụng tư thế của hình ảnh để làm điều gì đó vui nhộn.
Nếu muốn tham khảo mã hoàn chỉnh, bạn có thể tải xuống tại đây.