Quickstart¶
Time: ~10 minutes | Goal: Go from an empty Android Studio project to a 3D model you can orbit with touch gestures.
Prerequisites¶
- Android Studio Ladybug (2024.2.1) or newer
- An Android device or emulator running API 24+
- Basic familiarity with Kotlin and Jetpack Compose
Step 1: Create a new project¶
- Open Android Studio and select New Project.
- Choose the Empty Activity template (the one that generates a
ComponentActivitywithsetContent). - Set the minimum SDK to API 24.
- Finish the wizard and let Gradle sync.
You should have a working Compose app that displays "Hello Android" or similar.
Step 2: Add the dependency¶
Open your app-level build.gradle.kts and add SceneView:
dependencies {
implementation("io.github.sceneview:sceneview:3.2.0")
}
Sync Gradle.
Step 3: Add a 3D model¶
You need a glTF/GLB file in the assets folder. The Damaged Helmet from Khronos is a good first model.
- Create the directory
app/src/main/assets/models/. - Download the model:
- Save it as
app/src/main/assets/models/damaged_helmet.glb.
Tip
Any .glb or .gltf file works. If you have your own model, drop it in the same folder and update the path in the next step.
Step 4: Write the Scene composable¶
Replace the contents of MainActivity.kt with the following:
package com.example.my3dapp
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.Modifier
import io.github.sceneview.Scene
import io.github.sceneview.rememberCameraManipulator
import io.github.sceneview.rememberEngine
import io.github.sceneview.rememberEnvironmentLoader
import io.github.sceneview.rememberModelInstance
import io.github.sceneview.rememberModelLoader
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val engine = rememberEngine()
val modelLoader = rememberModelLoader(engine)
val environmentLoader = rememberEnvironmentLoader(engine)
Scene(
modifier = Modifier.fillMaxSize(),
engine = engine,
modelLoader = modelLoader,
cameraManipulator = rememberCameraManipulator(),
) {
rememberModelInstance(modelLoader, "models/damaged_helmet.glb")
?.let { instance ->
ModelNode(
modelInstance = instance,
scaleToUnits = 1.0f,
autoAnimate = true,
)
}
}
}
}
}
That is the entire app. Here is what each piece does:
| Call | Purpose |
|---|---|
rememberEngine() |
Creates the Filament rendering engine (one per screen) |
rememberModelLoader(engine) |
Loads glTF/GLB models from assets |
rememberEnvironmentLoader(engine) |
Loads HDR environment maps for lighting |
rememberCameraManipulator() |
Adds built-in orbit, pan, and zoom touch gestures |
Scene { } |
The 3D viewport composable — nodes go inside the trailing lambda |
rememberModelInstance(...) |
Asynchronously loads a model; returns null until ready |
ModelNode(...) |
Places the loaded model in the scene |
Always handle the null case
rememberModelInstance returns null while the model is loading. The ?.let pattern shown above is the idiomatic way to handle this. Do not force-unwrap with !!.
Step 5: Run it¶
- Click Run (or press
Shift+F10). - After a brief loading moment, you will see the Damaged Helmet rendered in your viewport.
- Drag to orbit around the model, pinch to zoom, and two-finger drag to pan.
That is a production-quality, physically-based 3D viewer in under 30 lines of code.
Next steps¶
- Add HDR lighting — Download a
.hdrenvironment map and pass it viarememberEnvironment(environmentLoader) { environmentLoader.createHDREnvironment("environments/sky_2k.hdr")!! }to theenvironmentparameter ofScene. - Try AR — Follow the AR Compose codelab to place models in the real world using
ARScene. - Explore the samples — The samples page covers model animation, camera manipulation, cloud anchors, and more.
- Browse the API — See the full API reference for every composable, node type, and loader.