两点之间的 SceneKit 对象
SceneKit Object between two points
给定 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 space?
(我正在使用 Swift 和 Kim Pedersens SCNVector3Extensions:https://github.com/devindazzle/SCNVector3Extensions)
没有容易的方法,但也不应该那么难。您应该实现一个算法,该算法经过以下步骤:
- 获取 A 和 B 的位置为
SCNVector3
- 计算出这些矢量点之间的距离、中点和角度(这是基本的矢量数学,你可以在网上找到很多代码示例)
- 创建您想要的任何形状,大小如下:(假设
d
是之前找到的距离)。
- 对于
SCNCapsule
和SCNTube
,将height
设置为距离
- 对于
SCNTorus
,将ringRadius
设置为d/2-pipeRadius
- 对于
SCNBox
,将任意一侧设置为d
- 将该形状移动到您之前找到的中间点
- 使用点之间的角度旋转形状(您可能需要调整轴)
完成后,您创建的形状应该与两端的点相交。您可以使用边界框检查这是否正确,确保右轴等于距离。
我没有代码示例,但请尝试一下,如果它不起作用,我可以为您调试。
我有好消息要告诉你!你可以 link 两个点,然后在这个 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)
}
}
}
给定 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 space?
(我正在使用 Swift 和 Kim Pedersens SCNVector3Extensions:https://github.com/devindazzle/SCNVector3Extensions)
没有容易的方法,但也不应该那么难。您应该实现一个算法,该算法经过以下步骤:
- 获取 A 和 B 的位置为
SCNVector3
- 计算出这些矢量点之间的距离、中点和角度(这是基本的矢量数学,你可以在网上找到很多代码示例)
- 创建您想要的任何形状,大小如下:(假设
d
是之前找到的距离)。- 对于
SCNCapsule
和SCNTube
,将height
设置为距离 - 对于
SCNTorus
,将ringRadius
设置为d/2-pipeRadius
- 对于
SCNBox
,将任意一侧设置为d
- 对于
- 将该形状移动到您之前找到的中间点
- 使用点之间的角度旋转形状(您可能需要调整轴)
完成后,您创建的形状应该与两端的点相交。您可以使用边界框检查这是否正确,确保右轴等于距离。
我没有代码示例,但请尝试一下,如果它不起作用,我可以为您调试。
我有好消息要告诉你!你可以 link 两个点,然后在这个 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)
}
}
}