1. סקירה כללית
ARCore היא פלטפורמה לפיתוח אפליקציות של מציאות רבודה ב-Android. התכונה תמונות רבודה מאפשרת ליצור אפליקציות AR שיכולות לזהות תמונות דו-ממדיות שנרשמו מראש בעולם האמיתי ולעגן תוכן וירטואלי מעלן.
בשיעור הזה תלמדו איך לשנות אפליקציה לדוגמה של ARCore כדי לשלב תמונות מרובות שזזות או מתקנות במקומן.
מה תפַתחו
ב-Codelab הזה, תסתמך על אפליקציה קיימת לדוגמה של ARCore. בסוף ה-Codelab, האפליקציה שלך תוכל:
- זיהוי יעד תמונה וצירוף מבוך וירטואלי על היעד
- עוקבים אחרי היעד שנע כל עוד רואים אותו בעיני המצלמה
זאת הפעם הראשונה שיצרת אפליקציית ARCore?
האם אתם מתכננים לכתוב קוד לדוגמה ב-Codelab הזה או רק לקרוא את הדפים האלה?
מה תלמדו
- איך משתמשים בתמונות מרובות ב-ARCore ב-Java
- איך למדוד את היכולת של תמונה לזהות על ידי ARCore
- איך לצרף תוכן וירטואלי לתמונה ולעקוב אחרי התנועה שלה
דרישות מוקדמות
כדי להשלים את ה-Codelab הזה צריך חומרה ותוכנה ספציפיות.
דרישות החומרה
- מכשיר שתומך ב-ARCore שמחובר באמצעות כבל USB למכונת הפיתוח
דרישות תוכנה
- ARCore APK 1.9.0 ואילך. בדרך כלל, ה-APK הזה מותקן אוטומטית במכשיר דרך חנות Play
- מחשב פיתוח עם Android Studio (גרסה 3.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 למכונת הפיתוח ומשתמשים בתפריט הפעלה > מריצים את 'app' כדי להריץ את גרסת ניפוי הבאגים במכשיר. בתיבת הדו-שיח שבה מופיעה בקשה לבחור מאיזה מכשיר להריץ, בוחרים את המכשיר המחובר ולוחצים על OK (אישור).
בפרויקט לדוגמה הזה נעשה שימוש ב-targetSdkVersion 28
. אם יש לכם שגיאת build כמו Failed to find Build Tools revision 28.0.3
, עליכם לפעול לפי ההוראות שמתוארות ב-Android Studio כדי להוריד ולהתקין את הגרסה הנדרשת של Android Build Tools.
אם הכול יסתיים בהצלחה, האפליקציה לדוגמה תופעל במכשיר ותתבקשו לתת הרשאה לתמונות ולסרטונים להופיע. מקישים על אישור כדי לתת הרשאה.
בדיקה באמצעות תמונה לדוגמה
הגדרת את סביבת הפיתוח כדי לבדוק את האפליקציה באמצעות תמונה לבדיקה.
חוזרים ב-Android Studio, בחלון Project עוברים אל app > נכסים, ולוחצים לחיצה כפולה על הקובץ default.jpg
כדי לפתוח אותו.
מכוונים את המצלמה של המכשיר לתמונה של כדור הארץ שעל המסך ופועלים לפי ההוראות כדי להתאים את התמונה שסורקים לצלב.
מסגרת תמונה תוצג כשכבת-על מעל התמונה, כך:
בשלב הבא נבצע שיפורים קלים באפליקציה לדוגמה.
3. הצגת מודל מבוך בתמונה הדו-ממדית
אפשר להתחיל לשחק עם תמונות מרובות על ידי הצגת מודל תלת-ממדי מעליו.
הורדת מודל תלת-ממדי
לצורך ה-Codelab הזה נשתמש ב'מבוך מעגלי – ירוק' מטעם Evol, ברישיון CC-BY 3.0. שמרתי עותק של המודל התלת-ממדי הזה במאגר github של ה-Codelab הזה, שנמצא כאן.
כדי להוריד את המודל ולהוסיף אותו ל-Android Studio, צריך לבצע את השלבים הבאים.
- עוברים אל מאגר ה-GitHub של ספריית ה-codelab הזו, third_party.
- לוחצים על GreenMaze_obj.zip, ולאחר מכן לוחצים על הלחצן הורדה.
תתבצע הורדה של קובץ בשם GreenMaze_obj.zip
.
- ב-Android Studio, יוצרים ספרייה של
green-maze
בקטע app > נכסים > מודלים - מחלצים את הקובץ
GreenMaze_obj.zip
ומעתיקים את התוכן למיקום הזה:arcore-android-sdk-x.xx.x/samples/augmented_image_java/app/src/main/assets/models/green-maze
- ב-Android Studio, עוברים אל אפליקציה > נכסים > מודלים > מבוך ירוק.
בתיקייה הזו אמורים להיות שני קבצים: GreenMaze.obj
ו-GreenMaze.mtl
.
עיבוד מודל המבוך
כדי להציג את המודל התלת-ממדי GreenMaze.obj
מעל התמונה הדו-ממדית הקיימת, פועלים לפי השלבים הבאים.
בפונקציה 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
.
הערה: מאחר שאין לך שליטה מלאה על המודל התלת-ממדי לדוגמה, הקוד שלמעלה משתמש בכמה 'קסם' . הגודל של מודל המבוך הוא 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
כי המודל התלת-ממדי של המבוך לא מתרכז סביב המקור (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
פרטי כדי לעבד את אשר.
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
מאפליקציה > נכסים > מודלים > green-maze אל app > נכסים.
מוסיפים את יחסי התלות הבאים לקובץ 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;
מפעילים את האפליקציה. עומר אמור לנוע עכשיו בצורה מציאותית כשמטים את התמונה.
הדוגמה הבאה משתמשת בטלפון אחר כדי להציג את התמונה. אתם יכולים להשתמש בכל מה שנוח לכם, כמו טאבלט, כריכה של ספר מודפס, או סתם נייר מודפס שמחובר לאובייקט שטוח.
זהו! תיהנו לנסות לתפוס את אמיר במבוך. רמז: קל יותר למצוא את היציאה כשמחזיקים את תמונת היעד הפוכה.
6. מזל טוב
מזל טוב, הגעת לסוף Codelab זה וכתוצאה מכך:
- יצירה והרצה של דוגמת AugmentedImage Java של ARCore.
- הדגימה עודכנה כדי להציג מודל מבוך בתמונה, בקנה מידה מתאים.
- השתמשה בתנוחה של התמונה כדי לעשות משהו כיפי.
כאן אפשר לעיין בקוד המלא.