Search code examples
androidsceneform

Centering a GLB model in Sceneform 1.16.0


How do I center a GLB model on the Android device screen programmatically now that RenderableSource.Builder().setRecenterMode() has been removed?

This is how I used to do it in Sceneform 1.15/1.17.1.

ModelRenderable.builder()
    .setSource(
    context,
    RenderableSource.Builder().setSource(context, Uri.parse(uri), RenderableSource.SourceType.GLB)
        .setScale(1f)
        .setRecenterMode(RenderableSource.RecenterMode.CENTER)
        .build()
    )
    .setRegistryId(uri)
    .build()
    .thenAccept { modelRenderable: ModelRenderable ->

Solution

  • Working solution adapted from SceneView: https://github.com/SceneView/sceneview-android/blob/5ede719cf10c6b72764500366802147d7323aa3f/sceneview/src/main/java/io/github/sceneview/node/ModelNode.kt#L361-L377

    /**
     * Centers the 3D model.
     *
     * @param origin Coordinate inside the model unit cube from where it is centered
     * - defaults to [0, 0, 0], which will center the model on the origin
     * - center horizontal | bottom aligned = [0, -1, 0]
     * - left | top aligned: [-1, 1, 0]
     */
    fun Node.setCenter(origin: Float3 = Float3(0f, 0f, 0f)) {
        renderableInstance?.filamentAsset?.let { asset ->
            val center = asset.boundingBox.center.let { v -> Float3(v[0], v[1], v[2]) }
            val halfExtent = asset.boundingBox.halfExtent.let { v -> Float3(v[0], v[1], v[2]) }
            val fCenter = -(center + halfExtent * origin) * Float3(1f, 1f, 1f)
            localPosition = Vector3(fCenter.x, fCenter.y, fCenter.z)
        }
    }
    
    object Constants {
        const val DEFAULT_RADIUS = 1f
    }
    
    operator fun Float3.plus(v: Float3) = Float3(x + v.x, y + v.y, z + v.z)
    operator fun Float3.minus(v: Float3) = Float3(x - v.x, y - v.y, z - v.z)
    operator fun Float3.times(v: Float3) = Float3(x * v.x, y * v.y, z * v.z)
    operator fun Float3.unaryMinus() = Float3(-x, -y, -z)