起床方向上SCNNode的一侧 [英] Get "up" side of SCNNode from Orientation

查看:82
本文介绍了起床方向上SCNNode的一侧的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在SCNScene中有一个SCNBox.场景设置动画后,SCNBox的更改即为方向,可以通过检查其presentationNode.orientation看到.该值在SCNVector4中返回.如何从SCNVector4中返回的值确定SCNBox的哪一侧是朝上的一侧?

I have an SCNBox in an SCNScene. Once the scene animates the SCNBox changes is orientation which can be seen by checking its presentationNode.orientation. This value is returned in an SCNVector4. How do I determine which side of the SCNBox is the up facing side from the values returned in the SCNVector4?

我试图规范化数据并提出以下数据

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.

是否有一种可靠的方法可以根据几何形状的方向属性确定SCNBox的朝上侧面?

Is there a reliable way to determine the up facing side of the SCNBox from its geometry's orientation property?

根据Toyos的答案,我想出了以下代码,该代码不起作用.希望这将有助于更接近最终目标.我还使用了从Scenekit提取顶点中找到的代码来获取我的SCNBoxNode的顶点.

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];
}

推荐答案

这里是一种返回朝上的脸部索引的方法.假定"boxNode"是一个由6个面组成的框,其顺序如下(任意):前/右/后/左/上/下.它返回面朝上的索引. 别忘了导入. 对于任意网格,您将不得不使用面法线而不是"boxNormals"(这并不明显,因为SceneKit网格的每个顶点有一个法线,而不是每个面有一个法线,因此您必须计算每个面的法线你自己).

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;
}

这篇关于起床方向上SCNNode的一侧的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆