SceneKit on OS X with thousands of objects

后端 未结 2 477
佛祖请我去吃肉
佛祖请我去吃肉 2020-12-28 10:27

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 th

2条回答
  •  感动是毒
    2020-12-28 10:57

    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)

    - (SCNNode *) flattenNodeHierarchy:(SCNNode *) input
    {
        SCNNode *result = [SCNNode node];
    
        NSUInteger nodeCount = [[input childNodes] count];
        if(nodeCount > 0){
        SCNNode *node = [[input childNodes] objectAtIndex:0];
    
            NSArray *vertexArray = [node.geometry geometrySourcesForSemantic:SCNGeometrySourceSemanticVertex];
            SCNGeometrySource *vertex = [vertexArray objectAtIndex:0];
    
            SCNGeometryElement *element = [node.geometry geometryElementAtIndex:0]; //todo: support multiple elements
            NSUInteger primitiveCount = element.primitiveCount;
            NSUInteger newPrimitiveCount = primitiveCount * nodeCount;
            size_t elementBufferLength = newPrimitiveCount * 3 * sizeof(int); //nTriangle x 3 vertex * size of int
            int* elementBuffer = (int*)malloc(elementBufferLength);
    
            /* simple case: here we consider that all the objects to flatten are the same
             In the regular case we should iterate on every geometry and accumulate the number of vertex/triangles etc...*/
    
            NSUInteger vertexCount = [vertex vectorCount];
            NSUInteger newVertexCount = vertexCount * nodeCount;
    
            SCNVector3 *newVertex = malloc(sizeof(SCNVector3) * newVertexCount);        
            SCNVector3 *newNormal = malloc(sizeof(SCNVector3) * newVertexCount); //assume same number of normal/vertex
    
            //fill
            NSUInteger vertexFillIndex = 0;
            NSUInteger primitiveFillIndex = 0;
            for(NSUInteger index=0; index< nodeCount; index++){
                NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    
                node = [[input childNodes] objectAtIndex:index];
    
                NSArray *vertexArray = [node.geometry geometrySourcesForSemantic:SCNGeometrySourceSemanticVertex];
                NSArray *normalArray = [node.geometry geometrySourcesForSemantic:SCNGeometrySourceSemanticNormal];
                SCNGeometrySource *vertex = [vertexArray objectAtIndex:0];
                SCNGeometrySource *normals = [normalArray objectAtIndex:0];
    
                if([vertex bytesPerComponent] != sizeof(float)){
                    NSLog(@"todo: support other byte per component");
                    continue;
                }
    
                float *vertexBuffer = (float *)[[vertex data] bytes];
                float *normalBuffer = (float *)[[normals data] bytes];
    
                CATransform3D t = [node transform];
                GLKMatrix4 matrix = MyGLKMatrix4FromCATransform3D(t);
    
                //append source
                for(NSUInteger vIndex = 0; vIndex < vertexCount; vIndex++, vertexFillIndex++){
                    GLKVector3 v = GLKVector3Make(vertexBuffer[vIndex * 3], vertexBuffer[vIndex * 3+1], vertexBuffer[vIndex * 3 + 2]);
                    GLKVector3 n = GLKVector3Make(normalBuffer[vIndex * 3], normalBuffer[vIndex * 3+1], normalBuffer[vIndex * 3 + 2]);
    
                    //transform
                    v = GLKMatrix4MultiplyVector3WithTranslation(matrix, v);
                    n = GLKMatrix4MultiplyVector3(matrix, n);
    
                    newVertex[vertexFillIndex] = SCNVector3Make(v.x, v.y, v.z);
                    newNormal[vertexFillIndex] = SCNVector3Make(n.x, n.y, n.z);
                }
    
                //append elements
                //here we assume that all elements are SCNGeometryPrimitiveTypeTriangles
                SCNGeometryElement *element = [node.geometry geometryElementAtIndex:0];
                const void *inputPrimitive = [element.data bytes];
                size_t bpi = element.bytesPerIndex;
    
                NSUInteger offset = index * vertexCount;
    
                for(NSUInteger pIndex = 0; pIndex < primitiveCount; pIndex++, primitiveFillIndex+=3){                
                    elementBuffer[primitiveFillIndex] = offset + _getIndex(inputPrimitive, bpi, pIndex*3);
                    elementBuffer[primitiveFillIndex+1] = offset + _getIndex(inputPrimitive, bpi, pIndex*3+1);
                    elementBuffer[primitiveFillIndex+2] = offset + _getIndex(inputPrimitive, bpi, pIndex*3+2);
                }
    
                [pool drain];
            }
    
            NSArray *sources = @[[SCNGeometrySource geometrySourceWithVertices:newVertex count:newVertexCount],
                                 [SCNGeometrySource geometrySourceWithNormals:newNormal count:newVertexCount]];
    
            NSData *newElementData = [NSMutableData dataWithBytesNoCopy:elementBuffer length:elementBufferLength freeWhenDone:YES];
            NSArray *elements = @[[SCNGeometryElement geometryElementWithData:newElementData
                                                                primitiveType:SCNGeometryPrimitiveTypeTriangles
                                                               primitiveCount:newPrimitiveCount bytesPerIndex:sizeof(int)]];
    
            result.geometry = [SCNGeometry geometryWithSources:sources elements:elements];
    
            //cleanup
            free(newVertex);
            free(newNormal);
        }
    
        return result;
    }
    
    //helpers:
    GLKMatrix4 MyGLKMatrix4FromCATransform3D(CATransform3D transform) {
        GLKMatrix4 m = {{transform.m11, transform.m12, transform.m13, transform.m14,
            transform.m21, transform.m22, transform.m23, transform.m24,
            transform.m31, transform.m32, transform.m33, transform.m34,
            transform.m41, transform.m42, transform.m43, transform.m44}};
        return m;
    }
    
    
    
    GLKVector3 MySCNVector3ToGLKVector3(SCNVector3 vector) {
        GLKVector3 v = {{vector.x, vector.y, vector.z}};
        return v;
    }
    

提交回复
热议问题