Jeremy1026 - 1 year ago 75

iOS Question

I have an

`SCNBox`

`SCNBox`

`presentationNode.orientation`

`SCNBox`

I have tried to normalize the data and came up with the following data

`Side 1 = (-x, 0, 0, +x)`

Side 2 = (0, -x, 0 +y)

Side 3 = (-x, +x, -y, y)

Side 4 = (x, x, y, y)

Side 5 = (-x, 0, +y, 0)

Side 6 = (-x, -y, +y, -x)

Unfortunately this isn't always true and checking against it sometimes returns invalid sides occasionally.

Is there a reliable way to determine the up facing side of the

`SCNBox`

Edit:

Based on Toyos answer, I have come up with the following code, which doesn't work. Hopefully this will help with coming closer to the end goal. I also used code found at Extracting vertices from scenekit to get the vertices of my SCNBoxNode.

`- (NSNumber *)valueForRotation:(SCNVector4)rotation andGeometry:(SCNGeometry*)geometry {`

SCNVector4 inverse = SCNVector4Make(rotation.x, rotation.y, rotation.z, -rotation.w);

CATransform3D transform = CATransform3DMakeRotation(inverse.w, inverse.x, inverse.y, inverse.z);

GLKMatrix4 matrix = GLKMatrix4Make(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);

GLKVector4 vector = GLKVector4Make(rotation.x, rotation.y, rotation.z, rotation.w);

GLKVector4 finalVector = GLKMatrix4MultiplyVector4(matrix, vector);

NSArray *vertexSources = [geometry geometrySourcesForSemantic:SCNGeometrySourceSemanticVertex];

SCNGeometrySource *vertexSource = vertexSources[0]; // TODO: Parse all the sources

NSInteger stride = vertexSource.dataStride; // in bytes

NSInteger offset = vertexSource.dataOffset; // in bytes

NSInteger componentsPerVector = vertexSource.componentsPerVector;

NSInteger bytesPerVector = componentsPerVector * vertexSource.bytesPerComponent;

NSInteger vectorCount = vertexSource.vectorCount;

SCNVector3 vertices[vectorCount]; // A new array for vertices

// for each vector, read the bytes

NSLog(@"vetor count %i",vectorCount);

float highestProduct = 0;

int highestVector = -1;

NSMutableArray *highVectors;

for (NSInteger i=0; i<vectorCount; i++) {

// Assuming that bytes per component is 4 (a float)

// If it was 8 then it would be a double (aka CGFloat)

float vectorData[componentsPerVector];

// The range of bytes for this vector

NSRange byteRange = NSMakeRange(i*stride + offset, // Start at current stride + offset

bytesPerVector); // and read the lenght of one vector

// Read into the vector data buffer

[vertexSource.data getBytes:&vectorData range:byteRange];

// At this point you can read the data from the float array

float x = vectorData[0];

float y = vectorData[1];

float z = vectorData[2];

// ... Maybe even save it as an SCNVector3 for later use ...

vertices[i] = SCNVector3Make(x, y, z);

// ... or just log it

NSLog(@"x:%f, y:%f, z:%f", x, y, z);

float product = (x * finalVector.x) + (y * finalVector.y) + (z * finalVector.z);

if (product > highestProduct) {

highestProduct = product;

highestVector = i;

}

}

NSLog(@"highestProduct = %f",highestProduct);

NSLog(@"highestVector = %i",highestVector);

NSLog(@"top verticy = %f, %f, %f",vertices[highestVector].x,vertices[highestVector].y,vertices[highestVector].z);

return [NSNumber numberWithInt:highestVector];

}

Answer Source

Here is a method that returns the index of the face that's facing up. It assumes that "boxNode" is a box made of 6 faces with the following (arbitrary) order: front / right / back / left / up / bottom. It returns the index of the face that is facing up. Don't forget to import then . For an arbitrary mesh, you would have to use the face normals instead of "boxNormals" (which is not obvious to compute since SceneKit meshes have one normal per vertex, not one normal per face, so you would have to compute the normals per face yourself).

```
- (NSUInteger) boxUpIndex:(SCNNode *)boxNode
{
SCNVector4 rotation = boxNode.rotation;
SCNVector4 invRotation = rotation; invRotation.w = -invRotation.w;
SCNVector3 up = SCNVector3Make(0,1,0);
//rotate up by invRotation
SCNMatrix4 transform = SCNMatrix4MakeRotation(invRotation.w, invRotation.x, invRotation.y, invRotation.z);
GLKMatrix4 glkTransform = SCNMatrix4ToGLKMatrix4(transform);
GLKVector3 glkUp = SCNVector3ToGLKVector3(up);
GLKVector3 rotatedUp = GLKMatrix4MultiplyVector3(glkTransform, glkUp);
//build box normals (arbitrary order here)
GLKVector3 boxNormals[6] = {{{0,0,1}},
{{1,0,0}},
{{0,0,-1}},
{{-1,0,0}},
{{0,1,0}},
{{0,-1,0}},
};
int bestIndex = 0;
float maxDot = -1;
for(int i=0; i<6; i++){
float dot = GLKVector3DotProduct(boxNormals[i], rotatedUp);
if(dot > maxDot){
maxDot = dot;
bestIndex = i;
}
}
return bestIndex;
}
```