J'ai une application Swift utilisant SceneKit pour iOS 8. Je charge une scène à partir d'un fichier .dae contenant un maillage contrôlé par un squelette. Au moment de l'exécution, je dois modifier les coordonnées de la texture. L'utilisation d'une transformation n'est pas une option - je dois calculer une UV différente et complètement nouvelle pour chaque sommet du maillage.
Je sais que la géométrie est immuable dans SceneKit, et j'ai lu que l'approche suggérée est de faire une copie manuellement. J'essaie de le faire, mais je finis toujours par planter en essayant de recréer le SCNSkinner
code in. Le crash est un EXC_BAD_ACCESS
intérieur C3DSourceAccessorGetMutableValuePtrAtIndex
. Malheureusement, il n'y a pas de code source pour cela, donc je ne sais pas pourquoi exactement cela plante. Je l'ai réduit à l' SCNSkinner
objet attaché au nœud de maillage. Si je ne règle pas cela, je ne reçois pas de plantage et les choses semblent fonctionner.
EDIT: Voici une pile d'appels plus complète du crash:
C3DSourceAccessorGetMutableValuePtrAtIndex
C3DSkinPrepareMeshForGPUIfNeeded
C3DSkinnerMakeCurrentMesh
C3DSkinnerUpdateCurrentMesh
__CFSetApplyFunction_block_invoke
CFBasicHashApply
CFSetApplyFunction
C3DAppleEngineRenderScene
...
Je n'ai trouvé aucune documentation ou exemple de code sur la création SCNSkinner
manuelle d' un objet. Puisque je le crée simplement sur la base d'un maillage précédemment fonctionnel, cela ne devrait pas être trop difficile. Je crée le SCNSkinner
conformément à la documentation Swift, en passant toutes les choses correctes dans le fichier init. Cependant, il existe une propriété squelette dans le SCNSkinner
que je ne sais pas comment définir. Je l'ai défini sur le squelette qui était sur l'original SCNSkinner
du maillage que je copie, ce qui, je pense, devrait fonctionner ... mais ce n'est pas le cas. Lors de la définition de la propriété squelette, elle ne semble pas être affectée. Le vérifier immédiatement après l'affectation montre qu'il est toujours nul. À titre de test, j'ai essayé de définir la propriété squelette du maillage d'origine sur autre chose, et après l'affectation, elle a également été laissée intacte.
Quelqu'un peut-il faire la lumière sur ce qui se passe? Ou comment créer et configurer correctement un SCNSkinner
objet manuellement?
Voici le code que j'utilise pour cloner manuellement un maillage et le remplacer par un nouveau (je n'ai modifié aucune des données source ici - j'essaie simplement de m'assurer de pouvoir créer une copie à ce stade) :
// 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)
Réponses:
Ces trois méthodes peuvent vous aider à trouver la solution:
Voir également ce lien .
la source
Je ne sais pas précisément ce qui provoque le plantage de votre code, mais voici un moyen de générer un maillage, des os et de skinning ce maillage - le tout à partir du code. Swift4 et iOS 12.
Dans l'exemple, il y a un maillage représentant la concaténation de deux cylindres, avec l'un des cylindres bifurquant à un angle de 45 degrés, comme ceci:
Les cylindres ne sont que des triangles extrudés, c'est-à-dire
radialSegmentCount = 3.
(notez qu'il y a 12 sommets, pas 9, puisque les deux cylindres ne sont pas vraiment joints. Les triangles sont ordonnés comme ceci:Il y a 3 os, correspondant aux têtes et aux pieds des cylindres, où l'os médian correspond à la tête du cylindre inférieur et simultanément au pied du cylindre supérieur. Ainsi , par exemple, les sommets
v0
,v2
etv4
correspondent àbone0
;v1
,v3
,v5
Correspondent àbone1
, et ainsi de suite. Cela explique pourquoiboneIndices
(voir ci-dessous) a la valeur que cela a.Les positions de repos des os correspondent aux positions de repos des cylindres dans la géométrie (
bone2
jaillit à un angle de 45 degrés debone1
, tout comme la géométrie du cylindre).Avec cela comme contexte, le code suivant crée tout le nécessaire pour habiller la géométrie:
Remarque: dans la plupart des cas, vous ne devez
UInt16
pas utiliserUInt8
.la source