如果我在SceneKit中有两个点(例如(1,2,3)
和(-1,-1,-1)
)。如何在两者之间画一条线?
[我看到可能可以使用一个SCNBox对象,但这仅允许我指定中心(例如,通过simdPosition
)。修改它的其他方法是变换(我不知道如何使用)或欧拉角(我不确定如何计算需要使用的角度)。
首先,您需要计算两点之间的航向和俯仰。 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
}
只需使用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)