۱. مرور کلی
ARCore پلتفرمی برای ساخت برنامههای واقعیت افزوده در اندروید است. تصاویر افزوده به شما این امکان را میدهد که برنامههای واقعیت افزودهای بسازید که میتوانند تصاویر دوبعدی از پیش ثبتشده در دنیای واقعی را تشخیص داده و محتوای مجازی را روی آنها قرار دهند.
این آزمایشگاه کد شما را در اصلاح یک برنامه نمونه ARCore موجود برای گنجاندن تصاویر افزودهای که در حال حرکت یا ثابت در محل هستند، راهنمایی میکند.
آنچه خواهید ساخت
در این آزمایشگاه کد، شما بر اساس یک برنامه نمونه ARCore که از قبل موجود است، برنامه خود را خواهید ساخت. در پایان این آزمایشگاه کد، برنامه شما قادر خواهد بود:
- تشخیص یک هدف تصویری و اتصال یک هزارتوی مجازی به هدف
- هدف متحرک را تا زمانی که در دید دوربین است، ردیابی کنید

آیا این اولین باری است که یک برنامه ARCore میسازید؟
آیا قصد دارید در این آزمایشگاه کد، کد نمونه بنویسید یا فقط میخواهید این صفحات را بخوانید؟
آنچه یاد خواهید گرفت
- نحوه استفاده از تصاویر افزوده در ARCore در جاوا
- چگونه میتوان توانایی تشخیص یک تصویر توسط ARCore را سنجید؟
- نحوه اتصال یک محتوای مجازی به یک تصویر و ردیابی حرکت آن
پیشنیازها
برای تکمیل این آزمایشگاه کد، به سختافزار و نرمافزار خاصی نیاز دارید.
الزامات سختافزاری
- یک دستگاه پشتیبانیشده با ARCore که از طریق کابل USB به دستگاه توسعه شما متصل شده باشد
نیازمندیهای نرمافزاری
- ARCore APK 1.9.0 یا بالاتر. این APK معمولاً به طور خودکار از طریق فروشگاه Play روی دستگاه نصب میشود.
- یک دستگاه توسعه با اندروید استودیو (نسخه ۳.۱ یا بالاتر)
- دسترسی به اینترنت، زیرا در طول توسعه نیاز به دانلود کتابخانهها خواهید داشت.
حالا که همه چیز را آماده کردهاید، بیایید شروع کنیم!
۲. محیط توسعه را راهاندازی کنید
دانلود SDK
ما با دانلود آخرین نسخه ARCore Android SDK از GitHub شروع میکنیم. آن را در محل دلخواه خود از حالت فشرده خارج کنید. برای این codelab، قدیمیترین نسخه SDK، نسخه ۱.۱۸.۱ است. نام پوشه arcore-android-sdk-x.xx.x خواهد بود، مقدار دقیق آن، نسخه SDK مورد استفاده شما خواهد بود.
اندروید استودیو را اجرا کنید و روی «باز کردن یک پروژه اندروید استودیو موجود» کلیک کنید.

به این پوشهی از حالت فشرده خارج شده بروید:
arcore-android-sdk-x.xx.x/samples/augmented_image_java
روی باز کردن کلیک کنید.
صبر کنید تا اندروید استودیو همگامسازی پروژه را تمام کند. اگر اندروید استودیو شما اجزای مورد نیاز را نداشته باشد، ممکن است با پیام Install missing platform and sync project مواجه شود. برای رفع مشکل، دستورالعملها را دنبال کنید.
اجرای برنامه نمونه
حالا که یک پروژه اپلیکیشن ARCore دارید که کار میکند، بیایید آن را امتحان کنیم.
دستگاه ARCore خود را به دستگاه توسعه متصل کنید و از منوی Run > Run 'app' برای اجرای نسخه اشکالزدایی روی دستگاه استفاده کنید. در پنجرهای که از شما خواسته میشود دستگاه مورد نظر برای اجرا را انتخاب کنید، دستگاه متصل را انتخاب کرده و روی OK کلیک کنید.


این پروژه نمونه از targetSdkVersion 28 استفاده میکند. اگر با خطای ساخت مانند Failed to find Build Tools revision 28.0.3 مواجه شدید، دستورالعملهای شرح داده شده در Android Studio را برای دانلود و نصب نسخه مورد نیاز Android Build Tools دنبال کنید.
اگر همه چیز موفقیتآمیز باشد، برنامه نمونه روی دستگاه اجرا میشود و از شما اجازه میگیرد تا به Augmented Image اجازه عکسبرداری و فیلمبرداری بدهید. برای اعطای مجوز، روی ALLOW ضربه بزنید.
با یک تصویر نمونه تست کنید
اکنون که محیط توسعه خود را تنظیم کردهاید، میتوانید با ارائه یک تصویر برای بررسی، برنامه را آزمایش کنید.
به اندروید استودیو برگردید، در پنجره پروژه ، به app > assets بروید و روی فایل default.jpg دوبار کلیک کنید تا باز شود.

دوربین دستگاه خود را به سمت تصویر زمین روی صفحه بگیرید و دستورالعملها را دنبال کنید تا تصویری که اسکن میکنید در کادر ضربدر قرار گیرد.
یک قاب تصویر روی تصویر قرار میگیرد، مانند این:

در مرحله بعد، بهبودهای کوچکی در برنامه نمونه ایجاد خواهیم کرد.
۳. نمایش مدل هزارتو روی تصویر دوبعدی
شما میتوانید با نمایش یک مدل سهبعدی روی تصاویر افزوده، بازی با آنها را شروع کنید.
یک مدل سه بعدی دانلود کنید
برای این آزمایشگاه کد، ما از « Circle Maze - Green » ساختهی Evol و دارای مجوز CC-BY 3.0 استفاده خواهیم کرد. من یک کپی از این مدل سهبعدی را در مخزن گیتهاب این آزمایشگاه کد ذخیره کردهام که میتوانید آن را اینجا پیدا کنید.
برای دانلود مدل و اضافه کردن آن به اندروید استودیو، این مراحل را دنبال کنید.
- به مخزن گیتهاب این codelab، دایرکتوری third_party، بروید.
- روی GreenMaze_obj.zip کلیک کنید و دکمه دانلود را بزنید.
این دستور فایلی به نام GreenMaze_obj.zip را دانلود میکند.
- در اندروید استودیو، دایرکتوری
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 - در اندروید استودیو، به مسیر app > assets > models > green-maze بروید.
باید دو فایل در این پوشه وجود داشته باشد: GreenMaze.obj و GreenMaze.mtl .

مدل هزارتو را رندر کنید
برای نمایش مدل سهبعدی GreenMaze.obj روی تصویر دوبعدی موجود، این مراحل را دنبال کنید.
در AugmentedImageRenderer.java ، یک متغیر عضو به نام mazeRenderer برای رندر مدل هزارتو اضافه کنید. از آنجا که هزارتو باید به تصویر متصل شود، منطقی است که mazeRenderer درون کلاس AugmentedImageRenderer قرار دهیم.
رندرکننده تصویر افزودهشده.java
// Add a member variable to hold the maze model.
private final ObjectRenderer mazeRenderer = new ObjectRenderer();
در تابع createOnGlThread() ، فایل GreenMaze.obj را بارگذاری کنید. برای سادگی، از همان بافت فریم به عنوان بافت آن استفاده کنید.
رندرکننده تصویر افزودهشده.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() را با کد زیر جایگزین کنید. این کد، اندازه هزارتو را با اندازه تصویر شناسایی شده تنظیم میکند و آن را روی صفحه نمایش میدهد.
رندرکننده تصویر افزودهشده.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 را به طور ناهموار مقیاسبندی کند تا ارتفاع هزارتو را به اندازه ۰.۱ افزایش دهد. توجه داشته باشید که باید تابع updateModelMatrix(float[] modelMatrix, float scaleFactor) موجود را نگه دارید و تابع overload شده 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);
}
کد را اجرا کنید. حالا هزارتو باید کاملاً بالای تصویر قرار بگیرد.

۴. اندی را به هزارتو اضافه کنید
حالا که یک هزارتو دارید، یک شخصیت اضافه کنید تا درون آن حرکت کند. از فایل andy.obj موجود در ARCore Android SDK استفاده کنید. بافت قاب تصویر را به عنوان بافت آن نگه دارید، زیرا با هزارتوی سبز رندر شده روی تصویر متفاوت به نظر میرسد.
در AugmentedImageRenderer.java ، یک ObjectRenderer خصوصی برای رندر کردن Andy اضافه کنید.
رندرکننده تصویر افزودهشده.java
// Render for Andy
private final ObjectRenderer andyRenderer = new ObjectRenderer();
در مرحله بعد، andyRenderer در انتهای createOnGlThread() مقداردهی اولیه کنید.
رندرکننده تصویر افزودهشده.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() در حالی که بالای هزارتو ایستاده است، رندر کنید.
رندرکننده تصویر افزودهشده.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 را تعیین کنید. این ابزار عددی بین ۰ تا ۱۰۰ را نمایش میدهد که ۱۰۰ سادهترین عدد برای تشخیص است.
. در اینجا یک مثال آورده شده است:
arcore-android-sdk-x.xx.x/tools/arcoreimg/macos$
$ ./arcoreimg eval-img --input_image_path=/Users/username/maze.jpg
100
maze.jpg مقدار ۱۰۰ دارد، بنابراین به راحتی توسط ARCore شناسایی میشود.
۵. اختیاری: کاری کنید که اندی در هزارتو حرکت کند
در نهایت، میتوانید کدی اضافه کنید تا اندی در هزارتو حرکت کند. برای مثال، از موتور فیزیک متنباز jBullet برای مدیریت شبیهسازی فیزیک استفاده کنید. اگر از این بخش صرفنظر کنید، کاملاً مشکلی نیست.
PhysicsController.java را دانلود کنید و آن را به پروژه خود در دایرکتوری اضافه کنید.
arcore-android-sdk-x.xx.x/samples/augmented_image_java/app/src/main/java/com/google/ar/core/examples/java/augmentedimage/
در اندروید استودیو، فایل GreenMaze.obj را به دایرکتوری assets پروژه اضافه کنید تا در زمان اجرا قابل بارگذاری باشد. فایل GreenMaze.obj از مسیر app > assets > models > green-maze در مسیر app > assets کپی کنید.
وابستگیهای زیر را به فایل build.gradle برنامه اضافه کنید.
برنامه/ساخت.gradle
// jbullet library
implementation 'cz.advel.jbullet:jbullet:20101010-1'
متغیری به andyPose تعریف کنید تا موقعیت فعلی اندی را ذخیره کند.
رندرکننده تصویر افزودهشده.java
// Create a new pose for the Andy
private Pose andyPose = Pose.IDENTITY;
فایل AugmentedImageRenderer.java را طوری تغییر دهید که Andy را با استفاده از متغیر جدید andyPose رندر کند.
رندرکننده تصویر افزودهشده.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 را دریافت کند.
رندرکننده تصویر افزودهشده.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;
برنامه را اجرا کنید. حالا اندی باید با کج کردن تصویر، به طور واقعی حرکت کند.
مثال زیر از یک گوشی دیگر برای نمایش تصویر استفاده میکند، میتوانید از هر چیزی که برایتان راحتتر است، مانند تبلت، یا جلد یک کتاب چاپی، یا فقط یک کاغذ چاپ شده که روی یک جسم صاف چسبیده است، استفاده کنید.

همین! از تلاش برای عبور دادن اندی از هزارتو لذت ببرید. راهنمایی: وقتی تصویر هدف را وارونه نگه دارید، پیدا کردن خروجی آسانتر است.
۶. تبریک
تبریک میگویم، شما به پایان این آزمایشگاه کد رسیدهاید و بنابراین:
- یک نمونه جاوا از ARCore AugmentedImage ساخته و اجرا شد.
- نمونه بهروزرسانی شد تا مدل هزارتو روی تصویر، در مقیاس مناسب، نمایش داده شود.
- از ژست تصویر برای انجام کاری جالب استفاده کردم.
اگر مایل به مشاهده کد کامل هستید، میتوانید آن را از اینجا دانلود کنید.