如何在SceneKit中的两点之间画一条线?

问题描述 投票:0回答:2

如果我在SceneKit中有两个点(例如(1,2,3)(-1,-1,-1))。如何在两者之间画一条线?

[我看到可能可以使用一个SCNBox对象,但这仅允许我指定中心(例如,通过simdPosition)。修改它的其他方法是变换(我不知道如何使用)或欧拉角(我不确定如何计算需要使用的角度)。

math 3d scenekit
2个回答
0
投票

首先,您需要计算两点之间的航向和俯仰。 Full post在这里,this answer解释了如何在任意两点之间进行操作。

[拥有两个角度后,如果尝试在SCNBox上使用欧拉角,则会注意到,仅修改音高(eulerAngles.x)或仅修改航向(eulerAngles.y)时,工作正常。但是,当您尝试同时修改两者时,您将run into issues。一种解决方案是wrap one node inside another

这似乎是一个很有用的建议,我创建了一个方便的包装器节点,该节点应该处理所有三个轴上的旋转:

import Foundation
import SceneKit

struct HeadingPitchBank {
    let heading: Float
    let pitch: Float
    let bank: Float

    /// returns the heading and pitch (bank is 0) represented by the vector
    static func from(vector: simd_float3) -> HeadingPitchBank {
        let heading = atan2f(vector.x, vector.z)
        let pitch = atan2f(sqrt(vector.x*vector.x + vector.z*vector.z), vector.y) - Float.pi / 2.0

        return HeadingPitchBank(heading: heading, pitch: pitch, bank: 0)
    }
}

class HeadingPitchBankWrapper: SCNNode {

    init(wrappedNode: SCNNode) {
        headingNode = SCNNode()
        pitchNode = SCNNode()
        bankNode = SCNNode()
        _wrappedNode = wrappedNode

        super.init()

        addChildNode(headingNode)
        headingNode.addChildNode(pitchNode)
        pitchNode.addChildNode(bankNode)
        bankNode.addChildNode(wrappedNode)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    var heading: Float {
        get {
            return headingNode.eulerAngles.y
        }
        set {
            headingNode.eulerAngles.y = newValue
        }
    }

    var pitch: Float {
        get {
            return pitchNode.eulerAngles.x
        }
        set {
            pitchNode.eulerAngles.x = newValue
        }
    }

    var bank: Float {
        get {
            return bankNode.eulerAngles.z
        }
        set {
            bankNode.eulerAngles.z = newValue
        }
    }

    var headingPitchBank: HeadingPitchBank {
        get {
            return HeadingPitchBank(heading: heading, pitch: pitch, bank: bank)
        }
        set {
            heading = newValue.heading
            pitch = newValue.pitch
            bank = newValue.bank
        }
    }

    var wrappedNode: SCNNode {
        return _wrappedNode
    }

    private var headingNode: SCNNode
    private var pitchNode: SCNNode
    private var bankNode: SCNNode
    private var _wrappedNode: SCNNode
}

然后您可以使用它轻松地在两点之间画一条线:

func createLine(start: simd_float3 = simd_float3(), end: simd_float3, color: UIColor, opacity: CGFloat? = nil, radius: CGFloat = 0.005) -> SCNNode {
    let length = CGFloat(simd_length(end-start))
    let box = SCNNode(geometry: SCNBox(width: radius, height: radius, length: length, chamferRadius: 0))
    box.geometry!.firstMaterial!.diffuse.contents = color

    let wrapper = HeadingPitchBankWrapper(wrappedNode: box)
    wrapper.headingPitchBank = HeadingPitchBank.from(vector: end - start)
    wrapper.simdPosition = midpoint(start, end)
    if let opacity = opacity {
        wrapper.opacity = opacity
    }
    return wrapper
}

0
投票

只需使用SCNGeometryPrimitiveType.line构建自定义几何:

let vertices: [SCNVector3] = [
    SCNVector3(1, 2, 3),
    SCNVector3(-1, -1, -1)
]

let linesGeometry = SCNGeometry(
    sources: [
        SCNGeometrySource(vertices: vertices)
    ],
    elements: [
        SCNGeometryElement(
            indices: [Int32]([0, 1]),
            primitiveType: .line
        )
    ]
)

let line = SCNNode(geometry: linesGeometry)
scene.rootNode.addChildNode(line)
© www.soinside.com 2019 - 2024. All rights reserved.