Установите шарнир SCNNode в ограничивающий центр объема, не меняя положение узла

Я ищу способ установить точку поворота узлов SCN (полученных при импорте файлов Collada) в их центроид (или в центр их ограничительной рамки. Я получаю центр с

 SCNVector3 center;
CGFloat radius;
[node getBoundingSphereCenter:&center radius:&radius];

Однако, когда я пытаюсь установить центр вращения узла (который является вектором 4D в отличие от вектора 3D центра) к центру, положение узла также изменяется.

node.pivot = SCNMatrix4MakeTranslation(center.x,center.y,center.z);

Как я могу компенсировать это движение - соотв. Как я могу только изменить шарнир узла, не влияя на его положение в пространстве? Или даже есть способ (без использования дополнительных пустых узлов) сделать это в Интерфейсном Разработчике?

2 ответа

Этот же вопрос был задан и здесь. Нормально ли для оси SCNNode изменение положения узлов?... но после поиска в Интернете в течение нескольких часов я не мог найти никакого закодированного решения этой проблемы. Вот как можно центрировать ось узла, не перемещая узел.

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

Возьми этот велосипед ниже. Ось z поворота кривошипа правой педали (синяя) направлена ​​вверх, в то время как на другой фотографии ось z поворота кривошипа левой педали (синяя) направлена ​​вниз. Причина, по которой эти оси отличаются, заключается в том, что когда человек рисовал модель велосипеда в SketchUp, он просто скопировал и перевернул первую рукоятку педали в противоположную сторону. Так что, к сожалению, очень часто можно получить импортированные модели DAE со специальной ориентацией и позицией!

 func centerPivotWithOutMoving(for node: SCNNode) -> SCNNode {

    let initialPos = activeNode.presentation.position

    var min = SCNVector3Zero
    var max = SCNVector3Zero
    node.__getBoundingBoxMin(&min, max: &max)

    node.pivot = SCNMatrix4MakeTranslation(
        min.x + (max.x - min.x)/2,
        min.y + (max.y - min.y)/2,
        min.z + (max.z - min.z)/2
    )
    let correctX = Float(min.x + (max.x - min.x)/2)
    let correctY = Float(min.y + (max.y - min.y)/2)
    let correctZ = Float(min.z + (max.z - min.z)/2)

    if node.convertVector(SCNVector3(0,0,1), from: parentNode).z < 0 {
        // if blue local z-axis is pointing downwards
        node.position = SCNVector3(initialPos.x - correctX, initialPos.y - correctY, initialPos.z - correctZ)
    } else {
        // if blue local z-axis is pointing upwards
        node.position = SCNVector3(initialPos.x + correctX, initialPos.y + correctY, initialPos.z + correctZ)
    }

    return node
}

Я только что тестировал код выше на двух различных ориентациях оси z, показанных выше, полный код также должен был бы иметь дело с осью x, y, используя эти два условия.

  node.convertVector(SCNVector3(0,1,0), from: parentNode).z < 0

  node.convertVector(SCNVector3(1,0,0), from: parentNode).z < 0   

Если есть лучший способ сделать это... пожалуйста, поделитесь?

Поворот - это не только центр вращения, это точка отсчета для позиции. Когда вы сбрасываете сводку, положение стержня относительно родительского объекта остается фиксированным. По сути, вы перемещаете геометрию относительно текущей позиции объекта.

Простое исправление состоит в том, чтобы изменить положение узла, используя отрицательные значения тех, которые использовались для сброса центральной точки. Если по какой-то причине вам нужно определенное значение, которое не позволяет этого, поместите свой узел в узел контейнера и используйте узел контейнера для положения, а ваш повторно развернутый узел для вращения.

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