Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to access vertex of geometry? #25

Closed
tapmyads-dev1 opened this issue Nov 19, 2022 · 5 comments
Closed

How to access vertex of geometry? #25

tapmyads-dev1 opened this issue Nov 19, 2022 · 5 comments

Comments

@tapmyads-dev1
Copy link

We are trying to access all vertex positions of geometry to show Highlight point on them
could you share example of how to assess geometry vertex positions

@warrenm
Copy link
Owner

warrenm commented Nov 19, 2022

As GLTFKit2 is a fairly low-level framework, this is tedious but ultimately straightforward. One approach is to declare an Objective-C category on the GLTFPrimitive class that returns packed position data:

@interface GLTFPrimitive (VertexPositionAccess)
- (NSData *_Nullable)copyPackedVertexPositions;
@end

which could be implemented as follows

@implementation GLTFPrimitive (VertexPositionAccess)

- (NSData *)copyPackedVertexPositions {
    GLTFAccessor *positionAccessor = self.attributes[GLTFAttributeSemanticPosition];
    if (positionAccessor == nil) {
        return nil; // No position data, because the primitive didn't contain a position accessor
    }
    const void *sourceBufferBase = positionAccessor.bufferView.buffer.data.bytes;
    const void *sourceBase = sourceBufferBase + positionAccessor.offset + positionAccessor.bufferView.offset;
    if (sourceBase == NULL) {
        return nil; // No position data, because buffer view or buffer is NULL, or because the buffer contains no data
    }
    NSInteger vertexCount = positionAccessor.count;
    NSInteger destinationStride = sizeof(float) * 3;
    NSInteger bufferLength = destinationStride * vertexCount;
    NSInteger sourceStride = positionAccessor.bufferView.stride;
    if (sourceStride == 0) {
        sourceStride = destinationStride;
    }
    if (sourceStride == destinationStride) {
        // Existing data is already packed; just return a data object that acts as a view on it
        return [NSData dataWithBytesNoCopy:(void *)sourceBase length:bufferLength freeWhenDone:NO];
    } else {
        // Existing data is *not* packed; we need to copy it element by element
        void *packedBuffer = malloc(bufferLength);
        for (int i = 0; i < vertexCount; ++i) {
            const void *sourcePtr = sourceBase + i * sourceStride;
            void *destPtr = packedBuffer + i * destinationStride;
            memcpy(destPtr, sourcePtr, destinationStride);
        }
        return [NSData dataWithBytesNoCopy:packedBuffer length:bufferLength freeWhenDone:YES];
    }
}

@end

Back in Swift, assuming you have a reference to a primitive object, you could print out all of its vertices like this:

let vertexCount = primitive.attributes[GLTFAttributeSemantic.position.rawValue]?.count ?? 0
if let positionData = primitive.copyPackedVertexPositions() {
    positionData.withUnsafeBytes { positionPtr in
        for i in 0..<vertexCount {
            let position = positionPtr.baseAddress!
                .advanced(by: MemoryLayout<Float>.stride * 3 * i)
                .assumingMemoryBound(to: Float.self)
            let x = position[0]
            let y = position[1]
            let z = position[2]
            print("\(x) \(y) \(z)")
        }
    }
}

If you need to iterate over triangles in indexed order instead of just the raw vertex list, you can write a similar extension to retrieve the index data from the primitive. This is slightly more complex, because indices can be 8, 16, or 32 bits each, but at least index data is guaranteed to be packed.

@warrenm
Copy link
Owner

warrenm commented Nov 19, 2022

If you've already converted a glTF asset to a SceneKit scene, you can instead retrieve the vertex source of an SCNGeometry using the sources(for:) method, then iterate its data instead, making sure to account for the stride between vertices.

@warrenm
Copy link
Owner

warrenm commented Nov 21, 2022

This issue will be automatically closed in 7 days if no further comment is received.

@warrenm
Copy link
Owner

warrenm commented Nov 29, 2022

Closing due to inactivity.

@warrenm warrenm closed this as completed Nov 29, 2022
@adellari
Copy link

Is this still the best way to get vertex position data?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants