简体   繁体   English

使用滚动 opengl ES 围绕场景旋转相机

[英]Rotate camera around scene with scrolling opengl ES

I am trying to rotate the camera around the scene using touch (scroll):我正在尝试使用触摸(滚动)围绕场景旋转相机:

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;
    }    
}

The camera moves in the render as follows:相机在渲染中移动如下:

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);
    }
}

This works well at first.这起初运作良好。 But then the camera starts to rotate not as expected.但随后相机开始不按预期旋转。 How can I make the camera move correctly relative to the center of the scene (object) using scrolling?如何使用滚动使相机相对于场景(对象)的中心正确移动? Maybe someone solved a similar problem?也许有人解决了类似的问题?

Thank you for any answer/comment!感谢您的任何回答/评论!

Workaround solution:解决方法:

  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);
  }

But with this approach, the camera moves away from the scene when rotating along the Y-axis.但是使用这种方法时,相机会在沿 Y 轴旋转时远离场景。

In matrix algebra, order does matter.在矩阵代数中,顺序确实很重要。 Since incremental rotations interleave matrices and break order, it won't work as you expect.由于增量旋转交错矩阵和中断顺序,它不会像您期望的那样工作。 Thus you need to rebuild the view-matrix based on cumulative delta x/y on every setMotion() call so that rotations would always be applied in right order as follows.因此,您需要在每次 setMotion() 调用时根据累积 delta 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);
    }
}

Appendix: Composing view-matrix only by setLookAtM附录:仅通过 setLookAtM 组合视图矩阵

It's surely possible to achieve the same only with setLookAtM.当然只有使用 setLookAtM 才能达到同样的效果。 To keep view-point in constant distance, move the view-point in spherical coordinates .要使视点保持恒定距离,请在球坐标中移动视点。 And adjust up-direction too.并向上调整。

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]
    );

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM