本文只是作者在工作中涉及到的一点 ARCore 的知识进行了记录,深度和广度都非常有限,仅做入门学习用。如有错误烦请指正。
目录
文章目录
- 目录
- ARCore 基础
- AR 概念
- ARCore 概念
- ARCore 中的坐标系
- Sceneform 开发
- Sceneform 开发步骤
- Sceneform Demo 实例
- Sceneform API 介绍
- Node 和 AnchorNode 的区别
- ViewRenderable 和 ModelRenderable 的区别
- setLocalPosition 和 setWorldPosition 的区别
- setLocalScale 和 setWorldScale 的区别
- overlapTest 和 hitTest 的区别
- Model in air 为什么会消失
- Sceneform、SceneView 和 Filament 的区别
ARCore 基础
AR 概念
AR 核心概念:
- 运动跟踪。
- 环境理解。检测特征点和平面,最重要的就是平面检测。
- 光线估计。估算出当前环境的光线强度,这样可以让虚拟物体显示在真实环境中更加逼真。
举个例子:得到平面信息后,平面是有姿态和边界的,平面是一个可跟踪对象,可以在平面上创建锚点(anchor),这是我们用来标定具体对象的位置信息。把平面当成桌子,把 anchor 当成苹果,就是在桌子上放一个苹果。再加上光估计和深度信息,使得「苹果」更真实。
什么是特征点呢?
图像灰度值发生剧烈变化的点或者在图像边缘上曲率较大的点。
AR = 实时视频 + 平面 + 虚拟物品。
ARCore 概念
ARCore 是 Google 的增强现实体验构建平台。用于在 Android 手机上进行 AR 开发。IOS 上是 ARKit 。
ARCore 中的坐标系
在 ARCore 中,相机左边为 X 轴正方向,相机上方为 Y 轴正方向,相机朝向的反方向为 Z 轴正方向。
Sceneform 开发
下载 ARCore SDK :
- ARCore SDK
- Sceneform SDK
可以看到有两个 SDK ,一个是 ARCore SDK 另一个是 Sceneform SDK 。 前者可以理解为通用版 SDK ,使用此版本需要强大的 OpenGL 知识做后盾。如果你对 OpenGL 不是很熟甚至是一无所知,则可以考虑使用后者。后者使用 Java 封装了 OpenGL ,使得开发者使用起来更容易。推荐使用 Sceneform 1.16.0
。
但是 Sceneform 目前已停止更新,谷歌已不再维护。而且 Sceneform SDK 仅能使用 android.support
,不能支持 androidx
。不过网上有大佬开源了一个支持 androidx
的 Sceneform SDK :sceneform-android 。
本文主要介绍 Sceneform 开发。
Sceneform 开发步骤
使用 ARCore 开发的一个整体步骤如下:
-
获取 ARFragment 。
-
加载模型。
在 onCreate 中加载模型:
ModelRenderable.builder().setSource(this, Uri.parse("models/arrow.glb")).setIsFilamentGltf(true).setAsyncLoadEnabled(true).build().thenAccept(model -> {arrowModel = model;}).exceptionally(throwable -> {Toast.makeText(this, "Unable to load model", Toast.LENGTH_LONG).show();return null;});
- 等待 ARCore 追踪。
@Override
public void onUpdate(FrameTime frameTime) {arFragment.onUpdate(frameTime);if (arFragment.getArSceneView().getArFrame() == null) {return;}TrackingState trackingState = arFragment.getArSceneView().getArFrame().getCamera().getTrackingState();Log.i(TAG, "tracking state: " + trackingState);if (trackingState != TrackingState.TRACKING) {return;}// 渲染模型
}
- 渲染模型
渲染时:
- 创建 Anchor 。
- 创建 AnchorNode 。
- 创建 TransformableNode 。
Vector3 position = new Vector(x, y, z);
Pose pose = Pose.makeTranslation(position.x, position.y, position.z);
Anchor anchor = arFragment.getArSceneView().getSession().createAnchor(pose);
Log.i(TAG, "anchor tracking state: " + anchor.getTrackingState());AnchorNode anchorNode = new AnchorNode(anchor);
anchorNode.setParent(arFragment.getArSceneView().getScene());TransformableNode transNode = new TransformableNode(arFragment.getTransformationSystem());
transNode.getScaleController().setMaxScale(50f);
transNode.setLocalScale(Vector3.one().scaled(10.0f));
transNode.getScaleController().setEnabled(true);
transNode.getRotationController().setEnabled(true);
transNode.getTranslationController().setEnabled(false);
transNode.setParent(anchorNode);
transNode.setRenderable(flagModel);
transNode.setOnTapListener(((hitTestResult, motionEvent) -> {Node node = hitTestResult.getNode();if (null != node) {node.setSelectable(true);}
}));
Sceneform Demo 实例
基于 Sceneform 框架开发了一个简单的 AR 实例,该实例实现了三维箭头的渲染。源码地址:arcore-sceneform-demo 。
效果如下:
Sceneform API 介绍
Node 和 AnchorNode 的区别
来自 ChatGPT :
ARCore 中的 AnchorNode 和 Node 都是 ARCore 中的基本节点类型,用于构建 AR 世界中的场景。
AnchorNode 是 ARCore 中的锚节点,用于在真实世界中定位虚拟场景中的节点,即将虚拟场景中的节点固定到现实世界的某个位置上。AnchorNode 可以通过 ARCore 的跟踪功能来确定其在真实世界中的位置,从而确定虚拟场景中节点的位置。因此,AnchorNode 通常用于需要在真实世界中固定位置的虚拟场景中,比如在桌面上放置一个虚拟的物体。
Node 是 ARCore 中的基本节点类型,用于表示 AR 世界中的一个对象或元素。Node 可以包含几何形状、纹理、材质和动画等内容,可以通过 Node 来构建 AR 世界中的各种场景和物体。Node 可以通过设置其在 ARCore 中的坐标系和相对于父节点的变换矩阵来确定其在 AR 世界中的位置和方向。
AnchorNode 和 Node 通常一起使用,AnchorNode 用于确定虚拟场景中节点在真实世界中的位置,Node 用于表示虚拟场景中的节点。通过将 Node 添加到 AnchorNode 上,可以将虚拟场景中的节点固定到真实世界中的某个位置上。
使用场景可以举个例子:比如在 AR 应用中,用户可以在桌面上放置一个虚拟的花瓶,用户放置花瓶的位置就是 AnchorNode,而花瓶本身就是 Node。用户可以通过手势或其他方式在桌面上选择一个位置,并将花瓶放置在该位置上。ARCore 确定选定位置的实际位置,并将 AnchorNode 固定在该位置上。然后将花瓶 Node 添加到 AnchorNode 上,花瓶就会出现在用户选择的位置上,并固定在那里。
总之,AnchorNode 和 Node 是 ARCore 中的两个基本节点类型,用于构建 AR 世界中的场景和物体,通过将 Node 添加到 AnchorNode 上,可以将虚拟场景中的节点固定到真实世界中的某个位置上。
ViewRenderable 和 ModelRenderable 的区别
来自 ChatGPT :
ViewRenderable 和 ModelRenderable 都是 ARCore Sceneform 中的节点类型,用于在 AR 世界中呈现不同类型的内容。
ViewRenderable 是用于呈现 Android View 的节点类型,可以将 Android View 嵌入到 ViewRenderable 中,然后将其添加到 ARCore 场景中。通过 ViewRenderable 可以呈现各种类型的 Android View,例如文本、按钮、图像、Web 视图等。使用 ViewRenderable 可以在 AR 场景中实现更复杂的用户界面。
ModelRenderable 是用于呈现 3D 模型的节点类型,可以将 3D 模型加载到 ModelRenderable 中,然后将其添加到 ARCore 场景中。通过 ModelRenderable 可以呈现各种类型的 3D 模型,例如家具、汽车、动物、机器人等。使用 ModelRenderable 可以在 AR 场景中实现更真实和生动的虚拟内容。
它们的区别主要在于呈现的内容不同,ViewRenderable 适用于呈现 Android View,ModelRenderable 适用于呈现 3D 模型。
使用场景:
ViewRenderable 可以用于在 AR 场景中呈现用户界面,例如在虚拟物体或位置上显示文本、图像、按钮、Web 视图等。例如,在 AR 应用中,可以使用 ViewRenderable 在虚拟物体旁边显示包含商品信息和评论的 Web 视图。
ModelRenderable 可以用于在 AR 场景中呈现虚拟物品,例如在家庭装修应用中,可以使用 ModelRenderable 在 AR 场景中呈现家具、灯具、窗帘等。在游戏中,可以使用 ModelRenderable 在 AR 场景中呈现敌人、宠物、角色等。
总之,ViewRenderable 和 ModelRenderable 是 ARCore Sceneform 中的两种节点类型,分别用于呈现 Android View 和 3D 模型。它们可以用于在 AR 场景中呈现不同类型的内容,提供更真实和生动的虚拟体验。
setLocalPosition 和 setWorldPosition 的区别
来自 ChatGPT :
setLocalPosition 和 setWorldPosition 都是 ARCore Sceneform 中的方法,用于设置节点在 AR 世界中的位置。它们的区别在于设置节点位置的坐标系不同。
setLocalPosition 方法用于设置节点相对于其父节点的本地坐标系中的位置。例如,如果一个节点是另一个节点的子节点,那么它的位置将相对于其父节点的位置。在 setLocalPosition 方法中,设置的坐标表示相对于父节点的偏移量。如果节点没有父节点,则相对于场景坐标系。
setWorldPosition 方法用于设置节点在 AR 世界坐标系中的位置。即设置节点相对于整个 AR 世界坐标系的位置。在 setWorldPosition 方法中,设置的坐标表示节点在 AR 世界坐标系中的位置。
因此,它们的适用场景不同:
setLocalPosition 适用于需要设置节点相对于其父节点的位置的场景,例如在场景中移动或旋转子节点。
setWorldPosition 适用于需要在整个 AR 世界坐标系中设置节点位置的场景,例如在 ARCore 场景中创建节点并将其放置在特定的位置上。
需要注意的是,setLocalPosition 和 setWorldPosition 方法都会影响节点的位置,应根据实际需要选择合适的方法。同时,节点的位置也可以通过设置节点的变换矩阵来改变。
setLocalScale 和 setWorldScale 的区别
来自 ChatGPT :
- setLocalScale(): 设置3D对象相对于其父对象的缩放比例,即本地缩放比例。
- setWorldScale(): 设置3D对象在世界坐标系下的缩放比例,即全局缩放比例。
同样需要注意的是:- 这两个方法都可以修改3D对象的缩放比例,但缩放中心点不同。setLocalScale方法在对象的中心点进行缩放,而setWorldScale方法则在世界坐标系中进行缩放。
- setLocalScale方法的缩放比例会随着3D对象的父对象的缩放而变化,而setWorldScale方法的缩放比例则不会受到父对象的影响。
- 建议在ARCore中使用setLocalScale方法进行缩放,因为它更符合常规的缩放方式,而且可以保持相对位置不变。而setWorldScale方法则适用于一些特殊的场景,如需要在不同的坐标系中进行缩放时。
在实际开发中,setLocalScale和setWorldScale方法可以用于控制3D对象的缩放比例,在AR应用程序中动态调整3D对象的大小。例如,在AR游戏中,可以使用这些方法来缩放游戏场景中的模型或道具,以适应不同的屏幕大小和分辨率。这些方法也可以用于AR体验中的交互设计,例如在AR应用程序中缩放虚拟物体以提高用户体验。
overlapTest 和 hitTest 的区别
来自 ChatGPT :
overlapTest 和 hitTest 都是 ARCore Sceneform 中用于检测射线与场景中物体相交的方法。它们的主要区别在于检测方式和返回结果,根据不同的使用场景选择不同的方法可以更好地实现功能需求。
overlapTest 方法是一种快速且低精度的相交检测方法,它只检测射线与场景中可渲染对象的包围盒是否相交。该方法返回一个 Node 列表,表示与射线包围盒相交的节点集合,但无法确定相交点的精确位置。
hitTest 方法是一种精确且耗时较长的相交检测方法,它会检测射线与场景中所有可渲染对象的三角形网格是否相交。该方法返回一个 HitResult 列表,表示与射线相交的节点集合以及相交点的精确位置等信息。
两种方法的使用场景有所不同:
● overlapTest 方法适用于相交检测精度要求不高的场景,例如:物体拾取、碰撞检测等。由于该方法速度较快,通常用于检测物体是否在视野范围内或者是否与其他物体发生碰撞等快速判断场景。
● hitTest 方法适用于相交检测精度要求较高的场景,例如:手势交互、虚拟物体与现实环境的交互等。由于该方法需要检测所有可渲染对象的三角形网格,因此速度较慢,通常用于需要获取精确交互位置的场景。
Model in air 为什么会消失
参考:https://stackoverflow.com/questions/64754305/anchornode-models-are-disappeared-in-android-sceneform-sdk
在 ARCore 渲染出模型后,在移动手机的过程中可能会出现模型偏移或消失的问题。
模型消失的几种情况:
- Move phone faster
- Lights are low
- Blocking camera vision
原因:
It is natural because the 3 cases you listed up makes ARCore hard to track the feature points. And surely, there is no way to overcome this issue because tracking feature points is ARCore’s job and not yours. I’d rather let users be aware that in some specific environment application might not work properly. Or you could go ask ARCore developers.
总的来说就是,如果移动手机过快、或光线较暗、或相机被遮挡,会导致 ARCore 难以追踪模型的特征点,所以模型会出现漂移或消失的问题。
Sceneform、SceneView 和 Filament 的区别
ARCore、Sceneform、SceneView、Filament 都是谷歌推出的开源 AR 框架。
Sceneform 是 Java 写的,现已不再维护。
SceneView 是 Kotlin 写的,现在还在维护。Sceneform 和 SceneView 可以理解为作用一样的东西,都是基于 ARCore + OpenGL ,只是实现语言不同。
Filament 是用 C++ 写的,适用于对渲染性能和质量要求较高的场景。
SceneView 和 Filament 的区别(来自 ChatGPT ):
Google Filament 和 SceneView 都是 Android 中用于渲染 3D 图形的技术。它们的作用、区别和使用场景如下:
- Google Filament 的作用和使用场景Google Filament 是一款基于 C++ 的高性能渲染引擎,支持多种平台和设备。它提供了一系列的 API 和工具,可以帮助开发者快速构建出高质量的 3D 渲染效果。Google Filament 支持多种材质和光照模型,可以实现逼真的光照效果和物理模拟,同时也支持开发者自定义材质和着色器。Google Filament 的使用场景包括游戏开发、AR/VR 应用、工业设计、建筑可视化等领域。
- SceneView 的作用和使用场景SceneView 是 Android SDK 中提供的一个类,用于在 Android 应用中显示 3D 场景。SceneView 基于 OpenGL ES 技术,支持从多个角度观察 3D 场景、交互操作、光照效果等。开发者可以通过 SceneView 添加和管理 3D 模型、材质、光源等元素,并实现动画效果和用户交互。SceneView 的使用场景包括游戏开发、AR/VR 应用、教育、文化创意等领域。
- Google Filament 和 SceneView 的区别Google Filament 和 SceneView 都可以用于渲染 3D 图形,但它们在实现方式、特点和适用场景上有所不同。Google Filament 是一款独立的渲染引擎,需要开发者使用 C++ 语言编写代码,支持更为复杂的 3D 渲染效果和物理模拟,适用于对渲染性能和质量要求较高的场景。而 SceneView 是 Android SDK 中提供的一个类,使用 Java 语言编写代码,使用 OpenGL ES 进行渲染,适用于一些简单的 3D 场景展示和轻量级的游戏开发。
综上所述,Google Filament 和 SceneView 都可以用于渲染 3D 图形,但它们的实现方式、特点和适用场景有所不同。开发者可以根据具体的需求和技术水平选择合适的技术方案。