Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>The semantic strings are SCNGeometrySourceSemanticVertex|Normal|Texcoord ...</p> <p>For multiple spheres the answer is yes, you have to transform the vertex/normals with the current node transform before flattening.</p> <p>Below is a simplified example (i.e it only supports merging the childs of "input" if they all have the same geometry)</p> <pre><code>- (SCNNode *) flattenNodeHierarchy:(SCNNode *) input { SCNNode *result = [SCNNode node]; NSUInteger nodeCount = [[input childNodes] count]; if(nodeCount &gt; 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&lt; 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 &lt; 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 &lt; 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; } </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload