我以編程方式創建了一個完全自定義的操作SCNNode。該節點具有自定義幾何體,骨架裝置作爲子節點的層次結構以及將骨架和幾何體綁定在一起的SCNSkinner對象。問題是這樣的:只要我克隆我的自定義節點,它就會失去幾何和骨架之間的綁定。爲了找到這個問題的根源,我用我能想到的最簡單的幾何 - 鑽機組合交換了我相當複雜的字符節點:一個12個頂點的幾何塊和一個3個關節的骨架鑽機。自定義SceneKit字符不會正確克隆
我曾經愛過在這一點上分享圖片,但不能這樣做,因爲我沒有足夠的聲譽,但...
-(SCNNode *)createCustomRigBlock {
// baseGeometry
SCNVector3 positions[] = {
SCNVector3Make(0, 0, 0),
SCNVector3Make(0, 0, 1),
SCNVector3Make(1, 0, 1),
SCNVector3Make(1, 0, 0),
SCNVector3Make(0, 1, 0),
SCNVector3Make(0, 1, 1),
SCNVector3Make(1, 1, 1),
SCNVector3Make(1, 1, 0),
SCNVector3Make(0, 2, 0),
SCNVector3Make(0, 2, 1),
SCNVector3Make(1, 2, 1),
SCNVector3Make(1, 2, 0)
};
SCNGeometrySource * baseGeometrySource = [SCNGeometrySource geometrySourceWithVertices:positions count:12];
typedef struct {
uint16_t a, b, c;
} Triangles;
Triangles tVectors[20] = {
0,1,2,
0,2,3,
0,1,5,
0,4,5,
4,5,9,
4,8,9,
1,2,6,
1,5,6,
5,6,10,
5,9,10,
2,3,7,
2,6,7,
6,7,11,
6,10,11,
3,0,4,
3,4,7,
7,4,8,
7,8,11,
8,9,10,
8,10,11
};
NSData *triangleData = [NSData dataWithBytes:tVectors length:sizeof(tVectors)];
SCNGeometryElement * baseGeometryElement = [SCNGeometryElement geometryElementWithData:triangleData primitiveType:SCNGeometryPrimitiveTypeTriangles primitiveCount:20 bytesPerIndex:sizeof(uint16_t)];
SCNGeometry * baseGeometry = [SCNGeometry geometryWithSources:[NSArray arrayWithObject:baseGeometrySource] elements:[NSArray arrayWithObject:baseGeometryElement]];
baseGeometry.firstMaterial.emission.contents = [UIColor greenColor];
baseGeometry.firstMaterial.doubleSided = YES;
baseGeometry.firstMaterial.transparency = 0.5;
SCNNode *customBlock = [SCNNode nodeWithGeometry:baseGeometry];
int stageSize = 30;
customBlock.position = SCNVector3Make(stageSize/2, 0, stageSize/2-6);
int vectorCount = (int)[(SCNGeometrySource *)[customBlock.geometry geometrySourcesForSemantic:SCNGeometrySourceSemanticVertex].firstObject vectorCount];
//bones ... the bones of the rig
NSMutableArray * bonesArray = [NSMutableArray new];
for (int i = 0; i < 3; i++) {
SCNNode * boneNode = [SCNNode new];
boneNode.name = [NSString stringWithFormat:@"bone_%i",i];
if (bonesArray.count > 0) {
[bonesArray.lastObject addChildNode:boneNode];
}
boneNode.position = SCNVector3Make((i>0 ? 0 : 0.5), (i>0 ? 0.75 : 0.25), (i>0 ? 0 : 0.5));
//add a sphere to each bone, to visually check its position etc.
SCNSphere *boneSphereGeom = [SCNSphere sphereWithRadius:0.1];
boneSphereGeom.firstMaterial.emission.contents = [UIColor redColor];
SCNNode * boneSphere = [SCNNode nodeWithGeometry:boneSphereGeom];
[boneNode addChildNode:boneSphere];
[bonesArray addObject:boneNode];
}
[customBlock addChildNode:bonesArray.firstObject];
//boneInverseBindTransforms ... this defines the geometries transformation in the default pose!
NSMutableArray * bibtArray = [NSMutableArray new];
for (int i = 0; i < 3; i++) {
SCNMatrix4 initialPositionMatrix = SCNMatrix4MakeTranslation(0.5, (i*0.75)+0.25, 0.5);
SCNMatrix4 inverseFinalMatrix = SCNMatrix4Invert(initialPositionMatrix);
NSValue * bibtValue = [NSValue valueWithSCNMatrix4:inverseFinalMatrix];
[bibtArray addObject:bibtValue];
}
//boneWeights ... the weights, at which each vertex is influenced by certain bones (which bones is defined by "boneIndices")
typedef struct {
float a, b, c;
} WeightVectors;
WeightVectors vectors[vectorCount];
for (int i = 0; i < vectorCount; i++) {
// set the same boneWeights for every vertex
vectors[i].a = 1;
vectors[i].b = 0;
vectors[i].c = 0;
}
NSData *weightData = [NSData dataWithBytes:vectors length:sizeof(vectors)];
SCNGeometrySource * boneWeightsGeometrySource = [SCNGeometrySource geometrySourceWithData:weightData
semantic:SCNGeometrySourceSemanticBoneWeights
vectorCount:vectorCount
floatComponents:YES
componentsPerVector:3
bytesPerComponent:sizeof(float)
dataOffset:offsetof(WeightVectors, a)
dataStride:sizeof(WeightVectors)];
//boneIndices
typedef struct {
short k, l, m; // boneWeight
} IndexVectors;
IndexVectors iVectors[vectorCount];
for (int i = 0; i < vectorCount; i++) {
if (i > 7) {
iVectors[i].k = 1;
iVectors[i].l = 0;
iVectors[i].m = 0;
} else {
iVectors[i].k = 0;
iVectors[i].l = 0;
iVectors[i].m = 0;
}
}
NSData *indexData = [NSData dataWithBytes:iVectors length:sizeof(iVectors)];
SCNGeometrySource * boneIndicesGeometrySource = [SCNGeometrySource geometrySourceWithData:indexData
semantic:SCNGeometrySourceSemanticBoneIndices
vectorCount:vectorCount
floatComponents:NO
componentsPerVector:3
bytesPerComponent:sizeof(short)
dataOffset:offsetof(IndexVectors, k)
dataStride:sizeof(IndexVectors)];
SCNSkinner * customBlockSkinner = [SCNSkinner skinnerWithBaseGeometry:baseGeometry
bones:bonesArray
boneInverseBindTransforms:bibtArray
boneWeights:boneWeightsGeometrySource
boneIndices:boneIndicesGeometrySource];
customBlock.skinner = customBlockSkinner;
[[bonesArray objectAtIndex:1] runAction:[SCNAction repeatActionForever:[SCNAction rotateByX:0 y:0 z:2 duration:2]]];
return customBlock;
}
這種習俗SCNNode完美的作品,如只要我直接將其添加到我的場景中即可。現在,在我當前的應用程序中,我需要多次將此節點添加到場景中。這就是爲什麼我需要克隆節點並將生成的克隆添加到場景中。但克隆自定義節點的結果是非常錯誤的。正如我上面提到的,幾何和骨架之間的綁定似乎已經丟失。克隆節點中的骨架仍然可以放置在我的場景中,但幾何體不再遵循骨架位置或變形。
我已經試過:
1) 我創建了一個新的節點,並添加原始幾何的副本吧。然後我克隆了骨架根節點,並將其添加到新節點。最後,我將原始skinner設置爲新鮮節點skinner。不幸的是,無濟於事。結果的行爲與直接克隆的節點完全相同。
SCNNode * newNode = [SCNNode node];
newNode.geometry = [node.geometry copy];
for (SCNNode * childNode in node.childNodes) {
[newNode addChildNode:[childNode clone]];
}
newNode.skinner = node.skinner;
2.) 在試圖重現的幾何形狀和我創建的SCNSkinner的深層副本,並使其新鮮節點的斯金納骨架之間的結合。但是這隻會導致C3DSourceAccessorGetMutableValuePtrAtIndex崩潰,我無法修復。
NSArray * newBones = [newNode childNodesPassingTest:^(SCNNode *child, BOOL *stop)
{
if (![child.name isEqualToString:@"manipulator"]) {
return YES;
}
return NO;
}];
NSArray * newBoneInverseBindTransforms = [node.skinner.boneInverseBindTransforms copy];
SCNGeometrySource * newBoneWeights = [SCNGeometrySource geometrySourceWithData:[node.skinner.boneWeights.data copy]
semantic:SCNGeometrySourceSemanticBoneWeights
vectorCount:node.skinner.boneWeights.vectorCount
floatComponents:node.skinner.boneWeights.floatComponents
componentsPerVector:node.skinner.boneWeights.componentsPerVector
bytesPerComponent:node.skinner.boneWeights.bytesPerComponent
dataOffset:node.skinner.boneWeights.dataOffset
dataStride:node.skinner.boneWeights.dataStride];
SCNGeometrySource * newBoneIndices = [SCNGeometrySource geometrySourceWithData:[node.skinner.boneIndices.data copy]
semantic:SCNGeometrySourceSemanticBoneIndices
vectorCount:node.skinner.boneIndices.vectorCount
floatComponents:node.skinner.boneIndices.floatComponents
componentsPerVector:node.skinner.boneIndices.componentsPerVector
bytesPerComponent:node.skinner.boneIndices.bytesPerComponent
dataOffset:node.skinner.boneIndices.dataOffset
dataStride:node.skinner.boneIndices.dataStride];
SCNSkinner * newSkinner = [SCNSkinner skinnerWithBaseGeometry:newNode.geometry
bones:newBones
boneInverseBindTransforms:newBoneInverseBindTransforms
boneWeights:newBoneWeights
boneIndices:newBoneIndices];
newNode.skinner = newSkinner;
的所有子節點恐怕'[節點flattenedClone]'不會做的伎倆。我以前已經嘗試過。它只會在C3DMeshCopy中的某處使用EXC_BAD_ACCESS來崩潰應用程序。但即使它能工作,這也不能解決我的問題。我想複製/克隆完整的節點結構,以便能夠操作骨架,從而對其網格進行操作。 – dthgs