在3D空间中对2D平面进行Billboarding,其中相机不是场景的中心

时间:2014-03-26 18:32:51

标签: objective-c macos opengl core-animation scenekit

我在OpenGL / SceneKit / CoreAnimation环境中遇到转换问题。我有我的LED场景。我还创建了一个与每个LED相交的平面。这架飞机将来是透明的,一旦我解决了广告牌问题,它将用于在LED周围画一个高亮圆圈。

Default Behavior

我正在尝试将飞机广告牌放到相机上。我遇到的问题是我无法找到确切的转换方式,以便在我构建的场景中完成这项工作。

在我的mouseDragged:方法中,我正在反转X旋转和Y旋转矩阵,将它们连接起来并将其用作最终变换以反转LED的正向旋转,使其看起来始终面向摄像机。

-(void)mouseDragged:(NSEvent *)theEvent
{

NSPoint winp    = [theEvent locationInWindow];
NSPoint p       = [sceneView convertPoint:winp fromView:nil];

mouseDraggedLocation = p;

//****************** TRANSFROM INIT ****************************************

CATransform3D localProjectionTransform;
CATransform3D translatedProjectionTransformX;
CATransform3D translatedProjectionTransformY;
CATransform3D translatedProjectionTransformFinal;

CATransform3D rotatedProjectionTransformX;
CATransform3D rotatedProjectionTransformY;
CATransform3D rotatedProjectionTransformFinal;

CATransform3D checkedProjectionTransform;
CATransform3D translatedProjectionTransformZ;
CATransform3D translationOnlyMatrix;


CATransform3D tempTransform;

//****************** TRANSFROM INIT ****************************************

// Figure out Angle

angleX = mouseDraggedLocation.x - mouseOldLocation.x;
angleY = mouseDraggedLocation.y - mouseOldLocation.y;

//********************************PLAYING WITH TRANSFORMS****************************




// X transform
rotatedProjectionTransformX = CATransform3DMakeRotation(angleX * ROTATION_FACTOR, 0, 1, 0);
// Y transform
rotatedProjectionTransformY = CATransform3DMakeRotation(angleY * ROTATION_FACTOR, -1.0f, 0.0f, 0.0f);
rotatedProjectionTransformFinal = CATransform3DConcat(rotatedProjectionTransformX, rotatedProjectionTransformY);

translatedProjectionTransformX = CATransform3DMakeTranslation(0, angleX * ROTATION_FACTOR, 0);
translatedProjectionTransformY = CATransform3DMakeTranslation( -1 *(angleY * ROTATION_FACTOR), 0, 0);
translatedProjectionTransformFinal = CATransform3DConcat(translatedProjectionTransformX, translatedProjectionTransformY);

                       //                      rootNode
                       //                            |
                       //                     ledArrayNode
                       //                     /                    \
                      //     outlinePlaneNode (s)      LEDGeomNode(s)


// OH GOD PLEASE DON'T HATE ME FOR THIS, it chooses nodes that aren't Outline nodes, just disregard as crap test coding.

for (SCNNode *NodeTemp in [ledArrayNode childNodes]) {

    if ( [NodeTemp.name rangeOfString:@"O"].location == NSNotFound) {
        localProjectionTransform = NodeTemp.transform;
        NodeTemp.transform = CATransform3DConcat(localProjectionTransform, rotatedProjectionTransformFinal);
    } else {

    }



}


// This is what does the rotation with the outline planes, the previous loop did normal rotations for the LEDGeom Nodes

tempTransform = CATransform3DInvert(rotatedProjectionTransformFinal);

for (SPCLedGeom *LEDTemp1 in LED_Array) {
    localProjectionTransform = LEDTemp1.LED_Outline_Plane_Node.transform;


    LEDTemp1.LED_Outline_Plane_Node.transform = CATransform3DConcat(localProjectionTransform, tempTransform);
}




mouseOldLocation.x = mouseDraggedLocation.x;
mouseOldLocation.y = mouseDraggedLocation.y;


}

如果我只是将运动锁定到任一轴而不是一起锁定,这通常适用于任何一个轴,

x-axis goofery

但是当我移动两个轴时,看起来Y轴需要大约2整圈才能“向上”(同样在Y轴上移动时,平面沿x轴顺时针/逆时针旋转),然后x轴“关闭”,不会像以前那样移动。

当我阅读关于billboarding时,要点是从旋转/变换矩阵中拉出平移方面并使用它,但是,在这些例子中,我认为相机被认为是场景的中心,然而,在SceneKit和我正在处理的事情中,中心是LED阵列的中心,当我按照mouseDragged:方法看到的移动LED节点时,摄像机是固定的。

1 个答案:

答案 0 :(得分:2)

最直接的方法就是使用SCNConstraint Here it is in the WWDC 2013 session.你应该下载并看一下才能看到它。无论如何,您可以使用约束来保持飞机瞄准相机。由于这些平面是透明的,实际上可见的很少,以围绕LED。我认为这是一个不错的选择。

nodeA.constraints = @[SCNLookAtConstraint lookAtConstraintWithTarget:nodeB];

在这种情况下,nodeB将是cameraNode,而nodeA将是包含所有平面的节点。

谢谢David Rönnqvist对于正确方向的箭头。