【问题标题】:How to rotate an 3D model using DragGesture in Android SceneForm如何在 Android SceneForm 中使用拖动手势旋转 3D 模型
【发布时间】:2022-02-23 03:29:21
【问题描述】:

我按照解决方案here 使用Sceneform Android SDK,根据用户的DragGesture 在X 轴上旋转TransformableNode。不过,我也想在 Y 轴和 Z 轴上旋转,类似于 ARCore SceneViewer 的做法。

我怎样才能做到这一点?

我目前拥有的是左侧(仅在 X 轴上旋转),而所需的是右侧(在所有轴上旋转,如 ARCore 场景查看器)。

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) {}
}

【问题讨论】:

    标签: android quaternions sceneform sceneview draggesture


    【解决方案1】:

    我在这里找到了可行的解决方案:https://github.com/chnouman/SceneView

    这里是相关的 sn-ps 代码,我进行了一些修改以使其适用于 .glb 文件。

    如果有人对此感兴趣,我已经分叉了这个 repo,并且正在开发键盘输入支持。

    渲染对象:

    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)
                }
    
    

    将对象添加到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
                        )
                    }
            }
        }
    

    自定义TransformableNode:

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

    自定义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) {}
    
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-01-02
      • 2020-10-03
      • 1970-01-01
      • 2019-10-16
      • 1970-01-01
      • 1970-01-01
      • 2017-10-02
      • 2010-12-18
      相关资源
      最近更新 更多