Physics Simulation 之 SCNPhysicsBody

此系列为官方文档翻译,用于学习SceneKit

概述

SceneKit准备渲染新帧时,会对场景中附加在节点上的物理体执行物理计算。 这些计算包括重力、摩擦和与其他物体的碰撞。 您还可以将自己的力和冲量应用于物体。 在SceneKit完成这些计算之后,它会在渲染帧之前更新节点对象的位置和方向。

要向节点添加物理,创建和配置SCNPhysicsBody对象,然后将其分配给SCNNode对象的physicsBody属性。 在您应用力或冲量之前,必须将物理体与节点对象关联。

一个物体的物理特性

当场景模拟物体时,SCNPhysicsBody类定义物体的物理特性。对于物理模拟,有三个属性最重要:

  • type 属性,它确定物体如何与模拟中的力和其他物体交互。 静态物体不受力和碰撞影响且无法移动。动态物体受到力和与其他类型物体的碰撞的影响。 运动物体不受力或碰撞影响,但可以直接移动它们,从而可能会影响动态物体发生碰撞。
  • physicsShape 属性,它定义物体的三维形状以进行碰撞检测。 使用简单形状而不是节点可见几何的详细信息,物理模拟运行得更快。 通常,您将一个物体的物理形状设置为大致匹配节点可见内容的边界框、球体或基本形状。 有关创建物理形状的详细信息,请参阅SCNPhysicsShape
  • kinematic() 属性。 对动态物体施加力或扭矩会导致其加速度(或角加速度)与其质量成比例。

场景中的所有值在SceneKit的物理模拟中使用国际单位制(SI),mass (质量)单位为千克;force (力)、impulse (冲量)和torque (扭矩)的单位是牛顿、牛顿秒和牛顿米;节点位置和大小的距离单位是米。 请注意,您不必尝试为物理量提供逼真的值 - 使用产生您所需行为或游戏玩法的任何值即可。
对于动态物体,您可以控制物体受力或碰撞的影响方式。 请参阅定义力如何影响物理体。

定义物体的类别和碰撞

当您设计使用物理的游戏时,定义在场景中出现的不同物理对象的各种类别。 为您的应用程序的行为定义不同类别的物理体。 一个物体可以分配给您想要的这些类别中的任意数量。 除了声明自己的类别之外,物理体还声明了它与哪些物体类别交互。

使用categoryBitMaskcollisionBitMask属性定义对象的碰撞行为。 SCNPhysicsCollisionCategory 中列出的常量为这些属性提供了默认值。 此外,使用 contactTestBitMask 属性,您可以定义一对物体生成接触消息(请参见 SCNPhysicsContactDelegate 协议),而不受到碰撞影响的交互。

相关物理类

物理场创建影响区域内所有物体的力,例如涡旋和引力。 有关详细信息和可用字段类型的列表,请参阅 SCNPhysicsField

您可以添加更高级别的行为,以控制多个物体之间的交互,例如关节和车辆。 有关详细信息和可用行为的列表,请参阅 SCNPhysicsBehavior

场景的 physicsWorld 属性持有一个管理影响整个场景的物理特性的 SCNPhysicsWorld 对象。

物理和渲染循环

SceneKit 将其物理模拟作为 SCNSceneRendererDelegate 中描述的渲染循环的一部分进行评估。在通过此循环的每个步骤中,SceneKit 确定具有附加物理体的所有节点的状态,并为一个时间步长模拟物理对这些物体的影响。例如,通过根据其速度和角速度更新物体的位置或旋转来模拟物理。在模拟物理之后,SceneKit 将物理模拟的结果应用于场景以供显示。

因为您不仅可以通过物理,而且可以通过动作和隐式和显式定义的动画动画 SceneKit 内容,所以 SceneKit 将物理模拟的结果不应用于场景中 SCNNode 对象,而应用于每个节点的呈现对象,表示其当前显示状态。 因此,更改受物理影响的节点的属性需要特别考虑。

如果更改受物理影响的节点的变换值或变换的任何其他属性,如位置和旋转之一,SceneKit将重置该节点的物理模拟。如果您只想更改变换的一个组件,同时将其他组件保留为其物理模拟值,请在更改前复制呈现节点的变换,如下所示:

1
2
3
4
//将演示节点的变换复制到模型节点。
node.transform = node.presentationNode.transform
//更改新变换中的一个组件
node.eulerAngles.z = newRollValue

相关API

创建物理体

1
init(type: SCNPhysicsBodyType, shape: SCNPhysicsShape?)

使用指定的类型和形状创建物理体。

1
class func  `static` () -> Self

创建一个不受力或碰撞影响且不能移动的物理体。

1
class func dynamic() -> Self

创建一个可以受力和碰撞影响的物理体。

1
class func kinematic() -> Self

创建一个不受力或碰撞影响,但在移动时可以引起影响其他物体的碰撞的物理体。

定义力如何影响物理体

1
var physicsShape: SCNPhysicsShape?

定义用于碰撞检测的物理体的实体体积。

1
var type: SCNPhysicsBodyType

一个常量,用于确定物理体如何响应力和碰撞。

1
enum SCNPhysicsBodyType

常量,用于确定物理体如何与力和其他物体交互,用于类型属性和创建物理体时。

1
var velocityFactor: SCNVector3

一个乘数,影响SceneKit将物理模拟计算的平移应用于包含物理体的节点。

1
var angularVelocityFactor: SCNVector3

一个乘数,影响SceneKit将物理模拟计算的旋转应用于包含物理体的节点。

1
var isAffectedByGravity: Bool

一个布尔值,用于确定场景中的恒定重力是否加速物体。

定义物体的物理属性

1
var mass: CGFloat

物体的质量,以千克为单位。

1
var charge: CGFloat

物体的电荷,以库仑为单位。

1
var friction: CGFloat

物体的滑动运动阻力。

1
var rollingFriction: CGFloat

物体的滚动运动阻力。

1
var restitution: CGFloat

确定物体在碰撞中损失或获得多少动能的因子。

1
var damping: CGFloat

减少物体的线性速度的因子。

1
var angularDamping: CGFloat

减少物体的角速度的因子。

1
var momentOfInertia: SCNVector3

物体的惯性矩,以包含物体的节点的本地坐标系表示。

1
var usesDefaultMomentOfInertia: Bool

一个布尔值,用于确定SceneKit是否自动计算物体的惯性矩,或允许设置自定义值。

1
var centerOfMassOffset: SCNVector3

物体质心相对于其本地坐标原点的位置。

处理接触和碰撞

1
var categoryBitMask: Int

定义该物理体属于的哪些类别的掩码。

1
var contactTestBitMask: Int

定义哪些类别的物体与此物理体发生交集通知。

1
var collisionBitMask: Int

定义哪些类别的物理体可以与此物理体碰撞。

1
struct SCNPhysicsCollisionCategory

用于物理体的categoryBitMaskcollisionBitMask属性的默认值。

1
var continuousCollisionDetectionThreshold: CGFloat

物体必须移动的最小距离,这样SceneKit才能应用更精确(但更昂贵)的算法来检测与其他物体的接触。

应用力、冲量和扭矩

1
func applyForce(SCNVector3, asImpulse: Bool)

将力或冲量应用于物体的质心。

1
func applyForce(SCNVector3, at: SCNVector3, asImpulse: Bool)

将力或冲量应用于物体的特定点。

1
func applyTorque(SCNVector4, asImpulse: Bool)

将净扭矩或角动量变化应用于物体。

1
func clearAllForces()

取消当前模拟步骤中作用于物理体上的所有连续力和扭矩。

在运动的物体中交互

1
var velocity: SCNVector3

描述物理体当前速度(以米/秒为单位)和运动方向的向量。

1
var angularVelocity: SCNVector4

描述物理体当前旋转轴和旋转速度(以弧度/秒为单位)的向量。

定义何时可以移动物体

1
var isResting: Bool

一个布尔值,指示物理体是否静止。

1
var allowsResting: Bool

一个布尔值,指定是否可以自动将物理体标记为静止。

1
func setResting(Bool)

告诉SceneKit是否将物体视为当前正在运动。

将物理体与其节点同步

1
func resetTransform()

更新物体在物理模拟中的位置和方向,以匹配其附加的节点。

实例属性

1
2
var angularRestingThreshold: CGFloat
var linearRestingThreshold: CGFloat

扩展

详细内容请看:SCNPhysicsBody