SceneKit выборочно окрашивает лицо по определенному индексу - PullRequest
1 голос
/ 17 апреля 2019

Моя цель: при заданном индексе i и некотором UIColor c сделать лицо с этим индексом цветным.

let vertices = // all of my vertices in the format of SCNVector3

let vertexSource = SCNGeometrySource(data: verticesData,
                                    semantic: .vertex,
                                    vectorCount: vertices.count,
                                    usesFloatComponents: true,
                                    componentsPerVector: 3,
                                    bytesPerComponent: MemoryLayout<Float>.size,
                                    dataOffset: 0,
                                    dataStride: MemoryLayout<SCNVector3>.size)


var colors: [SCNVector3] = vertices.map { SCNVector3(1, 1, 1) } // Make it all white color at first
colors[10] = SCNVector3(1, 0, 0)                                // Pick one at random and make it red
let colorSource = SCNGeometrySource(data: NSData(bytes: colors, length: MemoryLayout<SCNVector3>.size * colors.count) as Data,
                                    semantic: .color,
                                    vectorCount: colors.count,
                                    usesFloatComponents: true,
                                    componentsPerVector: 3,
                                    bytesPerComponent: MemoryLayout<Float>.size,
                                    dataOffset: 0,
                                    dataStride: MemoryLayout<SCNVector3>.size)

let elements = SCNGeometryElement(data: NSData(bytes: indices, length: MemoryLayout<Int32>.size * indices.count) as Data,
                                primitiveType: .polygon,
                                primitiveCount: indices.count / 4,
                                bytesPerIndex: MemoryLayout<Int32>.size)

let g = SCNGeometry(sources: [vertexSource, colorSource], elements: [element])

Мой 3D-объект отображается правильно. Это все белого цвета, как и ожидалось. Красное лицо, однако, не появляется. Я вижу намек на красный, но похоже, что SceneKit пытается закрасить вершины, а не лицо, которое образуют эти вершины. Как я могу заставить его просто закрасить лицо / многоугольник, созданный этими вершинами?

1 Ответ

1 голос
/ 22 мая 2019

То, что здесь происходит, лучше всего объяснить на простом примере. Вот плоскость, которая состоит из двух треугольников:

let vertices: [SCNVector3] = [
    SCNVector3(-1, 1, 0),
    SCNVector3( 1, 1, 0),
    SCNVector3( 1, -1, 0),
    SCNVector3(-1, -1, 0)
]
let indices: [UInt16] = [
    0, 3, 1,
    1, 3, 2
]
var colors: [SCNVector3] = vertices.map { _ in SCNVector3(1, 1, 1) }

Теперь, когда вы назначаете красный цвет только одной из записей в массиве colors, вы получаете такой результат:

enter image description here

Это имеет смысл, потому что вы назначаете цвет одной вершине, а не всему лицу. Красный цвет должен быть назначен каждому индексу лица (0, 3, 1), чтобы убедиться, что все лицо красное:

colors[0] = SCNVector3(1, 0, 0)
colors[3] = SCNVector3(1, 0, 0)
colors[1] = SCNVector3(1, 0, 0)

Что приводит к:

enter image description here

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

enter image description here

Тогда вам нужно будет продублировать вершины, общие для граней:

let vertices: [SCNVector3] = [
    SCNVector3(-1, 1, 0),
    SCNVector3(-1, -1, 0),
    SCNVector3( 1, 1, 0),

    SCNVector3( 1, 1, 0),
    SCNVector3(-1, -1, 0),
    SCNVector3( 1, -1, 0)
    ]

let indices: [UInt16] = [
    0, 1, 2,
    3, 4, 5
]

colors[0] = SCNVector3(1, 0, 0)
colors[1] = SCNVector3(1, 0, 0)
colors[2] = SCNVector3(1, 0, 0)
...