如何在代码中创build一个SceneKit SCNSkinner对象?

我有一个使用SceneKit for iOS 8的Swift应用程序。我从包含由骨架控制的网格的.dae文件加载场景。 在运行时,我需要修改纹理坐标。 使用变换不是一个选项 – 我需要为网格中的每个顶点计算一个不同的,全新的UV。

我知道几何在SceneKit中是不可改变的,而且我读过build议的方法是手动创build一个副本。 我试图做到这一点,但是当试图在代码中重新创buildSCNSkinner时,我总是会崩溃。 崩溃是EXC_BAD_ACCESS C3DSourceAccessorGetMutableValuePtrAtIndex 。 不幸的是,这里没有源代码,所以我不确定它为什么崩溃。 我已经缩小到连接到网格节点的SCNSkinner对象。 如果我没有设置,我不会崩溃,事情似乎正在工作。

编辑:这是一个更完整的崩溃调用堆栈:

 C3DSourceAccessorGetMutableValuePtrAtIndex C3DSkinPrepareMeshForGPUIfNeeded C3DSkinnerMakeCurrentMesh C3DSkinnerUpdateCurrentMesh __CFSetApplyFunction_block_invoke CFBasicHashApply CFSetApplyFunction C3DAppleEngineRenderScene ... 

我还没有find关于如何手动创build一个SCNSkinner对象的任何文档或示例代码。 由于我只是基于以前的工作网格创build它,所以不应该太困难。 我正在根据Swift文档创buildSCNSkinner ,将所有正确的东西传递给init。 但是, SCNSkinner中有一个骨架属性,我不知道如何设置。 我把它设置在我正在复制的网格的原始SCNSkinner上的骨架,我认为这应该工作…但它不。 当设置骨架属性时,它似乎不是分配。 在赋值之后立即检查它仍然是零。 作为一个testing,我试图将原始网格的骨架属性设置为其他东西,并且在分配之后它也保持原样。

任何人都可以阐明发生的事情吗? 或者如何手动正确创build和设置一个SCNSkinner对象?

这里是我用来手动克隆一个网格的代码,并用一个新的replace(我没有修改任何源数据在这里 – 我只是想确保我可以创build一个副本在这一点上) :

 // 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 tried 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, dataStride: verts![0].dataStride) 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, dataStride: normals![0].dataStride) 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, dataStride: texcoords![0].dataStride) 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, dataStride: boneWeights![0].dataStride) 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, dataStride: boneIndices![0].dataStride) 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) 

这三种方法可能会帮助您find解决scheme:

  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. 看到这个链接 。