Comment créer un object SceneKit SCNSkinner dans le code?

J’ai une application Swift utilisant SceneKit pour iOS 8. Je charge une scène à partir d’un fichier .dae contenant un maillage contrôlé par un squelette. Au moment de l’exécution, je dois modifier les coordonnées de texture. Utiliser une transformation n’est pas une option – je dois calculer un UV différent, complètement nouveau pour chaque sumt du maillage.

Je sais que la géomésortinge est immuable dans SceneKit, et j’ai lu que l’approche suggérée consiste à faire une copie manuellement. J’essaie de le faire, mais je SCNSkinner par SCNSkinner en SCNSkinner en essayant de recréer le SCNSkinner dans le code. Le crash est un EXC_BAD_ACCESS dans C3DSourceAccessorGetMutableValuePtrAtIndex . Malheureusement, il n’y a pas de code source pour cela, alors je ne sais pas exactement pourquoi il se bloque. Je l’ai réduit à l’object SCNSkinner attaché au nœud de maillage. Si je ne mets pas ça, je ne tombe pas en panne et les choses semblent fonctionner.

EDIT: Voici une stack d’appels plus complète du crash:

 C3DSourceAccessorGetMutableValuePtrAtIndex C3DSkinPrepareMeshForGPUIfNeeded C3DSkinnerMakeCurrentMesh C3DSkinnerUpdateCurrentMesh __CFSetApplyFunction_block_invoke CFBasicHashApply CFSetApplyFunction C3DAppleEngineRenderScene ... 

Je n’ai trouvé aucune documentation ou exemple de code sur la façon de créer un object SCNSkinner manuellement. Comme je ne le crée que sur un maillage antérieur, cela ne devrait pas être trop difficile. Je crée le SCNSkinner conformément à la documentation de Swift, en transmettant toutes les choses correctes dans init. Cependant, il existe une propriété squelette dans SCNSkinner dont je ne sais pas comment définir. Je le place sur le squelette qui se trouvait sur le SCNSkinner original du maillage que je copie, ce qui, je pense, devrait fonctionner … mais ce n’est pas le cas. Lors de la définition de la propriété squelette, elle ne semble pas être affectée. Le vérifier immédiatement après l’affectation montre qu’il est toujours nul. En guise de test, j’ai essayé de définir la propriété du squelette du maillage original sur autre chose, et après l’assignation, elle a également été laissée intacte.

Quelqu’un peut-il faire la lumière sur ce qui se passe? Ou comment créer et configurer correctement un object SCNSkinner manuellement?

Voici le code que j’utilise pour cloner manuellement un maillage et le remplacer par un nouveau (je n’ai modifié aucune des données source ici – j’essaie simplement de m’assurer de pouvoir en créer une copie à ce stade) :

 // This is at the start of the app, just so you can see how the scene is set up. // I add the .dae contents into its own node in the scene. This seems to be the // standard way to put multiple .dae models into the same scene. This doesn't seem to // have any impact on the problem I'm having -- I've sortinged without this indirection // and the same problem exists. let scene = SCNScene() let modelNode = SCNNode() modelNode.name = "ModelNode" scene.rootNode.addChildNode(modelNode) let modelScene = SCNScene(named: "model.dae") if modelScene != nil { if let childNodes = modelScene?.rootNode.childNodes { for childNode in childNodes { modelNode.addChildNode(childNode as SCNNode) } } } // This happens later in the app after a tap from the user. let modelNode = scnView.scene!.rootNode.childNodeWithName("ModelNode", recursively: true) let modelMesh = modelNode?.childNodeWithName("MeshName", recursively: true) let verts = modelMesh?.geometry!.geometrySourcesForSemantic(SCNGeometrySourceSemanticVertex) let normals = modelMesh?.geometry!.geometrySourcesForSemantic(SCNGeometrySourceSemanticNormal) let texcoords = modelMesh?.geometry!.geometrySourcesForSemantic(SCNGeometrySourceSemanticTexcoord) let boneWeights = modelMesh?.geometry!.geometrySourcesForSemantic(SCNGeometrySourceSemanticBoneWeights) let boneIndices = modelMesh?.geometry!.geometrySourcesForSemantic(SCNGeometrySourceSemanticBoneIndices) let geometry = modelMesh?.geometry!.geometryElementAtIndex(0) // Note: the vertex and normal data is shared. let vertsData = NSData(data: verts![0].data) let texcoordsData = NSData(data: texcoords![0].data) let boneWeightsData = NSData(data: boneWeights![0].data) let boneIndicesData = NSData(data: boneIndices![0].data) let geometryData = NSData(data: geometry!.data!) let newVerts = SCNGeometrySource(data: vertsData, semantic: SCNGeometrySourceSemanticVertex, vectorCount: verts![0].vectorCount, floatComponents: verts![0].floatComponents, componentsPerVector: verts![0].componentsPerVector, bytesPerComponent: verts![0].bytesPerComponent, dataOffset: verts![0].dataOffset, dataSsortingde: verts![0].dataSsortingde) let newNormals = SCNGeometrySource(data: vertsData, semantic: SCNGeometrySourceSemanticNormal, vectorCount: normals![0].vectorCount, floatComponents: normals![0].floatComponents, componentsPerVector: normals![0].componentsPerVector, bytesPerComponent: normals![0].bytesPerComponent, dataOffset: normals![0].dataOffset, dataSsortingde: normals![0].dataSsortingde) let newTexcoords = SCNGeometrySource(data: texcoordsData, semantic: SCNGeometrySourceSemanticTexcoord, vectorCount: texcoords![0].vectorCount, floatComponents: texcoords![0].floatComponents, componentsPerVector: texcoords![0].componentsPerVector, bytesPerComponent: texcoords![0].bytesPerComponent, dataOffset: texcoords![0].dataOffset, dataSsortingde: texcoords![0].dataSsortingde) let newBoneWeights = SCNGeometrySource(data: boneWeightsData, semantic: SCNGeometrySourceSemanticBoneWeights, vectorCount: boneWeights![0].vectorCount, floatComponents: boneWeights![0].floatComponents, componentsPerVector: boneWeights![0].componentsPerVector, bytesPerComponent: boneWeights![0].bytesPerComponent, dataOffset: boneWeights![0].dataOffset, dataSsortingde: boneWeights![0].dataSsortingde) let newBoneIndices = SCNGeometrySource(data: boneIndicesData, semantic: SCNGeometrySourceSemanticBoneIndices, vectorCount: boneIndices![0].vectorCount, floatComponents: boneIndices![0].floatComponents, componentsPerVector: boneIndices![0].componentsPerVector, bytesPerComponent: boneIndices![0].bytesPerComponent, dataOffset: boneIndices![0].dataOffset, dataSsortingde: boneIndices![0].dataSsortingde) let newGeometry = SCNGeometryElement(data: geometryData, primitiveType: geometry!.primitiveType, primitiveCount: geometry!.primitiveCount, bytesPerIndex: geometry!.bytesPerIndex) let newMeshGeometry = SCNGeometry(sources: [newVerts, newNormals, newTexcoords, newBoneWeights, newBoneIndices], elements: [newGeometry]) newMeshGeometry.firstMaterial = modelMesh?.geometry!.firstMaterial let newModelMesh = SCNNode(geometry: newMeshGeometry) let bones = modelMesh?.skinner?.bones let boneInverseBindTransforms = modelMesh?.skinner?.boneInverseBindTransforms let skeleton = modelMesh!.skinner!.skeleton! let baseGeometryBindTransform = modelMesh!.skinner!.baseGeometryBindTransform newModelMesh.skinner = SCNSkinner(baseGeometry: newMeshGeometry, bones: bones, boneInverseBindTransforms: boneInverseBindTransforms, boneWeights: newBoneWeights, boneIndices: newBoneIndices) newModelMesh.skinner?.baseGeometryBindTransform = baseGeometryBindTransform // Before this assignment, newModelMesh.skinner?.skeleton is nil. newModelMesh.skinner?.skeleton = skeleton // After, it is still nil... however, skeleton itself is completely valid. modelMesh?.removeFromParentNode() newModelMesh.name = "MeshName" let meshParentNode = modelNode?.childNodeWithName("MeshParentNode", recursively: true) meshParentNode?.addChildNode(newModelMesh) 

Ces trois méthodes peuvent vous aider à trouver la solution:

  1.  SCNNode *hero = [SCNScene sceneNamed:@"Hero"].rootNode; SCNNode *hat = [SCNScene sceneNamed:@"FancyFedora"].rootNode; hat.skinner.skeleton = hero.skinner.skeleton; 
  2.  [Export ("initWithFrame:")] public UIView (System.Drawing.RectangleF frame) : base (NSObjectFlag.Empty) { // Invoke the init method now. var initWithFrame = new Selector ("initWithFrame:").Handle; if (IsDirectBinding) Handle = ObjCRuntime.Messaging.IntPtr_objc_msgSend_RectangleF (this.Handle, initWithFrame, frame); else Handle = ObjCRuntime.Messaging.IntPtr_objc_msgSendSuper_RectangleF (this.SuperHandle, initWithFrame, frame); } 
  3. Voir aussi ce lien .