ฉันมีแอป Swift ที่ใช้ SceneKit สำหรับ iOS 8 ฉันโหลดฉากจากไฟล์. แดที่มีเมชที่ควบคุมโดยโครงกระดูก ในรันไทม์ฉันต้องแก้ไขพิกัดพื้นผิว การใช้การแปลงไม่ใช่ตัวเลือก - ฉันต้องคำนวณ UV ใหม่ที่แตกต่างกันโดยสิ้นเชิงสำหรับจุดยอดแต่ละจุดในตาข่าย
ฉันรู้ว่ารูปทรงเรขาคณิตไม่เปลี่ยนรูปใน SceneKit และฉันได้อ่านว่าแนวทางที่แนะนำคือการทำสำเนาด้วยตนเอง ฉันพยายามทำเช่นนั้น แต่ฉันมักจะขัดข้องเมื่อพยายามสร้างSCNSkinner
โค้ดใหม่อีกครั้ง ความผิดพลาดเป็นภายในEXC_BAD_ACCESS
C3DSourceAccessorGetMutableValuePtrAtIndex
น่าเสียดายที่ไม่มีซอร์สโค้ดสำหรับสิ่งนี้ดังนั้นฉันจึงไม่แน่ใจว่าทำไมมันถึงขัดข้อง ฉันได้ จำกัด ให้แคบลงตามSCNSkinner
วัตถุที่ติดกับโหนดตาข่าย ถ้าไม่ตั้งค่าก็ไม่เกิดปัญหาและดูเหมือนว่าสิ่งต่างๆจะใช้งานได้
แก้ไข:นี่คือกลุ่มการโทรที่สมบูรณ์ยิ่งขึ้นของความผิดพลาด:
C3DSourceAccessorGetMutableValuePtrAtIndex
C3DSkinPrepareMeshForGPUIfNeeded
C3DSkinnerMakeCurrentMesh
C3DSkinnerUpdateCurrentMesh
__CFSetApplyFunction_block_invoke
CFBasicHashApply
CFSetApplyFunction
C3DAppleEngineRenderScene
...
ฉันไม่พบเอกสารประกอบหรือรหัสตัวอย่างเกี่ยวกับวิธีสร้างSCNSkinner
วัตถุด้วยตนเอง เนื่องจากฉันเพิ่งสร้างมันขึ้นมาจากตาข่ายที่ใช้งานได้ก่อนหน้านี้จึงไม่น่าจะยากเกินไป ฉันกำลังสร้างSCNSkinner
ตามเอกสาร Swift โดยส่งผ่านสิ่งที่ถูกต้องทั้งหมดไปยัง 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)