出于性能原因,我试图将游戏中的图形迁移到OpenGL。
到目前为止,我设法完成了前两项任务:
public void onDrawFrame(GL10 gl) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity();
gl.glTranslatef(120, 160, 0); // move rotation point
gl.glRotatef(angle, 0.0f, 0.0f, 1.0f); // rotate
gl.glTranslatef(-120, -160, 0); // restore rotation point
mesh.draw(gl); // draws 100x100 px rectangle with the following coordinates: (70, 110, 170, 210)
}
public void onSurfaceChanged(GL10 gl, int width, int height) {
gl.glViewport(0, 0, width, height);
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
gl.glOrthof(0f, (float)width, (float)height, 0f, -1f, 1f);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
}
但是当我试图围绕x或y旋转我的盒子时,我的盒子发生了令人讨厌的事情并且没有透视效果。我尝试使用其他函数而不是glRotate(glFrustum,glPerspective,gluLookAt,应用"倾斜"矩阵),但我无法使它们正常工作。
答案 0 :(得分:3)
出于性能原因,我正试图将游戏中的图形迁移到OpenGL。
我需要使用精确的屏幕坐标绘制对象。在240x320屏幕的中心说一个100x100像素的盒子。
对于透视,您还需要一些镜头长度,这决定了FOV。 FOV是观察平面距离与可见范围的比率。在近平面的情况下,它变为{left,right,top,bottom}/near
。为简单起见,我们假设水平FOV和对称投影,即
FOV = 2*|left|/near = 2*|right|/near = extent/distance
或者如果你更倾向于角色
FOV = 2*tan(angular FOV / 2)
对于90°FOV,镜头的长度是焦平面宽度的一半。你的焦平面是240x320像素,所以120左右,160到顶部和底部。 OpenGL并没有真正的焦点,但我们可以说近距离和远距离的中间平面是“焦点”。
因此,假设物体的平均可见范围约为可见平面极限的数量级,即对于240x360的可见平面,物体的平均尺寸约为200px。因此,有意义的是,近距离到远距离剪切的距离为200,因此关于焦平面的距离为+ - 100。因此,对于90°的FOV,焦平面具有距离
2*tan(90°/2) = extent/distance
2*tan(45°) = 2 = 240/distance
2*distance = 240
distance = 120
120,因此近距离和远距离的剪切距离分别为20和220.
最后但并非最不重要的是,近剪裁平面限制必须按near_distance / focal_distance = 20/120
进行缩放所以
left = -120 * 20/120 = -20
right = 120 * 20/120 = 20
bottom = -180 * 20/120 = -30
top = 180 * 20/120 = 30
所以这给了我们glFrustum参数:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-20, 20, -30, 30, 20, 220);
最后但同样重要的是,我们必须将世界起源转移到“焦点”平面
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0, 0, -120);
我需要围绕Z轴旋转它,保持其大小。
进行。
我需要围绕X轴旋转它,具有透视效果,保持(或接近)它的大小。 我需要围绕Y轴旋转它,具有透视效果,保持(或接近)它的大小。
透视不保留大小。这就是它的观点。你可以使用很长的镜头,即小视场。
作为一般性专业提示:在绘图处理程序中执行所有OpenGL操作。不要在重塑处理程序中设置投影。它很难看,只要你想要一些HUD或其他类型的叠加,你就不得不丢弃它。所以这是如何改变它:
public void onDrawFrame(GL10 gl) {
// fov, extents are parameters set somewhere else
// 2*tan(fov/2.) = width/distance =>
float distance = width/(2.*tan(fov));
float near = distance - extent/2;
float far = distance + extent/2;
if(near < 1.) {
near = 1.;
}
float left = (-width/2) * near/distance;
float right = ( width/2) * near/distance;
float bottom = (-height/2) * near/distance;
float top = ( height/2) * near/distance;
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glViewport(0, 0, width, height);
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
gl.glFrustum(left, right, bottom, top, near, far);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glTranslatef(0, 0, -focal);
gl.glTranslatef(120, 160, 0); // move rotation point
gl.glRotatef(angle, 0.0f, 0.0f, 1.0f); // rotate
gl.glTranslatef(-120, -160, 0); // restore rotation point
mesh.draw(gl); // draws 100x100 px rectangle with the following coordinates: (70, 110, 170, 210)
}
public void onSurfaceChanged(GL10 gl, int new_width, int new_height) {
width = new_width;
height = new_height;
}
答案 1 :(得分:1)
您需要使用透视投影矩阵,然后使用模型视图矩阵来获得正确的位置和缩放。
答案 2 :(得分:0)
您正在使用正交投影(glOrthof()
),它会明确禁用透视图。
相反的是glFrustum()
,通常由gluPerspective() /包裹,它更易于使用,但需要GLU库。