SceneView / sceneview-android

SceneView is a 3D and AR Android Composable and View with Google Filament and ARCore. This is a Sceneform replacement in Kotlin
Apache License 2.0
758 stars 151 forks source link

3D Model doesn't rotate in Vertical 360 view in ARScene. #416

Closed UmerHamza closed 4 months ago

UmerHamza commented 4 months ago

I want to show 3D model on wall and rotate in 360 with changing of its floating size.but 3D model doesn't rotate vertically , its just rotate horizentally. i want to do this like its working in "Model view compose" sample app using ARScene. please help me in this.

const val kModelFile = "models/frame_1.glb" const val kMaxModelInstances = 9

@Composable fun ArScene1() { // Retrieve data from next screen

Box(
    modifier = Modifier.fillMaxSize(),
) {
    // The destroy calls are automatically made when their disposable effect leaves
    // the composition or its key changes.
    val engine = rememberEngine()
    val modelLoader = rememberModelLoader(engine)
    val materialLoader = rememberMaterialLoader(engine)
    val cameraNode = rememberARCameraNode(engine)
    val childNodes = rememberNodes()
    val view = rememberView(engine)
    val collisionSystem = rememberCollisionSystem(view)

    var planeRenderer by remember { mutableStateOf(true) }

    val modelInstances = remember { mutableListOf<ModelInstance>() }
    var trackingFailureReason by remember {
        mutableStateOf<TrackingFailureReason?>(null)
    }
    var frame by remember { mutableStateOf<Frame?>(null) }
    ARScene(
        modifier = Modifier.fillMaxSize(),
        childNodes = childNodes,
        engine = engine,
        view = view,
        modelLoader = modelLoader,
        collisionSystem = collisionSystem,
        sessionConfiguration = { session, config ->
            config.depthMode =
                when (session.isDepthModeSupported(Config.DepthMode.AUTOMATIC)) {
                    true -> Config.DepthMode.AUTOMATIC
                    else -> Config.DepthMode.DISABLED
                }
            config.instantPlacementMode = Config.InstantPlacementMode.LOCAL_Y_UP
            config.lightEstimationMode =
                Config.LightEstimationMode.ENVIRONMENTAL_HDR
        },
        cameraNode = cameraNode,
        planeRenderer = planeRenderer,
        onTrackingFailureChanged = {
            trackingFailureReason = it
        },
        onSessionUpdated = { session, updatedFrame ->
            frame = updatedFrame

            if (childNodes.isEmpty()) {
                updatedFrame.getUpdatedPlanes()
                    .firstOrNull { it.type == Plane.Type.HORIZONTAL_UPWARD_FACING }
                    ?.let { it.createAnchorOrNull(it.centerPose) }?.let { anchor ->
                        childNodes += createAnchorNode(
                            engine = engine,
                            modelLoader = modelLoader,
                            materialLoader = materialLoader,
                            modelInstances = modelInstances,
                            anchor = anchor
                        )
                    }
            }
        },
        onGestureListener = rememberOnGestureListener(
            onSingleTapConfirmed = { motionEvent, node ->
                if (node == null) {
                    val hitResults = frame?.hitTest(motionEvent.x, motionEvent.y)
                    hitResults?.firstOrNull {
                        it.isValid(
                            depthPoint = false,
                            point = false
                        )
                    }?.createAnchorOrNull()
                        ?.let { anchor ->
                            planeRenderer = false
                            childNodes += createAnchorNode(
                                engine = engine,
                                modelLoader = modelLoader,
                                materialLoader = materialLoader,
                                modelInstances = modelInstances,
                                anchor = anchor
                            )
                        }
                }
            })
    )
    Text(
        modifier = Modifier
            .systemBarsPadding()
            .fillMaxWidth()
            .align(Alignment.TopCenter)
            .padding(top = 16.dp, start = 32.dp, end = 32.dp),
        textAlign = TextAlign.Center,
        fontSize = 28.sp,
        color = Color.White,
        text = trackingFailureReason?.let {
            it.getDescription(LocalContext.current)
        } ?: if (childNodes.isEmpty()) {
            stringResource(R.string.point_your_phone_down)
        } else {
            stringResource(R.string.tap_anywhere_to_add_model)
        }
    )
}

}

private fun createAnchorNode( engine: Engine, modelLoader: ModelLoader, materialLoader: MaterialLoader, modelInstances: MutableList, anchor: Anchor ): AnchorNode { val anchorNode = AnchorNode(engine = engine, anchor = anchor) val modelNode = ModelNode( modelInstance = modelInstances.apply { if (isEmpty()) { this += modelLoader.createInstancedModel(kModelFile, kMaxModelInstances) } }.removeLast(), // Scale to fit in a 0.5 meters cube scaleToUnits = 0.009f, autoAnimate = true, centerOrigin = Position(x = 0.0f, y = 0.0f, z = 0.0f) ).apply { // Model Node needs to be editable for independent rotation from the anchor rotation isEditable = true isPositionEditable=false } val boundingBoxNode = CubeNode( engine, size = modelNode.extents, center = modelNode.center, materialInstance = materialLoader.createColorInstance(Color.White.copy(alpha = 0.5f)) ).apply { isVisible = false }

Node(engine)

modelNode.addChildNode(boundingBoxNode)
anchorNode.addChildNode(modelNode)

listOf(modelNode, anchorNode).forEach {
    it.onEditingChanged = { editingTransforms ->
        boundingBoxNode.isVisible = editingTransforms.isNotEmpty()
    }
}
return anchorNode

}

UmerHamza commented 4 months ago

issue resolved.