【问题标题】:SceneKit Object between two points两点之间的 SceneKit 对象
【发布时间】:2015-07-23 06:51:20
【问题描述】:

给定 2 个 3D 点 (a,b) 和一个 SCNCapsule、SCNTorus、SCNTube 等, 如何定位对象,使对象从 a 点开始并在 b 点结束?

Swift 或 Objective-C 中的代码示例将不胜感激。

从 Moustachs 的回答中,我设法做了一个二维解决方案:

var v1 = SCNVector3(x: Float(a.x), y: Float(a.y), z: 0.0)
var v2 = SCNVector3(x: Float(b.x), y: Float(b.y), z: 0.0)

let height = CGFloat(v1.distance(v2))
var capsule = SCNCapsule(capRadius: 0.1, height: height)

var node = SCNNode(geometry: capsule)

var midpoint = (v1 + v2) / 2.0

node.position = midpoint

var rotp = v2 - midpoint

let rotx = atan2( rotp.y, rotp.x )
node.eulerAngles = SCNVector3Make(0.0, 0.0, rotx)

self.addChildNode(node)

我知道,完整的 3D 旋转有无数种解决方案,但我不关心第三轴。尽管如此,似乎即使是第二个轴旋转也不适合我。也许我的数学让我望而却步。谁能告诉我如何将此代码提升到 3D 空间?

(我正在使用 Swift 和 Kim Pedersens SCNVector3Extensions:https://github.com/devindazzle/SCNVector3Extensions

【问题讨论】:

    标签: swift scenekit


    【解决方案1】:

    我要告诉你一个好消息!您可以链接两个点并在此 Vector 上放置一个 SCNNode !

    拿着这个,享受在两点之间画线吧!

    class   CylinderLine: SCNNode
    {
        init( parent: SCNNode,//Needed to line to your scene
            v1: SCNVector3,//Source
            v2: SCNVector3,//Destination
            radius: CGFloat,// Radius of the cylinder
            radSegmentCount: Int, // Number of faces of the cylinder
            color: UIColor )// Color of the cylinder
        {
            super.init()
    
            //Calcul the height of our line
            let  height = v1.distance(v2)
    
            //set position to v1 coordonate
            position = v1
    
            //Create the second node to draw direction vector
            let nodeV2 = SCNNode()
    
            //define his position
            nodeV2.position = v2
            //add it to parent
            parent.addChildNode(nodeV2)
    
            //Align Z axis
            let zAlign = SCNNode()
            zAlign.eulerAngles.x = CGFloat(M_PI_2)
    
            //create our cylinder
            let cyl = SCNCylinder(radius: radius, height: CGFloat(height))
            cyl.radialSegmentCount = radSegmentCount
            cyl.firstMaterial?.diffuse.contents = color
    
            //Create node with cylinder
            let nodeCyl = SCNNode(geometry: cyl )
            nodeCyl.position.y = CGFloat(-height/2)
            zAlign.addChildNode(nodeCyl)
    
            //Add it to child
            addChildNode(zAlign)
    
            //set constraint direction to our vector
            constraints = [SCNLookAtConstraint(target: nodeV2)]
        }
    
        override init() {
            super.init()
        }
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
        }
    }
    
    private extension SCNVector3{
        func distance(receiver:SCNVector3) -> Float{
            let xd = receiver.x - self.x
            let yd = receiver.y - self.y
            let zd = receiver.z - self.z
            let distance = Float(sqrt(xd * xd + yd * yd + zd * zd))
    
            if (distance < 0){
                return (distance * -1)
            } else {
                return (distance)
            }
        }
    }
    

    【讨论】:

    • sqrt 总是积极的
    • 这里的position = v1有什么用?
    • addChildNode这个函数是什么?实际上,我正在将它用于 ARKit,试图在两个顶点之间创建 CylinderLine,当我使用它时,它向我显示了几个错误,有人可以帮忙吗?
    【解决方案2】:

    没有简单的方法可以做到,但也不应该那么难。您应该实现一个经过以下步骤的算法:

    • 获取 A & B 的位置为SCNVector3
    • 算出这些向量点之间的距离、中点和角度(这是基本的向量数学,您可以在网上找到很多代码示例)
    • 创建您想要的任何形状,尺寸如下:(假设d 是先前找到的距离)。
      • 对于SCNCapsuleSCNTube,将height 设置为距离
      • 对于SCNTorus,将ringRadius 设置为d/2-pipeRadius
      • 对于SCNBox,将任意一侧设置为d
    • 将该形状移动到您之前找到的中间点
    • 使用点之间的角度旋转形状(您可能需要调整轴)

    完成此操作后,您创建的形状应该与两端的点相交。您可以使用边界框检查这是否正确,确保右轴等于距离。

    我没有代码示例,但请尝试一下,如果它不起作用,我可以为您调试。

    【讨论】:

    • 我已根据您的输入为问题添加了二维解决方案
    猜你喜欢
    • 2016-05-02
    • 2018-01-07
    • 2020-02-16
    • 2014-03-20
    • 2017-04-26
    • 2012-03-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多