使用平移手势旋转相机使用lookat功能

时间:2016-04-01 11:51:46

标签: ios swift opengl-es metal

我尝试使用lookat功能旋转相机和平移手势。我使用swift和Metal(在这种情况下,Metal与OpenGLES一样)。这是我的代码

lookat函数:

 let kEye = V3f(0.0, 0.0, -2.0)
 var ktarget = V3f(0.0, 0.0, 0.0)
 let kUp = V3f(0.0, 1.0, 0.0)    
 var viewMatrix = lookAt(kEye, center: ktarget, up: kUp)

泛手势:

func pan(panGesture: UIPanGestureRecognizer){

        if panGesture.state == UIGestureRecognizerState.Changed{
            let pointInView = panGesture.locationInView(self.view)
            let xDelta = (lastPanLocation.x - pointInView.x)/self.view.bounds.width * panSensivity
            let yDelta = (lastPanLocation.y - pointInView.y)/self.view.bounds.height * panSensivity
            lastPanLocation = pointInView

            var viewDirection = rotationM3f(kUp, angle: Float(-xDelta)) * viewDirection
            var toRotateAround = Cross(viewDirection, b: kUp)
            viewDirection = rotationM3f(toRotateAround, angle: Float(-yDelta)) * viewDirection
            ktarget = kEye + viewDirection

        } else if panGesture.state == UIGestureRecognizerState.Began {
            lastPanLocation = panGesture.locationInView(self.view)
        }
    }

一开始,它工作正常,一段时间后平移相机,viewDirection和toRotateAround矢量将变为-0.0,-0.0,0.0,当手指垂直移动但相机不上下看时,任何人都知道什么代码错了?感谢~~~

1 个答案:

答案 0 :(得分:1)

您只修改了视图方向(最后为ktarget),但忘记了kUP。一旦这两个向量变为平行,则交叉积为零,一切都会中断。

您正在寻找的解决方案是使用kUpviewDirection的叉积重新计算toRotateAround向量。

使用此类轮播时,您需要将数据视为基本向量和位置(location=kEyeforward=ktarget-keyeup=kUpright=cross(forward, up))。基本矢量总是彼此垂直(我建议它们也被标准化),当你旋转时,你总是围绕另一个基矢量旋转其中一个矢量,旋转后你需要使用十字产品重新计算第三个矢量

因此,要向左或向右旋转,您可以围绕forward旋转up,然后使用forwardup之间的叉制产品来获取right向量。 (这里的右矢量是可选的,因为你不使用它)

要向上或向下旋转,您可以围绕forward向量旋转right向量,并使用forwardright之间的叉积来获取新的top矢量。

然后,为了向左或向右倾斜,您可以在up周围旋转forward并获取带有2个使用向量的叉积的right向量。

如果你看到你会发现的逻辑,总有两种方法可以沿一个轴旋转。例如,要向左或向右旋转,您也可以围绕right旋转up向量,并使用rightup的叉积来查找新的向前向量。 / p>

虽然有一招。这里描述的程序非常适合自由运动,例如飞行模拟,您可以“倾斜”。它不适用于第一人称射击游戏,其中向上总是在屏幕的中心水平(我希望你看到差异)。要创建此FPS方式,您实际上需要将up保留为(0,1,0),但是前方必须永远不会是(0,1,0),但它可以是(0.001, 0.09, 0),这非常接近直接向上看。因此,只要您将向上角度限制为某个值,就应该没问题。还有其他方法......