JOGL2太阳系模拟:相机环绕行星并朝向行星的实现问题
JOGL2 太阳系模拟相机旋转问题解决
问题描述
用JOGL2开发太阳系模拟程序,当前相机可环绕行星运动,但无法绕自身Y轴旋转朝向行星。启用旋转代码后,地球与相机都会偏移到太阳中心,导致模拟异常。现有可正常运行的代码如下:
//Rotate and place the camera at it's position //dt = angle between camera's lookat direction and the planet. //The camera can't rotate but it can orbit. It needs to do both // gl.glRotatef(dt, 0.0f, 1.0f, 0.0f); gl.glTranslatef(-camX, -camY, -camZ); //draw the planets for(Planet p : this.artbook) { setColor(p); gl.glPushMatrix(); //Go to planet's position in orbit and rotate on its y axis gl.glTranslatef(p.getX(), 0.0f, p.getZ()); gl.glRotatef(p.getRotation(), 0.0f, 1.0f, 0.0f); //draw the planet glu.gluSphere(quad, p.getRadius(), 10, 10); gl.glPopMatrix(); }
需求:实现相机环绕行星的同时,绕自身Y轴旋转朝向行星,且其余天体在相机视角下显示正常。
问题根源与修正方案
问题出在矩阵变换的顺序上。OpenGL采用矩阵右乘规则,代码中的变换顺序与实际作用顺序相反:
错误原因
之前先执行glRotatef再执行glTranslatef,相当于先把整个世界绕太阳中心(坐标系原点)旋转dt角度,再平移到相机位置的反方向。这会导致相机的实际位置被旋转偏移,行星的位置也被同步旋转,最终两者重叠在太阳中心。
修正代码
调换平移与旋转的顺序,先平移到相机位置的反方向(让相机处于坐标系原点),再绕Y轴旋转(此时旋转是基于相机自身的局部坐标系,即绕自身Y轴旋转):
//Rotate and place the camera at it's position //dt = angle between camera's lookat direction and the planet. //先平移到相机位置的反方向,使相机处于坐标系原点 gl.glTranslatef(-camX, -camY, -camZ); //再绕Y轴旋转,让相机朝向行星(旋转基于相机自身局部坐标系) gl.glRotatef(dt, 0.0f, 1.0f, 0.0f); //draw the planets for(Planet p : this.artbook) { setColor(p); gl.glPushMatrix(); //Go to planet's position in orbit and rotate on its y axis gl.glTranslatef(p.getX(), 0.0f, p.getZ()); gl.glRotatef(p.getRotation(), 0.0f, 1.0f, 0.0f); //draw the planet glu.gluSphere(quad, p.getRadius(), 10, 10); gl.glPopMatrix(); }
补充说明
确保dt的计算正确:dt应为相机当前朝向与行星方向之间的Y轴夹角,可通过计算相机到行星的向量与初始朝向向量的夹角得到,保证旋转后相机视线准确对准行星。
内容的提问来源于stack exchange,提问作者Red Richardson
相关产品推荐
相关产品推荐

