Tôi có một ứng dụng Swift bằng SceneKit cho iOS 8. Tôi tải một cảnh từ tệp .dae có chứa lưới được điều khiển bởi khung. Trong thời gian chạy, tôi cần sửa đổi tọa độ kết cấu. Sử dụng một phép biến đổi không phải là một lựa chọn - tôi cần tính toán một tia UV khác, hoàn toàn mới cho mỗi đỉnh trong lưới.
Tôi biết hình học là bất biến trong SceneKit và tôi đã đọc rằng cách tiếp cận được đề xuất là tạo một bản sao theo cách thủ công. Tôi đang cố gắng làm điều đó, nhưng cuối cùng tôi luôn gặp sự cố khi cố gắng tạo lại SCNSkinner
mã trong mã. Vụ tai nạn là một EXC_BAD_ACCESS
bên trong C3DSourceAccessorGetMutableValuePtrAtIndex
. Thật không may, không có mã nguồn nào cho việc này, vì vậy tôi không chắc chính xác tại sao nó lại gặp sự cố. Tôi đã thu hẹp nó xuống SCNSkinner
đối tượng được gắn vào nút lưới. Nếu tôi không đặt điều đó, tôi sẽ không gặp sự cố và mọi thứ dường như đang hoạt động.
CHỈNH SỬA: Đây là một ngăn xếp cuộc gọi đầy đủ hơn về sự cố:
C3DSourceAccessorGetMutableValuePtrAtIndex
C3DSkinPrepareMeshForGPUIfNeeded
C3DSkinnerMakeCurrentMesh
C3DSkinnerUpdateCurrentMesh
__CFSetApplyFunction_block_invoke
CFBasicHashApply
CFSetApplyFunction
C3DAppleEngineRenderScene
...
Tôi không tìm thấy bất kỳ tài liệu hoặc mã ví dụ nào về cách tạo một SCNSkinner
đối tượng theo cách thủ công. Vì tôi chỉ tạo nó dựa trên một lưới đã làm việc trước đó, nên không quá khó. Tôi đang tạo SCNSkinner
theo tài liệu Swift, chuyển tất cả những thứ chính xác vào init. Tuy nhiên, có một thuộc tính khung SCNSkinner
mà tôi không chắc chắn về cách đặt. Tôi đặt nó vào khung trên bản gốc SCNSkinner
của lưới mà tôi đang sao chép, mà tôi nghĩ sẽ hoạt động ... nhưng nó không. Khi đặt thuộc tính bộ xương, nó dường như không được chỉ định. Kiểm tra nó ngay sau khi được giao cho thấy rằng nó vẫn là con số không. Như một bài kiểm tra, tôi đã cố gắng đặt thuộc tính khung của lưới gốc thành một thứ khác và sau khi gán nó cũng được giữ nguyên.
Bất cứ ai có thể làm sáng tỏ những gì đang xảy ra? Hoặc làm thế nào để tạo và thiết lập một SCNSkinner
đối tượng theo cách thủ công một cách chính xác ?
Đây là mã tôi đang sử dụng để sao chép thủ công một lưới và thay thế nó bằng một lưới mới (Tôi chưa sửa đổi bất kỳ dữ liệu nguồn nào ở đây - tôi chỉ đang cố gắng đảm bảo rằng tôi có thể tạo một bản sao tại thời điểm này) :
// 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)