Hướng dẫn xây dựng ứng dụng thực tế tăng cường(AR) trên Android

0
73

ung-dung-AR

Mình là một coder nhưng lại có sở thích nghiên cứu lịch sử. Tình cờ mình biết đến người Vikings, những chiến binh hiếu chiến thời cổ đại. Liệu người Vikings có thực sự sử dụng pháo trong các cuộc chiến không? Mình không chắc chắn về điều đó, tuy nhiên không có lí do gì mà người Vikings lại không thể có pháo trong thế giới AR(công nghệ thực tế tăng cường)… hehe

1. Đôi chút về công nghệ thực tế tăng cường VR

Tại WWDC 2017, Apple đã công bố ARKit – một bước đột phá vào thế giới phát triển AR. Không chịu thua kém đối thủ, ngay sau đó Google đã công bố ARCore, được trích xuất từ ​​dự án bản đồ Tango. Dự án Tango yêu cầu sử dụng các thiết bị có cảm biến độ sâu, do đó ARCore chắc chắn sẽ hoạt động tốt trên hầu hết các thiết bị Android.

AR đang trở thành một xu hướng công nghệ tương lai mà các ông lớn đều đã vào cuộc. Bạn là lập trình viên dày dặn kinh nghiệm hay chỉ là beginner thì chắc chắn đều muốn nắm bắt xu hướng này. Đúng không?

Chờ chút! Bạn có thể xem một số bản demo ARCore tại trang web AR Experiments.
Ứng dụng ARCore có thể được phát triển bằng cách sử dụng OpenGL, Unity hoặc Unreal. Trong bài hướng dẫn này, mình sẽ xây dựng bằng cách modify lại project mẫu do Google cung cấp(sử dụng OpenGL), hoàn toàn viết bằng Kotlin

Lưu ý:

  • Do ARCore không thể hoạt động trên các Android Emulator. Do đó, bạn sẽ cần có device thật hỗ trợ ARCore như Samsung Galaxy S8 hoặc Google Pixel / Pixel XL với Android Nougat (7.0) trở lên
  • Nếu bạn không có một trong các thiết bị đó, bạn vẫn có thể trải nghiệm AR với SDK ARCore.

Bạn đã sẵn sàng để khám phá thế giới mới đầy táo bạo này chưa?

2. Cài đặt môi trường dự án AR

Như các bài viết trước, các bạn tải dự án mình tạo sẵn bộ khung tại đây nhé

Mở project trong Android Studio 3.0 Beta 5 trở lên.(Nó cũng có thể chạy nếu bạn đang sử dụng Android Studio 2.3.3 với plugin Kotlin)

Trước khi chạy project, bạn cũng cần tải xuống và cài đặt ARCore Service do Google cung cấp.

Dịch vụ ARCore có thể được cài đặt bằng lệnh adb sau:

$ adb install -r -d arcore-preview.apk
Chờ chút! Các bạn có thể tham khảo toàn bộ các lệnh của adb tại đây.

Giờ đây, bạn có thể nhấn Run/Run ‘app’ hoặc nhấn Ctrl-R để khởi động và chạy.

Trước tiên, bạn sẽ được nhắc cung cấp quyền đối với máy ảnh và sau khi phê duyệt, bạn sẽ thấy một nhóm radio buttons ở trên cùng, sử dụng để chọn loại đối tượng cần chèn vào cảnh.

Bạn sẽ thấy một snackbar ở dưới cùng với dòng chữ  “Searching for surfaces…”. Bạn cũng có thể thấy một vài điểm được đánh dấu, đó là những điểm sẽ được theo dõi. Nhắm vào bề mặt phẳng, plane sẽ được phát hiện:

huong dan xay dung ung dung AR tren android

Khi plane đầu tiên được phát hiện, thanh snackbar sẽ biến mất và mặt phẳng được tô sáng trên màn hình. Lưu ý rằng plane có màu sáng có thể gặp sự cố khi detect.

Hướng dẫn xây dựng ứng dụng thực tế tăng cường(AR) trên Android

3. Tìm hiểu sơ lược ARCode SDK sử dụng trong project mẫu

Project có các model 3D mà mình sử dụng trong thư mục main/assets của Android Studio. Trong đó có chứa các model cho viking, cannon, và target. Các tập tin model 3D đã được tạo bằng Blender ( Các bạn có thể tham khảo hướng dẫn làm sao có thể tạo model 3D bằng Blender).

Bên trong thư mục res/raw, có OpenGL shaders, tất cả mình lấy từ Google ARCore sample app. Ngoài ra, Bạn còn thấy một package có tên là rendering, có chứa một số OpenGL renderers và  utilities từ Google ARCore sample app. Ngoài ra còn có một lớp với tên là PlaneAttachment viết bằng Kotlin và sử dụng SDK ARCore.

3.1. Planes, Anchors, và Poses

Lớp PlaneAttachment được xây dựng bằng cách sử dụng một Plane và một Anchor. Và lớp PlaneAttachment có thể được sử dụng để xây dựng một Pose – Cả ba đều từ SDK ARCore.

  • Một plane mô tả một bề mặt phẳng thực.
  • Một Anchor mô tả một vị trí cố định và định hướng trong không gian.
  • Một Pose mô tả sự chuyển đổi tọa độ từ một hệ thống này sang hệ thống khác, từ object’s local frame đến world coordinate frame. Bạn có thể đọc thêm tài liệu chính thức ở đây documentation.

Vì vậy, bạn có thể hiểu đại khái là: PlaneAttachment cho phép bạn gắn một anchor vào một plane và lấy ra pose tương ứng.

3.2. ARCore Session là gì?

Trong project có sử dụng đối tượng Session ARCore trong MainActivity. Session này mô tả toàn bộ trạng thái AR và bạn sẽ sử dụng nó để đính kèm các anchor vào plane khi người dùng chạm vào màn hình.

Trong setupSession (), được gọi từ onCreate (…), ứng dụng sẽ kiểm tra xem thiết bị có hỗ trợ ARCore không. Nếu không, một Toast sẽ hiển thị và thoát activity.

Giả sử bạn có thiết bị được hỗ trợ, đã đến lúc thiết lập một số object để hiển thị trên màn hình!

4. Thêm Objects

Mở MainActivity và thêm các thuộc tính sau:

private val vikingObject = ObjectRenderer()
private val cannonObject = ObjectRenderer()
private val targetObject = ObjectRenderer()

Mỗi thuộc tính được định nghĩa là một ObjectRenderer. Tiếp theo thêm ba thuộc tính PlaneAttachment như dưới đây

private var vikingAttachment: PlaneAttachment? = null
private var cannonAttachment: PlaneAttachment? = null
private var targetAttachment: PlaneAttachment? = null

Cách viết trên nghĩa là các thuộc tính sẽ có giá trị mặc định là null và sẽ được tạo sau khi user chạm vào màn hình.

Bạn cần thiết lập một số đối tượng mà bạn sẽ làm trong onSurfaceCreated(…). Tìm khối try-catch có sẵn trong hàm và thêm phần xử lý  try-catch như sau:

// Prepare the other rendering objects.
try {
  vikingObject.createOnGlThread(this, "viking.obj", "viking.png")
  vikingObject.setMaterialProperties(0.0f, 3.5f, 1.0f, 6.0f)
  cannonObject.createOnGlThread(this, "cannon.obj", "cannon.png")
  cannonObject.setMaterialProperties(0.0f, 3.5f, 1.0f, 6.0f)
  targetObject.createOnGlThread(this, "target.obj", "target.png")
  targetObject.setMaterialProperties(0.0f, 3.5f, 1.0f, 6.0f)
} catch (e: IOException) {
  Log.e(TAG, "Failed to read obj file")
}

Bạn đang sử dụng các tệp model 3D được cung cấp trong ứng dụng để thiết lập từng đối tượng trong số ba đối tượng, cũng như thiết lập một số thuộc tính material trên mỗi đối tượng.

5. Thêm các Anchors vào Session

Tìm hàm handleTaps(…) trong MainActivity. Thêm câu lệnh if ngay phía trên comment trước câu lệnh break như sau:

when (mode) {
  Mode.VIKING -> vikingAttachment = addSessionAnchorFromAttachment(vikingAttachment, hit)
  Mode.CANNON -> cannonAttachment = addSessionAnchorFromAttachment(cannonAttachment, hit)
  Mode.TARGET -> targetAttachment = addSessionAnchorFromAttachment(targetAttachment, hit)
}

Giá trị của biến mode được quản lý bởi radio buttons phía trên màn hình. Mode là một enum class. Tỉ lệ factor được sử dụng để điều chỉnh kích thước của model 3D tương ứng.

Trong câu lệnh when với từng chế độ, bạn sẽ thiết lập một giá trị mới cho PlaneAttachment tương ứng sử dụng tệp đính kèm cũ và giá trị nhận được khi tap vào màn hình. Giá trị này là một ARCore PlaneHitResult xác định giao điểm của 3D ray khi touch và một plane.

Bây giờ bạn cần thêm hàm addSessionAnchorFromAttachment(…)như sau:

private fun addSessionAnchorFromAttachment(
  previousAttachment: PlaneAttachment?, hit: PlaneHitResult): PlaneAttachment {
  previousAttachment?.let {
    session.removeAnchors(Arrays.asList(previousAttachment.anchor))
  }
  return PlaneAttachment(hit.plane, session.addAnchor(hit.hitPose))
}

Nếu previousAttachment là khác null, đầu tiên bạn cần loại bỏ anchor của nó khỏi session. Sau đó thêm vào một anchor mới cho session và tiếp tục nhận giá trị mới từ PlaneAttachment, base trên PlaneHitResult plane và một anchor từ PlaneHitResult pose.

Đền đây, bạn gần như đã sẵn sàng để xem ứng dụng của bạn hoạt động như thế nào rồi!

viking cannons

6. Drawing các Objects

Bước cuối cùng bạn cần làm là vẽ các objects lên màn hình. Bạn đã tạo tệp đính kèm plane khi người dùng touch vào. Tiếp theo bạn cần phải vẽ các objects như là một phần của màn hình hiển thị.

Nhìn vào hàm onDrawFrame(…). Thêm vào khối try như sau:

drawObject(vikingObject, vikingAttachment, Mode.VIKING.scaleFactor,
  projectionMatrix, viewMatrix, lightIntensity)
drawObject(cannonObject, cannonAttachment, Mode.CANNON.scaleFactor,
  projectionMatrix, viewMatrix, lightIntensity)
drawObject(targetObject, targetAttachment, Mode.TARGET.scaleFactor,
  projectionMatrix, viewMatrix, lightIntensity)

Bạn đang gọi đến một hàm pre-existing drawObject(…)helper để lấy object, phần đính kèm tương ứng, hệ số tỷ lệ tương ứng cũng như các ma trận và các giá trị cần thiết cho OpenGL để vẽ object

private fun computeProjectionMatrix(): FloatArray {
  val projectionMatrix = FloatArray(16)
  session.getProjectionMatrix(projectionMatrix, 0, 0.1f, 100.0f)
  return projectionMatrix
}

private fun computeViewMatrix(frame: Frame): FloatArray {
  val viewMatrix = FloatArray(16)
  frame.getViewMatrix(viewMatrix, 0)
  return viewMatrix
}

private fun computeLightIntensity(frame: Frame) = frame.lightEstimate.pixelIntensity

Giá trị projectionMatrix được tính toán từ ARCore Session. Giá trị viewMatrix được tính toán từ ARCore Frame( để mô tả trạng thái AR tại một thời điểm cụ thể). Hàm lightIntensity cũng có thể được xác đinh từ frame.

Về cơ bản là xong rồi đấy. Bạn chạy lại ứng dụng xem nào.

Bạn thử chọn một một chế độ Viking, Cannon hay Target. Sau đó, tìm một plane trên máy ảnh của bạn và touch để đặt một object. Khi bạn đã đặt tất cả các objects, nếu xoay điện thoại, bạn sẽ thấy màn hình như sau

huong dan xay dung ung dung AR tren android

7. Tổng kết

Như vậy, mình hoàn thành hướng dẫn về cách sử dụng ARCore với OpenGL trong Android Studio. Để biết thêm thông tin, hãy xem ARCore API và  ARCore Overview.

Bạn có thể download toàn bộ source code của projec trong hướng dẫn này tại đây:

Bạn cũng có thể sử dụng ARCore with Unity và  ARCore with Unreal. Ngoài Android, ARCore cũng có thể phát triển cho website và bạn có thể tìm thêm thông tin tại đây. Cuối cùng, nếu bạn tò mò muốn tìm hiểu thêm và trải nghiệm xem AR như thế nào thì các bạn vào Google experiments site để xem một số demo rất thú vị nhé

Mình hy vọng các bạn sẽ thích phần giới thiệu ngắn gọn về ARCore này. Hãy để lại comment để cùng nhau trao đổi thêm về xu hướng công nghệ mới này nhé.

 

BÌNH LUẬN

Please enter your comment!
Please enter your name here