我尝试使用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,当手指垂直移动但相机不上下看时,任何人都知道什么代码错了?感谢~~~
答案 0 :(得分:1)
您只修改了视图方向(最后为ktarget
),但忘记了kUP
。一旦这两个向量变为平行,则交叉积为零,一切都会中断。
您正在寻找的解决方案是使用kUp
和viewDirection
的叉积重新计算toRotateAround
向量。
使用此类轮播时,您需要将数据视为基本向量和位置(location=kEye
,forward=ktarget-keye
,up=kUp
,right=cross(forward, up)
)。基本矢量总是彼此垂直(我建议它们也被标准化),当你旋转时,你总是围绕另一个基矢量旋转其中一个矢量,旋转后你需要使用十字产品重新计算第三个矢量
因此,要向左或向右旋转,您可以围绕forward
旋转up
,然后使用forward
和up
之间的叉制产品来获取right
向量。 (这里的右矢量是可选的,因为你不使用它)
要向上或向下旋转,您可以围绕forward
向量旋转right
向量,并使用forward
和right
之间的叉积来获取新的top
矢量。
然后,为了向左或向右倾斜,您可以在up
周围旋转forward
并获取带有2个使用向量的叉积的right
向量。
如果你看到你会发现的逻辑,总有两种方法可以沿一个轴旋转。例如,要向左或向右旋转,您也可以围绕right
旋转up
向量,并使用right
和up
的叉积来查找新的向前向量。 / p>
虽然有一招。这里描述的程序非常适合自由运动,例如飞行模拟,您可以“倾斜”。它不适用于第一人称射击游戏,其中向上总是在屏幕的中心水平(我希望你看到差异)。要创建此FPS方式,您实际上需要将up
保留为(0,1,0)
,但是前方必须永远不会是(0,1,0)
,但它可以是(0.001, 0.09, 0)
,这非常接近直接向上看。因此,只要您将向上角度限制为某个值,就应该没问题。还有其他方法......