在设备上 运行 时没有子节点
Don't have childNodes when running on device
我创建了一个简单的项目来试用 SceneKit,添加了一个包含人物角色和相机的场景。
问题是代码在模拟器和设备上的行为不同。
将人角色加载到 SCNNode 对象时,在模拟器中,此 "man" 节点具有子节点,这些子节点本身包含几何图形。
然而,当 运行在设备上运行时,man 节点不包含子节点并且它本身具有几何图形。
为什么会这样?谁能解释一下我究竟搞砸了什么?
我已将示例项目上传到 GitHub,因此您可以在您的模拟器和设备上查看并运行它。
https://github.com/iamBlueGene/SceneKitExperiment
谢谢,Eli。
我将以下方法添加到您的 ViewController.m
只是为了看看发生了什么。
- (void)printNodeTree: (SCNNode*)node levelIndent:(NSString*) indent{
if (node != nil) {
BOOL hasGeom = node.geometry == nil;
NSString *nodeName = [NSString stringWithFormat:@"%@%@", indent, node.name];
NSString *geomStr = [NSString stringWithFormat:@"%@ has geometry: %@", indent, hasGeom ? @"YES" : @"NO"];
printf("%s \n", [nodeName UTF8String]);
printf("%s \n", [geomStr UTF8String]);
for (id childNode in [node childNodes]) {
[self printNodeTree:childNode levelIndent:[NSString stringWithFormat:@"%@ ",indent]];
}
} else {
return;
}
}
并且在模拟器和设备上 运行 时(传递对 man 节点的引用时)收到以下输出。
Model_1
has geometry: YES
Model_1-splitContainer
has geometry: YES
Model_1-splitContainer-split0
has geometry: NO
Model_1-splitContainer-split1
has geometry: NO
Model_1-splitContainer-split2
has geometry: NO
Model_1-splitContainer-split3
has geometry: NO
. . .
这似乎与您在设备上 运行 时看到的一致。查看 XCode 场景编辑器和 Blender 显示有几个组件显然正在合并。
导入场景时可以指定一些选项。默认记录为不展平场景(正如我们观察到的那样),但只是为了确认我尝试了以下操作。这产生了与上面相同的输出。
NSDictionary* sceneLoadOpts = [NSDictionary dictionaryWithObjectsAndKeys:
SCNSceneSourceFlattenSceneKey, [NSNumber numberWithBool:NO],
nil];
SCNScene *characterScene = [SCNScene sceneNamed:@"character-male-muscle.dae"
inDirectory:nil
options:sceneLoadOpts];
设备(或模拟器)不直接加载 .dae
文件。这是由scntool
编译成一个c3d文件。我将 dae 转换为 c3d 文件,然后再转换回 dae,发现不同的组件仍然存在。扁平化不是此压缩过程的结果。
最后我在 Blender 中加载模型并重新排列模型树,使所有几何节点都与父节点处于同一级别。这确实导致了模拟器和设备上的多个几何组件,但这可能有点远...
顶点数 (65535) 和这些组件的名称 ("splitContainerX") 似乎表明由于顶点索引 (2^16) 的限制,它们只是单独的几何组件。简而言之,我认为您真的不想将此模型视为单独的组件。目前的理论是,在 dae 文件中的某处有一个标志,表明这些组件应尽可能合并。
我想我已经弄明白了。
问题在于,由于顶点数量的限制,顶点在 .dae 文件中跨容器拆分,因此不同的配置可以不同地打开文件。
您可以尝试再次打开场景并再次导出(或者如果可以的话,可能只导出角色)并再次检查。
我创建了一个简单的项目来试用 SceneKit,添加了一个包含人物角色和相机的场景。
问题是代码在模拟器和设备上的行为不同。
将人角色加载到 SCNNode 对象时,在模拟器中,此 "man" 节点具有子节点,这些子节点本身包含几何图形。
然而,当 运行在设备上运行时,man 节点不包含子节点并且它本身具有几何图形。
为什么会这样?谁能解释一下我究竟搞砸了什么?
我已将示例项目上传到 GitHub,因此您可以在您的模拟器和设备上查看并运行它。
https://github.com/iamBlueGene/SceneKitExperiment
谢谢,Eli。
我将以下方法添加到您的 ViewController.m
只是为了看看发生了什么。
- (void)printNodeTree: (SCNNode*)node levelIndent:(NSString*) indent{
if (node != nil) {
BOOL hasGeom = node.geometry == nil;
NSString *nodeName = [NSString stringWithFormat:@"%@%@", indent, node.name];
NSString *geomStr = [NSString stringWithFormat:@"%@ has geometry: %@", indent, hasGeom ? @"YES" : @"NO"];
printf("%s \n", [nodeName UTF8String]);
printf("%s \n", [geomStr UTF8String]);
for (id childNode in [node childNodes]) {
[self printNodeTree:childNode levelIndent:[NSString stringWithFormat:@"%@ ",indent]];
}
} else {
return;
}
}
并且在模拟器和设备上 运行 时(传递对 man 节点的引用时)收到以下输出。
Model_1
has geometry: YES
Model_1-splitContainer
has geometry: YES
Model_1-splitContainer-split0
has geometry: NO
Model_1-splitContainer-split1
has geometry: NO
Model_1-splitContainer-split2
has geometry: NO
Model_1-splitContainer-split3
has geometry: NO
. . .
这似乎与您在设备上 运行 时看到的一致。查看 XCode 场景编辑器和 Blender 显示有几个组件显然正在合并。
导入场景时可以指定一些选项。默认记录为不展平场景(正如我们观察到的那样),但只是为了确认我尝试了以下操作。这产生了与上面相同的输出。
NSDictionary* sceneLoadOpts = [NSDictionary dictionaryWithObjectsAndKeys:
SCNSceneSourceFlattenSceneKey, [NSNumber numberWithBool:NO],
nil];
SCNScene *characterScene = [SCNScene sceneNamed:@"character-male-muscle.dae"
inDirectory:nil
options:sceneLoadOpts];
设备(或模拟器)不直接加载 .dae
文件。这是由scntool
编译成一个c3d文件。我将 dae 转换为 c3d 文件,然后再转换回 dae,发现不同的组件仍然存在。扁平化不是此压缩过程的结果。
最后我在 Blender 中加载模型并重新排列模型树,使所有几何节点都与父节点处于同一级别。这确实导致了模拟器和设备上的多个几何组件,但这可能有点远...
顶点数 (65535) 和这些组件的名称 ("splitContainerX") 似乎表明由于顶点索引 (2^16) 的限制,它们只是单独的几何组件。简而言之,我认为您真的不想将此模型视为单独的组件。目前的理论是,在 dae 文件中的某处有一个标志,表明这些组件应尽可能合并。
我想我已经弄明白了。
问题在于,由于顶点数量的限制,顶点在 .dae 文件中跨容器拆分,因此不同的配置可以不同地打开文件。
您可以尝试再次打开场景并再次导出(或者如果可以的话,可能只导出角色)并再次检查。