ARCore学习三:SceneForm

565 阅读2分钟

ARCore支持Java, C, Unity以及Unreal这几种开发方式。在Java SDK中新增了SceneForm api来支持渲染。这确实是一个比较大的进步,毕竟裸写OpenGL还是有点麻烦的。

Sceneform 是一个 3D 框架,让您无需 OpenGL 即可轻松构建 ARCore 应用。它会在执行必要的 ARCore 运行时检查后自动处理 ARCore 会话管理:

  1. 检查是否安装了兼容版本的 [Google Play Services for AR],必要时提示用户安装或更新
  2. 检查应用是否有权访问相机,并在应用尚未获得授权时请求用户权限

检查通过后,ArFragment 会创建:

  1. 可通过 getArSceneView() 访问的 ArSceneView

    • 将会话中的相机图像渲染到其表面上
    • 呈现内置 Sceneform 用户体验动画,向用户展示应如何移动手机以激活 AR 体验。
    • 使用默认的 PlaneRenderer Planes 检测到突出显示内容
  2. 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

附:SceneForm 1.5官网