รูปภาพเสริมด้วย ARCore

1. ภาพรวม

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

Codelab นี้จะแนะนำคุณตลอดการแก้ไขแอปตัวอย่าง ARCore ที่มีอยู่เพื่อรวม Augmented Images ที่เคลื่อนไหวหรืออยู่กับที่

สิ่งที่คุณจะสร้าง

ใน Codelab นี้ คุณจะสร้างขึ้นจากแอปตัวอย่าง ARCore ที่มีอยู่ก่อนแล้ว เมื่อสิ้นสุด Codelab แล้ว แอปจะทำสิ่งต่อไปนี้ได้

  • ตรวจหาเป้าหมายรูปภาพและแนบเขาวงกตเสมือนบนเป้าหมาย
  • ติดตามเป้าหมายเคลื่อนที่ตราบใดที่ยังอยู่ในมุมมองกล้อง

6bc6605df89de525.gif

นี่เป็นการสร้างแอป ARCore เป็นครั้งแรกใช่ไหม

ใช่ ไม่

คุณวางแผนจะเขียนโค้ดตัวอย่างใน Codelab นี้หรือแค่อยากอ่านหน้าเหล่านี้

เขียนโค้ดตัวอย่าง เพียงอ่านหน้าเว็บเหล่านี้

สิ่งที่คุณจะได้เรียนรู้

  • วิธีใช้ Augmented Images ใน ARCore ใน Java
  • วิธีวัดความสามารถของรูปภาพที่ ARCore จะจดจำได้
  • วิธีแนบเนื้อหาเสมือนจริงในรูปภาพและติดตามการเคลื่อนไหว

ข้อกำหนดเบื้องต้น

คุณจะต้องใช้ฮาร์ดแวร์และซอฟต์แวร์เฉพาะเพื่อทำงาน Codelab นี้ให้เสร็จสมบูรณ์

ข้อกำหนดเกี่ยวกับฮาร์ดแวร์

ข้อกำหนดของซอฟต์แวร์

  • ARCore APK 1.9.0 ขึ้นไป โดยปกติแล้ว APK นี้จะได้รับการติดตั้งโดยอัตโนมัติบนอุปกรณ์ผ่าน Play Store
  • เครื่องสำหรับการพัฒนาที่มี Android Studio (เวอร์ชัน 3.1 ขึ้นไป)
  • การเข้าถึงอินเทอร์เน็ต เนื่องจากคุณจะต้องดาวน์โหลดไลบรารีระหว่างการพัฒนา

ในตอนนี้คุณมีทุกอย่างพร้อมแล้ว มาเริ่มกันเลย

2. ตั้งค่าสภาพแวดล้อมในการพัฒนาซอฟต์แวร์

ดาวน์โหลด SDK

เราจะเริ่มด้วยการดาวน์โหลด ARCore Android SDK เวอร์ชันล่าสุดจาก GitHub แตกไฟล์ซิปไปยังตำแหน่งที่คุณต้องการ SDK เวอร์ชันแรกสุดคือ 1.18.1 สำหรับ Codelab นี้ เราจะเรียกโฟลเดอร์นี้ว่า arcore-android-sdk-x.xx.x ค่าที่แน่นอนจะเป็นเวอร์ชันของ SDK ที่คุณใช้

เปิด Android Studio แล้วคลิกเปิดโปรเจ็กต์ Android Studio ที่มีอยู่

5fbf2b21609187cc.png

ไปยังโฟลเดอร์ที่แตกไฟล์แล้วนี้

arcore-android-sdk-x.xx.x/samples/augmented_image_java

คลิกเปิด

โปรดรอให้ Android Studio ซิงค์โปรเจ็กต์ให้เสร็จ หาก Android Studio ของคุณไม่มีคอมโพเนนต์ที่จำเป็น อาจดำเนินการไม่สำเร็จเมื่อมีข้อความว่า Install missing platform and sync project ทำตามวิธีการเพื่อแก้ไขปัญหา

เรียกใช้แอปตัวอย่าง

ตอนนี้คุณมีโปรเจ็กต์แอป ARCore ที่ใช้งานได้ มาลองทดสอบกัน

เชื่อมต่ออุปกรณ์ ARCore กับเครื่องพัฒนาแล้วใช้เมนู Run > เรียกใช้ "แอป" เพื่อเรียกใช้เวอร์ชันแก้ไขข้อบกพร่องในอุปกรณ์ ในกล่องโต้ตอบที่แจ้งให้เลือกอุปกรณ์ที่จะเรียกใช้ ให้เลือกอุปกรณ์ที่เชื่อมต่อแล้วคลิกตกลง

1aa2c6faa7ecdbd0.png

92e4c144a632b4ca.png

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

หากทุกอย่างสำเร็จ แอปตัวอย่างจะเปิดขึ้นในอุปกรณ์และให้คุณขออนุญาตอนุญาตให้ Augmented Image ถ่ายภาพและวิดีโอ แตะอนุญาตเพื่อให้สิทธิ์

ทดสอบกับรูปภาพตัวอย่าง

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

กลับไปที่ Android Studio ในหน้าต่างโปรเจ็กต์ จากนั้นไปที่แอป > เนื้อหา แล้วดับเบิลคลิกไฟล์ default.jpg เพื่อเปิด

9b333680e7b9f247.jpeg

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

กรอบรูปภาพจะวางซ้อนอยู่ด้านบนรูปภาพดังนี้

999e05ed35964f6e.png

ต่อไป เราจะทำการปรับปรุงเล็กๆ น้อยๆ กับแอปตัวอย่าง

3. แสดงโมเดลเขาวงกตในรูปภาพ 2 มิติ

คุณสามารถเริ่มใช้งาน Augmented Images ด้วยการแสดงโมเดล 3 มิติอยู่ด้านบน

ดาวน์โหลดโมเดล 3 มิติ

สำหรับ Codelab นี้ เราจะใช้ "Circle Maze - Green" โดย Evol และได้รับอนุญาตภายใต้ CC-BY 3.0 เราเก็บสำเนาของโมเดล 3 มิตินี้ในที่เก็บ Git สำหรับ Codelab แล้ว ซึ่งดูได้ที่นี่

ทำตามขั้นตอนต่อไปนี้เพื่อดาวน์โหลดโมเดลและรวมไว้ใน Android Studio

  1. ไปที่ที่เก็บ GitHub ของ Codelab นี้หรือไดเรกทอรีของบุคคลที่สาม
  2. คลิก GreenMaze_obj.zip แล้วคลิกปุ่มดาวน์โหลด

การดำเนินการนี้จะดาวน์โหลดไฟล์ชื่อ GreenMaze_obj.zip

  1. ใน Android Studio ให้สร้างไดเรกทอรี green-maze ในส่วนแอป > เนื้อหา > รุ่น
  2. แตกไฟล์ ZIP GreenMaze_obj.zip และคัดลอกเนื้อหาไปยังตำแหน่งนี้: arcore-android-sdk-x.xx.x/samples/augmented_image_java/app/src/main/assets/models/green-maze
  3. ใน Android Studio ให้ไปที่แอป > เนื้อหา > รุ่น > เขาวงกตสีเขียว

โฟลเดอร์นี้ควรมี 2 ไฟล์: GreenMaze.obj และ GreenMaze.mtl

a1f33a2d2d407e03.png

แสดงภาพโมเดลเขาวงกต

ทำตามขั้นตอนต่อไปนี้เพื่อแสดงโมเดล 3 มิติ GreenMaze.obj บนรูปภาพ 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);
}

เรียกใช้โค้ด ตอนนี้เขาวงกตควรจะพอดีกับด้านบนรูปภาพพอดี

772cbe2a8baef3ba.png

4. เพิ่ม Andy เข้าไปในเขาวงกต

เมื่อคุณมีเขาวงกตแล้ว ให้เพิ่มตัวละครเพื่อย้ายไปด้านใน ใช้ไฟล์ 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);

  }

เรียกใช้โค้ดของคุณ คุณจะเห็นแอนดี้ยืนอยู่บนเขาวงกต

cb1e74569d7ace69.png

ระบุคุณภาพของรูปภาพเป้าหมาย

ARCore ใช้ฟีเจอร์ด้านภาพเพื่อจดจำรูปภาพ เนื่องจากคุณภาพที่แตกต่างกัน รูปภาพบางรูปอาจจดจำได้ยาก

arcoreimg เป็นเครื่องมือบรรทัดคำสั่งที่ช่วยให้คุณกำหนดได้ว่ารูปภาพจะเป็นที่รู้จักมากน้อยเพียงใดใน ARCore ซึ่งจะแสดงตัวเลขระหว่าง 0 ถึง 100 โดย 100 คือตัวเลขที่จำได้ง่ายที่สุด

ที่ใช้เวลาเพียง 2 นาที มีตัวอย่างดังต่อไปนี้

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. ไม่บังคับ: ให้แอนดี้เคลื่อนที่ไปในเขาวงกต

ขั้นตอนสุดท้าย คุณสามารถเพิ่มโค้ดบางอย่างเพื่อทำให้ Andy เคลื่อนที่ไปในเขาวงกตได้ เช่น ใช้เครื่องมือฟิสิกส์แบบโอเพนซอร์ส 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 จากแอป > เนื้อหา > รุ่น > green-maze ไปยัง แอป > เนื้อหา

เพิ่มทรัพยากร 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 เพื่อแสดงผลแอนดี้โดยใช้ตัวแปร 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() เพื่อรับการอัปเดตท่าทางของ Andy

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;

เรียกใช้แอป ตอนนี้แอนดี้ควรเคลื่อนไปรอบๆ ได้อย่างสมจริงเมื่อคุณเอียงภาพ

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

2f0df284705d3704.gif

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

6. ขอแสดงความยินดี

ขอแสดงความยินดี คุณมาถึงส่วนสุดท้ายของ Codelab แล้ว และนี่คือ:

  • สร้างและเรียกใช้ตัวอย่าง ARCore AugmentedImage Java
  • อัปเดตตัวอย่างเพื่อแสดงโมเดลเขาวงกตในขนาดที่เหมาะสม
  • ใช้ท่าถ่ายรูปเพื่อทำกิจกรรมสนุกๆ

ดูโค้ดทั้งหมดได้โดยดาวน์โหลดที่นี่

สนุกกับการทำ Codelab นี้ไหม

ใช่ ไม่

ได้เรียนรู้สิ่งที่เป็นประโยชน์ในการทำ Codelab นี้ไหม

ใช่ ไม่

คุณสร้างแอปใน Codelab นี้เสร็จแล้วหรือยัง

ใช่ ไม่

คุณวางแผนที่จะสร้างแอป ARCore ในอีก 6 เดือนข้างหน้าไหม

ใช่ อาจจะ ไม่