You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

Android Compose中SceneView 3D骰子背景透明问题求助

解决Compose中SceneView 3D骰子背景透明问题

针对你遇到的SceneView始终显示黑色背景、无法透出下方Compose图层的问题,可通过以下关键修改实现透明背景:

1. 配置Engine启用透明背景

创建rememberEngine时,指定透明的清除色,避免引擎自动填充黑色:

val engine = rememberEngine {
    renderConfig = RenderConfig(
        clearColor = Color(0, 0, 0, 0), // 完全透明的清除色
        clearFlags = ClearFlag.COLOR or ClearFlag.DEPTH // 保留深度缓冲清除,保证3D渲染正确性
    )
}

2. 禁用Environment背景层

明确设置环境背景为无,避免默认的不透明背景覆盖:

environment = rememberEnvironment(environmentLoader, isOpaque = false) {
    background = Background.NONE
}

3. 简化SceneView修饰符

移除多余的.background(Color.Transparent),SceneView自身透明后会直接透出下方Compose内容:

SceneView(
    modifier = modifier,
    // 其他参数保持不变
)

修改后的完整代码

fun Dice3DScene(result: Int, isRolling: Boolean, modifier: Modifier = Modifier) {
    val engine = rememberEngine {
        renderConfig = RenderConfig(
            clearColor = Color(0, 0, 0, 0),
            clearFlags = ClearFlag.COLOR or ClearFlag.DEPTH
        )
    }
    val modelLoader = rememberModelLoader(engine)
    val environmentLoader = rememberEnvironmentLoader(engine)

    var modelNode by remember { mutableStateOf<ModelNodeImpl?>(null) }
    var prevFrameTime by remember { mutableStateOf<Long?>(null) }

    val rotations = mapOf(
        1 to Rotation(0f, 0f, 0f),
        2 to Rotation(0f, 90f, 0f),
        3 to Rotation(90f, 0f, 0f),
        4 to Rotation(-90f, 0f, 0f),
        5 to Rotation(0f, -90f, 0f),
        6 to Rotation(180f, 0f, 0f)
    )

    SceneView(
        modifier = modifier,
        engine = engine,
        modelLoader = modelLoader,
        isOpaque = false,
        surfaceType = SurfaceType.TextureSurface,
        environment = rememberEnvironment(environmentLoader, isOpaque = false) {
            background = Background.NONE
        },
        cameraNode = rememberCameraNode(engine) {
            position = Position(z = 4.0f)
        },
        onFrame = { frameTimeNanos ->
            modelNode?.let { node ->
                if (isRolling) {
                    val delta = (frameTimeNanos.intervalSeconds(prevFrameTime) * 1000.0).toFloat()
                    node.rotation = Rotation(
                        x = node.rotation.x + delta,
                        y = node.rotation.y + delta * 1.5f,
                        z = node.rotation.z + delta * 0.5f
                    )
                } else {
                    val target = rotations[result] ?: Rotation(0f, 0f, 0f)
                    node.rotation = Rotation(
                        x = lerpAngle(node.rotation.x % 360f, target.x, 0.1f),
                        y = lerpAngle(node.rotation.y % 360f, target.y, 0.1f),
                        z = lerpAngle(node.rotation.z % 360f, target.z, 0.1f)
                    )
                }
            }
            prevFrameTime = frameTimeNanos
        }
    ) {
        LightNode(
            type = LightManager.Type.DIRECTIONAL,
            intensity = 100_000f,
            direction = Direction(-1f, -1f, -1f)
        )

        rememberModelInstance(modelLoader, "dice.glb")?.let { modelInstance ->
            ModelNode(
                modelInstance = modelInstance,
                scaleToUnits = 1.0f,
                centerOrigin = Position(0f, 0f, 0f),
                apply = {
                    modelNode = this
                }
            )
        }
    }
}

核心逻辑说明

  • 引擎清除色设为全透明,从根源阻止黑色背景填充
  • 禁用环境背景层,避免额外的不透明覆盖
  • 依赖SceneView自身的透明属性透出下方Compose内容,无需额外背景修饰

内容的提问来源于stack exchange,提问作者Daniel Espinosa

火山引擎 最新活动