SceneKit:如何从3D模型中识别和访问人脸?

Cra*_*lot 2 3d mesh polygon ios scenekit

在 Blender 中,您可以查看和访问 3D 模型的每个面,如下所示: https: //poly.google.com/view/6mRHqTCZHxw

在此输入图像描述

SceneKit 是否可以做同样的事情,即访问模型的每个面?

这个问题是类似的,暗示这是不可能的,但没有确认 SceneKit 是否允许您以编程方式访问模型的所有面。(它的重点是识别触摸的脸部。)

两个问题:

1)你能以编程方式访问每张脸吗?

2) 您能否过滤并仅访问可见的面(即忽略“内部”或被其他面遮挡的面)?

Sté*_*pin 7

@Xartec 对第一个问题的答案的实现,也基于 Apple 文档,在 Swift 5.3 中:

extension SCNGeometryElement {
    var faces: [[Int]] {
        func arrayFromData<Integer: BinaryInteger>(_ type: Integer.Type, startIndex: Int = 0, size: Int) -> [Int] {
            assert(self.bytesPerIndex == MemoryLayout<Integer>.size)
            return [Integer](unsafeUninitializedCapacity: size) { arrayBuffer, capacity in
                self.data.copyBytes(to: arrayBuffer, from: startIndex..<startIndex + size * MemoryLayout<Integer>.size)
                capacity = size
            }
                .map { Int($0) }
        }

        func integersFromData(startIndex: Int = 0, size: Int = self.primitiveCount) -> [Int] {
            switch self.bytesPerIndex {
            case 1:
                return arrayFromData(UInt8.self, startIndex: startIndex, size: size)
            case 2:
                return arrayFromData(UInt16.self, startIndex: startIndex, size: size)
            case 4:
                return arrayFromData(UInt32.self, startIndex: startIndex, size: size)
            case 8:
                return arrayFromData(UInt64.self, startIndex: startIndex, size: size)
            default:
                return []
            }
        }

        func vertices(primitiveSize: Int) -> [[Int]] {
            integersFromData(size: self.primitiveCount * primitiveSize)
                .chunked(into: primitiveSize)
        }

        switch self.primitiveType {
        case .point:
            return vertices(primitiveSize: 1)
        case .line:
            return vertices(primitiveSize: 2)
        case .triangles:
            return vertices(primitiveSize: 3)
        case .triangleStrip:
            let vertices = integersFromData(size: self.primitiveCount + 2)
            return (0..<vertices.count - 2).map { index in
                Array(vertices[(index..<(index + 3))])
            }
        case .polygon:
            let polygonSizes = integersFromData()
            let allPolygonsVertices = integersFromData(startIndex: polygonSizes.count * self.bytesPerIndex, size: polygonSizes.reduce(into: 0, +=))
            var current = 0
            return polygonSizes.map { count in
                defer {
                    current += count
                }
                return Array(allPolygonsVertices[current..<current + count])
            }
        @unknown default:
            return []
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

生成的数组是一个面数组,每个面包含一个顶点索引列表。可以在那里找到
如何从中提取顶点的答案,并且可以更新以获取颜色。SCNGeometrySource/sf/answers/4672420581/

您将需要这个扩展来实现chunked(into:)上面使用的方法:


extension Collection {
    func chunked(into size: Index.Stride) -> [[Element]] where Index: Strideable {
        precondition(size > 0, "Chunk size should be atleast 1")
        return stride(from: self.startIndex, to: self.endIndex, by: size).map {
            Array(self[$0..<Swift.min($0.advanced(by: size), self.endIndex)])
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

对于#2,我不相信有办法。