Неправильные данные вершин при получении источников из геометрии SCNNode
Я использую приведенный ниже код внутри расширения SCNGeometry, чтобы получить данные вершины, и аналогичный код для .normals, моя цель — создать клонированную сетку из исходного узла, чтобы раскрасить каждую вершину, но когда я пытаюсь создать другой узел с этими вершинами и нормалями в результирующей сетке есть несколько перепутанных треугольников, у меня есть небольшая сетка для тестирования, и вот что я получил. Кто-нибудь из вас может подсказать, что я мог делать неправильно?
В примере эта функция возвращает мне массив из 50 вершин, в то время как сетка на самом деле имеет 18 граней, следовательно, результатом должен быть массив из 54 вершин, я прав?
Оригинальная сетка Клонированная сетка
Расширение:
func extGetVertices() -> [SCNVector3]? {
let sources = self.sources(for: .vertex)
guard let source = sources.first else{return nil}
let stride = source.dataStride / source.bytesPerComponent
let offset = source.dataOffset / source.bytesPerComponent
let vectorCount = source.vectorCount
return source.data.withUnsafeBytes { (buffer : UnsafePointer<Float>) -> [SCNVector3] in
var result = Array<SCNVector3>()
for i in 0...vectorCount - 1 {
let start = i * stride + offset
result.append(SCNVector3(buffer[start], buffer[start+ 1], buffer[start+ 2]))
}
return result
}
}
цель:
#
# object obj_12853878
#
v 1097 957 36
v 779.26361083984375 992 0
v 707.26361083984375 590.5828857421875 91
v 1076 334.41595458984375 0
v 748.26361083984375 326.41595458984375 0
v 732.01263427734375 22.33051872253417968 0
v 1110.4652099609375 639.2049560546875 0
v 335.71615600585937504 680.5828857421875 39
v 314.88912963867187504 369.207000732421875 9.023892608628001E-14
v 350.4644775390625 926.65570068359375 -33
v 36 358.41595458984375 0
v 0 0 -33
v 0 680.5828857421875 -27
v 0 957 19
v 335.71615600585937504 22 0
v 1076 0 30
# 16 vertices
vn -0.08388713002204895 0.23459480702877044 0.9684669375419616
vn 0 0 1
vn 0.24344816803932188 -0.28190669417381288 0.92804181575775152
vn -0.1642393171787262 -0.11176854372024536 0.98006796836853024
vn -0.11669350415468216 0.28533965349197388 0.9512959122657776
vn 0.00356122362427413 -0.0920381024479866 0.99574911594390864
vn -0.19254806637763976 0.06056648120284081 0.9794166088104248
vn 0.13100945949554444 -0.1627427488565445 0.97793215513229376
vn -0.0974447876214981 -0.0058451765216887 0.9952237606048584
vn -0.03258795291185379 -0.3300407826900482 0.9434040188789368
vn 0.23050078749656676 -0.09988142549991608 0.967932403087616
vn -0.07897967845201492 0.233848974108696 0.96905976533889776
vn 0.00482096569612622 -0.1245955303311348 0.99219590425491328
vn -0.18483471870422364 0.28617173433303832 0.940181851387024
vn -0.08079835772514343 0.08905769884586334 0.99274384975433344
vn 1.8364935581471252E-16 -2.4888339972415545E-16 1
# 16 vertex normals
g obj_12853878
s 1
f 1//1 2//1 3//1
f 4//2 5//2 6//2
f 7//3 3//3 5//3
f 3//4 8//4 9//4
f 2//5 10//5 8//5
f 9//6 11//6 12//6
f 8//7 13//7 11//7
f 10//8 14//8 13//8
f 15//9 9//9 12//9
f 5//10 3//10 9//10
f 7//11 1//11 3//11
f 2//12 8//12 3//12
f 8//13 11//13 9//13
f 10//14 13//14 8//14
f 4//15 6//15 16//15
f 7//2 5//2 4//2
f 5//2 15//2 6//2
f 5//16 9//16 15//16
#18 polygons
Код клона:
guard let let vertices = node.geometry?.extGetVertices() else {return nil}
guard let let normals = node.geometry?.extGetNormals() else {return nil}
guard let let indices = (0..<vertices.count).indices.map {Int32($0)}
let vertexSource = SCNGeometrySource(vertices: vertices)
let indexElement = SCNGeometryElement(indices: indices, primitiveType: SCNGeometryPrimitiveType.triangles)
let normalSource = SCNGeometrySource(normals: normals)
let voxelGeometry = SCNGeometry(sources: [vertexSource, normalSource], elements: [indexElement])
let voxelMaterial = SCNMaterial()
voxelMaterial.diffuse.contents = UIColor.white
voxelGeometry.materials = [voxelMaterial]
let clonedNode = SCNNode(geometry: voxelGeometry)
2 ответа
Хорошо, я нашел свою первоначальную проблему, я создавал массив индексов как серию последовательных чисел, но их можно было получить и из исходного меша.
func extGetIndices() -> [Int32]? {
guard let dataCount = self.elements.first?.data.count else { return nil }
let faces = self.elements.first?.data.withUnsafeBytes {(ptr: UnsafeRawBufferPointer) -> [Int32] in
guard let boundPtr = ptr.baseAddress?.assumingMemoryBound(to: Int32.self) else {return []}
let buffer = UnsafeBufferPointer(start: boundPtr, count: dataCount / 4)
return Array<Int32>(buffer)
}
return faces
}
Итак, обновленный код для клонирования узла:
guard let let vertices = node.geometry?.extGetVertices() else {return nil}
guard let let normals = node.geometry?.extGetNormals() else {return nil}
guard let let indices = node.geometry?.extGetIndices() else {return nil}
let vertexSource = SCNGeometrySource(vertices: vertices)
let indexElement = SCNGeometryElement(indices: indices, primitiveType: SCNGeometryPrimitiveType.triangles)
let normalSource = SCNGeometrySource(normals: normals)
let voxelGeometry = SCNGeometry(sources: [vertexSource, normalSource], elements: [indexElement])
let voxelMaterial = SCNMaterial()
voxelMaterial.diffuse.contents = UIColor.white
voxelGeometry.materials = [voxelMaterial]
let clonedNode = SCNNode(geometry: voxelGeometry)
Кроме того, узел можно раскрасить с помощью SCNGeometrySource типа color и добавить цвета для каждой вершины:
let colors = getRandomColors(vertices.count)
let colorData = NSData(bytes: colors , length: MemoryLayout<SCNVector3>.stride * colors.count)
let colorSource = SCNGeometrySource(data: colorData as Data, semantic: .color, vectorCount: colors.count, usesFloatComponents: true, componentsPerVector: 3, bytesPerComponent: MemoryLayout<Float>.size, dataOffset: 0, dataStride: MemoryLayout<SCNVector3>.stride)
let voxelGeometry = SCNGeometry(sources: [vertexSource, normalSource, colorSource ], elements: [indexElement])
//random colors function
func getRandomColors(count: Int) -> [SCNVector3] {
var colors: [SCNVector3] = []
for _ in 0..<count {
let red = Double.random(in: 0...1)
let green = Double.random(in: 0...1)
let blue = Double.random(in: 0...1)
colors.append(SCNVector3(red, green, blue))
}
return colors
}
Вот пример:
func cloneNode(node: SCNNode) -> SCNNode? {
guard let vertices = node.geometry?.extGetVertices() else {return nil}
guard let normals = node.geometry?.extGetNormals() else {return nil}
let indices = (0..<vertices.count).indices.map {Int32($0)}
// initialise color source
struct RGBColor {
let r,g,b : Float
}
var colors : [RGBColor] = []
// to have contiguous memory space
colors.reserveCapacity(vertices.count)
// convert to color geometry source
let colorsAsData = NSData(bytes: colors, length: MemoryLayout<RGBColor>.size * colors.count) as Data
// fill colors arrays
let colorSource = SCNGeometrySource(data: colorsAsData,
semantic: .color,
vectorCount: colors.count,
usesFloatComponents: true,
componentsPerVector: 3,
bytesPerComponent: MemoryLayout<Float>.size,
dataOffset: MemoryLayout.offset(of: \RGBColor.r)!,
dataStride: MemoryLayout<RGBColor>.stride)
let vertexSource = SCNGeometrySource(vertices: vertices)
let indexElement = SCNGeometryElement(indices: indices, primitiveType: SCNGeometryPrimitiveType.triangles)
let normalSource = SCNGeometrySource(normals: normals)
// Add the colors source in the list
let voxelGeometry = SCNGeometry(sources: [vertexSource, normalSource, colorSource], elements: [indexElement])
let voxelMaterial = SCNMaterial()
voxelMaterial.diffuse.contents = UIColor.white
voxelGeometry.materials = [voxelMaterial]
let clonedNode = SCNNode(geometry: voxelGeometry)
return clonedNode
}