### Swift SceneKit Integration with Animations Source: https://context7.com/warrenm/gltfkit2/llms.txt Integrate GLTFKit2 with SceneKit in Swift to load models and play animations. This example shows asynchronous loading and playing the first animation found. ```Swift // Swift - SceneKit integration with animations import GLTFKit2 import SceneKit class ViewController: NSViewController { var sceneView: SCNView! var animations = [GLTFSCNAnimation]() func loadModel() { guard let url = Bundle.main.url(forResource: "Model", withExtension: "glb") else { return } GLTFAsset.load(with: url, options: [:]) { [weak self] (progress, status, asset, error, _) in guard status == .complete, let asset = asset else { return } DispatchQueue.main.async { let source = GLTFSCNSceneSource(asset: asset) self?.sceneView.scene = source.defaultScene self?.animations = source.animations // Play first animation if available if let firstAnimation = source.animations.first { firstAnimation.animationPlayer.animation.usesSceneTimeBase = false firstAnimation.animationPlayer.animation.repeatCount = .greatestFiniteMagnitude source.defaultScene?.rootNode.addAnimationPlayer(firstAnimation.animationPlayer, forKey: nil) firstAnimation.animationPlayer.play() } } } } } ``` -------------------------------- ### Build and Run gltfkit2 Tests Source: https://github.com/warrenm/gltfkit2/blob/master/GLTFKit2/deps/cgltf/README.md Instructions for building and executing the test suite for gltfkit2. This involves navigating to the test directory, creating a build directory, configuring with CMake, compiling, and running the Python test script. ```bash cd test ; mkdir build ; cd build ; cmake .. -DCMAKE_BUILD_TYPE=Debug make -j cd .. ./test_all.py ``` -------------------------------- ### Accessing Extensions and Extras in Objective-C Source: https://context7.com/warrenm/gltfkit2/llms.txt Demonstrates how to access asset-level, root-level, and object-specific extensions and extras from a glTF asset. It also shows how to retrieve data from the texture transform extension. Ensure GLTFKit2 is imported. ```Objective-C // Objective-C - Accessing extensions and extras #import GLTFAsset *asset = [GLTFAsset assetWithURL:modelURL options:@{} error:nil]; // Asset-level extensions info NSLog(@"Extensions used: %@", asset.extensionsUsed); NSLog(@"Extensions required: %@", asset.extensionsRequired); // Root-level extensions if (asset.rootExtensions.count > 0) { NSLog(@"Root extensions: %@", asset.rootExtensions); } // Root-level extras if (asset.rootExtras) { NSLog(@"Root extras: %@", asset.rootExtras); } // Access extensions on any GLTFObject for (GLTFNode *node in asset.nodes) { if (node.extensions.count > 0) { NSLog(@"Node '%@' extensions: %@", node.name, node.extensions); } if (node.extras) { NSLog(@"Node '%@' extras: %@", node.name, node.extras); // Extras can contain arbitrary JSON data if ([node.extras isKindOfClass:[NSDictionary class]]) { NSDictionary *extrasDict = (NSDictionary *)node.extras; NSString *customProperty = extrasDict[@"myCustomProperty"]; } } } // Access texture transform extension data for (GLTFMaterial *material in asset.materials) { if (material.metallicRoughness.baseColorTexture.transform) { GLTFTextureTransform *transform = material.metallicRoughness.baseColorTexture.transform; NSLog(@"Texture offset: (%.2f, %.2f)", transform.offset.x, transform.offset.y); NSLog(@"Texture rotation: %.2f", transform.rotation); NSLog(@"Texture scale: (%.2f, %.2f)", transform.scale.x, transform.scale.y); // Get the combined transform matrix simd_float4x4 uvMatrix = transform.matrix; } } ``` -------------------------------- ### Load glTF from File Source: https://github.com/warrenm/gltfkit2/blob/master/GLTFKit2/deps/cgltf/README.md Use this function to parse a glTF file from disk. Ensure CGLTF_IMPLEMENTATION is defined in exactly one source file. The library does not load external buffer or image data by default. ```c #define CGLTF_IMPLEMENTATION #include "cgltf.h" cgltf_options options = {0}; cgltf_data* data = NULL; cgltf_result result = cgltf_parse_file(&options, "scene.gltf", &data); if (result == cgltf_result_success) { /* TODO make awesome stuff */ cgltf_free(data); } ``` -------------------------------- ### C Headers for gltfkit2 Source: https://github.com/warrenm/gltfkit2/blob/master/GLTFKit2/deps/cgltf/README.md These are the standard C headers required by the gltfkit2 implementation. Ensure these are available in your build environment. ```c #include #include #include #include #include #include #include // If asserts are enabled. ``` -------------------------------- ### Access Punctual Light Data (KHR_lights_punctual) Source: https://context7.com/warrenm/gltfkit2/llms.txt Retrieves punctual light data, including color, intensity, and type (directional, point, spot), from a GLTF asset. It also identifies nodes with attached lights. ```objective-c // Objective-C - Accessing light data #import GLTFAsset *asset = [GLTFAsset assetWithURL:modelURL options:@{} error:nil]; for (GLTFLight *light in asset.lights) { NSLog(@"Light: %@", light.name); NSLog(@"Color: (%.2f, %.2f, %.2f)", light.color.x, light.color.y, light.color.z); NSLog(@"Intensity: %.2f", light.intensity); switch (light.type) { case GLTFLightTypeDirectional: NSLog(@"Type: Directional"); break; case GLTFLightTypePoint: NSLog(@"Type: Point"); NSLog(@"Range: %.2f", light.range); break; case GLTFLightTypeSpot: NSLog(@"Type: Spot"); NSLog(@"Range: %.2f", light.range); NSLog(@"Inner cone angle: %.2f rad (%.2f deg)", light.innerConeAngle, GLTFDegFromRad(light.innerConeAngle)); NSLog(@"Outer cone angle: %.2f rad (%.2f deg)", light.outerConeAngle, GLTFDegFromRad(light.outerConeAngle)); break; } } // Find nodes with attached lights for (GLTFNode *node in asset.nodes) { if (node.light) { NSLog(@"Node '%@' has light '%@'", node.name, node.light.name); // Light direction/position is determined by node transform } } ``` -------------------------------- ### Load glTF from Memory Source: https://github.com/warrenm/gltfkit2/blob/master/GLTFKit2/deps/cgltf/README.md Parses glTF data directly from a memory buffer. Define CGLTF_IMPLEMENTATION in one source file. External resources like buffers and images are not loaded automatically. ```c #define CGLTF_IMPLEMENTATION #include "cgltf.h" void* buf; /* Pointer to glb or gltf file data */ size_t size; /* Size of the file data */ cgltf_options options = {0}; cgltf_data* data = NULL; cgltf_result result = cgltf_parse(&options, buf, size, &data); if (result == cgltf_result_success) { /* TODO make awesome stuff */ cgltf_free(data); } ``` -------------------------------- ### Load glTF Asset Asynchronously (Swift) Source: https://github.com/warrenm/gltfkit2/blob/master/README.md Use this method to load a glTF 2.0 model asynchronously. The URL must be a local file URL. Loading of remote assets and resources is not supported. ```swift let url = ... GLTFAsset.load(with: url, options: [:]) { (progress, status, maybeAsset, maybeError, _) in // Check for completion and/or error, use asset if complete, etc. } ``` -------------------------------- ### Load glTF Asset Asynchronously (Objective-C) Source: https://context7.com/warrenm/gltfkit2/llms.txt Loads a glTF asset asynchronously with progress reporting. This is the preferred method as it doesn't block the main thread. The handler is called multiple times during loading with progress updates and finally with the completed asset. ```objective-c // Objective-C - Asynchronous loading with progress #import NSURL *assetURL = [NSURL fileURLWithPath:@"/path/to/model.gltf"]; [GLTFAsset loadAssetWithURL:assetURL options:@{} handler:^(float progress, GLTFAssetStatus status, GLTFAsset *asset, NSError *error, BOOL *stop) { switch (status) { case GLTFAssetStatusParsing: NSLog(@"Parsing... %.0f%%", progress * 100); break; case GLTFAssetStatusValidating: NSLog(@"Validating..."); break; case GLTFAssetStatusProcessing: NSLog(@"Processing..."); break; case GLTFAssetStatusComplete: NSLog(@"Asset loaded successfully!"); NSLog(@"Copyright: %@", asset.copyright); NSLog(@"Generator: %@", asset.generator); // Use asset on main thread dispatch_async(dispatch_get_main_queue(), ^{ [self displayAsset:asset]; }); break; case GLTFAssetStatusError: NSLog(@"Error loading asset: %@", error.localizedDescription); break; } }]; ``` -------------------------------- ### Load glTF Asset Asynchronously (Objective-C) Source: https://github.com/warrenm/gltfkit2/blob/master/README.md Use this method to load a glTF 2.0 model asynchronously. The URL must be a local file URL. Loading of remote assets and resources is not supported. ```obj-c NSURL *url = ...; [GLTFAsset loadAssetWithURL:url options:@{} handler:^(float progress, GLTFAssetStatus status, GLTFAsset *asset, NSError *error, BOOL *stop) { // Check for completion and/or error, use asset if complete, etc. }]; ``` -------------------------------- ### Access Camera Data in Objective-C Source: https://context7.com/warrenm/gltfkit2/llms.txt Retrieve camera projection parameters, including perspective and orthographic settings, and identify nodes with attached cameras. Camera position and orientation can be derived from the node's transform matrix. ```Objective-C // Objective-C - Accessing camera data #import GLTFAsset *asset = [GLTFAsset assetWithURL:modelURL options:@{} error:nil]; for (GLTFCamera *camera in asset.cameras) { NSLog(@"Camera: %@", camera.name); NSLog(@"Near: %.2f, Far: %.2f", camera.zNear, camera.zFar); if (camera.perspective) { GLTFPerspectiveProjectionParams *persp = camera.perspective; NSLog(@"Type: Perspective"); NSLog(@"Y FOV: %.2f rad (%.2f deg)", persp.yFOV, GLTFDegFromRad(persp.yFOV)); NSLog(@"Aspect ratio: %.2f", persp.aspectRatio); } if (camera.orthographic) { GLTFOrthographicProjectionParams *ortho = camera.orthographic; NSLog(@"Type: Orthographic"); NSLog(@"X magnitude: %.2f", ortho.xMag); NSLog(@"Y magnitude: %.2f", ortho.yMag); } } // Find nodes with attached cameras for (GLTFNode *node in asset.nodes) { if (node.camera) { NSLog(@"Camera '%@' attached to node '%@'", node.camera.name, node.name); // Camera position/orientation from node.matrix } } ``` -------------------------------- ### glTF PBR to Metal Roughness Kernel Source: https://github.com/warrenm/gltfkit2/blob/master/GLTFKit2/GLTFKit2/impl/WorkflowShaders.txt A Metal compute kernel that processes diffuse and specular-glossiness textures to generate base color and roughness-metallic textures. It samples input textures, applies optional unpremultiplication, and uses the get_rm_from_sg function for conversion. ```metal kernel void sg_to_mr(texture2d diffuseTexture [[texture(0)]], texture2d specularGlossinessTexture [[texture(1)]], texture2d baseColorTexture [[texture(2)]], texture2d roughnessMetallicTexture [[texture(3)]], constant sg_to_rm_params ¶ms [[buffer(0)]], uint2 index [[thread_position_in_grid]]) { constexpr sampler linearSampler(coord::normalized, address::clamp_to_edge, filter::linear); uint outputWidth = baseColorTexture.get_width(); uint outputHeight = baseColorTexture.get_height(); if (index.x >= outputWidth || index.y >= outputHeight) { return; } float2 uv { float(index.x) / outputWidth, float(index.y) / outputHeight }; float3 diffuseColor = {0}; float opacity = 1; if (!is_null_texture(diffuseTexture)) { float4 sampledDiffuse = diffuseTexture.sample(linearSampler, uv); if (params.unpremultiplyDiffuse) { sampledDiffuse.rgb /= sampledDiffuse.a; } diffuseColor.rgb = sampledDiffuse.rgb; opacity = sampledDiffuse.a; } float3 specularColor = params.specularFactor; float glossiness = params.glossinessFactor; if (!is_null_texture(specularGlossinessTexture)) { float4 sampledSpecGloss = specularGlossinessTexture.sample(linearSampler, uv); if (params.unpremultiplySpecular) { specularColor *= (sampledSpecGloss.rgb / sampledSpecGloss.a); } else { specularColor *= sampledSpecGloss.rgb; } glossiness *= sampledSpecGloss.a; } float3 baseColor; float metallic, roughness; get_rm_from_sg(diffuseColor.rgb, specularColor, glossiness, &baseColor, &metallic, &roughness); baseColorTexture.write(float4(baseColor, opacity), ushort2(index)); roughnessMetallicTexture.write(float4(0.0, roughness, metallic, 1.0), ushort2(index)); } ``` -------------------------------- ### Convert GLTFAsset to MDLAsset for Model I/O Source: https://context7.com/warrenm/gltfkit2/llms.txt Converts a GLTFAsset to an MDLAsset for use with the Model I/O framework. Supports custom buffer allocators for Metal integration. ```Objective-C // Objective-C - Model I/O integration #import #import #import GLTFAsset *gltfAsset = [GLTFAsset assetWithURL:modelURL options:@{} error:nil]; // Convert to MDLAsset using class extension MDLAsset *mdlAsset = [MDLAsset assetWithGLTFAsset:gltfAsset]; // Or with a custom buffer allocator for Metal integration id device = MTLCreateSystemDefaultDevice(); MTKMeshBufferAllocator *allocator = [[MTKMeshBufferAllocator alloc] initWithDevice:device]; MDLAsset *metalAsset = [MDLAsset assetWithGLTFAsset:gltfAsset bufferAllocator:allocator]; // Access meshes from MDLAsset for (MDLObject *object in metalAsset) { if ([object isKindOfClass:[MDLMesh class]]) { MDLMesh *mesh = (MDLMesh *)object; NSLog(@"Mesh vertex count: %lu", (unsigned long)mesh.vertexCount); } } ``` -------------------------------- ### Load glTF Asset Synchronously (Objective-C) Source: https://context7.com/warrenm/gltfkit2/llms.txt Loads a glTF 2.0 asset from a local file URL synchronously. This method blocks until the asset is fully loaded. Use when immediate access to asset data is required. ```objective-c // Objective-C - Synchronous loading #import NSURL *assetURL = [[NSBundle mainBundle] URLForResource:@"Model" withExtension:@"glb"]; NSError *error = nil; GLTFAsset *asset = [GLTFAsset assetWithURL:assetURL options:@{} error:&error]; if (asset) { NSLog(@"Loaded asset: %@", asset.name); NSLog(@"Version: %@", asset.version); NSLog(@"Meshes: %lu", (unsigned long)asset.meshes.count); NSLog(@"Materials: %lu", (unsigned long)asset.materials.count); NSLog(@"Animations: %lu", (unsigned long)asset.animations.count); NSLog(@"Default scene: %@", asset.defaultScene.name); // Access nodes in the default scene for (GLTFNode *node in asset.defaultScene.nodes) { NSLog(@"Node: %@, has mesh: %@", node.name, node.mesh ? @"YES" : @"NO"); } } else { NSLog(@"Failed to load asset: %@", error.localizedDescription); } ``` -------------------------------- ### Access PBR Material Properties in Objective-C Source: https://context7.com/warrenm/gltfkit2/llms.txt Iterate through materials in a GLTF asset to access PBR properties, textures, and advanced extensions. Ensure the asset is loaded before accessing materials. ```objective-c #import GLTFAsset *asset = [GLTFAsset assetWithURL:modelURL options:@{} error:nil]; for (GLTFMaterial *material in asset.materials) { NSLog(@"Material: %@", material.name); NSLog(@"Double-sided: %@", material.isDoubleSided ? @"YES" : @"NO"); NSLog(@"Alpha mode: %ld", (long)material.alphaMode); NSLog(@"Alpha cutoff: %.2f", material.alphaCutoff); NSLog(@"Unlit: %@", material.isUnlit ? @"YES" : @"NO"); // Metallic-Roughness PBR properties if (material.metallicRoughness) { GLTFPBRMetallicRoughnessParams *pbr = material.metallicRoughness; NSLog(@"Base color: (%.2f, %.2f, %.2f, %.2f)", pbr.baseColorFactor.x, pbr.baseColorFactor.y, pbr.baseColorFactor.z, pbr.baseColorFactor.w); NSLog(@"Metallic factor: %.2f", pbr.metallicFactor); NSLog(@"Roughness factor: %.2f", pbr.roughnessFactor); if (pbr.baseColorTexture) { NSLog(@"Has base color texture: YES"); } if (pbr.metallicRoughnessTexture) { NSLog(@"Has metallic-roughness texture: YES"); } } // Emissive properties if (material.emissive) { GLTFEmissiveParams *emissive = material.emissive; NSLog(@"Emissive factor: (%.2f, %.2f, %.2f)", emissive.emissiveFactor.x, emissive.emissiveFactor.y, emissive.emissiveFactor.z); NSLog(@"Emissive strength: %.2f", emissive.emissiveStrength); } // Clearcoat extension if (material.clearcoat) { NSLog(@"Clearcoat factor: %.2f", material.clearcoat.clearcoatFactor); NSLog(@"Clearcoat roughness: %.2f", material.clearcoat.clearcoatRoughnessFactor); } // Transmission extension if (material.transmission) { NSLog(@"Transmission factor: %.2f", material.transmission.transmissionFactor); } // Volume extension if (material.volume) { NSLog(@"Thickness factor: %.2f", material.volume.thicknessFactor); NSLog(@"Attenuation distance: %.2f", material.volume.attenuationDistance); } // Sheen extension if (material.sheen) { NSLog(@"Sheen color: (%.2f, %.2f, %.2f)", material.sheen.sheenColorFactor.x, material.sheen.sheenColorFactor.y, material.sheen.sheenColorFactor.z); } // Iridescence extension if (material.iridescence) { NSLog(@"Iridescence factor: %.2f", material.iridescence.iridescenceFactor); NSLog(@"Iridescence IOR: %.2f", material.iridescence.iridescenceIndexOfRefraction); } // Index of refraction if (material.indexOfRefraction) { NSLog(@"IOR: %.2f", material.indexOfRefraction.floatValue); } } ``` -------------------------------- ### Load GLTF Assets with Security-Scoped URLs Source: https://context7.com/warrenm/gltfkit2/llms.txt Configures asset loading for sandboxed applications to access files outside their container. Pass the asset directory URL to enable security-scoped access to connected resources. ```objective-c // Objective-C - Security-scoped loading for sandboxed apps #import // When loading .gltf files with external resources (textures, .bin files) // from outside the app sandbox, pass the directory URL NSURL *assetURL = openPanel.URL; // User-selected file NSURL *assetDirectory = [assetURL URLByDeletingLastPathComponent]; NSDictionary *options = @{ GLTFAssetAssetDirectoryURLKey: assetDirectory }; [GLTFAsset loadAssetWithURL:assetURL options:options handler:^(float progress, GLTFAssetStatus status, GLTFAsset *asset, NSError *error, BOOL *stop) { if (status == GLTFAssetStatusComplete) { // Asset and all connected resources loaded successfully // The framework handles security-scoped access internally } }]; ``` -------------------------------- ### Advanced SceneKit Access with GLTFSCNSceneSource Source: https://context7.com/warrenm/gltfkit2/llms.txt Use GLTFSCNSceneSource for fine-grained control over SceneKit elements. Access default and all scenes, nodes, cameras, lights, and animations. Load asset metadata like copyright and generator. ```Objective-C // Objective-C - Advanced SceneKit access with GLTFSCNSceneSource #import #import GLTFAsset *asset = [GLTFAsset assetWithURL:modelURL options:@{} error:nil]; GLTFSCNSceneSource *source = [[GLTFSCNSceneSource alloc] initWithAsset:asset]; // Access default scene SCNScene *defaultScene = source.defaultScene; // Access all scenes for (SCNScene *scene in source.scenes) { NSLog(@"Scene available"); } // Access individual nodes for (SCNNode *node in source.nodes) { NSLog(@"Node: %@", node.name); } // Access cameras for (SCNCamera *camera in source.cameras) { NSLog(@"Camera FOV: %f", camera.fieldOfView); } // Access lights for (SCNLight *light in source.lights) { NSLog(@"Light type: %ld", (long)light.type); } // Access and play animations for (GLTFSCNAnimation *animation in source.animations) { NSLog(@"Animation: %@", animation.name); animation.animationPlayer.animation.usesSceneTimeBase = NO; animation.animationPlayer.animation.repeatCount = HUGE_VALF; [defaultScene.rootNode addAnimationPlayer:animation.animationPlayer forKey:animation.name]; [animation.animationPlayer play]; } // Get asset metadata NSString *copyright = [source propertyForKey:GLTFAssetPropertyKeyCopyright]; NSString *generator = [source propertyForKey:GLTFAssetPropertyKeyGenerator]; ``` -------------------------------- ### Configure Draco Mesh Decompression Source: https://context7.com/warrenm/gltfkit2/llms.txt Sets up Draco mesh decompression by implementing the GLTFDracoMeshDecompressor protocol and registering a custom decompressor class. This allows GLTFKit2 to load assets with Draco-compressed meshes. ```objective-c // Objective-C - Draco decompression setup #import // Implement the protocol in your decompressor class @interface MyDracoDecompressor : NSObject @end @implementation MyDracoDecompressor + (GLTFPrimitive *)newPrimitiveForCompressedBufferView:(GLTFBufferView *)bufferView attributeMap:(NSDictionary *)attributes { // Get compressed data NSData *compressedData = bufferView.buffer.data; const uint8_t *bytes = (const uint8_t *)compressedData.bytes + bufferView.offset; size_t length = bufferView.length; // Decode with Draco library (implementation depends on your Draco integration) // Create and return a GLTFPrimitive with decoded data // ... Draco decoding implementation ... return decodedPrimitive; } @end // Register the decompressor before loading assets [GLTFAsset setDracoDecompressorClassName:@"MyDracoDecompressor"]; // Now load assets with Draco-compressed meshes GLTFAsset *asset = [GLTFAsset assetWithURL:dracoModelURL options:@{} error:nil]; ``` -------------------------------- ### Using Material Variants in Objective-C Source: https://context7.com/warrenm/gltfkit2/llms.txt Apply specific material variants to a glTF model when loading it with GLTFSCNSceneSource. This allows switching between different material configurations defined within the glTF file. ```Objective-C // Objective-C - Using material variants #import GLTFAsset *asset = [GLTFAsset assetWithURL:modelURL options:@{} error:nil]; // List available material variants for (GLTFMaterialVariant *variant in asset.materialVariants) { NSLog(@"Available variant: %@", variant.name); } // Load scene with a specific variant applied if (asset.materialVariants.count > 0) { GLTFMaterialVariant *selectedVariant = asset.materialVariants[0]; GLTFSCNSceneSource *source = [[GLTFSCNSceneSource alloc] initWithAsset:asset applyingMaterialVariant:selectedVariant]; sceneView.scene = source.defaultScene; } // Access effective material for a variant on a primitive for (GLTFMesh *mesh in asset.meshes) { for (GLTFPrimitive *primitive in mesh.primitives) { GLTFMaterial *baseMaterial = primitive.material; for (GLTFMaterialVariant *variant in asset.materialVariants) { GLTFMaterial *variantMaterial = [primitive effectiveMaterialForVariant:variant]; if (variantMaterial) { NSLog(@"Variant '%@' uses material: %@", variant.name, variantMaterial.name); } } } } ``` -------------------------------- ### Access Animation Data in Objective-C Source: https://context7.com/warrenm/gltfkit2/llms.txt Iterate through animations in a GLTF asset to access channels, samplers, keyframe times, and values. This code requires the GLTFKit2 framework and a loaded GLTF asset. ```objective-c // Objective-C - Accessing animation data #import GLTFAsset *asset = [GLTFAsset assetWithURL:modelURL options:@{} error:nil]; for (GLTFAnimation *animation in asset.animations) { NSLog(@"Animation: %@", animation.name); NSLog(@"Channels: %lu", (unsigned long)animation.channels.count); NSLog(@"Samplers: %lu", (unsigned long)animation.samplers.count); for (GLTFAnimationChannel *channel in animation.channels) { GLTFAnimationTarget *target = channel.target; GLTFAnimationSampler *sampler = channel.sampler; NSLog(@"Target node: %@", target.node.name); NSLog(@"Target path: %@", target.path); // translation, rotation, scale, or weights // Interpolation mode switch (sampler.interpolationMode) { case GLTFInterpolationModeLinear: NSLog(@"Interpolation: Linear"); break; case GLTFInterpolationModeStep: NSLog(@"Interpolation: Step"); break; case GLTFInterpolationModeCubic: NSLog(@"Interpolation: Cubic"); break; } // Access keyframe times GLTFAccessor *inputAccessor = sampler.input; NSData *timesData = GLTFPackedDataForAccessor(inputAccessor); const float *times = (const float *)timesData.bytes; NSLog(@"Keyframe count: %ld", (long)inputAccessor.count); NSLog(@"Duration: %.2f seconds", times[inputAccessor.count - 1]); // Access keyframe values GLTFAccessor *outputAccessor = sampler.output; NSData *valuesData = GLTFPackedDataForAccessor(outputAccessor); NSLog(@"Output value dimension: %ld", (long)outputAccessor.dimension); } } ``` -------------------------------- ### Load glTF Asset Asynchronously (Swift) Source: https://context7.com/warrenm/gltfkit2/llms.txt Loads a glTF asset asynchronously in Swift. This method is non-blocking and provides progress updates. Ensure to handle the asset on the main thread after loading. ```swift // Swift - Asynchronous loading import GLTFKit2 let assetURL = Bundle.main.url(forResource: "DamagedHelmet", withExtension: "glb", subdirectory: "Models")! GLTFAsset.load(with: assetURL, options: [:]) { (progress, status, maybeAsset, maybeError, _) in DispatchQueue.main.async { switch status { case .complete: guard let asset = maybeAsset else { return } print("Loaded asset with \(asset.meshes.count) meshes") self.processAsset(asset) case .error: if let error = maybeError { print("Failed to load glTF asset: \(error)") } default: print("Loading progress: \(Int(progress * 100))%") } } } ``` -------------------------------- ### Convert glTF PBR to Metal Roughness Source: https://github.com/warrenm/gltfkit2/blob/master/GLTFKit2/GLTFKit2/impl/WorkflowShaders.txt Converts glTF's diffuse, specular, and glossiness inputs into Metal's base color, metallic, and roughness outputs. It calculates base color from both diffuse and specular components and mixes them based on the metallic value. ```metal static void get_rm_from_sg(float3 diffuse, float3 specular, float glossiness, thread float3 *outBaseColor, thread float *outMetallic, thread float *outRoughness) { const float epsilon = 1e-6; float oneMinusSpecularStrength = 1 - max_component(specular); float metallic = solve_metallic(y_from_rgb(diffuse), y_from_rgb(specular), oneMinusSpecularStrength); float3 baseColorFromDiffuse = diffuse * (oneMinusSpecularStrength / (1 - dielectricF0.r) / max(1 - metallic, epsilon)); float3 baseColorFromSpecular = specular - (dielectricF0 * (1 - metallic)) * (1 / max(metallic, epsilon)); float3 baseColor = mix(baseColorFromDiffuse, baseColorFromSpecular, metallic * metallic); *outBaseColor = baseColor; *outMetallic = metallic; *outRoughness = 1 - glossiness; } ``` -------------------------------- ### Write glTF to File Source: https://github.com/warrenm/gltfkit2/blob/master/GLTFKit2/deps/cgltf/README.md Writes a `cgltf_data` structure to a glTF file. Requires `CGLTF_IMPLEMENTATION` and `CGLTF_WRITE_IMPLEMENTATION` to be defined. The function does not deallocate the provided data structure. ```c #define CGLTF_IMPLEMENTATION #define CGLTF_WRITE_IMPLEMENTATION #include "cgltf_write.h" cgltf_options options = {0}; cgltf_data* data = /* TODO must be valid data */; cgltf_result result = cgltf_write_file(&options, "out.gltf", data); if (result != cgltf_result_success) { /* TODO handle error */ } ``` -------------------------------- ### Convert glTF Asset to SceneKit Scene Source: https://context7.com/warrenm/gltfkit2/llms.txt Converts a loaded GLTFAsset into a SceneKit SCNScene. This conversion preserves meshes, materials, lights, cameras, and animations. Options can be provided to control aspects like alpha-blended material depth writing. ```Objective-C // Objective-C - SceneKit integration #import #import // Load the asset GLTFAsset *asset = [GLTFAsset assetWithURL:modelURL options:@{} error:nil]; // Convert to SceneKit scene using class extension SCNScene *scene = [SCNScene sceneWithGLTFAsset:asset]; // Or with options to control alpha-blended material depth writing SCNScene *sceneWithOptions = [SCNScene sceneWithGLTFAsset:asset options:@{GLTFSCNAlphaBlendedMaterialsWriteDepth: @YES}]; // Assign to SCNView sceneView.scene = scene; sceneView.allowsCameraControl = YES; sceneView.autoenablesDefaultLighting = YES; // Add environment lighting scene.lightingEnvironment.contents = @"studio.hdr"; scene.lightingEnvironment.intensity = 1.0; ``` -------------------------------- ### Load glTF Asset from NSData Source: https://context7.com/warrenm/gltfkit2/llms.txt Loads a glTF asset from in-memory NSData. Supports both .gltf and .glb formats. Use this when assets are downloaded or extracted from archives. The asynchronous version provides progress updates and status. ```Objective-C // Objective-C - Loading from NSData #import // Load data from any source (network, archive, etc.) NSData *assetData = [NSData dataWithContentsOfURL:downloadedURL]; NSError *error = nil; GLTFAsset *asset = [GLTFAsset assetWithData:assetData options:@{} error:&error]; if (asset) { NSLog(@"Successfully loaded asset from data"); NSLog(@"Extensions used: %@", [asset.extensionsUsed componentsJoinedByString:@", "]); NSLog(@"Extensions required: %@", [asset.extensionsRequired componentsJoinedByString:@", "]); } // Asynchronous version with handler [GLTFAsset loadAssetWithData:assetData options:@{} handler:^(float progress, GLTFAssetStatus status, GLTFAsset *asset, NSError *error, BOOL *stop) { if (status == GLTFAssetStatusComplete) { // Process loaded asset } }]; ``` -------------------------------- ### Access Skeletal Animation (Skin) Data Source: https://context7.com/warrenm/gltfkit2/llms.txt Iterates through skins in a GLTF asset to access joint hierarchies and inverse bind matrices. It also identifies nodes that are skinned. ```objective-c // Objective-C - Accessing skin/skeleton data #import GLTFAsset *asset = [GLTFAsset assetWithURL:modelURL options:@{} error:nil]; for (GLTFSkin *skin in asset.skins) { NSLog(@"Skin: %@", skin.name); NSLog(@"Joint count: %lu", (unsigned long)skin.joints.count); // Skeleton root node if (skin.skeleton) { NSLog(@"Skeleton root: %@", skin.skeleton.name); } // Joint hierarchy for (GLTFNode *joint in skin.joints) { NSLog(@"Joint: %@, isJoint: %@", joint.name, joint.isJoint ? @"YES" : @"NO"); if (joint.parentNode) { NSLog(@" Parent: %@", joint.parentNode.name); } } // Inverse bind matrices if (skin.inverseBindMatrices) { NSData *ibmData = GLTFPackedDataForAccessor(skin.inverseBindMatrices); const simd_float4x4 *matrices = (const simd_float4x4 *)ibmData.bytes; NSLog(@"Inverse bind matrix count: %ld", (long)skin.inverseBindMatrices.count); } } // Find skinned nodes for (GLTFNode *node in asset.nodes) { if (node.skin) { NSLog(@"Node '%@' uses skin '%@'", node.name, node.skin.name); if (node.mesh) { NSLog(@" Mesh: %@", node.mesh.name); } } } ``` -------------------------------- ### Convert GLTFScene to RealityKit Entity Source: https://context7.com/warrenm/gltfkit2/llms.txt Converts a GLTFScene to a RealityKit Entity for AR and visionOS applications. Supports PBR materials, lights, cameras, and animations. Use async loading for RealityKit. ```Swift // Swift - RealityKit integration (iOS 15+, macOS 12+, visionOS) import GLTFKit2 import RealityKit // Async loading for RealityKit Task { do { let url = Bundle.main.url(forResource: "Model", withExtension: "glb")! let entity = try await GLTFRealityKitLoader.load(from: url) // Add to RealityKit scene arView.scene.anchors.append(AnchorEntity(world: .zero)) arView.scene.anchors.first?.addChild(entity) // Play animations stored in the entity if let animation = entity.availableAnimations.first { entity.playAnimation(animation.repeat()) } } catch { print("Failed to load glTF: \(error)") } } // Manual conversion from GLTFScene let asset = try GLTFAsset(url: modelURL) if let scene = asset.defaultScene { await MainActor.run { let entity = GLTFRealityKitLoader.convert(scene: scene, asset: asset) // Use entity in your RealityKit scene } } ``` -------------------------------- ### Max Component Helper Function Source: https://github.com/warrenm/gltfkit2/blob/master/GLTFKit2/GLTFKit2/impl/WorkflowShaders.txt A utility function to find the maximum component value within a float3 vector. Used in PBR calculations. ```metal static float max_component(float3 v) { return max(max(v.x, v.y), v.z); } ``` -------------------------------- ### Write glTF to Memory Source: https://github.com/warrenm/gltfkit2/blob/master/GLTFKit2/deps/cgltf/README.md Serializes a `cgltf_data` structure into a memory buffer. Ensure `CGLTF_IMPLEMENTATION` and `CGLTF_WRITE_IMPLEMENTATION` are defined. The provided data is not deallocated by this function. ```c #define CGLTF_IMPLEMENTATION #define CGLTF_WRITE_IMPLEMENTATION #include "cgltf_write.h" cgltf_options options = {0}; cgltf_data* data = /* TODO must be valid data */; cgltf_size size = cgltf_write(&options, NULL, 0, data); char* buf = malloc(size); cgltf_size written = cgltf_write(&options, buf, size, data); if (written != size) { /* TODO handle error */ } ``` -------------------------------- ### Y from RGB Helper Function Source: https://github.com/warrenm/gltfkit2/blob/master/GLTFKit2/GLTFKit2/impl/WorkflowShaders.txt Calculates the luminance (Y) of an RGB color using standard coefficients. This is often used in PBR calculations involving diffuse or specular intensity. ```metal static float y_from_rgb(float3 rgb) { return dot(rgb, float3(0.2126, 0.7152, 0.0722)); } ``` -------------------------------- ### Traverse Scene Graph Nodes in Objective-C Source: https://context7.com/warrenm/gltfkit2/llms.txt Traverse the scene graph to access node names, transformations, and attached components like meshes, cameras, and lights. This function recursively visits child nodes. ```Objective-C // Objective-C - Scene graph traversal #import GLTFAsset *asset = [GLTFAsset assetWithURL:modelURL options:@{} error:nil]; void traverseNode(GLTFNode *node, int depth) { NSString *indent = [@"" stringByPaddingToLength:depth * 2 withString:@" " startingAtIndex:0]; NSLog(@"%@Node: %@", indent, node.name); // Transform components NSLog(@"%@ Translation: (%.2f, %.2f, %.2f)", indent, node.translation.x, node.translation.y, node.translation.z); NSLog(@"%@ Rotation: (%.2f, %.2f, %.2f, %.2f)", indent, node.rotation.vector.x, node.rotation.vector.y, node.rotation.vector.z, node.rotation.vector.w); NSLog(@"%@ Scale: (%.2f, %.2f, %.2f)", indent, node.scale.x, node.scale.y, node.scale.z); // Full 4x4 transform matrix simd_float4x4 matrix = node.matrix; // Attached components if (node.mesh) { NSLog(@"%@ Mesh: %@", indent, node.mesh.name); } if (node.camera) { NSLog(@"%@ Camera attached", indent); } if (node.light) { NSLog(@"%@ Light: %@", indent, node.light.name); } if (node.skin) { NSLog(@"%@ Skin: %@", indent, node.skin.name); } // Morph target weights if (node.weights) { NSLog(@"%@ Morph weights: %@", indent, node.weights); } // Mesh GPU instancing if (node.meshInstances) { NSLog(@"%@ Instance count: %ld", indent, (long)node.meshInstances.instanceCount); for (NSInteger i = 0; i < node.meshInstances.instanceCount; i++) { simd_float4x4 instanceTransform = [node.meshInstances transformAtIndex:i]; // Use instance transform for rendering } } // Recurse into children for (GLTFNode *child in node.childNodes) { traverseNode(child, depth + 1); } } // Traverse from scene roots for (GLTFScene *scene in asset.scenes) { NSLog(@"Scene: %@", scene.name); for (GLTFNode *rootNode in scene.nodes) { traverseNode(rootNode, 0); } } ``` -------------------------------- ### Access GLTF Mesh Data and Primitives Source: https://context7.com/warrenm/gltfkit2/llms.txt Provides direct access to mesh geometry data including vertices, normals, tangents, texture coordinates, and indices. Useful for custom rendering or mesh processing. ```Objective-C // Objective-C - Accessing mesh data #import GLTFAsset *asset = [GLTFAsset assetWithURL:modelURL options:@{} error:nil]; for (GLTFMesh *mesh in asset.meshes) { NSLog(@"Mesh: %@", mesh.name); NSLog(@"Morph target names: %@", mesh.targetNames); for (GLTFPrimitive *primitive in mesh.primitives) { // Get position attribute GLTFAttribute *positionAttr = [primitive attributeForName:GLTFAttributeSemanticPosition]; if (positionAttr) { GLTFAccessor *accessor = positionAttr.accessor; NSLog(@"Vertex count: %ld", (long)accessor.count); NSLog(@"Min bounds: %@", accessor.minValues); NSLog(@"Max bounds: %@", accessor.maxValues); // Get packed vertex data NSData *positionData = GLTFPackedDataForAccessor(accessor); const float *positions = (const float *)positionData.bytes; for (NSInteger i = 0; i < MIN(accessor.count, 5); i++) { NSLog(@"Vertex %ld: (%.2f, %.2f, %.2f)", (long)i, positions[i*3], positions[i*3+1], positions[i*3+2]); } } // Get normal attribute GLTFAttribute *normalAttr = [primitive attributeForName:GLTFAttributeSemanticNormal]; if (normalAttr) { NSLog(@"Has normals: YES"); } // Get texture coordinates GLTFAttribute *texCoordAttr = [primitive attributeForName:GLTFAttributeSemanticTexcoord0]; if (texCoordAttr) { NSLog(@"Has texture coordinates: YES"); } // Get indices if (primitive.indices) { NSData *indexData = GLTFPackedDataForAccessor(primitive.indices); NSLog(@"Index count: %ld", (long)primitive.indices.count); } // Access morph targets for (NSArray *target in primitive.targets) { for (GLTFAttribute *attr in target) { NSLog(@"Morph target attribute: %@", attr.name); } } } } ``` -------------------------------- ### Access GLTF Texture and Image Data Source: https://context7.com/warrenm/gltfkit2/llms.txt Extracts image data from GLTFImage objects for custom texture processing. Supports embedded images, external file references, and data URIs. Includes sampler settings and options for CGImage or Metal texture. ```objective-c // Objective-C - Accessing texture/image data #import #import GLTFAsset *asset = [GLTFAsset assetWithURL:modelURL options:@{} error:nil]; for (GLTFTexture *texture in asset.textures) { NSLog(@"Texture: %@", texture.name); // Sampler settings if (texture.sampler) { GLTFTextureSampler *sampler = texture.sampler; NSLog(@"Mag filter: %ld", (long)sampler.magFilter); NSLog(@"Min/mip filter: %ld", (long)sampler.minMipFilter); NSLog(@"Wrap S: %ld", (long)sampler.wrapS); NSLog(@"Wrap T: %ld", (long)sampler.wrapT); } // Get image source (prefers BasisU/WebP if available) GLTFImage *image = texture.basisUSource ?: texture.webpSource ?: texture.source; if (image) { // Infer media type NSString *mediaType = [image inferMediaType]; NSLog(@"Image media type: %@", mediaType); // Get CGImage for CPU-based processing CGImageRef cgImage = [image newCGImage]; if (cgImage) { NSLog(@"Image size: %zux%zu", CGImageGetWidth(cgImage), CGImageGetHeight(cgImage)); CGImageRelease(cgImage); } // Get Metal texture for GPU rendering (requires KTX2 support) id device = MTLCreateSystemDefaultDevice(); id mtlTexture = [image newTextureWithDevice:device]; if (mtlTexture) { NSLog(@"Metal texture: %lux%lu", mtlTexture.width, mtlTexture.height); } } } // Access images directly for (GLTFImage *image in asset.images) { NSLog(@"Image: %@", image.name); if (image.uri) { NSLog(@"URI: %@", image.uri); } if (image.bufferView) { NSLog(@"Embedded in buffer view, MIME type: %@", image.mimeType); } } ``` -------------------------------- ### Calculate Metallic Value Source: https://github.com/warrenm/gltfkit2/blob/master/GLTFKit2/GLTFKit2/impl/WorkflowShaders.txt Solves for the metallic value based on diffuse, specular, and a one-minus-specular-strength factor. Handles cases where specular is less than the dielectric Fresnel reflectance. ```metal static float solve_metallic(float diffuse, float specular, float oneMinusSpecularStrength) { if (specular < dielectricF0.r) { return 0; } float a = dielectricF0.r; float b = diffuse * oneMinusSpecularStrength / (1 - dielectricF0.r) + specular - 2 * dielectricF0.r; float c = dielectricF0.r - specular; float D = b * b - 4 * a * c; return saturate((-b + sqrt(D)) / (2 * a)); } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.