SceneKit - пользовательская геометрия не отображается

Я должен увидеть 2 желтых треугольника, но ничего не вижу.

class Terrain {

    private class func createGeometry () -> SCNGeometry {

        let sources = [
            SCNGeometrySource(vertices:[
                SCNVector3(x: -1.0, y: -1.0, z:  0.0),
                SCNVector3(x: -1.0, y:  1.0, z:  0.0),
                SCNVector3(x:  1.0, y:  1.0, z:  0.0),
                SCNVector3(x:  1.0, y: -1.0, z:  0.0)], count:4),
            SCNGeometrySource(normals:[
                SCNVector3(x:  0.0, y:  0.0, z: -1.0),
                SCNVector3(x:  0.0, y:  0.0, z: -1.0),
                SCNVector3(x:  0.0, y:  0.0, z: -1.0),
                SCNVector3(x:  0.0, y:  0.0, z: -1.0)], count:4)
        ]

        let elements = [
            SCNGeometryElement(indices: [0, 2, 3, 0, 1, 2], primitiveType: .Triangles)
        ]

        let geo = SCNGeometry(sources:sources, elements:elements)

        let mat = SCNMaterial()
        mat.diffuse.contents = UIColor.yellowColor()
        mat.doubleSided = true
        geo.materials = [mat]

        return geo
    }

    class func createNode () -> SCNNode {

        let node = SCNNode(geometry: createGeometry())
        node.name = "Terrain"
        node.position = SCNVector3()
        return node
    }
}

Я использую это следующим образом:

let terrain = Terrain.createNode()
sceneView.scene?.rootNode.addChildNode(terrain)


let camera = SCNCamera()
camera.zFar = 10000
self.camera = SCNNode()
self.camera.camera = camera
self.camera.position = SCNVector3(x: -20, y: 15, z: 30)
let constraint = SCNLookAtConstraint(target: terrain)
constraint.gimbalLockEnabled = true
self.camera.constraints = [constraint]

sceneView.scene?.rootNode.addChildNode(self.camera)

Я получаю другие узлы с нестандартной геометрией, которые я вижу. В чем дело?

2 ответа

Решение

Примечание: см. Ответ Эша, который является гораздо лучшим подходом для современного Swift, чем этот.

Ваш индексный массив имеет неправильный элемент размера. Это выводится как [Int], Тебе нужно [CInt],

Я вырвал у тебя elements настроить в:

    let indices = [0, 2, 3, 0, 1, 2] // [Int]
    print(sizeof(Int))               // 8
    print(sizeof(CInt))              // 4
    let elements = [
        SCNGeometryElement(indices: indices, primitiveType: .Triangles)
    ]

Чтобы индексы были упакованы как ожидаемый массив C, объявите тип явно:

    let indices: [CInt] = [0, 2, 3, 0, 1, 2]

Пользовательская геометрия SceneKit в Swift на iOS не работает, но эквивалентный код Objective C делает более детальным, но он написан для Swift 1, так что вам придется сделать некоторый перевод.

SCNGeometryElement(indices:, primitiveType:) нигде не документируется, хотя и появляется в заголовках.

Хэл Мюллер совершенно прав в том, что задействованные индексы должны быть определенного типа, но следует отметить, что эта функциональность значительно изменилась в последних версиях языка Swift. Следует отметить, что SCNGeometryElement(indices:, primitiveType:) теперь работает отлично в Swift 4, и я бы посоветовал не использовать CInt который не работал для меня. Вместо этого используйте один из стандартных целочисленных типов, который соответствует FixedWidthInteger протокол, т.е. Int32, Если вы знаете, что в вашей сетке задействовано максимальное количество вершин, используйте наименьший размер битов, который будет охватывать все из них.

Пример:

    let vertices = [
        SCNVector3(x: 5, y: 4, z: 0),
        SCNVector3(x: -5 , y: 4, z: 0),
        SCNVector3(x: -5, y: -5, z: 0),
        SCNVector3(x: 5, y: -5, z: 0)
    ]

    let allPrimitives: [Int32] = [0, 1, 2, 0, 2, 3]
    let vertexSource = SCNGeometrySource(vertices: vertices)
    let element = SCNGeometryElement(indices: allPrimitives, primitiveType: .triangles)
    let geometry = SCNGeometry(sources: [vertexSource], elements: [element])

    SCNNode(geometry: geometry)

Что тут происходит?

Сначала мы создаем массив vertices описывающие точки в трехмерном пространстве. allPrimitives массив описывает, как эти вершины соединяются. Каждый элемент является индексом из vertices массив. Поскольку мы используем треугольники, их следует рассматривать в группах по три, по одному на каждый угол. Для простоты я сделал здесь простой плоский квадрат. Затем мы создаем источник геометрии с семантическим типом vertices используя исходный массив всех вершин и геометрический элемент, используя allPrimitives массив, также сообщая ему, что они являются треугольниками, поэтому он знает, чтобы сгруппировать их по три. Затем они могут быть использованы для создания SCNGeometry объект, с помощью которого мы инициализируем наш SCNNode,

Простой способ думать об этом состоит в том, что источник вершин существует только для перечисления всех вершин в объекте. Элемент геометрии существует только для описания того, как эти вершины связаны. Это SCNGeometry который объединяет эти два объекта вместе, чтобы создать окончательное физическое представление.

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