レンダリング可能なオブジェクトを作成する

Renderable は 3D モデルで、頂点、マテリアル、テクスチャなどで構成されます。Node にアタッチして、シーンの一部としてレンダリングできます。このページでは、Renderable を作成および変更する方法について説明します。

Android ウィジェットから作成する

標準の Android ウィジェットから ViewRenderable を作成できます。シーン内ではフラットカードとしてレンダリングされます。

鍵を作成するには:

  1. res > layout にレイアウト ファイルを作成します。例:

    <TextView xmlns:android="http://schemas.android.com/apk/res/android"
       
    android:id="@+id/planetInfoCard"
       
    android:layout_width="wrap_content"
       
    android:layout_height="wrap_content"
       
    android:layout_weight="1"
       
    android:background="@drawable/rounded_bg"
       
    android:gravity="center"
       
    android:orientation="vertical"
       
    android:padding="6dp"
       
    android:text="Test"
       
    android:textAlignment="center" />
  2. ViewRenderable をビルドします。

    ViewRenderable.builder()
       
    .setView(this, R.layout.test_view)
       
    .build()
       
    .thenAccept(renderable -> testViewRenderable = renderable);

    このバージョンの setView() は、インフレートされたレイアウト ファイルのリソース ID を受け取ります。また、setView(View) を呼び出して、プログラムで作成されたビューからレンダリング可能なものを作成することもできます。

シーンのすべての build() メソッドは CompletableFuture を返します。オブジェクトは別のスレッドでビルドされ、コールバック関数はメインスレッドで実行されます。

レンダリング可能なサイズは、View オブジェクトのサイズに基づきます。デフォルトでは、ビューの 250 dp ごとにレンダリング可能な範囲は 1 メートルになります。setSizer(ViewSizer) を使用して、ビューのサイズの計算方法を変更します。

基になるビューを変更すると、レンダリング可能な表示に影響します。レンダリング可能なビューが接続されたノードは、タップイベントをビューにディスパッチするため、ボタンのタップなどに応答できます。

// update button text when the renderable's node is tapped
Button button = (Button) renderable.getView();
button
.setOnClickListener((button) -> button.setText("clicked"));

3D アセットから作成する

Sceneform には、3D アセット ファイル(OBJ、FBX、glTF)を Sceneform バイナリ アセット(SFB)に変換するためのツールとプラグインが用意されており、これを ModelRenderable に組み込むことができます。

詳しくは、3D アセットのインポートとプレビューをご覧ください。

実行時にシンプルな図形を作成する

立方体、球体、円柱などのシンプルな図形を作成するには、ShapeFactoryMaterialFactory を使用します。これにより、シンプルな図形やマテリアルからレンダリング可能なオブジェクトを作成できます。

赤い球体を作成するには、次のようにします。

MaterialFactory.makeOpaqueWithColor(this, new Color(android.graphics.Color.RED))
       
.thenAccept(
            material
-> {
              redSphereRenderable
=
                 
ShapeFactory.makeSphere(0.1f, new Vector3(0.0f, 0.15f, 0.0f), material); });

3D モデルを実行時に読み込む

glTF または glb ファイルとして保存された 3D モデルは、変換なしで実行時に読み込むことができます。これにより、アプリケーションでレンダリングされるモデルの柔軟性が大幅に向上しますが、モデルは実行時に読み込まれるため、ビルド時に sfb に変換する際に行われる最適化のメリットが得られません。このため、ユーザーとデバイスが 3D モデルをさまざまなデバイスやネットワーク条件でテストして、ユーザーが快適に使用できるか確認することをおすすめします。

ランタイム アセットの読み込みを使用するには、app/build.gradle 内のアセット ライブラリへの依存関係を追加する必要があります。

  dependencies {
     implementation
'com.google.ar.sceneform:assets:1.15.0'
 
}

RenderableSource クラスは、glTF ファイルの読み込みと、レンダリング可能なオブジェクトを作成する ModelRenderable.Builder のソース オブジェクトの作成を処理します。

たとえば、インターネットからモデルを読み込むには、次のようになります。

 private static final String GLTF_ASSET =
   
"https://github.com/KhronosGroup/glTF-Sample-Models/raw/master/2.0/Duck/glTF/Duck.gltf";

 
/* When you build a Renderable, Sceneform loads model and related resources
 * in the background while returning a CompletableFuture.
 * Call thenAccept(), handle(), or check isDone() before calling get().
 */

 
ModelRenderable.builder()
   
.setSource(this, RenderableSource.builder().setSource(
           
this,
           
Uri.parse(GLTF_ASSET),
           
RenderableSource.SourceType.GLTF2)
           
.setScale(0.5f)  // Scale the original model to 50%.
           
.setRecenterMode(RenderableSource.RecenterMode.ROOT)
           
.build())
   
.setRegistryId(GLTF_ASSET)
   
.build()
   
.thenAccept(renderable -> duckRenderable = renderable)
   
.exceptionally(
        throwable
-> {
         
Toast toast =
             
Toast.makeText(this, "Unable to load renderable " +
              GLTF_ASSET
, Toast.LENGTH_LONG);
          toast
.setGravity(Gravity.CENTER, 0, 0);
          toast
.show();
         
return null;
       
});

: リモートからリソースにアクセスするには、AndroidManifest.xml にインターネット権限を含める必要があります。

    <manifest>
     
<!-- Needed to load a glTF from the internet. -->
       
<uses-permission android:name="android.permission.INTERNET"/>

   
</manifest>

実行時にレンダリング可能に変更する

複数のノードでレンダリング可能を使用している場合、そのレンダリング可能に対する変更はすべてのノードに適用されます。この動作を回避するには、makeCopy() を呼び出して、レンダリング可能なインスタンスを別途作成します。また、レンダリング可能なすべてのマテリアルで makeCopy() も呼び出されます。

blueSphereRenderable = redSphereRenderable.makeCopy();
blueSphereRenderable
.getMaterial().setFloat3(
                 
MaterialFactory.MATERIAL_COLOR, new Color(android.graphics.Color.BLUE));