相机绕物体运行时不稳定

问题描述 投票:0回答:1

我正在尝试让相机绕 JOGL 太阳系模型中的一颗行星运行,但该行星不想停留在视野中心。相机基本上应该围绕地球绕一个完美的圆,实际上是在一个固定的半径上绕地球运行。行星应该始终出现在屏幕中央,但它并没有停留在那里。我试图弄清楚行星的计算位置和行星的实际位置之间是否存在距离,或者我是否需要使用一些三角操作,但我得到的只是一个更混乱的相机和行星。

==========编辑==================

我还尝试使用 gluLookAt 来设置相机:

  • 相机位置是围绕地球的圆上的一个点
  • 焦点是行星的 x,0,z 坐标
  • 向上向量就是 0,1,0

但相机似乎只是停留在原点,没有旋转或平移。

这是我的显示功能

public void display(GLAutoDrawable drawable) {
    //initialise the display matrix
    gl = initMatrix(drawable, GL2.GL_MODELVIEW);
    
    //get earth position
    float earthX = artbook.get(3).getX(),
            earthZ = artbook.get(3).getZ(),
            earthRotation = artbook.get(3).getRotation();
    //Draw each planet
    Planet art;
    for(int i = 0; i < artbook.size(); i++) {
        returnToOrigin();

        //apply camera transformations first
        gl.glRotatef(-(earthRotation), 0, 1, 0);
        gl.glTranslatef(-earthX, 0, -earthZ-0.1f);
        
        //then draw the planets
        art = artbook.get(i);
        drawPlanet(art);
    }
    frameCount += 1;
}

此轨道函数可找到行星与太阳当前的轨道角

 /**
 * Finds the orbital angle of the planet on it's orbit and translate the planet there 
 * @param art
 * @return the actual offset of the planet
 */
private void orbitPlanet(Planet art) {
    float sunRadius = 109.3f,
            radius = art.getRadius(),
            offset = art.getOffset(),
            orbit;
    
    //if the planet isn't the sun, skew the offset
    float skew = sunRadius + radius;
    if(radius != sunRadius) offset += skew;
    
    //Get the new orbital position of the planet
    orbit = art.orbit(frameCount) % 360;
    
    //set the position of the planet
    float x = (float) (offset * Math.cos(Math.toRadians(orbit)));
    float z = (float) (offset * Math.sin(Math.toRadians(orbit)));
    gl.glTranslatef(x, 0, z);
    art.setX(x);
    art.setZ(z);
}

这是 Planet 类函数,用于确定给定帧期间的轨道角。

 /**
 * Finds the new orbital angle at the current frame
 * @param frameCount The current Frame
 * @return The new angle the planet makes with the sun
 */
public float orbit(float frameCount) {
    //find the new orbit angle theta and the delta between the current and new orbit
    float theta = frameCount * 1/(this.orbitRate);
    this.orbit = theta;
    return this.orbit;
}
java opengl camera jogl
1个回答
0
投票

绕其轴 {0,1,0} 旋转的行星旋转,而该行星本身又绕太阳旋转(原点 {0,0,0})。

一般算法是

P' = ProjectionMatrix * ViewMatrix * ModelMatrix * P

然后(在详细介绍之前)步骤如下:

投影矩阵

  • 将矩阵模式设置为
    GL_PROJECTION
  • 加载投影矩阵

查看矩阵

  • 将矩阵模式设置为
    GL_MODELVIEW
  • 通过 lookAt
  • 设置视图矩阵

模型矩阵

  • 将行星平移到其轨道位置:
    • 旋转(行星轨道弧度)
    • 平移(轨道半径)
  • 使行星绕其轴旋转

P

  • 渲染星球

查看矩阵

由于相机绕行星运行,我们需要计算行星的位置。 为此,我们假设轨道平面是 xz 平面,y 是向上向量。

哪里

angle:以弧度表示的轨道角
半径:从原点到行星中心的距离

planet_x = cos(angle) * radius;
planet_y = 0;
planet_z = sin(angle) * radius;

现在我们有了行星位置,它是 lookAt 函数的目标参数,剩下的就是计算眼睛位置。 这里我们再次假设,轨道平面与上面相同(xz 平面)。

从您的描述中,我们知道相机以与绕其自身轴旋转相同的速度绕行星运行, 因此,我们只需重用上述操作中计算出的 sin/cos 值 (cx, sz),并将其乘以到地球中心的距离。

eye_x = cx * distance;
eye_y = 0;
eye_z = sz * distance;

但是,那是在原点附近,我们仍然需要将其转换为实际的行星位置

eye_x += planet_x;
eye_z += planet_z;

模型矩阵

由于我们手动计算了行星位置(请参阅 ViewMatrix 部分),因此我们可以省略旋转部分并将其简单地转换为计算的位置。


我们算法的实际组成如下:

/* ProjectionMatrix */
glMatrixMode(GL_PROJECTION);
gluPerspective(fovy, aspect, zNear, zFar);

/* ViewMatrix */
glMatrixMode(GL_MODELVIEW);
gluLookAt(
    eye_x, eye_y, eye_z,          //eye
    planet_x, planet_y, planet_z, //target
    0, 1, 0                       //up vector: y-axis
);

/* ModelMatrix */
glTranslatef(planet_x, planet_y, planet_z);
glRotatef(
    angle,  //rotation angle in radians of the planet around its own axis
    0, 1, 0 //rotation vector, since the rotation takes place in the xz-plane -> y-axis
);

/* planet */
gluSphere(...);
© www.soinside.com 2019 - 2024. All rights reserved.