android - 使用滚动opengl ES围绕场景旋转相机
问题描述
我正在尝试使用触摸(滚动)围绕场景旋转相机:
public class SurfaceView extends GLSurfaceView
implements GestureDetector.OnGestureListener {
SceneRenderer renderer;
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
renderer.setMotion(distanceX, distanceY); // pass movement to render
return true;
}
}
相机在渲染中移动如下:
public class SceneRenderer implements GLSurfaceView.Renderer {
private float[] viewMatrix = new float[16];
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
Matrix.setLookAtM(viewMatrix, 0, 0f, 0f, 3f,
0f, 0f, 0f, 0f, 1.0f, 0.0f);
}
...
// movement of camera
public synchronized void setMotion(float xDistance, float yDistance) {
Matrix.rotateM(viewMatrix, 0, -xDistance * 0.1f, 0, 1, 0);
Matrix.rotateM(viewMatrix, 0, -yDistance * 0.1f, 1, 0, 0);
}
}
这起初运作良好。但随后相机开始不按预期旋转。如何使用滚动使相机相对于场景(对象)的中心正确移动?也许有人解决了类似的问题?
感谢您的任何回答/评论!
解决方法:
private float kx = 0f;
private float ky = 0f;
private float radius = 3.0f;
private float x, y, z = 0f;
...
public synchronized void setMotion(float xDistance, float yDistance) {
kx = kx + xDistance * 0.001f;
x = (float) (radius * Math.sin(kx));
z = (float) (radius * Math.cos(kx));
ky = ky + yDistance * 0.001f;
y = (float) (radius * Math.sin(ky));
Matrix.setLookAtM(viewMatrix, 0, x, -y, z, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
}
但是使用这种方法时,相机会在沿 Y 轴旋转时远离场景。
解决方案
在矩阵代数中,顺序确实很重要。由于增量旋转交错矩阵和中断顺序,它不会像您期望的那样工作。因此,您需要根据每次 setMotion() 调用的累积增量 x/y 重建视图矩阵,以便始终按正确顺序应用旋转,如下所示。
public class SceneRenderer implements GLSurfaceView.Renderer {
private float[] viewMatrix = new float[16];
private float cumulativeX = 0.0f;
private float cumulativeY = 0.0f;
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
Matrix.setLookAtM(viewMatrix, 0, 0f, 0f, 3f,
0f, 0f, 0f, 0f, 1.0f, 0.0f);
cumulativeX = 0.0f;
cumulativeY = 0.0f;
}
...
// movement of camera
public synchronized void setMotion(float xDistance, float yDistance) {
cumulativeX += xDistance;
cumulativeY += yDistance;
Matrix.setLookAtM(viewMatrix, 0, 0f, 0f, 3f,
0f, 0f, 0f, 0f, 1.0f, 0.0f);
//Matrix.rotateM(viewMatrix, 0, -cumulativeX * 0.1f, 0, 1, 0);
//Matrix.rotateM(viewMatrix, 0, -cumulativeY * 0.1f, 1, 0, 0);
Matrix.rotateM(viewMatrix, 0, -cumulativeY * 0.1f, 1, 0, 0);
Matrix.rotateM(viewMatrix, 0, -cumulativeX * 0.1f, 0, 1, 0);
}
}
附录:仅通过 setLookAtM 组合视图矩阵
当然只有使用 setLookAtM 才能达到同样的效果。要使视点保持恒定距离,请在球坐标中移动视点。并向上调整。
public synchronized void setMotion(float xDistance, float yDistance) {
kx = kx + xDistance * 0.001f;
ky = ky + yDistance * 0.001f;
x = (float) (radius * Math.cos(ky) * Math.sin(kx));
z = (float) (radius * Math.cos(ky) * Math.cos(kx));
y = (float) (radius * Math.sin(ky));
float[] up =
{
(float) (Math.sin(ky) * Math.sin(kx)),
(float) (Math.cos(ky)),
(float) (Math.sin(ky) * Math.cos(kx)),
};
Matrix.setLookAtM(viewMatrix, 0,
x, -y, z,
0f, 0f, 0f,
up[0], up[1], up[2]
);
}
推荐阅读
- c - 程序返回错误的数字
- c++ - 在游戏引擎布局中使用 shared_ptr?
- r - 绘制 3D 平面和矢量
- html - 无法更改标题中的链接颜色代码
- visual-foxpro - 在字符串中浏览年份
- javascript - 强制 JavaScript setTimout 函数在 x 毫秒后运行
- oauth-2.0 - 是否有任何 OAuth 授权支持代表用户授予访问权限,而无需用户交互?
- laravel - 如何将默认 elqount 分页查询字符串更改为其他页面=?
- laravel - PhpStorm 为相同的方法显示不同的颜色
- javascript - 如何通过单击或悬停在第一个 div 元素旁边水平显示另一个 div 元素?在第一个 div