pot*_*ato 3 shape ios scenekit
我正在尝试创建一个结合了原始形状的自定义物理形状.目标是创建一个圆角的立方体.适当的方法似乎是init(形状:变换:)我在这里找到https://developer.apple.com/library/prerelease/ios/documentation/SceneKit/Reference/SCNPhysicsShape_Class/index.html#//apple_ref/occ/clm/SCNPhysicsShape/shapeWithShapes:转换:
我想这可以用8个球体,12个圆柱体和中间的盒子来完成.任何人都可以提供这样做的例子吗?
是的,您可能已经注意到,从SCNBox圆角创建物理主体会忽略倒角半径.实际上,几乎所有的基本几何形状(盒子,球体,圆柱体,金字塔,茶壶等)都会产生理想化形式的物理形状,而不是将它们的顶点网格直接转换为物理体.
一般来说,这是一件好事.在理想化球体上执行碰撞检测比在近似球体的一百三十个三角形网格上(在球体中心的半径距离内测试点?)要快得多.同上一个理想化的盒子(将点转换为盒子的局部坐标系,边界内的x/y/z文本).
该init(shapes:transforms:)用于初始化SCNShape是建立从这些理想化的形状复杂形状的好方法.其实,这样是init(node:options:)初始化:如果您传递[SCNPhysicsShapeKeepAsCompoundKey: true]的options参数,你可以传递一个SCNNode包含子节点,其几何形状是原始形状的层次,而且每个几何形状其理想化的物理形状的SceneKit将转变创造一个物理形状的前所有人的结合.
我将展示每个例子.但首先,一些共享的背景:
let side: CGFloat = 1 // one side of the cube
let radius: CGFloat = side / 4 // the corner radius
// the visual (but not physical) cube
let cube = SCNNode(geometry: SCNBox(width: side, height: side, length: side, chamferRadius: radius))
Run Code Online (Sandbox Code Playgroud)
以下是制作它的镜头init(shapes:transforms:):
var compound: SCNPhysicsShape {
let sphereShape = SCNPhysicsShape(geometry: SCNSphere(radius: radius), options: nil)
let spheres = [SCNPhysicsShape](count: 8, repeatedValue: sphereShape)
let sphereTransforms = [
SCNMatrix4MakeTranslation( radius, radius, radius),
SCNMatrix4MakeTranslation(-radius, radius, radius),
SCNMatrix4MakeTranslation(-radius, -radius, radius),
SCNMatrix4MakeTranslation(-radius, -radius, -radius),
SCNMatrix4MakeTranslation( radius, -radius, -radius),
SCNMatrix4MakeTranslation( radius, radius, -radius),
SCNMatrix4MakeTranslation(-radius, radius, -radius),
SCNMatrix4MakeTranslation( radius, -radius, radius),
]
let transforms = sphereTransforms.map {
NSValue(SCNMatrix4: $0)
}
return SCNPhysicsShape(shapes: spheres, transforms: transforms)
}
cube.physicsBody = SCNPhysicsBody(type: .Dynamic, shape: compound)
Run Code Online (Sandbox Code Playgroud)
你在那里看到的舞蹈sphereTransforms和transforms是因为SceneKit期待一个ObjC NSArray它的每个参数,以及NSArrayS可只包含ObjC对象......一个转换是SCNMatrix4,它是一个结构,所以我们在把它包起来NSValue存放它在一个NSArray.在Swift中,使用数组很方便SCNMatrix4,然后map用来获取NSValue包装每个元素的数组.(NSArray当我们将我们传递[NSValue]给SceneKit API 时,Swift自动桥接到引擎盖下.)
这会创建一个只是立方体圆角的主体 - 它们之间有空的空间.根据您需要圆角立方体碰撞的情况,这可能就足够了.例如,如果你只是想在地板上制作圆角立方体骰子,那么角落碰撞是唯一重要的,因为地板不会在没有接触角落球体的情况下与模具中间碰撞.如果这就是您所需要的一切,那就去吧 - 如果物理形状尽可能简单,您将获得最佳性能.
如果你想制作一个更精确的复合形状,边缘有圆柱,面上有三个盒子或六个平面,你可以扩展上面的例子.只需为每种形状制作形状变换数组,并在转换[NSValue]并传递给SceneKit 之前连接数组.(请注意,圆柱体将需要旋转和平移变换,因此结合SCNMatrix4MakeTranslation使用SCNMatrix4Rotate.)
然后,所有数学都变得难以想象.嵌套要求进行SCNMatrix4Whatever数学运算并不是那么有趣.所以你可以用节点代替它:
var nodeCompound: SCNNode {
// a node to hold the compound geometry
let parent = SCNNode()
// one node with a sphere
let sphere = SCNNode(geometry: SCNSphere(radius: radius))
// inner func to clone the sphere to a specific position
func corner(x x: CGFloat, y: CGFloat, z: CGFloat) -> SCNNode {
let node = sphere.clone()
node.position = SCNVector3(x: x, y: y, z: z)
return node
}
// clone the sphere to each corner as child nodes
parent.addChildNode(corner(x: radius, y: radius, z: radius))
parent.addChildNode(corner(x: -radius, y: radius, z: radius))
parent.addChildNode(corner(x: -radius, y: -radius, z: radius))
parent.addChildNode(corner(x: -radius, y: -radius, z: -radius))
parent.addChildNode(corner(x: radius, y: -radius, z: -radius))
parent.addChildNode(corner(x: radius, y: radius, z: -radius))
parent.addChildNode(corner(x: -radius, y: radius, z: -radius))
parent.addChildNode(corner(x: radius, y: -radius, z: radius))
return parent
}
Run Code Online (Sandbox Code Playgroud)
将此节点放在场景中,您可以在定位球体(和圆柱体等)时可视化结果.请注意,此节点不必实际添加到场景中(除非您出于调试目的将其可视化).一旦你得到它你想要它,用它来创建一个物理形状,并将该形状分配给你真正想要在场景中绘制的另一个节点:
cube.physicsBody = SCNPhysicsBody(type: .Dynamic,
shape: SCNPhysicsShape(node: nodeCompound,
options: [SCNPhysicsShapeKeepAsCompoundKey: true]))
Run Code Online (Sandbox Code Playgroud)
顺便说一下,如果你在这里放下keep-as-compound选项,你将得到一个形状,它是你的八个角球的凸包网格(无论你是否也放入边和面,因为它们位于船体内).也就是说,它可以让你得到一个圆角立方体的近似值......角半径将比理想化的几何体更不平滑,但是根据你需要这个碰撞体,你可能只需要它.
| 归档时间: |
|
| 查看次数: |
1574 次 |
| 最近记录: |