opengl - 如何计算相机的UP和位置?

标签 opengl matrix lwjgl perspectivecamera ray-picking

我想实现在我的游戏中。
我关注this实现指南。

为了计算实际光线,我缺少 lookAtup 向量。

问题

我使用 glRotateglTranslate 而不是 gluLookAt(eye,target,up) 来旋转和移动相机。

问题

如何根据我的旋转和平移/矩阵计算lookAtup

代码片段

用键盘移动相机

if (game.keys[Keyboard.KEY_W]) {
    position.x -= (float) (Math.sin(-rotation.y * Math.PI / 180) * speed);
    position.z -= (float) (Math.cos(-rotation.y * Math.PI / 180) * speed);
}
if (game.keys[Keyboard.KEY_S]) {
    position.x += (float) (Math.sin(-rotation.y * Math.PI / 180) * speed);
    position.z += (float) (Math.cos(-rotation.y * Math.PI / 180) * speed);
}
if (game.keys[Keyboard.KEY_A]) {
    position.x += (float) (Math.sin((-rotation.y - 90) * Math.PI / 180) * speed);
    position.z += (float) (Math.cos((-rotation.y - 90) * Math.PI / 180) * speed);
}
if (game.keys[Keyboard.KEY_D]) {
    position.x += (float) (Math.sin((-rotation.y + 90) * Math.PI / 180) * speed);
    position.z += (float) (Math.cos((-rotation.y + 90) * Math.PI / 180) * speed);
}

用鼠标旋转相机

if (Mouse.isGrabbed()) {
    float mouseDX = Mouse.getDX() * 0.8f * 0.16f;
    float mouseDY = Mouse.getDY() * 0.8f * 0.16f;
    if (rotation.y + mouseDX >= 360) {
        rotation.y = rotation.y + mouseDX - 360;
    } else if (rotation.y + mouseDX < 0) {
        rotation.y = 360 - rotation.y + mouseDX;
    } else {
        rotation.y += mouseDX;
    }
    if (rotation.x - mouseDY >= -89 && rotation.x - mouseDY <= 89) {
        rotation.x += -mouseDY;
    } else if (rotation.x - mouseDY < -89) {
        rotation.x = -89;
    } else if (rotation.x - mouseDY > 89) {
        rotation.x = 89;
    }
}

更新相机

glRotatef(rotation.x, 1, 0, 0);
glRotatef(rotation.y, 0, 1, 0);
glRotatef(rotation.z, 0, 0, 1);
glTranslatef(-position.x + zoom, -position.y - 7 + zoom * -1.05f, -position.z);






我的实现

相机

private void updateCamera() {
    DoubleBuffer m = createDoubleBuffer(16);
    glGetDouble(GL_MODELVIEW_MATRIX, m);
    vUp.x = (float) m.get(1);
    vUp.y = (float) m.get(5);
    vUp.z = (float) m.get(9);

    vPos.x = (float) -(m.get(0) * m.get(12) + m.get(1) * m.get(13) + m.get(2) * m.get(14));
    vPos.y = (float) -(m.get(4) * m.get(12) + m.get(5) * m.get(13) + m.get(6) * m.get(14));
    vPos.z = (float) -(m.get(8) * m.get(12) + m.get(9) * m.get(13) + m.get(10) * m.get(14));

    vBack.x = (float) m.get(2);
    vBack.y = (float) m.get(6);
    vBack.z = (float) m.get(10);

    glRotatef(rotation.x, 1, 0, 0);
    glRotatef(rotation.y, 0, 1, 0);
    glRotatef(rotation.z, 0, 0, 1);
    glTranslatef(-position.x + zoom, -position.y, -position.z);
}

挑选

public void picking(float screenX, float screenY, PickingRay pickingRay) {
    helper.Vector3f view = camera.vBack;
    view.x *= -1;
    view.y *= -1;
    view.z *= -1;
    helper.Vector3f screenHorizontally = new helper.Vector3f(0, 0, 0);
    helper.Vector3f screenVertically = new helper.Vector3f(0, 0, 0);
    float viewAngle = 150; // fovy 150
    float nearClippingPlaneDistance = 1; // was mus hier rein?
    int viewportWidth = width;         // 1200
    int viewportHeight = height;       // 900
    screenHorizontally.crossAndAssign(view, camera.vUp).normalize();
    screenVertically.crossAndAssign(screenHorizontally, view).normalize();

    final float radians = (float) (viewAngle * Math.PI / 180f);
    float halfHeight = (float) (Math.tan(radians / 2) * nearClippingPlaneDistance);
    float halfScaledAspectRatio = halfHeight * getViewportAspectRatio();

    screenVertically.scale(halfHeight);
    screenHorizontally.scale(halfScaledAspectRatio);

    pickingRay.getClickPosInWorld().set(camera.vPos);
    pickingRay.getClickPosInWorld().add(view);

    screenX -= (float) viewportWidth / 2f;
    screenY -= (float) viewportHeight / 2f;
    screenX /= ((float) viewportWidth / 2f);
    screenY /= ((float) viewportHeight / 2f);

    pickingRay.getClickPosInWorld().x += screenHorizontally.x * screenX + screenVertically.x * screenY;
    pickingRay.getClickPosInWorld().y += screenHorizontally.y * screenX + screenVertically.y * screenY;
    pickingRay.getClickPosInWorld().z += screenHorizontally.z * screenX + screenVertically.z * screenY;

    pickingRay.getDirection().set(pickingRay.getClickPosInWorld());
    // pickingRay.getDirection().sub(cpos); // cpos is always [0,0,0]
    System.out.println("x: " + pickingRay.getClickPosInWorld().x + " y: " + pickingRay.getClickPosInWorld().y + " z: " + pickingRay.getClickPosInWorld().z);  // ends in [0, -3.7, 0] to [0, 3.7, 0]
}

最佳答案

你可以从OpenGL的模型 View 矩阵中获取它。

检索矩阵(在设置 View 之后但在应用任何对象转换之前),如下所示:

GLfloat m[16];
glGetFloatv(GL_MODELVIEW_MATRIX, m);

然后向上向量的 X、Y 和 Z 分量位于 m[1]m[5]m[9]. “右”和“后”向量分别为 int m[0]m[4]m[8] m[2]m[6]m[10]

请参阅 this link 了解更多信息。

要获取相机位置,您必须使用 m[12]m[13]m[14],如 here 中所述。例如:

camX = -(m[0] * m[12] + m[1] * m[13] + m[2] * m[14]);
camY = -(m[4] * m[12] + m[5] * m[13] + m[6] * m[14]);
camZ = -(m[8] * m[12] + m[9] * m[13] + m[10] * m[14]);

关于opengl - 如何计算相机的UP和位置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24996932/

相关文章:

OpenCV:将矩阵乘以范围 (0,1) 中的常数。如何处理数据?

java - 间接绘制AWT/Swing组件?

java - (LWJGL3) 使用 glTexSubImage3D 上传图像数据后,OpenGL 2D 纹理数组保持为空

iphone - 将点数组转换为三角形带的快速方法?

c++ - glReadPixels 始终在 glClearColor 中返回相同的值

matlab - 从现有矩阵创建新矩阵

python - 从上三角获取矩阵的索引

java - GLFWKeyCallback 类型的 free() 方法未定义

c++ - 如何在《糖果粉碎传奇》等游戏中为图 block 分配颜色

c++ - OpenGL 2D 纹理无法正确显示 C++