0

I followed the solution here for rotating a TransformableNode on the X axis based on the user's DragGesture, using the Sceneform Android SDK. However, I would also like to rotate on the Y and Z axis as well, similar to how ARCore SceneViewer does it.

How can I achieve that?

What I have currently is on the left (rotates only on X axis), and what is desired is on the right (rotates on all axes, as in ARCore Scene Viewer).

class DragRotationController(transformableNode: BaseTransformableNode, gestureRecognizer: DragGestureRecognizer) :
    BaseTransformationController<DragGesture>(transformableNode, gestureRecognizer) {

    // Rate that the node rotates in degrees per degree of twisting.
    var rotationRateDegrees = 0.5f

    public override fun canStartTransformation(gesture: DragGesture): Boolean {
        return transformableNode.isSelected
    }

    public override fun onContinueTransformation(gesture: DragGesture) {

        var localRotation = transformableNode.localRotation

        val rotationAmountX = gesture.delta.x * rotationRateDegrees
        val rotationDeltaX = Quaternion(Vector3.up(), rotationAmountX)
        localRotation = Quaternion.multiply(localRotation, rotationDeltaX)

        // *** this only rotates on X axis. How do I rotate on all axes? ***

        transformableNode.localRotation = localRotation
    }

    public override fun onEndTransformation(gesture: DragGesture) {}
}
VIN
  • 6,385
  • 7
  • 38
  • 77

1 Answers1

0

I was able to find a working solution here: https://github.com/chnouman/SceneView

Here are the relevant snippets of code, with some of my adaptations to make it work for .glb files.

I have forked this repo and am working on keyboard input support if anyone's interested in that.

Rendering the object:

private fun renderLocalObject() {

        skuProgressBar.setVisibility(View.VISIBLE)
        ModelRenderable.builder()
            .setSource(this,
                RenderableSource.builder().setSource(
                    this,
                    Uri.parse(localModel),
                    RenderableSource.SourceType.GLB)/*RenderableSource.SourceType.GLTF2)*/
                    .setScale(0.25f)
                    .setRecenterMode(RenderableSource.RecenterMode.ROOT)
                    .build())
            .setRegistryId(localModel)
            .build()
            .thenAccept { modelRenderable: ModelRenderable ->
                skuProgressBar.setVisibility(View.GONE)
                addNodeToScene(modelRenderable)
            }

Adding the object to the SceneView:

private fun addNodeToScene(model: ModelRenderable) {
        if (sceneView != null) {
            val transformationSystem = makeTransformationSystem()
            var dragTransformableNode = DragTransformableNode(1f, transformationSystem)
            dragTransformableNode?.renderable = model
            sceneView.getScene().addChild(dragTransformableNode)
            dragTransformableNode?.select()
            sceneView.getScene()
                .addOnPeekTouchListener { hitTestResult: HitTestResult?, motionEvent: MotionEvent? ->
                    transformationSystem.onTouch(
                        hitTestResult,
                        motionEvent
                    )
                }
        }
    }

Custom TransformableNode:

class DragTransformableNode(val radius: Float, transformationSystem: TransformationSystem) :
    TransformableNode(transformationSystem) {
    val dragRotationController = DragRotationController(
        this,
        transformationSystem.dragRecognizer
    )
}

Custom TransformationController:

class DragRotationController(
        private val transformableNode: DragTransformableNode,
        gestureRecognizer: DragGestureRecognizer
) :
    BaseTransformationController<DragGesture>(transformableNode, gestureRecognizer) {

    companion object {

        private const val initialLat = 26.15444376319647
        private const val initialLong = 18.995950736105442

        var lat: Double = initialLat
        var long: Double = initialLong
    }

    // Rate that the node rotates in degrees per degree of twisting.
    private var rotationRateDegrees = 0.5f

    public override fun canStartTransformation(gesture: DragGesture): Boolean {
        return transformableNode.isSelected
    }

    private fun getX(lat: Double, long: Double): Float {
        return (transformableNode.radius * Math.cos(Math.toRadians(lat)) * Math.sin(Math.toRadians(long))).toFloat()
    }

    private fun getY(lat: Double, long: Double): Float {
        return transformableNode.radius * Math.sin(Math.toRadians(lat)).toFloat()
    }

    private fun getZ(lat: Double, long: Double): Float {
        return (transformableNode.radius * Math.cos(Math.toRadians(lat)) * Math.cos(Math.toRadians(long))).toFloat()
    }

    override fun onActivated(node: Node?) {
        super.onActivated(node)
        Handler().postDelayed({
            transformCamera(lat, long)
        }, 0)
    }

    public override fun onContinueTransformation(gesture: DragGesture) {

        val rotationAmountY = gesture.delta.y * rotationRateDegrees
        val rotationAmountX = gesture.delta.x * rotationRateDegrees
        val deltaAngleY = rotationAmountY.toDouble()
        val deltaAngleX = rotationAmountX.toDouble()

        long -= deltaAngleX
        lat += deltaAngleY

        //lat = Math.max(Math.min(lat, 90.0), 0.0)

        transformCamera(lat, long)
    }

    private fun transformCamera(lat: Double, long: Double) {
        val camera = transformableNode.scene?.camera

        var rot = Quaternion.eulerAngles(Vector3(0F, 0F, 0F))
        val pos = Vector3(getX(lat, long), getY(lat, long), getZ(lat, long))
        rot = Quaternion.multiply(rot, Quaternion(Vector3.up(), (long).toFloat()))
        rot = Quaternion.multiply(rot, Quaternion(Vector3.right(), (-lat).toFloat()))
        camera?.localRotation = rot
        camera?.localPosition = pos
    }

    fun resetInitialState() {
        transformCamera(initialLat, initialLong)
    }



    public override fun onEndTransformation(gesture: DragGesture) {}


}
VIN
  • 6,385
  • 7
  • 38
  • 77
  • This work fine . But i have two model i want to rotate one one model and with this code whole camera view is rotating the whole model is rotating can you please help me to rotate only model not the camera. – Amit pandey Apr 28 '23 at 06:15