I'm following this tutorial: http://blog.bignerdranch.com/754-scenekit-in-mountain-lion/
I'm interested in using Scene Kit, but my scenes might potentially have thousands of spheres. To stress-test Scene Kit I tried this:
SCNSphere *sphere = [SCNSphere sphereWithRadius:0.5];
for (int i=0; i<10; i++) {
for(int j=0; j<10; j++){
for(int k=0; k<10; k++){
SCNNode *myNode = [SCNNode nodeWithGeometry:sphere];
myNode.position = SCNVector3Make(i,j,k);
[root addChildNode:myNode];
}
}
}
This works fine for, say, 1000 spheres (10^3) but fails (perhaps unsurprisingly) for 1,000,000 spheres (100^3). I don't mind not being able to use a million spheres, but I'd like to work out what the sensible upper bound is (5,000? 15,000?) and how to increase it.
What can I do to mitigate this? e.g. I've tried sphere.segmentCount = 3 and while that speeds up rendering, it doesn't have much effect on memory usage, which I suspect is the limiting factor.
Also, there doesn't seem to be a SCNPoint class. I was thinking about switching to just displaying a point when the number of spheres is too high, but I can't see from the SceneKit documentation how to display a simple point -- the simplest I can see is a triangle.
Any help is much appreciated.
Edit: @toyos suggested that the SCNSphere objects are merged into single SCNGeometry object (provided they don't need to be independently animated, which they don't), but I can't find an easy way to do this.
SCNGeometry is created by using [SCNGeometry geometryWithSources:(* NSArray)sources geometryWithElements:(* NSArray) elements]
as documented here, but I'm not clear as to how to create an SCNGeometry
object from my spheres.
e.g. for a single sphere, I could see using sphere.geometryElementCount
to get the number of elements and then using that to populate an array using [sphere geometryElementAtIndex:(NSInteger)elementIndex]
which would give me the elements, but I'm not sure how to get the "sources" (or what they even are). The method to get the geometry sources is [sphere geometrySourcesForSemantic:(NSString*) semantic]
, but what is this semantic string? (is it meant to be "normals" or "vertices" or is this something else? the documentation quite helpfully says the semantic is "The semantic value of the geometry source." without saying what possible values of the semantic are)
That's just for a single sphere, which would be fairly pointless (since SCNSphere
is just a subclass of SCNGeometry
anyway), so now I have to add multiple spheres. So would I have to manually translate the vertices of the sphere when adding them to my SCNGeometry
object?
I'm just trying to figure out the most sensible way to do this.
The semantic strings are SCNGeometrySourceSemanticVertex|Normal|Texcoord ...
For multiple spheres the answer is yes, you have to transform the vertex/normals with the current node transform before flattening.
Below is a simplified example (i.e it only supports merging the childs of "input" if they all have the same geometry)
How best to do this depends on exactly what you're looking to accomplish.
Are these thousands of points (a star field backdrop for an outer space scene, perhaps) static, or do they need to move with respect to each other? Do they actually need to be spheres? How much detail do they need?
If they don't need to move independently, merging them into a single geometry is a good idea. On Mavericks (OS X 10.9) you don't need do mess with geometry data yourself to do that — create a node for each one, then parent them all to a single node (not your scene's root node), and call
flattenedClone
to get a copy of that node whose geometries are combined.If they don't need to have much detail, there are a few options for improving performance.
One is to reduce the
segmentCount
of the sphere geometry — you don't need 5000 triangles to draw a sphere that'll only be a couple of pixels wide when rendered, which is about what you get with the default segment count of 48. (If you're going to mess with the geometry data or flatten nodes immediately after reducing the segment count, be sure to call[SCNTransaction flush]
to make sure it gets updated.)Another is to reduce the triangle count further. Are the stars (or whatever) small enough that they even need to be spheres? If your scene can be set up so they're always oriented toward the camera,
SCNPlane
might be better — with its minimum segment count it's just two triangles.Do they even need to be triangles? Scene Kit can render points — there's not a
SCNGeometry
subclass for them because it's generally not useful to independently position and transform single points. But you can create a custom geometry using an array of vertex positions and theSCNGeometryPrimitiveTypePoint
geometry element type. And if you want to customize the rendering of single points, you can attach shaders (or shader modifiers) to the geometry.