Android:OpenGL 2.0使用Matrix.setLookAtM旋转/移动相机

时间:2013-04-15 18:59:45

标签: android matrix opengl-es-2.0

所以这是我今天的第二个问题,我可能会推动我的运气 简而言之,制作一个3D第一人称,你可以在那里四处走动。

在我的OnDrawFrame中我正在使用

Matrix.setLookAtM(mViewMatrix, 0, eyeX , eyeY, eyeZ , lookX , lookY , lookZ , upX, upY, upZ);

向后移动,向后移动,向左移动等我使用类似的东西(列出前向代码)

float v[] = {mRenderer.lookX - mRenderer.eyeX,mRenderer.lookY - mRenderer.eyeY, mRenderer.lookZ - mRenderer.eyeZ};

mRenderer.eyeX += v[0] * SPEED_MOVE;
mRenderer.eyeZ += v[2] * SPEED_MOVE;

mRenderer.lookX +=  v[0] * SPEED_MOVE;
mRenderer.lookZ +=  v[2] * SPEED_MOVE;

这有效

现在我想环顾四周,尝试移植我的iPhone openGL 1.0代码。这是左/右

float v[] = {mRenderer.lookX - mRenderer.eyeX,mRenderer.lookY - mRenderer.eyeY, mRenderer.lookZ - mRenderer.eyeZ};

if (x > mPreviousX )
{
 mRenderer.lookX  +=  ((Math.cos(SPEED_TURN / 2) * v[0]) - (Math.sin(SPEED_TURN / 2) * v[2]));
 mRenderer.lookZ  +=  ((Math.sin(SPEED_TURN / 2) * v[0]) + (Math.cos(SPEED_TURN / 2) * v[2]));
}
else
{
 mRenderer.lookX  -=  (Math.cos(SPEED_TURN / 2) *v[0] - Math.sin(SPEED_TURN / 2) * v[2]);
 mRenderer.lookZ  -=  (Math.sin(SPEED_TURN / 2) *v[0] + Math.cos(SPEED_TURN / 2) * v[2]);
}

这适用于35度,然后是心理?

有什么想法吗?

2 个答案:

答案 0 :(得分:5)

首先,我建议不要追踪look向量,而是追踪forward向量,然后在lookAt方法中使用eye+forward生成look向量。这样,您可以在移动时完全取消look上的更新,而无需计算v向量(mRenderer.eyeX += forward.x * SPEED_MOVE; ...)

为了使事情变得更简单,我建议您在更改它们时对矢量forwardup进行规范化(我将按照您在以下方法中的方式进行考虑)。

现在轮换有两种方式。使用rightup向量来移动forward(以及up),这对于小转弯非常有用(我说最多10度并且上限为90度)或计算当前角度,添加任意角度并重新创建矢量。

首次提到的旋转方法非常简单:

vector forward = forward
vector up = up
vector right = cross(forward, up) //this one might be the other way around as up, forward :)
//going left or right:
forward = normalized(forward + right*rotationSpeedX)
//going up or down:
forward = normalized(forward + up*rotationSpeedY)
vector right = cross(forward, up) //this one might be the other way around
vector up = normalized(cross(forward, right)) //this one might be the other way around
//tilt left or right:
up = normalized(up + right*rotationZ)

第二种方法需要一点三角法:

通常要计算一个角度,你可以调用atan(forward.z/forward.x)并添加一些if语句,因为生成的结果只有180度角(我相信你能找到一些答案) web来从矢量获得旋转)。获取垂直旋转的up向量也是如此。然后在获得角度后,您可以轻松地向角度添加一些度数,并使用sincos重新创建向量。但是有一个问题,如果你以这种方式旋转相机,那么前方面朝上(0,1,0),你需要从up向量获得第一次旋转,从forward获得第二次旋转。矢量,但你可以避免所有这一切,如果你将最大垂直角度限制在+ - 85度(并且有很多游戏实际上这样做)。第二件事是如果你使用这种方法,你的环境必须支持+ -infinitive,否则atan(forward.z/forward.x)会在forward.x == 0时生效。

还有一些关于第一种方法的补充。由于我看到你试图在2D空间中移动,因此使用移动速度的前向矢量应该是normalized(forward.x, 0, forward.z),重要的是将其标准化,否则如果相机向上或向下倾斜更多,则移动速度会变慢。 第二件事是当您向左/向右旋转时,您可能希望强制up向量到(0,1,0)+标准化右向量,最后从向前和向右重新创建向上向量。那么你应该再对垂直旋转进行限制(up.z应该大于一些小值,如.01)

答案 1 :(得分:0)

原来我的轮换代码错了

if (x > mPreviousX )
{
 mRenderer.lookX  = (float) (mRenderer.eyeX +  ((Math.cos(SPEED_TURN / 2) * v[0]) - (Math.sin(SPEED_TURN / 2) * v[2])));
 mRenderer.lookZ  =  (float) (mRenderer.eyeZ +  ((Math.sin(SPEED_TURN / 2) * v[0]) + (Math.cos(SPEED_TURN / 2) * v[2])));
}
else
{
 mRenderer.lookX  =  (float) (mRenderer.eyeX + ((Math.cos(-SPEED_TURN / 2) * v[0]) - (Math.sin(-SPEED_TURN / 2) * v[2])));
 mRenderer.lookZ  =  (float) (mRenderer.eyeZ + ((Math.sin(-SPEED_TURN / 2) * v[0]) + (Math.cos(-SPEED_TURN / 2) * v[2])));
}