物理模拟(Physics Simulation)主要用来实现:
- 将动态行为添加到场景中的对象
- 检测碰撞并响应物体之间的接触
- 模拟真实的物理效应,如重力,弹力和 汽车模拟
1. 物理体(Physics Bodies)
1.1 SCNPhysicsBody 类
添加到节点上的物理模拟属性。
当SceneKit准备渲染新的一帧时,它会对连接到场景中节点的物理实体执行物理计算。 这些计算包括重力,摩擦以及与其他物体的碰撞。 你也可以将自己的力量和冲动应用于身体。 SceneKit完成这些计算后,它会在渲染帧之前更新节点对象的位置和方向。
要将物理模拟添加到节点,请创建并配置一个 SCNPhysicsBody 对象,然后将其赋给 SCNNode对象 的 physicsBody
属性。 在对其施加力或冲击之前,物理体必须与节点对象相关联。
planeNode.physicsBody = SCNPhysicsBody(type:.kinematic, shape: nil)
1.1.1 一个对象的物理特征
SCNPhysicsBody 类在场景模拟时定义身体的物理特征。 有三个重要的属性:
type
属性,用于确定对象在模拟中如何与力和其他物体进行交互:① 静态物体(static)不受力量和碰撞的影响,不能移动;② 动态物体(dynamic)受到力量和与其他身体类型碰撞的影响;③ 运动物体(kinematic)不受力或碰撞的影响,但通过直接移动它们,可能会导致影响动态物体的碰撞。physicsShape
属性,它定义用于碰撞检测目的的三维形体。 使用简单形状代替节点的可见几何体的精细细节时,物理模拟运行速度更快。 通常,您将一个物体的物理形状设置为与其节点的可见内容大致相匹配的边界框,球体或原始形状。 有关创建物理形状的详细信息,请参阅 SCNPhysicsShape。kinematic()
属性, 对动力体(dynamic body)施加力或力矩会导致与其质量成比例的加速度(或角加速度)。
1.1.2 定义一个物体的类别和碰撞(Category and Collisions)
当你设计使用物理效果的游戏时,你可以按需在场景中定义不同类别的物理体。一个物理体可以分配到多个类别中。 除了声明对象自己的类别之外,它还会声明它可以与哪些类别的物理体进行交互。
使用 categoryBitMask
和 collisionBitMask
属性来定义对象的碰撞行为。 SCNPhysicsCollisionCategory中列出的常量为这些属性提供默认值。 另外,通过 contactTestBitMask
属性,实现 SCNPhysicsContactDelegate 的协议方法,可以获取到发生碰撞的对象 。
关于碰撞和类别,另外有一篇博客专门讲解。
1.1.3 与之相关的类
”物理场”会产生影响某个区域所有物体的力量,例如涡旋和引力吸引力。 有关可用字段类型的详细信息和列表,后面 SCNPhysicsField类 会详细讲解。
你可以添加更高级别的行为来控制多个物体之间的交互,例如关节和轮式车辆。 有关可用行为的详细信息和列表,后面 SCNPhysicsBehavior会详细讲解。
场景的physicsWorld
属性包含一个 SCNPhysicsWorld 对象,用于管理影响整个场景的物理特性。
1.1.4 物理模拟和渲染循环
SceneKit 将物理模拟作为渲染循环的一部分,遵守 SCNSceneRendererDelegate 协议,在每次渲染循环的时候,SceneKit 确定每个添加在每个节点上的物理模拟,并且同步计算出物理模拟对物体的影响。
例如,基于速度更新物体的位置,SceneKit将物理模拟的结果应用到场景中进行显示。
不仅可以通过物理模拟为 SceneKit 内容创建动画,还可以通过动作(action)来隐式或显式定义的动画。
注意, SceneKit并不是将物理模拟的结果应用于场景中的 SCNNode 对象,而是应用于表示其当前显示状态的每个节点的表示对象。因此,改变受物理影响的节点的属性需要特别考虑。
如果更改变 transform
属性或者transform
属性中的某个值(如物理位置或旋转),则 SceneKit 将重置该节点的物理模拟。
如果只想更改变换 transform 中的某个值,请在进行更改之前复制该演示节点的transform ,如下所示:
// Copy the presentation node's transform to the model node.
node.transform = node.presentationNode.transform
// Change one component of the new transform
node.eulerAngles.z = newRollValue
SCNPhysicsShape 类
对物理体的外观的抽象,用于调整碰撞检测。
当SceneKit为场景中的 SCNPhysicsBody对象 执行接触检测和其他模拟时,它将使用 SCNPhysicsShape 描述的物理形状,而不是可见对象的渲染几何体。 这种方法既提高了仿真性能,又可让你更轻松地设计玩家可与之互动的场景元素周围的游戏玩法。
2. 碰撞和接触检测
SCNPhysicsContactDelegate 协议
当场景中两个物理实体之间发生接触或碰撞(Contact)时,可以使用这些方法进行响应。
要接收 Contact 消息,请设置 SCNPhysicsWorld 对象的 contactDelegate 属性。 当 Contact 开始,Contact 信息发生变化以及 Contact结束时,SceneKit 会调用委托方法。
SCNPhysicsContact 类
两个物理体之间接触的详细信息。
开发者不直接创建 SCNPhysicsContact 实例; 无论何时发生contact ,SceneKit都会自动创建这些对象。
要接收 contact 消息,设置 SCNPhysicsWorld 对象的 contactDelegate 属性后,实现 SCNPhysicsContactDelegate 协议方法。 接下来,对于场景中的每个物理实体,设置 categoryBitMask
和 collisionBitMask
属性以定义哪些交互应生成contact 消息。
这一块刚开始不好理解,三言两语难讲清楚,详细请参考 SceneKit中的物理模拟 | Bit-masks 。
3. 物理场景( Physics in a Scene )
SCNPhysicsWorld
全局模拟场景中的碰撞,重力,关节和其他物理效应。
不要直接创建SCNPhysicsWorld对象; 相反,参考请 SCNScene对象的physicsWorld 属性。 使用物理世界对象来执行以下任务:
- 管理物理模拟的全局属性,例如其速度和恒定的引力(为了更精确地控制重力和类似的效果,请参阅 SCNPhysicsField 类)
- 注册修改场景中物理实体(如关节和车辆)之间交互的行为。 有关更多详细信息,请参阅 SCNPhysicsBehavior
- 当两个物理体彼此接触时,指定一个委托对象来接收消息
SCNPhysicsField 类
SCNPhysicsField 对象可以将引力、电磁和气流等外力应用于物理体的特定区域上。
您可以创建许多类型的场效应,例如引力,电磁和气流。 要将场效应添加到场景中,请创建要使用的类型的物理场,然后将其附加到场景中节点的physicsField 属性。
物理场可以影响 SCNPhysicsBody对象 和 SCNParticleSystem对象产生的粒子。
SCNPyhsicsBehavior 类
包含多个物理体的的关节、车辆模拟和其他高级行为的抽象父类。
SCNPhysicsBehavior对象定义一个或多个物理体的高级行为,修改物理模拟的结果。 这些高级行为包括连接多个物体的关节,以便它们一起移动;车辆定义,使物体像汽车一样滚动。 你从不直接使用这个类; 相反,你实例化了一个定义你想添加到物理世界中的行为类型的子类。
4. 关节(Joints)
SCNPhysicsHingeJoint 类
连接两个物体并允许它们在一个轴上相互转动的物理行为。
铰链(Hinge)具有单一的自由度(旋转)。 你还可以使用铰链连接来固定物体,以便它只能通过围绕包含它的节点的坐标空间中的特定轴旋转来移动。
SCNPhysicsSliderJoint 类
连接两个物体并允许它们相互滑动并围绕其连接点旋转的物理行为。
根据滑块(Slider)关节是否允许滑动或旋转,滑块关节可以具有零个,一个或两个自由度。 您还可以使用滑块接头固定一个物体,以便只能通过在包含该物体的节点的坐标空间中滑动特定的轴来移动物体。 您也可以使用滑块接头作为电机,对连接的物体施加力或扭矩。
SCNPhysicsBallSocketJoint 类
连接两个物理体并允许它们在任何方向上相互转动的物理行为。
动图来自 Physics Joints in Unity 2D 一文中。
5. 汽车模拟(Vehicle Simulation)
SCNPhysicsVehicle类
一种物理行为,修改一个物理体的行为,像汽车,摩托车或其他轮式车辆。
要搭建一辆车,请将 SCNPhysicsBody对象 指定为底盘,并将SCNPhysicsVehicleWheel对象作为其车轮。 对于每个车轮,您可以定义悬架和牵引力等物理特征,并将场景中的节点关联起来以提供车轮的大小和视觉表示。 在构建车辆后,可以通过加速,制动和转向来控制它。
尽管也可以使用一组物理体和关节来共同模拟轮式车辆,但 SCNPhysicsVehicle类实现了更高级别的仿真,可以提供逼真的车辆行为和更高效的仿真性能。
SCNPhysicsVehicleWheel 类
上面已经提到了,SCNPhysicsVehicleWheel是与物理车辆行为相关的单个车轮的外观和物理特征。