Skip to content

SceneScope.MeshNode lacks boundingBox parameter for custom geometry #711

@becmer

Description

@becmer

What happened?

Geometry.Builder computes a valid boundingBox, and the underlying MeshNode class accepts boundingBox and passes it into RenderableManager.Builder. However, the SceneScope.MeshNode(...) composable does not expose any boundingBox parameter, so callers cannot forward the computed box when creating custom meshes.

This causes Filament to abort during renderable construction with:

AABB can't be empty, unless culling is disabled and the object is not a shadow caster/receiver

What did you expect?

SceneScope.MeshNode(...) should expose a boundingBox: Box? = null parameter and forward it to MeshNodeImpl. There is no way to pass the computed geometry.boundingBox, so the renderable is built without a valid AABB and crashes. Add boundingBox to the composable signature and pass it through to the node constructor.

Minimal reproduction

package com.example

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import com.google.android.filament.RenderableManager
import com.google.android.filament.Skybox
import io.github.sceneview.Scene
import io.github.sceneview.createEnvironment
import io.github.sceneview.geometries.Geometry
import io.github.sceneview.geometries.UvCoordinate
import io.github.sceneview.math.Direction
import io.github.sceneview.math.Position
import io.github.sceneview.math.Rotation
import io.github.sceneview.rememberCameraNode
import io.github.sceneview.rememberEngine
import io.github.sceneview.rememberEnvironment
import io.github.sceneview.rememberEnvironmentLoader
import io.github.sceneview.rememberMainLightNode
import io.github.sceneview.rememberMaterialLoader

class MainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            val engine = rememberEngine()
            val materialLoader = rememberMaterialLoader(engine)
            val environmentLoader = rememberEnvironmentLoader(engine)

            val material = remember(materialLoader) {
                materialLoader.createColorInstance(Color.Red)
            }

            val customCubeGeometry = remember(engine) {
                val h = 0.5f
                val vertices = listOf(
                    // Front (z+) - CCW
                    Geometry.Vertex(
                        Position(-h, -h, h),
                        Direction(0f, 0f, 1f),
                        UvCoordinate(0f, 1f)
                    ),
                    Geometry.Vertex(
                        Position(h, -h, h),
                        Direction(0f, 0f, 1f),
                        UvCoordinate(1f, 1f)
                    ),
                    Geometry.Vertex(
                        Position(h, h, h),
                        Direction(0f, 0f, 1f),
                        UvCoordinate(1f, 0f)
                    ),
                    Geometry.Vertex(
                        Position(-h, h, h),
                        Direction(0f, 0f, 1f),
                        UvCoordinate(0f, 0f)
                    ),
                    // Back (z-) - CCW
                    Geometry.Vertex(
                        Position(h, -h, -h),
                        Direction(0f, 0f, -1f),
                        UvCoordinate(0f, 1f)
                    ),
                    Geometry.Vertex(
                        Position(-h, -h, -h),
                        Direction(0f, 0f, -1f),
                        UvCoordinate(1f, 1f)
                    ),
                    Geometry.Vertex(
                        Position(-h, h, -h),
                        Direction(0f, 0f, -1f),
                        UvCoordinate(1f, 0f)
                    ),
                    Geometry.Vertex(
                        Position(h, h, -h),
                        Direction(0f, 0f, -1f),
                        UvCoordinate(0f, 0f)
                    ),
                    // Top (y+)
                    Geometry.Vertex(
                        Position(-h, h, h),
                        Direction(0f, 1f, 0f),
                        UvCoordinate(0f, 1f)
                    ),
                    Geometry.Vertex(
                        Position(h, h, h),
                        Direction(0f, 1f, 0f),
                        UvCoordinate(1f, 1f)
                    ),
                    Geometry.Vertex(
                        Position(h, h, -h),
                        Direction(0f, 1f, 0f),
                        UvCoordinate(1f, 0f)
                    ),
                    Geometry.Vertex(
                        Position(-h, h, -h),
                        Direction(0f, 1f, 0f),
                        UvCoordinate(0f, 0f)
                    ),
                    // Bottom (y-)
                    Geometry.Vertex(
                        Position(-h, -h, -h),
                        Direction(0f, -1f, 0f),
                        UvCoordinate(0f, 1f)
                    ),
                    Geometry.Vertex(
                        Position(h, -h, -h),
                        Direction(0f, -1f, 0f),
                        UvCoordinate(1f, 1f)
                    ),
                    Geometry.Vertex(
                        Position(h, -h, h),
                        Direction(0f, -1f, 0f),
                        UvCoordinate(1f, 0f)
                    ),
                    Geometry.Vertex(
                        Position(-h, -h, h),
                        Direction(0f, -1f, 0f),
                        UvCoordinate(0f, 0f)
                    ),
                    // Right (x+)
                    Geometry.Vertex(
                        Position(h, -h, h),
                        Direction(1f, 0f, 0f),
                        UvCoordinate(0f, 1f)
                    ),
                    Geometry.Vertex(
                        Position(h, -h, -h),
                        Direction(1f, 0f, 0f),
                        UvCoordinate(1f, 1f)
                    ),
                    Geometry.Vertex(
                        Position(h, h, -h),
                        Direction(1f, 0f, 0f),
                        UvCoordinate(1f, 0f)
                    ),
                    Geometry.Vertex(
                        Position(h, h, h),
                        Direction(1f, 0f, 0f),
                        UvCoordinate(0f, 0f)
                    ),
                    // Left (x-)
                    Geometry.Vertex(
                        Position(-h, -h, -h),
                        Direction(-1f, 0f, 0f),
                        UvCoordinate(0f, 1f)
                    ),
                    Geometry.Vertex(
                        Position(-h, -h, h),
                        Direction(-1f, 0f, 0f),
                        UvCoordinate(1f, 1f)
                    ),
                    Geometry.Vertex(
                        Position(-h, h, h),
                        Direction(-1f, 0f, 0f),
                        UvCoordinate(1f, 0f)
                    ),
                    Geometry.Vertex(
                        Position(-h, h, -h),
                        Direction(-1f, 0f, 0f),
                        UvCoordinate(0f, 0f)
                    )
                )
                val indices = listOf(
                    0, 1, 2, 0, 2, 3,       // Front
                    4, 5, 6, 4, 6, 7,       // Back
                    8, 9, 10, 8, 10, 11,    // Top
                    12, 13, 14, 12, 14, 15, // Bottom
                    16, 17, 18, 16, 18, 19, // Right
                    20, 21, 22, 20, 22, 23  // Left
                )
                Geometry.Builder()
                    .vertices(vertices)
                    .indices(indices)
                    .build(engine)
            }

            val environment = rememberEnvironment(environmentLoader) {
                createEnvironment(
                    engine = engine,
                    isOpaque = true,
                    skybox = Skybox.Builder()
                        .color(0.3f, 0.5f, 0.7f, 1.0f)
                        .build(engine)
                )
            }

            Scene(
                modifier = Modifier.fillMaxSize(),
                engine = engine,
                environment = environment,
                cameraNode = rememberCameraNode(engine) {
                    position = Position(z = 4.0f)
                },
                mainLightNode = rememberMainLightNode(engine) {
                    intensity = 100_000.0f
                },
                cameraManipulator = null
            ) {
                MeshNode(
                    primitiveType = RenderableManager.PrimitiveType.TRIANGLES,
                    vertexBuffer = customCubeGeometry.vertexBuffer,
                    indexBuffer = customCubeGeometry.indexBuffer,
                    boundingBox = customCubeGeometry.boundingBox,
                    materialInstance = material,
                    apply = {
                        rotation = Rotation(45f, 45f, 0f)
                    }
                )
            }
        }
    }
}

SceneView version

3.3.0

Module

sceneview (3D only)

Logs / stack trace


Device / OS

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions