iOS 8 용 SceneKit을 사용하는 Swift 앱이 있습니다. 골격으로 제어되는 메시가 포함 된 .dae 파일에서 장면을로드합니다. 런타임에 텍스처 좌표를 수정해야합니다. 변형을 사용하는 것은 옵션이 아닙니다. 메시의 각 정점에 대해 완전히 새로운 UV를 계산해야합니다.
저는 SceneKit에서 지오메트리를 변경할 수 없다는 것을 알고 있으며 제안 된 접근 방식은 수동으로 복사하는 것임을 읽었습니다. 나는 그렇게하려고 노력하고 있지만 SCNSkinner
코드 를 다시 만들려고 할 때 항상 충돌이 발생 합니다. 충돌은 EXC_BAD_ACCESS
내부 C3DSourceAccessorGetMutableValuePtrAtIndex
입니다. 불행히도 이것에 대한 소스 코드가 없기 때문에 정확히 왜 충돌하는지 모르겠습니다. SCNSkinner
메쉬 노드에 연결된 개체 로 좁혔습니다 . 설정하지 않으면 충돌이 발생하지 않고 작동하는 것처럼 보입니다.
편집 : 다음은 충돌의 더 완전한 호출 스택입니다.
C3DSourceAccessorGetMutableValuePtrAtIndex
C3DSkinPrepareMeshForGPUIfNeeded
C3DSkinnerMakeCurrentMesh
C3DSkinnerUpdateCurrentMesh
__CFSetApplyFunction_block_invoke
CFBasicHashApply
CFSetApplyFunction
C3DAppleEngineRenderScene
...
SCNSkinner
수동으로 개체 를 만드는 방법에 대한 문서 나 예제 코드를 찾지 못했습니다 . 이전에 작업 한 메시를 기반으로 생성하고 있기 때문에 그렇게 어렵지 않습니다. 내가 만드는거야 SCNSkinner
초기화에 올바른 일을 모두 통과, 스위프트 문서에 따라. 그러나 SCNSkinner
설정 방법을 잘 모르겠다 는 골격 속성이 있습니다. SCNSkinner
복사중인 메시 의 원본에있는 스켈레톤으로 설정 했는데 작동해야한다고 생각합니다 ...하지만 그렇지 않습니다. 스켈레톤 속성을 설정할 때 할당되는 것처럼 보이지 않습니다. 할당 직후에 확인하면 여전히 nil임을 알 수 있습니다. 테스트로 원래 메시의 스켈레톤 속성을 다른 것으로 설정하려고했고 할당 후에도 그대로 두었습니다.
아무도 무슨 일이 일어나고 있는지에 대해 밝힐 수 있습니까? 또는 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)