从scenekit中提取顶点

Dar*_*ren 16 collada scenekit

我对了解scenekit几何有问题.

我有Blender的默认立方体,我导出为collada(DAE),并且可以将它带入scenekit ....一切都很好.

现在我想看到立方体的顶点.在DAE中,我可以看到"Cube-mesh-positions-array"的以下内容,

"1 1 -1 1 -1 -1 -1 -0.9999998 -1 -0.9999997 1 -1 1 0.9999995 1 0.9999994 -1.000001 1 -1 -0.9999997 1 -1 1 1"

现在我想在scenekit中做的是使用以下内容返回顶点:

SCNGeometrySource *vertexBuffer = [[cubeNode.geometry geometrySourcesForSemantic:SCNGeometrySourceSemanticVertex] objectAtIndex:0];
Run Code Online (Sandbox Code Playgroud)

如果我处理vertexBuffer(我已经尝试了很多查看数据的方法),它似乎不正确.

有人可以解释"SCNGeometrySourceSemanticVertex"给我的内容,以及如何正确提取顶点数据?我想看到的是:

X = "float"
Y = "float"
Z = "float"
Run Code Online (Sandbox Code Playgroud)

此外,我正在调查以下类/方法,这看起来很有前景(这里有一些好的数据值),但是来自gmpe的数据显示为空,是否有人能够解释"SCNGeometryElement"的数据属性包含什么?

SCNGeometryElement *gmpe = [theCurrentNode.geometry geometryElementAtIndex:0];
Run Code Online (Sandbox Code Playgroud)

谢谢,非常感谢,

d

Dav*_*ist 25

几何源

当你调用时,geometrySourcesForSemantic:你会得到一个SCNGeometrySource具有给定语义的对象数组,在你的情况下是顶点数据的来源).

此数据可能已经被编码在许多不同的方式和多个源可以用不同的使用相同的数据strideoffset.源本身有一堆的属性让你能够解码data例如像

  • dataStride
  • dataOffset
  • vectorCount
  • componentsPerVector
  • bytesPerComponent

您可以使用这些组合来确定data要读取哪些部分并从中创建顶点.

解码

步幅告诉您应该步进多少字节到达下一个向量,偏移量告诉您在到达该向量的相关数据段之前应该偏离该向量的起始偏移的字节数.您应该为每个向量读取的字节数是componentsPerVector*bytesPerComponent

读出单个几何源的所有顶点的代码看起来像这样

// Get the vertex sources
NSArray *vertexSources = [geometry geometrySourcesForSemantic:SCNGeometrySourceSemanticVertex];

// Get the first source
SCNGeometrySource *vertexSource = vertexSources[0]; // TODO: Parse all the sources

NSInteger stride = vertexSource.dataStride; // in bytes
NSInteger offset = vertexSource.dataOffset; // in bytes

NSInteger componentsPerVector = vertexSource.componentsPerVector;
NSInteger bytesPerVector = componentsPerVector * vertexSource.bytesPerComponent;
NSInteger vectorCount = vertexSource.vectorCount;

SCNVector3 vertices[vectorCount]; // A new array for vertices

// for each vector, read the bytes
for (NSInteger i=0; i<vectorCount; i++) {

    // Assuming that bytes per component is 4 (a float)
    // If it was 8 then it would be a double (aka CGFloat)
    float vectorData[componentsPerVector];

    // The range of bytes for this vector
    NSRange byteRange = NSMakeRange(i*stride + offset, // Start at current stride + offset
                                    bytesPerVector);   // and read the lenght of one vector

    // Read into the vector data buffer
    [vertexSource.data getBytes:&vectorData range:byteRange];

    // At this point you can read the data from the float array
    float x = vectorData[0];
    float y = vectorData[1];
    float z = vectorData[2];

    // ... Maybe even save it as an SCNVector3 for later use ...
    vertices[i] = SCNVector3Make(x, y, z);

    // ... or just log it 
    NSLog(@"x:%f, y:%f, z:%f", x, y, z);
}
Run Code Online (Sandbox Code Playgroud)

几何元素

这将为您提供所有顶点,但不会告诉您如何使用它们来构造几何体.为此,您需要几何元素来管理顶点的索引.

您可以从geometryElementCount属性中获取一块几何的几何元素的数量.然后你可以使用不同的元素geometryElementAtIndex:.

元素可以告诉您顶点是使用单个三角形还是三角形条带.它还告诉你每个索引的字节数(索引可能是ints或shorts,这对于解码它是必要的data.


oli*_*ver 5

如果数据不连续(向量大小不等于步幅),这是一种扩展方法,当从 DAE 文件加载几何时可能会出现这种情况。它也不使用 copyByte 函数。

extension  SCNGeometry{


    /**
     Get the vertices (3d points coordinates) of the geometry.

     - returns: An array of SCNVector3 containing the vertices of the geometry.
     */
    func vertices() -> [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
                let x = buffer[start]
                let y = buffer[start + 1]
                let z = buffer[start + 2]
                result.append(SCNVector3(x, y, z))
            }
            return result
        }
    }
}
Run Code Online (Sandbox Code Playgroud)