シーンを作成して操作する

このページでは、Sceneを構築して操作するための一般的なヒントについて説明します。

AR なしでシーンをレンダリングする

SceneView クラスを使用すると、デバイスのカメラや AR セッションを使用せずに 3D シーンをレンダリングできます。これは、アプリで AR を使用せずに 3D オブジェクトをプレビューする場合や、AR をサポートしていないデバイスで代替機能を提供する場合に役立ちます。

デフォルトでは、SceneView は AR カメラからの画像を表示せず、背景が黒くなります。背景色を変更するには、view.setBackgroundColor() を呼び出すか、次のようにレイアウト内で背景色を定義します。

<com.google.ar.sceneform.SceneView
   
android:id="@+id/scene_view"
   
android:layout_width="match_parent"
   
android:layout_height="match_parent"
   
android:background="@color/deep_teal"/>

シーンの Camera ノードは原点(位置 0,0,0)に配置され、前方(方向 0,0,-1)に配置されます。カメラの位置と回転は AR モーション トラッキングとは関連付けられていないため、他のノードと同じようにカメラの位置やアニメーションを変更できます。

Camera camera = sceneView.getScene().getCamera();
camera
.setLocalRotation(Quaternion.axisAngle(Vector3.right(), -30.0f));

ユーザーの操作

ユーザー タップの処理

ユーザーが画面にタッチすると、シーンとノードおよびシーンにアタッチされたイベント ハンドラとリスナーにタッチイベントが伝播されます。この動作は、タップイベントが Android のビューやビューグループに伝播する仕組みに似ています。伝播の順番は次のとおりです。

  1. イベントは、scene.addOnPeekTouchListener() に追加されたリスナーに送信されます。

    これは、ピークタップ リスナーのシーンがイベントを利用できない点を除いて、viewGroup.intercept() と似ています。

  2. イベントは、レイが交差する最初のノードに渡されます。

    • ノードは、true を返す onTouchEvent() メソッドセットを定義することで、イベントを使用できます。
    • onTouchEvent() メソッドが false を返す場合、またはリスナーが定義されていない場合、イベントはノードの親に伝播されます。このプロセスは、イベントが使用されるかシーンに達するまで続きます。
  3. 最後に、どのリスナーもイベントを使用していない場合は、イベントは scene.onTouchListener() に渡されます。

操作の検出

ArFragment には、タップ(選択)、ドラッグ(移動)、ピンチ(拡大)、回転(回転)のサポートが組み込まれています。

例については、HelloSceneform サンプルアプリの HelloSceneformActivity.java をご覧ください。

カスタムノードを作成する

カスタム Android ビューの作成と同様に、Node をサブクラス化することでカスタムノードを作成できます。次のような場合はカスタムノードを作成できます。

  • ノードのライフサイクルで onUpdate()onActivateonDeactivate() などのイベントにアクセスする場合。
  • ノードのグループで構成されるノードを作成する。
  • 多くのコードを複製するため、サブクラスに分解できます。

例については、ソーラーシステム サンプルアプリPlanet.java をご覧ください。

ノードのアニメーション化

ノードをアニメーション化するには、次の 2 つの方法があります。

ObjectAnimator でアニメーション化する

以下は、スポットライトの強さをアニメーション化する例です。

final int durationInMilliseconds = 1000;
final float minimumIntensity = 1000.0f;
final float maximumIntensity = 3000.0f;
ValueAnimator intensityAnimator =
   
ObjectAnimator.ofFloat(
        spotlightNode
.getLight(), "intensity", minimumIntensity, maximumIntensity);
intensityAnimator
.setDuration(durationInMilliseconds);
intensityAnimator
.setRepeatCount(ValueAnimator.INFINITE);
intensityAnimator
.setRepeatMode(ValueAnimator.REVERSE);
intensityAnimator
.start();

詳細については、ObjectAnimator を使用したアニメーション化をご覧ください。

onUpdate でのアニメーション

ノードの onUpdate() をオーバーライドして、フレームごとにアニメーション化します。次の例では、Solar System サンプルアプリの Planet.java から、地球が回転した場合でも、フレームごとに情報カードを調整し、ユーザーに合わせて表示しています。

@Override
public void onUpdate(FrameTime frameTime) {
 
Vector3 cameraPosition = getScene().getCamera().getWorldPosition();
 
Vector3 cardPosition = infoCard.getWorldPosition();
 
Vector3 direction = Vector3.subtract(cameraPosition, cardPosition);
 
Quaternion lookRotation = Quaternion.lookRotation(direction, Vector3.up());
  infoCard
.setWorldRotation(lookRotation);
}

照明を追加する

Lights は、シーン内の任意のノードにアタッチできます。デフォルトでは、すべてのシーンシーンに Sun ノードが含まれており、このノードにディレクショナル ライトが接続されています。

太陽光を変更したり、シーンに独自の照明を追加したりできます。次の例では、スポットライトが追加されます。

Light spotLightYellow =
   
Light.builder(this, Light.Type.FOCUSED_SPOTLIGHT)
       
.setColor(new Color(android.graphics.Color.YELLOW))
       
.setShadowCastingEnabled(true)
       
.build();

次に、setLight() を呼び出して、ノードに接続します。

プレーン ビジュアリゼーションのカスタマイズ

デフォルトでは、シーンに ARCore で検出された PlaneRenderer がハイライト表示されます。Planesたとえば、次のようになります。

検出された平面のレンダリングに使用するデフォルトのマテリアルとテクスチャを変更できます。テクスチャの変更方法は次のとおりです。

Texture.Sampler sampler =
       
Texture.Sampler.builder()
               
.setMinFilter(Texture.Sampler.MinFilter.LINEAR)
               
.setWrapMode(Texture.Sampler.WrapMode.REPEAT)
               
.build();

// R.drawable.custom_texture is a .png file in src/main/res/drawable
Texture.builder()
       
.setSource(this, R.drawable.custom_texture)
       
.setSampler(sampler)
       
.build()
       
.thenAccept(texture -> {
          arSceneView
.getPlaneRenderer()
                 
.getMaterial().thenAccept(material ->
                  material
.setTexture(PlaneRenderer.MATERIAL_TEXTURE, texture));
       
});

シャドウ

シャドウを使用すると、レンダリング可能なものが現実世界に埋もれて見えるようになり、ユーザーが奥行きや空間を感じることができます。

シーンには、シャドウをキャストできるオブジェクトと、シャドウを受信できるオブジェクトがあります。

  • LightsRenderables はシャドウをキャストできます。

    影のキャストは、デフォルトでは太陽では有効になっていますが、照明では有効になっていません。setShadowCastingEnabled() を呼び出してオンにします。

  • RenderablesPlaneRenderer はシャドウを受信できます。

    デフォルトでは、シャドウの受信が有効になっています。オフにするには、setShadowReceiver() を呼び出します。

レンダリング可能なものがシャドウをキャストして受け取る場合、シャドウ自体もキャストできます。