如何旋转具有固定锚点的 SCNNode?

Posted

技术标签:

【中文标题】如何旋转具有固定锚点的 SCNNode?【英文标题】:How rotate a SCNNode with a fixed anchor point? 【发布时间】:2020-04-02 16:51:38 【问题描述】:

我正在尝试制作一个游戏,其中给你一个球体,它的半径和球体表面上的一个点。我使用 SceneKit 作为我的基本框架。球体是SCNSphere,半径是SCNCylinder,它被小心地放置,使它看起来像球体的半径(圆柱体的高度等于球体的半径,它位于球体)。球体表面上的点是应用在球体表面上的SKScene作为其材质。

我的目标是使圆柱体的一端固定在球体的中心并旋转它,使其尖端可以在球体表面的每个点上。

我试图通过使用SCNAction 来达到同样的效果,但它与我想要的效果相去甚远。

我的代码是:

struct SceneKitView: UIViewRepresentable 
    func makeUIView(context:      UIViewRepresentableContext<SceneKitView>) -> SCNView 

    //SCNScene

     let sceneView = SCNView()
        sceneView.scene = SCNScene()
        sceneView.allowsCameraControl = true
        sceneView.autoenablesDefaultLighting = true
        sceneView.backgroundColor = UIColor.white
        sceneView.frame = CGRect(x: 0, y: 10, width: 0, height: 1)

    //A SKScene used as a material for a Sphere 

        let surfacematerial =  SKScene(size: CGSize(width: 300, height: 200))
        let point = SKShapeNode(circleOfRadius: 2)
        surfacematerial.backgroundColor = SKColor.blue
        point.fillColor = SKColor.red
        point.lineWidth = 0
        point.position = CGPoint(x: surfacematerial.size.width/2.0, y: surfacematerial.size.height/2.0)
        surfacematerial.addChild(point)


     //The SCNSphere    

        let sphere = SCNSphere(radius: CGFloat(2))

        let spherematerial = SCNMaterial()
        spherematerial.diffuse.contents = surfacematerial
        sphere.materials = [spherematerial]
        let spherenode = SCNNode(geometry: sphere)
        spherenode.position = SCNVector3(x: 1.0, y: 1.0, z: 1.0)
        spherenode.opacity = CGFloat(0.6)

    //The radius of the sphere( a SCNCylinder )   

        let cylinder = SCNCylinder(radius: 0.02, height: 2.0)
        let cylindernode = SCNNode(geometry: cone)
        cylindernode.position = SCNVector3(x: 1, y: 2, z: 1)
        cylinder.firstMaterial?.diffuse.contents = UIColor.green

    //Rotating the radius 

        func degreesToRadians(_ degrees: Float) -> CGFloat 
            return CGFloat(degrees * .pi / 180)
        

           let rotate = SCNAction.rotate(by: degreesToRadians(90.0),   around: SCNVector3(x: 1, y: 0 , z: 0), duration: 10)



        sceneView.scene?.rootNode.addChildNode(conenode)

        sceneView.scene?.rootNode.addChildNode(spherenode)


        return sceneView
    

    func updateUIView(_ uiView: SCNView, context: UIViewRepresentableContext<SceneKitView>) 

    

    typealias UIViewType = SCNView

请帮我解决这个问题。

【问题讨论】:

【参考方案1】:

有几种不同的方法可以做到这一点,我不清楚一旦超过 90 度的样本,你想如何旋转,这会有所不同。

这里是如何使用圆柱体绘制带有矢量的线(搜索帖子 35002232)。有几个选择,我喜欢这个答案:“class CylinderLine: SCNNode”并使用了它的一个版本。这将使您可以使用矢量,但每次更改时都必须绘制和删除。

如果您有目标节点,您也可以尝试查看方法。如果你想移动一个目标节点(可能是一个不可见的节点)并让你的圆柱跟随它,这很有效:

baseNode.constraints = []
let vConstraint = SCNLookAtConstraint(target: targetNode)
vConstraint.isGimbalLockEnabled = true
baseNode.constraints = [vConstraint]

它最适用于基础节点,然后将您的圆柱节点添加为子节点,以便将其固定到您的基础节点。然后你的 baseNode 聚焦在目标上,你的圆柱体将自动旋转。

您还必须从在正确的位置绘制它开始。这是一个内部装有火管的 3D 坦克示例。设置 vNode 的目标会使所有内容一起旋转。只需将 SCNBox 更改为 Sphere - 它的工作原理相同。

let BoxGeometry = SCNBox(width: 0.8, height: 0.8, length: 0.8, chamferRadius: 0.0)
let vNode = SCNNode(geometry: BoxGeometry)
BoxGeometry.materials = setDefenseTextures(vGameType: vGameType)

let tubeGeometry = SCNTube(innerRadius: 0.03, outerRadius: 0.05, height: 0.9)
let fireTube = SCNNode(geometry: tubeGeometry)
tubeGeometry.firstMaterial?.diffuse.contents  = data.getTextureColor(vTheme: 0, vTextureType: .barrelColor)

fireTube.position = SCNVector3(0, 0.2, -0.3)
let vRotateX = SCNAction.rotateBy(x: CGFloat(Float(GLKMathDegreesToRadians(-90))), y: 0, z: 0, duration: 0)
fireTube.runAction(vRotateX)
vNode.addChildNode(fireTube)

【讨论】:

以上是关于如何旋转具有固定锚点的 SCNNode?的主要内容,如果未能解决你的问题,请参考以下文章

js 定位到某个锚点的方法

如何在“func renderer(SCNSceneRenderer, nodeFor: ARAnchor) -> SCNNode?”中旋转 SCNNode?

如何围绕指定的锚点旋转 2D 容器小部件?

如何将 SCNNode 旋转多个角度?

如何围绕多个轴旋转 SCNNode?

如何在 SceneKit 中移动旋转的 SCNNode?