# Create a Renderable

A
[`Renderable`](https://developers.google.com/sceneform/reference/com/google/ar/sceneform/rendering/Renderable)
is a 3D model and consists of vertices, materials, textures, and more. It can be
attached to a
[`Node`](https://developers.google.com/sceneform/reference/com/google/ar/sceneform/Node)
and rendered as part of a scene. This page describes how to create and modify
`Renderable`s.

## Create from Android widgets

You can create a
[`ViewRenderable`](https://developers.google.com/sceneform/reference/com/google/ar/sceneform/rendering/ViewRenderable)
from standard android widgets. These are rendered as flat cards in the scene.

To create one:

1. Create a layout file in **res \> layout**. For example:

       <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. Build the `ViewRenderable`.

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

   This version of
   [`setView()`](https://developers.google.com/sceneform/reference/com/google/ar/sceneform/rendering/ViewRenderable.Builder#setView(android.content.Context,%20int))
   takes the resource ID of the uninflated layout file. You can also call
   [`setView(View)`](https://developers.google.com/sceneform/reference/com/google/ar/sceneform/rendering/ViewRenderable.Builder#setView(android.content.Context,%20android.view.View))
   to create a renderable from programmatically created views.

All `build()` methods in Sceneform return a
[`CompletableFuture`](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html).
The object is built on a separate thread and the callback function is executed
on the main thread.

The size of the renderable is based on the size of the `View` object. By
default, every 250dp for the view becomes 1 meter for the renderable. Use
[`setSizer(ViewSizer)`](https://developers.google.com/sceneform/reference/com/google/ar/sceneform/rendering/ViewRenderable.Builder#public-viewrenderable.builder-setsizer-viewsizer-viewsizer)
to change how the size of the view is calculated.

Changes to the underlying view affect how the renderable is displayed. Nodes
with a view renderable attached will dispatch touch events to the view, so you
can, for example respond to a button press.

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

## Create from a 3D asset

Sceneform provides tools and plugins for converting 3D assets files (OBJ, FBX,
glTF) to Sceneform binary assets (SFB), which can then be built into a
[`ModelRenderable`](https://developers.google.com/sceneform/reference/com/google/ar/sceneform/rendering/ModelRenderable).

For more information, see [Import and Preview 3D Assets](https://developers.google.com/sceneform/develop/import-assets).

## Create simple shapes at runtime

Simple shapes such as cubes, spheres and cylinders can be created using
[`ShapeFactory`](https://developers.google.com/sceneform/reference/com/google/ar/sceneform/rendering/ShapeFactory)
and
[`MaterialFactory`](https://developers.google.com/sceneform/reference/com/google/ar/sceneform/rendering/MaterialFactory)
let your create renderable objects from simple shapes and materials.

Here's how to create a red sphere:

    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); });

## Load 3D models at runtime

3D models stored as `glTF` or `glb` files can be loaded at runtime without
conversion. This greatly improves the flexibility of the models rendered in your
application, but the trade-off is the model is read at runtime and does not
benefit from the optimization that is done during build time conversion to
`sfb`. Because of this, it is recommended you test your application and 3D
models on a wide range of devices and network conditions to make sure your users
have a great experience.

In order to use runtime asset loading you need to add the dependency on the
assets library in the `app/build.gradle`:

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

The
[`RenderableSource`](https://developers.google.com/sceneform/reference/com/google/ar/sceneform/assets/RenderableSource)
class handles loading the glTF file and creating a source object for
`ModelRenderable.Builder` that creates the renderable object.

For example, loading a model from the internet looks like this:

     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;
            });

**Note**: In order to access resources remotely, you need to include the
Internet permission in your AndroidManifest.xml:

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

        </manifest>

## Modify renderables at runtime

If multiple nodes use the renderable, then changes to that renderable apply to
all nodes. To avoid that behavior, call
[`makeCopy()`](https://developers.google.com/sceneform/reference/com/google/ar/sceneform/rendering/ModelRenderable#public-modelrenderable-makecopy-)
to create a separate renderable instance. Note this also calls
[`makeCopy()`](https://developers.google.com/sceneform/reference/com/google/ar/sceneform/rendering/ModelRenderable#public-modelrenderable-makecopy-)
on every material in the renderable.

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