ARCore支持Java, C, Unity以及Unreal这几种开发方式。在Java SDK中新增了SceneForm api来支持渲染。这确实是一个比较大的进步,毕竟裸写OpenGL还是有点麻烦的。
Sceneform 是一个 3D 框架,让您无需 OpenGL 即可轻松构建 ARCore 应用。它会在执行必要的 ARCore 运行时检查后自动处理 ARCore 会话管理:
- 检查是否安装了兼容版本的 [Google Play Services for AR],必要时提示用户安装或更新
- 检查应用是否有权访问相机,并在应用尚未获得授权时请求用户权限
检查通过后,ArFragment 会创建:
-
可通过
getArSceneView()访问的ArSceneView:- 将会话中的相机图像渲染到其表面上
- 呈现内置 Sceneform 用户体验动画,向用户展示应如何移动手机以激活 AR 体验。
- 使用默认的
PlaneRendererPlanes检测到突出显示内容
-
ARCore
Session,可通过getSession()访问
<fragment android:name="com.google.ar.sceneform.ux.ArFragment"
android:id="@+id/ux_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Node node = new Node();
node.setParent(arFragment.getArSceneView().getScene());
node.setRenderable(andyRenderable);
ARSceneView 已附加 Scene。场景是一种树状数据结构,其中包含要呈现的虚拟对象的 Node。
每个节点都包含 Sceneform 对其进行渲染(包括其位置、屏幕方向和可渲染对象)以及与其进行交互所需的所有信息(包括其冲突形状和事件监听器)。
可以将节点添加到其他节点,以形成父子关系。如果某个节点是另一个节点的子级,则该节点会随着其父级而移动、旋转和缩放,就像在身体移动时手臂会如何移动。一个节点可以有多个子级,但只能有一个父级,从而形成一种树状结构。这种结构称为场景图。
每一帧,Sceneform 都会从相机的视角(由 ARCore 运动跟踪指导)渲染场景图。您的应用可以通过监听触摸和手势事件、针对节点执行命中测试以及放置锚点来与场景互动
public class HelloSceneformActivity extends AppCompatActivity {
private static final String TAG = GltfActivity.class.getSimpleName();
private static final double MIN_OPENGL_VERSION = 3.0;
private ArFragment arFragment;
private ModelRenderable andyRenderable;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (!checkIsSupportedDeviceOrFinish(this)) {
return;
}
setContentView(R.layout.activity_ux);
arFragment = (ArFragment) getSupportFragmentManager().findFragmentById(R.id.ux_fragment);
// When you build a Renderable, Sceneform loads its resources in the background while returning
// a CompletableFuture. Call thenAccept(), handle(), or check isDone() before calling get().
ModelRenderable.builder()
.setSource(this, Uri.parse(
"https://gitee.com/XiaoShiTou123/gltf/raw/master/glTF/model.glb"))
.build()
.thenAccept(renderable -> andyRenderable = renderable)
.exceptionally(
throwable -> {
Toast toast =
Toast.makeText(this, "Unable to load andy renderable", Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();
return null;
});
arFragment.setOnTapArPlaneListener(
(HitResult hitResult, Plane plane, MotionEvent motionEvent) -> {
if (andyRenderable == null) {
return;
}
// Create the Anchor.
Anchor anchor = hitResult.createAnchor();
AnchorNode anchorNode = new AnchorNode(anchor);
anchorNode.setParent(arFragment.getArSceneView().getScene());
// Create the transformable andy and add it to the anchor.
TransformableNode andy = new TransformableNode(arFragment.getTransformationSystem());
andy.setParent(anchorNode);
andy.setRenderable(andyRenderable);
andy.select();
});
}
public static boolean checkIsSupportedDeviceOrFinish(final Activity activity) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
Log.e(TAG, "Sceneform requires Android N or later");
Toast.makeText(activity, "Sceneform requires Android N or later", Toast.LENGTH_LONG).show();
activity.finish();
return false;
}
String openGlVersionString =
((ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE))
.getDeviceConfigurationInfo()
.getGlEsVersion();
if (Double.parseDouble(openGlVersionString) < MIN_OPENGL_VERSION) {
Log.e(TAG, "Sceneform requires OpenGL ES 3.0 later");
Toast.makeText(activity, "Sceneform requires OpenGL ES 3.0 or later", Toast.LENGTH_LONG)
.show();
activity.finish();
return false;
}
return true;
}
}
ArFragment ArSceneView SceneView Scene
ModelRenderable
ViewRenderable