SceneView vs. the alternatives¶
An honest comparison for developers evaluating 3D and AR options.
The landscape¶
| Library | Approach | Status |
|---|---|---|
| SceneView | Jetpack Compose composables, Filament + ARCore | Active, v3.2.0 |
| Google Sceneform | View-based, custom renderer, ARCore | Abandoned (archived 2021) |
| Raw ARCore SDK | Low-level session/frame API, bring your own renderer | Active but no UI layer |
| Unity | Full game engine embedded via UnityPlayerActivity |
Active, heavy |
| Rajawali | OpenGL ES wrapper, imperative scene graph | Maintenance mode |
Side-by-side: adding a 3D model viewer¶
// build.gradle
implementation("io.github.sceneview:sceneview:3.2.0")
// One composable
@Composable
fun ModelViewer() {
val engine = rememberEngine()
val modelLoader = rememberModelLoader(engine)
val model = rememberModelInstance(modelLoader, "models/helmet.glb")
Scene(
modifier = Modifier.fillMaxSize(),
engine = engine,
modelLoader = modelLoader,
cameraManipulator = rememberCameraManipulator()
) {
model?.let { ModelNode(modelInstance = it, scaleToUnits = 1.0f) }
}
}
~15 lines · 1 file · 0 XML · 0 lifecycle callbacks · 0 manual cleanup
// XML layout required
// <fragment android:name="com.google.ar.sceneform.ux.ArFragment" />
class ModelViewerActivity : AppCompatActivity() {
private lateinit var arFragment: ArFragment
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_model_viewer)
arFragment = supportFragmentManager
.findFragmentById(R.id.arFragment) as ArFragment
arFragment.setOnTapArPlaneListener { hitResult, _, _ ->
val anchor = hitResult.createAnchor()
ModelRenderable.builder()
.setSource(this, Uri.parse("helmet.sfb"))
.build()
.thenAccept { renderable ->
val anchorNode = AnchorNode(anchor)
anchorNode.setParent(arFragment.arSceneView.scene)
val modelNode = TransformableNode(
arFragment.transformationSystem)
modelNode.renderable = renderable
modelNode.setParent(anchorNode)
}
}
}
override fun onResume() { super.onResume() }
override fun onPause() { super.onPause() }
override fun onDestroy() { super.onDestroy() }
}
~80+ lines · 3+ files · Manual lifecycle · .sfb format deprecated
// You get a Session, Frame, and Camera. That's it.
// Bring your own renderer (OpenGL ES or Vulkan).
// Manage GL surface, shader compilation, mesh uploading,
// lighting, shadows, and frame timing yourself.
500–1000+ lines before rendering a single triangle
// Unity export as Android library
implementation(project(":unityLibrary"))
class UnityViewerActivity : UnityPlayerActivity() {
// All logic in C# inside Unity
}
40–350 MB APK overhead · No Compose integration · Separate build pipeline
Feature matrix¶
| Feature | SceneView | Sceneform | Raw ARCore | Unity |
|---|---|---|---|---|
| Jetpack Compose | Native | No | No | No |
| Declarative nodes | Yes | No (imperative) | No API | No (C#) |
| Auto lifecycle | Yes | Manual | Manual | Unity-managed |
| PBR rendering | Filament | Limited | DIY | Unity renderer |
| glTF/GLB | Yes | .sfb (deprecated) | DIY | Yes |
| Physics | Built-in | No | No | Built-in |
| Post-processing | Bloom, DOF, SSAO | No | DIY | Yes |
| Dynamic sky | Yes | No | No | Yes (HDRP) |
| AR planes | Yes | Yes | Yes | Yes |
| AR image tracking | Yes | Yes | Yes | Yes |
| AR face tracking | Yes | Yes | Yes | Yes |
| Cloud anchors | Yes | Yes | Yes | Yes |
| Geospatial API | Yes | No | Yes | Yes |
| ViewNode (Compose in 3D) | Yes | No | No | No |
| AI tooling (MCP) | Yes | No | No | No |
| APK size impact | ~5 MB | ~3 MB | ~1 MB | 40–350 MB |
| Active maintenance | Yes | Abandoned | Yes |
Common objections¶
We already use Unity for 3D
Unity is right for 3D-first games. But for adding 3D to an existing Compose app — a product viewer, an AR feature, data visualization — Unity's 60–350 MB runtime, separate C# pipeline, and no Compose integration make it overkill. SceneView adds ~5 MB and works inside your existing Compose screens.
Can't we just use ARCore directly?
ARCore gives you tracking data (planes, anchors, poses) but no rendering. You'd need your own OpenGL/Vulkan renderer — months of work for a team with graphics expertise. SceneView gives you ARCore + Filament rendering, wrapped in Compose composables.
Sceneform worked fine for us
Google archived Sceneform in 2021. The .sfb format is deprecated. No Compose support.
No new ARCore features (geospatial, streetscape, depth). The community fork has unresolved
issues including 16 KB page size compliance required by Android 15 (API 35).
See the Migration guide for a step-by-step walkthrough.
Is it production-ready?
Yes. SceneView is built on Filament (Google's production rendering engine) and ARCore (Google's production AR platform). Used in production apps on Google Play. The API is stable and versioned with migration guides for breaking changes.
Migration from Sceneform¶
| Sceneform | SceneView |
|---|---|
ArFragment |
ARScene { } composable |
ModelRenderable.builder() |
rememberModelInstance(modelLoader, path) |
AnchorNode(anchor).setParent(scene) |
AnchorNode(anchor = a) { ... } |
TransformableNode |
ModelNode with gesture parameters |
.sfb model format |
.glb / .gltf (standard glTF) |
onResume / onPause / onDestroy |
Automatic (Compose lifecycle) |
node.setParent(null); node.destroy() |
Remove from composition |