我有一个Swift应用程序使用SceneKit iOS 8。从一个.dae文件加载一个场景,包含一个骨架控制的网格。
在运行时,我需要修改纹理坐标。使用变换不是一个选项 – 我需要为网格中的每个顶点计算一个不同的,全新的UV。
在运行时,我需要修改纹理坐标。使用变换不是一个选项 – 我需要为网格中的每个顶点计算一个不同的,全新的UV。
我知道几何在SceneKit中是不可变的,我已经读过,建议的方法是手动复制一个副本。我试图这样做,但我总是最终崩溃时试图重新创建SCNSkinner在代码中。崩溃是在C3DSourceAccessorGetMutableValuePtrAtIndex内的EXC_BAD_ACCESS。不幸的是,没有这个源代码,所以我不知道为什么它崩溃。我将它缩小到连接到网格节点的SCNSkinner对象。如果我不设置,我不会崩溃,事情似乎工作。
编辑:这里是一个更完整的调用堆栈的崩溃:
C3DSourceAccessorGetMutableValuePtrAtIndex C3DSkinPrepareMeshForGPUIfNeeded C3DSkinnerMakeCurrentMesh C3DSkinnerUpdateCurrentMesh __CFSetApplyFunction_block_invoke CFBasicHashApply CFSetApplyFunction C3DAppleEngineRenderScene ...
我没有找到任何关于如何手动创建SCNSkinner对象的文档或示例代码。因为我只是基于一个以前工作的网格创建它,它不应该太难。我根据Swift文档创建SCNSkinner,将所有正确的东西传递到init。但是,在SCNSkinner中有一个框架属性,我不知道如何设置。我把它设置到我复制的网格的原始SCNSkinner上的骨架,我认为
应该工作…但它不。设置框架属性时,它似乎未分配。在分配之后立即检查它是否仍然为零。作为一个测试,我试图将原始网格的骨架属性设置为别的东西,并且在分配之后,它也保持不变。
任何人都可以知道发生了什么?或者如何手动正确创建和设置SCNSkinner对象?
这里是我使用的代码手动克隆一个网格,并用一个新的替换(我没有修改任何源数据在这里 – 我只是想确保我可以在这一点上创建一个副本) :
// 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)
这三种方法可以帮助您找到解决方案:
>
SCNNode *hero = [SCNScene sceneNamed:@"Hero"].rootNode; SCNNode *hat = [SCNScene sceneNamed:@"FancyFedora"].rootNode; hat.skinner.skeleton = hero.skinner.skeleton;
>
[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,frame); }
>参见this link。