从基元创build自定义形状

我正在尝试创build一个结合了原始形状的自定义物理形状。 目标是创build一个圆形的立方体。 适当的方法似乎是init(形状:转换:)我在这里findhttps://developer.apple.com/library/prerelease/ios/documentation/SceneKit/Reference/SCNPhysicsShape_Class/index.html#//apple_ref/occ / clm / SCNPhysicsShape / shapeWithShapes:转换 :

我想这可以用8个球体,12个气瓶和一个中间的盒子来完成。 任何人都可以提供一个这样做的例子吗?

是的,正如您可能已经注意到的那样,从具有圆angular的SCNBox创build物理SCNBox忽略了倒angular半径。 实际上,几乎所有的基本几何形状(盒子,球体,圆柱体,金字塔, 茶壶等等)都会生成理想forms的物理形状,而不是将它们的顶点网格直接转换为物理体。

一般来说,这是一件好事。 在理想化的球体上执行碰撞检测比在一个接近球体的一百一十个三angular形的网格(在球体中心的半径距离内testing的点)快得多。 一个理想化的盒子(转换为盒子的本地坐标系统,x / y / z范围内的文本)。

SCNShapeinit(shapes:transforms:)初始化SCNShape是从这些理想化的形状构build复杂形状的好方法。 实际上, init(node:options:)初始化程序也是如此:如果为optionsparameter passing了[SCNPhysicsShapeKeepAsCompoundKey: true] ,则可以传递一个SCNNode ,该SCNNode包含其几何形状为原始形状的子节点的层次结构,并且SceneKit将分别转换将这些几何形状与其理想化的物理形状相结合,然后创build出所有这些形状的物理形状。

我将展示每个例子。 但首先,一些共享的上下文:

 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)) 

这里有一个使用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) 

你在那里用sphereTransformstransforms看到的舞蹈是因为SceneKit需要一个ObjC NSArray的每个参数,而NSArrays只能包含ObjC对象…一个转换是一个SCNMatrix4 ,这是一个结构,所以我们必须包装它在一个NSValue存储在一个NSArray 。 在Swift中,使用SCNMatrix4数组很方便,然后使用map来获取包含每个元素的NSValue数组。 (当我们将[NSValue]传递给SceneKit API时,Swift会自动桥接到NSArray的底层。)

这会创build一个只是圆angular的圆体 – 它们之间有空的空间。 根据你需要圆angular立方体碰撞的情况,这可能就足够了。 例如,如果您只是想在地板上制作圆angular立方体的骰子,angular落碰撞是唯一重要的,因为地板不会碰到骰子的中间,也不会碰到angular球。 如果这就是你所需要的,那就去做吧 – 如果你的物理形状尽可能简单,你会得到最好的性能。

如果你想要做出更精确的复合形状,边缘圆柱体和三个面或六个面的面,你可以扩展上面的例子。 只需将各种形状的数组转换为各种形状,并在转换为[NSValue]并传递给SceneKit之前连接数组。 (请注意,气缸将需要旋转和平移变换,因此将SCNMatrix4MakeTranslationSCNMatrix4Rotate结合使用。)

再次,所有这些math越来越难以形象化。 嵌套调用SCNMatrix4Whatever做什么math都不是那么好玩。 所以你可以用节点来做:

 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(xx: 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 } 

把这个节点放在一个场景中,当你放置球体(和圆柱体等)时,你可以看到结果。 注意,这个节点并不需要实际添加到你的场景中(除非是为了debugging目的而将其可视化)。 一旦你已经得到了它的样子,用它来创build一个物理形状,然后把这个形状分配给你实际想要在场景中绘制的其他节点:

 cube.physicsBody = SCNPhysicsBody(type: .Dynamic, shape: SCNPhysicsShape(node: nodeCompound, options: [SCNPhysicsShapeKeepAsCompoundKey: true])) 

顺便说一句,如果你在这里放弃保持复合的选项,你会得到一个形状,这是一个八angular球体的凸包网格(不pipe你是否也放入了边和面,因为它们位于船体内)。 也就是说,它可以得到一个圆angular立方体的近似值…圆angular半径将比理想几何体更不光滑,但取决于您需要的这个碰撞体,它可能是您所需要的。

Interesting Posts