Проблема масштабирования при обнаружении контакта с физикой в ​​ios arkit + scenekit

У меня есть простая трехмерная область, содержащая 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, но скрыто, а затем применить эти движения к более мелким объектам. Как вы понимаете, это повлияет на производительность всей сцены ...

Вы имеете в виду, что вы изменяете масштаб узла после того, как он был создан и к нему был прикреплен SCNPhysicsBody?

drewster 16.04.2018 03:22

@drewster Я создаю узлы в нужном мне масштабе, затем применяю к ним физические тела, а затем добавляю их на сцену. В приведенном выше коде для моих границ я вычисляю размер уровня, используя его ограничивающую рамку min и max, и применяю его масштаб, как в сцене.

nightbird 16.04.2018 13:29
2
2
460
1

Ответы 1

Расстояние проникновения первого контакта отрицательное, что указывает на наличие зазора. Этот промежуток не увеличивается при уменьшении размера моделирования.

Чтобы устранить вышеупомянутый избыток, я реализовал дополнительную проверку контактов в Contact Delegate, чтобы не принимать первый обнаруженный контакт для определенной категории, а вместо этого обеспечивать положительное значение протяженности проникновения, таким образом обеспечивая перекрытие между два объекта, прежде чем инициировать изменение направления объекта, связанного с границей.

Другие вопросы по теме