SCNGeometry с полигоном в качестве примитиваТипа

Пытаясь выяснить, как я создаю SCNGeometry с полигоном как primitiveType, моя цель состоит в том, чтобы добавить узел в форме многоугольника как дочерний элемент сферы и сделать его похожим на MKPolygon для набора карт, как в этом примере.

MKPolygon

Мой текущий код:

//Take an arbitrary array of vectors
let vertices: [SCNVector3] = [
SCNVector3Make(-0.1304485, 0.551937, 0.8236193),
SCNVector3Make(0.01393811, 0.601815, 0.7985139),
SCNVector3Make(0.2971005, 0.5591929, 0.7739732),
SCNVector3Make(0.4516893, 0.5150381, 0.7285002),
SCNVector3Make(0.4629132, 0.4383712, 0.7704169),
SCNVector3Make(0.1333823, 0.5224985, 0.8421428),
SCNVector3Make(-0.1684743, 0.4694716, 0.8667254)]

//Does polygon shape require indices?
let indices: [Int] = [0,1,2,3,4,5,6]

let vertexSource = SCNGeometrySource(vertices: vertices)
let indexData = Data(bytes: indices, count: indices.count * MemoryLayout<Int>.size)

//Note!!! I get compiler error if primitiveCount is greater than 0
let element = SCNGeometryElement(data: indexData, primitiveType: .polygon, primitiveCount: 0, bytesPerIndex: MemoryLayout<Int>.size)
let geometry = SCNGeometry(sources: [vertexSource], elements: [element])

let material = SCNMaterial()
material.diffuse.contents = UIColor.purple.withAlphaComponent(0.75)
material.isDoubleSided = true
geometry.firstMaterial = material

let node = SCNNode(geometry: geometry)

При использовании SCNGeometryElement, как это, я получаю пустой узел.

1 ответ

Решение

У вас есть проблемы:

  1. SceneKit (и Metal) поддерживают только 32-битные целые числа в качестве индексов ( источник). Таким образом, тип вашего массива индексов должен быть [Int32],

  2. Для полигонов SceneKit нужны две части информации: количество точек в многоугольнике и индекс точки в массиве вершин. Из яблочной документации по SCNGeometryPrimitiveTypePolygon (которая существует только в Objective-C):

Свойство data элемента содержит две последовательности значений.

  • Первая последовательность имеет число значений, равное значению primitiveCount элемента геометрии. Каждое значение в этой последовательности указывает количество вершин в примитиве многоугольника. Например, если первая последовательность [5, 3], геометрический элемент содержит пятиугольник, за которым следует треугольник.
  • Остальные данные представляют собой последовательность индексов вершин. Каждая запись в первой последовательности указывает соответствующее количество записей во второй последовательности. Например, если первая последовательность включает значения [5, 3], вторая последовательность включает пять индексов для пятиугольника, за которыми следуют три индекса для треугольника.

Вам нужно изменить ваш индексный массив на:

let indices: [Int32] = [7, /* We have a polygon with seven points */,
                        0,1,2,3,4,5,6 /* The seven indices for our polygon */
                       ]

Тогда вы можете установить primitiveCount к 1 (у нас есть один многоугольник для рисования) и нужно изменить размер нашего буфера

let indexData = Data(bytes: indices, 
                     count: indices.count * MemoryLayout<Int32>.size)

// Now without runtime error
let element = SCNGeometryElement(data: indexData, 
                                 primitiveType: .polygon,
                                 primitiveCount: 1, 
                                 bytesPerIndex: MemoryLayout<Int32>.size)
Другие вопросы по тегам