Filament provides first-class support for Android with Java/Kotlin bindings and Maven distribution. This guide covers setup, initialization, and rendering on Android.
Installation
Maven Dependencies
Add Filament libraries to your Android project using Maven Central:
repositories {
mavenCentral()
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.69.4'
}
Available Libraries
Filament provides several Android libraries in the com.google.android.filament group:
Artifact Description filament-androidThe core Filament rendering engine filament-android-debugDebug version with additional validation gltfio-androidglTF 2.0 loader for Filament filament-utils-androidKTX loading, Kotlin math, and camera utilities filamat-androidRuntime material builder/compiler
Initialization
Always initialize Filament before using any APIs:
class MainActivity : Activity () {
companion object {
init {
Filament. init ()
}
}
}
You must call Filament.init() before creating any Filament resources. This loads the JNI library needed by the API.
Basic Setup
Create the rendering surface
Set up a SurfaceView for rendering: private lateinit var surfaceView: SurfaceView
private lateinit var uiHelper: UiHelper
private lateinit var choreographer: Choreographer
override fun onCreate (savedInstanceState: Bundle ?) {
super . onCreate (savedInstanceState)
surfaceView = SurfaceView ( this )
setContentView (surfaceView)
choreographer = Choreographer. getInstance ()
setupSurfaceView ()
}
Configure UiHelper
Use UiHelper to manage the surface lifecycle: private fun setupSurfaceView () {
uiHelper = UiHelper (UiHelper.ContextErrorPolicy.DONT_CHECK)
uiHelper.renderCallback = SurfaceCallback ()
// Optional: set a specific resolution
// uiHelper.setDesiredSize(1280, 720)
uiHelper. attachTo (surfaceView)
}
Create Engine and components
Initialize the Filament engine, renderer, and scene: private lateinit var engine: Engine
private lateinit var renderer: Renderer
private lateinit var scene: Scene
private lateinit var view: View
private lateinit var camera: Camera
private fun setupFilament () {
engine = Engine. Builder ()
. featureLevel (Engine.FeatureLevel.FEATURE_LEVEL_0)
. build ()
renderer = engine. createRenderer ()
scene = engine. createScene ()
view = engine. createView ()
camera = engine. createCamera (engine.entityManager. create ())
view.camera = camera
view.scene = scene
}
UiHelper and SwapChain Management
The UiHelper class simplifies SwapChain management for SurfaceView, TextureView, or SurfaceHolder:
inner class SurfaceCallback : UiHelper . RendererCallback {
override fun onNativeWindowChanged (surface: Surface ) {
swapChain?. let { engine. destroySwapChain (it) }
var flags = uiHelper.swapChainFlags
if (engine.activeFeatureLevel == Engine.FeatureLevel.FEATURE_LEVEL_0) {
if (SwapChain. isSRGBSwapChainSupported (engine)) {
flags = flags or SwapChainFlags.CONFIG_SRGB_COLORSPACE
}
}
swapChain = engine. createSwapChain (surface, flags)
displayHelper. attach (renderer, surfaceView.display)
}
override fun onDetachedFromSurface () {
displayHelper. detach ()
swapChain?. let {
engine. destroySwapChain (it)
engine. flushAndWait ()
swapChain = null
}
}
override fun onResized (width: Int , height: Int ) {
view.viewport = Viewport ( 0 , 0 , width, height)
val aspect = width. toDouble () / height. toDouble ()
camera. setProjection (
Camera.Projection.PERSPECTIVE,
45.0 , aspect, 0.1 , 100.0
)
FilamentHelper. synchronizePendingFrames (engine)
}
}
Rendering Loop
Use Choreographer to schedule frames at vsync:
inner class FrameCallback : Choreographer . FrameCallback {
override fun doFrame (frameTimeNanos: Long ) {
choreographer. postFrameCallback ( this )
if (uiHelper.isReadyToRender) {
if (renderer. beginFrame (swapChain !! , frameTimeNanos)) {
renderer. render (view)
renderer. endFrame ()
}
}
}
}
override fun onResume () {
super . onResume ()
choreographer. postFrameCallback (frameScheduler)
}
override fun onPause () {
super . onPause ()
choreographer. removeFrameCallback (frameScheduler)
}
Creating Geometry
Example of creating a simple triangle mesh:
Vertex Data
Vertex Buffer
Index Buffer
data class Vertex ( val x: Float , val y: Float , val z: Float , val color: Int )
val vertexCount = 3
val vertexSize = 3 * 4 + 4 // 3 floats + 1 int
val vertexData = ByteBuffer. allocate (vertexCount * vertexSize)
. order (ByteOrder. nativeOrder ())
. apply {
put ( Vertex ( 1.0f , 0.0f , 0.0f , 0xffff0000 . toInt ()))
put ( Vertex ( - 0.5f , 0.866f , 0.0f , 0xff00ff00 . toInt ()))
put ( Vertex ( - 0.5f , - 0.866f , 0.0f , 0xff0000ff . toInt ()))
}
. flip ()
fun ByteBuffer . put (v: Vertex ): ByteBuffer {
putFloat (v.x)
putFloat (v.y)
putFloat (v.z)
putInt (v.color)
return this
}
Building Renderables
Create a renderable entity and add it to the scene:
val renderable = EntityManager. get (). create ()
RenderableManager. Builder ( 1 )
. boundingBox ( Box ( 0.0f , 0.0f , 0.0f , 1.0f , 1.0f , 0.01f ))
. geometry (
0 ,
PrimitiveType.TRIANGLES,
vertexBuffer,
indexBuffer,
0 ,
3
)
. material ( 0 , material.defaultInstance)
. build (engine, renderable)
scene. addEntity (renderable)
Material Loading
Load precompiled materials from assets:
private fun loadMaterial () {
val buffer = readUncompressedAsset ( "materials/baked_color.filamat" )
material = Material. Builder ()
. payload (buffer, buffer. remaining ())
. build (engine)
}
private fun readUncompressedAsset (assetName: String ): ByteBuffer {
assets. openFd (assetName). use { fd ->
val input = fd. createInputStream ()
val dst = ByteBuffer. allocate (fd.length. toInt ())
val src = Channels. newChannel (input)
src. read (dst)
src. close ()
return dst. apply { rewind () }
}
}
Cleanup
Always destroy resources in the correct order:
override fun onDestroy () {
super . onDestroy ()
choreographer. removeFrameCallback (frameScheduler)
uiHelper. detach ()
engine. destroyEntity (renderable)
engine. destroyRenderer (renderer)
engine. destroyVertexBuffer (vertexBuffer)
engine. destroyIndexBuffer (indexBuffer)
engine. destroyMaterial (material)
engine. destroyView (view)
engine. destroyScene (scene)
engine. destroyCameraComponent (camera.entity)
val entityManager = EntityManager. get ()
entityManager. destroy (renderable)
entityManager. destroy (camera.entity)
engine. destroy ()
}
Backend Support
Filament on Android supports:
OpenGL ES 3.0+ - Wide device compatibility
Vulkan 1.0+ - Modern devices with better performance
The backend is selected automatically based on device capabilities.
Next Steps
glTF Loading Load 3D models using gltfio-android
Materials Create and customize materials
Lighting Set up lights and IBL
Camera Configure camera and projection