场景包的性能问题

问题描述:

我已经有了一行三维数组值,我想要在3D中进行可视化,并且我在OS X下使用了它的场景套件。我以笨拙的方式将每列用作X轴上的一个点,将每一行作为Z轴上的一个点,将每个值作为Y轴上的标准化点 - 我将球放在矢量由每个数据点定义。它有效,但看起来不太好。场景包的性能问题

我也通过在Drawing a line between two points using SceneKit(他发布的答案,而不是原始问题)基础上构建基于@ Matthew函数的行网格来完成此操作。对于每个点,我使用他的函数绘制两条线 - 我的当前点和右下一个点之间的一条线,以及当前点和前一个点之间的另一个点(除非没有额外的列/行,当然)。

使用第二种方法,我的结果看起来好多了......但是性能相当糟糕!完成初始渲染需要相当长的时间,并且如果我使用触控板/鼠标旋转或翻译场景,我还不如拿一杯咖啡等到我的系统再次可用(并且这不是很多夸张)。使用球体方法,事物渲染和更新速度非常快。

有关如何在使用线条方法时提高性能的任何建议? (请注意,我不想同时添加行和球体)。代码方面,方法之间的唯一区别是调用以下哪个方法(并且对于每个点,addPixelAt ...都被调用一次,但addLineAt ...被称为大多数点的两倍)。

enter image description here

- (SCNNode *)addPixelAtRow:(CGFloat)row Column:(CGFloat)column size:(CGFloat)size color:(NSColor *)color 
{ 
    CGFloat radius = 0.5; 

    SCNSphere *ball = [SCNSphere sphereWithRadius:radius*1.5]; 
    SCNMaterial *material = [SCNMaterial material]; 
    [[material diffuse] setContents:color]; 
    [[material specular] setContents:color]; 
    [ball setMaterials:@[material]]; 

    SCNNode *ballNode = [SCNNode nodeWithGeometry:ball]; 
    [ballNode setPosition:SCNVector3Make(column, size, row)]; 

    [_baseNode addChildNode:ballNode]; 
    return ballNode; 
} 

enter image description here

- (SCNNode *)addLineFromRow:(CGFloat)row1 Column:(CGFloat)column1 size:(CGFloat)size1 
         toRow2:(CGFloat)row2 Column2:(CGFloat)column2 size2:(CGFloat)size2 color:(NSColor *)color 
{ 
    SCNVector3 positions[] = { 
     SCNVector3Make(column1, size1, row1), 
     SCNVector3Make(column2, size2, row2) 
    }; 

    int indices[] = {0, 1}; 

    SCNGeometrySource *vertexSource = [SCNGeometrySource geometrySourceWithVertices:positions count:2]; 

    NSData *indexData = [NSData dataWithBytes:indices length:sizeof(indices)]; 

    SCNGeometryElement *element = [SCNGeometryElement geometryElementWithData:indexData 
                   primitiveType:SCNGeometryPrimitiveTypeLine 
                   primitiveCount:1 
                   bytesPerIndex:sizeof(int)]; 

    SCNGeometry *line = [SCNGeometry geometryWithSources:@[vertexSource] elements:@[element]]; 
    SCNMaterial *material = [SCNMaterial material]; 
    [[material diffuse] setContents:color]; 
    [[material specular] setContents:color]; 
    [line setMaterials:@[material]]; 

    SCNNode *lineNode = [SCNNode nodeWithGeometry:line]; 

    [_baseNode addChildNode:lineNode]; 
    return lineNode; 
} 
+0

我们需要了解更多关于性能问题和测量结果的信息吗?问题是否有太多的平局?太多的三角形? CPU是否做了太多工作? etc. – 2014-10-28 18:54:16

+0

另外,你是单独使用线还是他们只是组成一个网格? (截图可能是有用的,知道自己在做什么,但它没有相关的性能问题) – 2014-10-28 18:56:30

+0

@DavidRönnqvist我还不能肯定这里的答案,但我可以说,它不仅是我的应用程序,它受到当发生这种情况,这是完整的系统。我可以说的是,即使在使用球体方法时,在我创建最后一个节点之后,我仍然可以看到场景大约一秒钟。 – mah 2014-10-28 18:57:04

从你已经在你的问题,我会说,你的主要问题是平局的呼叫数量显示的数据。你的是在成千上万,这是方式太多了。它应该更接近~100。

你有这么多绘制调用的原因是你的场景中有很多不同的对象(每一行)。更好的(但更高级的解决方案)可能会为包含所有行的整个网格生成单个元素。如果您想要使用该网格实现相同的渲染(根据高度使用从冷到暖的颜色),那么您可以在着色器修改器中执行此操作。但是,在你的情况下,我将首先展开所有行(因为这将是最小的代码更改,并且应该在你的情况下仍然有显着的性能改进)。

(优化性能始终是一个反复的过程。一旦你解决一件事就会有另一件事也是最昂贵的操作。如果没有你的代码,我只能说你会与当前的性能问题帮助)

创建一个空节点(无需将其添加到场景中)并生成所有行,并将其添加到此节点。然后,通过在节点上调用flattenedClone创建节点的扁平副本包含所有行

SCNNode *nodeWithAllTheLines = [SCNNode node]; 
// create all the lines and add them to it... 
SCNNode *flattenedNode = [nodeWithAllTheLines flattenedClone]; 
[_baseNode addChildNode:flattenedNode]; 

当你这样做,你应该看到钻石后绘制调用的数量显著下降(数统计数据),并希望业绩大幅增长。

+0

良好的一般建议。着色器修改器可能是最好的方法。您甚至不需要为此生成自定义几何图形 - 使用具有所需网格分辨率的“SCNPlane”。对于高度贴图数据,可以将一个浮点数组作为着色器统一,或者将其填充到着色器中的纹理和样本中。 – rickster 2014-10-28 21:17:21

+0

@rickster是的,我忘记了你可以修改片段着色器中的几何体:) – 2014-10-28 21:21:28

+0

另外,即使是扁平化的节点,你也要做大量的工作来构建基本上相同的20k几何体。如果你采用这种方法,你只需要一个'SCNGeometry'实例(包含一个源和元素),其中包含从{0,0,0}到'{0,0,1}'的行本地空间。然后使用每个节点的'position','rotation'和'scale'来定位它的线段。 – rickster 2014-10-28 21:21:30