У меня есть простая трехмерная область, содержащая 4 стены, каждая из которых представляет собой SCNNode с простой геометрией SCNBox, прямоугольной формы и соответствующим прикрепленным SCNPhysicsBody. SCNPhysicsBody использует SCNPhysicsShape.ShapeType.boundingBox и имеет статический тип. Вот фрагмент кода:
let size = (self.levelNode.boundingBox.max - self.levelNode.boundingBox.min) * self.levelNode.scale
//x //z
let geometryA = SCNBox(width: CGFloat(size.x), height: CGFloat(1 * self.levelNode.scale.x), length: 0.01, chamferRadius: 0)
let geometryB = SCNBox(width: CGFloat(size.z), height: CGFloat(1 * self.levelNode.scale.x), length: 0.01, chamferRadius: 0)
geometryA.firstMaterial?.diffuse.contents = UIColor(red: 0.0, green: 0.2, blue: 1.0, alpha: 0.65)
geometryB.firstMaterial?.diffuse.contents = UIColor(red: 0.0, green: 0.2, blue: 1.0, alpha: 0.65)
let nodeA = SCNNode(geometry: geometryA)
nodeA.position += self.levelNode.position
nodeA.position += SCNVector3(0, 0.25 * self.levelNode.scale.y, -size.z/2)
nodeA.name = "Boundary-01"
let nodeB = SCNNode(geometry: geometryA)
nodeB.position += self.levelNode.position
nodeB.position += SCNVector3(0, 0.25 * self.levelNode.scale.y, size.z/2)
nodeB.name = "Boundary-03"
let nodeC = SCNNode(geometry: geometryB)
nodeC.position += self.levelNode.position
nodeC.position += SCNVector3(-size.x/2, 0.25 * self.levelNode.scale.y, 0)
nodeC.eulerAngles = SCNVector3(0, -Float.pi/2, 0)
nodeC.name = "Boundary-02"
let nodeD = SCNNode(geometry: geometryB)
nodeD.position += self.levelNode.position
nodeD.position += SCNVector3(size.x/2, 0.25 * self.levelNode.scale.y, 0)
nodeD.eulerAngles = SCNVector3(0, Float.pi/2, 0)
nodeD.name = "Boundary-04"
let nodes = [nodeA, nodeB, nodeC, nodeD]
for node in nodes {
//
let shape = SCNPhysicsShape(geometry: node.geometry!, options: [
SCNPhysicsShape.Option.type : SCNPhysicsShape.ShapeType.boundingBox])
let body = SCNPhysicsBody(type: .static, shape: shape)
node.physicsBody = body
node.physicsBody?.isAffectedByGravity = false
node.physicsBody?.categoryBitMask = Bitmask.boundary.rawValue
node.physicsBody?.contactTestBitMask = Bitmask.edge.rawValue
node.physicsBody?.collisionBitMask = 0
scene.rootNode.addChildNode(node)
node.physicsBody?.resetTransform()
}
Внутри этой области я периодически порождаю сущности. У каждого также есть геометрия SCNBox, которая на этот раз имеет форму куба, меньшего размера, чем стены, и те же параметры для физического тела, что и выше.
Чтобы упростить поведение моих сущностей внутри этой игровой области, я вычисляю их пути перемещения, а затем применяю SCNAction к соответствующему узлу, чтобы переместить их. SCNAction перемещает и узел, и физическое тело, прикрепленное к нему.
Я использую контактный делегат SCNPhysicsWorld, чтобы определять, когда объект достигает одной из граничных стен. Затем я вычисляю для него случайную траекторию от этой стены в другом направлении, очищаю его действия и применяю новое движение SCNAction.
Вот тут и становится интересно ...
Когда этот «мир» в масштабе 1: 1. Контакты обнаруживаются как нормальные как в стандартной SCNScene, так и в сцене, спроецированной с помощью ARKit. Видимый контакт, то есть видимое изменение направления объекта, кажется, близко к границе, как и ожидалось. Когда я проверяю contact.penetrationDistance каждого контакта, их значения, например, 0,00294602662324905.
НО, когда я изменяю масштаб этого «мира» на что-то меньшее, скажем, эквивалент 10 см ширины в ARKit, симуляция разваливается.
Контакты между объектом и граничным узлом имеют сравнительно большой видимый зазор между ними при обнаружении контакта. Тем не менее, contact.penetrationDistance имеет ту же величину, что и раньше.
Я включил параметры отладки ARSCNView, чтобы показать физические формы в рендере, и все они имеют правильные пропорции, соответствующие ограничивающей рамке их узла.
Как видно из приведенного выше примера кода, граничные узлы создаются после того, как я масштабировал уровень во время настройки пользователя AR. Они добавляются к корневому узлу сцены, а не как дочерний узел узла уровня. Тот же код используется для создания сущностей.
Раньше я пробовал использовать функцию resetTransform () для физических тел, но это не давало надежного масштабирования физических тел после того, как я масштабировал уровень, поэтому я решил сгенерировать узлы для границ и объектов после того, как уровень были масштабированы.
В документации Apple говорится, что если SCNPhysicsBody не является настраиваемой формой, он будет принимать масштаб геометрии узла, примененной к нему. На меня это не влияет, поскольку я генерирую геометрию и соответствующие узлы после того, как масштабирование было применено к уровню.
Одно из предположений на данный момент состоит в том, что физическое моделирование разваливается на таком маленьком масштабе. Но я не полагаюсь на симуляцию сил, перемещающих тела ...
Есть ли более подходящий способ масштабирования мира физики?
Или я обнаружил ошибку в SCNPhysicsWorld, это что-то вне моего контроля в данный момент.
Одно из решений, о котором я подумал, заключалось в том, чтобы запустить всю симуляцию в масштабе 1: 1, но скрыто, а затем применить эти движения к более мелким объектам. Как вы понимаете, это повлияет на производительность всей сцены ...
@drewster Я создаю узлы в нужном мне масштабе, затем применяю к ним физические тела, а затем добавляю их на сцену. В приведенном выше коде для моих границ я вычисляю размер уровня, используя его ограничивающую рамку min и max, и применяю его масштаб, как в сцене.
Расстояние проникновения первого контакта отрицательное, что указывает на наличие зазора. Этот промежуток не увеличивается при уменьшении размера моделирования.
Чтобы устранить вышеупомянутый избыток, я реализовал дополнительную проверку контактов в Contact Delegate, чтобы не принимать первый обнаруженный контакт для определенной категории, а вместо этого обеспечивать положительное значение протяженности проникновения, таким образом обеспечивая перекрытие между два объекта, прежде чем инициировать изменение направления объекта, связанного с границей.
Вы имеете в виду, что вы изменяете масштаб узла после того, как он был создан и к нему был прикреплен SCNPhysicsBody?