c++ - 坐标变换和投影问题

标签 c++ opengl 3d projection qglwidget

我一直在尝试将我的鼠标坐标转换为 OpenGL 场景中的 3D 空间坐标。

目前,我的投影有点乱(我认为),当我在场景中移动时,它似乎没有完全考虑到我的“相机”。为了检查这一点,我画了一条线。

我的调整大小函数:

    void oglWidget::resizeGL(int width, int height)
    {
        if (height == 0) {
            height = 1;
        }
        pMatrix.setToIdentity();
        pMatrix.perspective(fov, (float) width / (float) height, -1, 1);
        glViewport(0, 0, width, height);
    }

我的渲染函数(paintGl())如下:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
QMatrix4x4 mMatrix;
QMatrix4x4 vMatrix;

QMatrix4x4 cameraTransformation;
cameraTransformation.rotate(alpha, 0, 1, 0);
cameraTransformation.rotate(beta, 1, 0, 0);

QVector3D cameraPosition = cameraTransformation * QVector3D(camX, camY, distance);
QVector3D cameraUpDirection = cameraTransformation * QVector3D(0, 1, 0);
vMatrix.lookAt(cameraPosition, QVector3D(camX, camY, 0), cameraUpDirection);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();    
gluLookAt(cameraPosition.x(), cameraPosition.y(), cameraPosition.z(), camX, camY, 0, cameraUpDirection.x(), cameraUpDirection.y(), cameraUpDirection.z());

shaderProgram.bind();
shaderProgram.setUniformValue("mvpMatrix", pMatrix * vMatrix * mMatrix);
shaderProgram.setUniformValue("texture", 0);


for (int x = 0; x < tileCount; x++)
{
    shaderProgram.setAttributeArray("vertex", tiles[x]->vertices.constData());
    shaderProgram.enableAttributeArray("vertex");
    shaderProgram.setAttributeArray("textureCoordinate", textureCoordinates.constData());
    shaderProgram.enableAttributeArray("textureCoordinate");
    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, tiles[x]->image.width(), tiles[x]->image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, tiles[x]->image.bits());
    glDrawArrays(GL_TRIANGLES, 0, tiles[x]->vertices.size());
}
shaderProgram.release();

并创建我的 Ray:

GLdouble modelViewMatrix[16];
GLdouble projectionMatrix[16];
GLint viewport[4];
GLfloat winX, winY, winZ;
glGetDoublev(GL_MODELVIEW_MATRIX, modelViewMatrix);
glGetDoublev(GL_PROJECTION_MATRIX, projectionMatrix);
glGetIntegerv(GL_VIEWPORT, viewport);

winX = (float)x;
winY = (float)viewport[3] - (float)y;
glReadPixels( winX, winY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ );

GLdouble nearPlaneLocation[3];
gluUnProject(winX, winY, 0, modelViewMatrix, projectionMatrix,
             viewport, &nearPlaneLocation[0], &nearPlaneLocation[1],
        &nearPlaneLocation[2]);

GLdouble farPlaneLocation[3];
gluUnProject(winX, winY, 1, modelViewMatrix, projectionMatrix,
             viewport, &farPlaneLocation[0], &farPlaneLocation[1],
        &farPlaneLocation[2]);

 QVector3D nearP = QVector3D(nearPlaneLocation[0], nearPlaneLocation[1],
            nearPlaneLocation[2]);
 QVector3D farP = QVector3D(farPlaneLocation[0], farPlaneLocation[1],
            farPlaneLocation[2]);

我觉得我在使用冲突的系统或其他东西。

我应该使用不同的变量来管理我的相机吗?我看到有关投影 View 、模型 View 等的讨论,但我不知道如何使用它以及如何使用着色器程序。对于 OpenGL,我还是新手。

澄清一下:我正在尝试将我的鼠标坐标转换为 3D 空间坐标。到目前为止,它似乎半工作,只是没有考虑相机旋转。我确认我的问题与光线创建或坐标的未投影有关,而不是与我实际的光线拾取逻辑有关。

最佳答案

混合使用不同的功能组/级别,您很可能被绊倒了。您有使用固定函数矩阵堆栈的某些方面。例如,在您的绘图函数中:

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();    
gluLookAt(cameraPosition.x(), cameraPosition.y(), cameraPosition.z(), camX, camY, 0, cameraUpDirection.x(), cameraUpDirection.y(), cameraUpDirection.z());

或者在你的非投影函数中:

glGetDoublev(GL_MODELVIEW_MATRIX, modelViewMatrix);
glGetDoublev(GL_PROJECTION_MATRIX, projectionMatrix);

但在其他地方,您正在构建自己的矩阵,并将它们作为制服传递到着色器中:

vMatrix.lookAt(cameraPosition, QVector3D(camX, camY, 0), cameraUpDirection);
...
shaderProgram.setUniformValue("mvpMatrix", pMatrix * vMatrix * mMatrix);

这是实现相同功能的两种不同方式。但是你不能随意混合和匹配它们的各个部分。如果你想让事情保持清洁和可预测,你应该选择一个,并坚持下去。由于第一个是已弃用的遗留功能,我建议您坚持构建自己的矩阵,并使用着色器代码中定义的制服。

举例说明为什么您当前的功能组合令人失望:您使用 glGetDoublev(GL_PROJECTION_MATRIX, ...) 从固定函数矩阵堆栈获取当前投影矩阵.但至少在此处显示的代码中,您永远不会使用矩阵堆栈指定投影矩阵。所以这只是给你单位矩阵。就 OpenGL 而言,作为制服传递给着色器程序的 pMatrix 矩阵是完全不相关的。

重写你的整个代码对于这个答案来说有点多,所以这里只是关键部分的指针:

  • 摆脱所有引用矩阵堆栈的调用。这包括 glMatrixMode()glLoadIdentity()gluLookAt()glGetDoublev() 调用获取当前矩阵。
  • 为所有渲染使用着色器(如果您还没有使用的话),并在 GLSL 代码中将您需要的所有矩阵定义为统一矩阵。
  • 使用您自己的代码或广泛使用的矩阵/vector 库之一自行计算和管理矩阵。
  • 将这些矩阵作为制服传递给着色器。

现在,对于非投影,看起来您已经有了模型、 View 和投影矩阵(pMatrixvMatrixmMatrix)。所以不需要任何 glGet*() 调用来从 OpenGL 中检索它们。将vMatrixmMatrix相乘得到modelViewMatrix,直接使用pMatrix作为传递给的投影矩阵>gluUnProject().

严格来说,我也认为 GLU 已弃用。但是,如果您仍然愿意使用 gluUnProject(),那么目前这可能是最简单的方法。否则,常用的矩阵库很可能有它的实现。或者,如果您不怕弄脏自己的双手,那么如果您查找一些说明基础计算的规范/文档,实现起来应该不难。

关于c++ - 坐标变换和投影问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28421319/

相关文章:

c++ - Cocos2D-X选择合适 Sprite 表的最高效方式

c++ - 两种包含重复算法的时间复杂度差异

c++ - 取消 pthread_cond_wait() 挂起与 PRIO_INHERIT 互斥锁

c++ - 有没有办法更改现有GLFW窗口的MSAA样本数量?

javascript - 以编程方式将 3-D 形状添加到必应 map (虚拟地球)

c++ - 在光线追踪中对球体进行荒谬的反射

c++ - 医疗 3D 规划软件的最佳技术

c++ - 如何在数字上处理 log(0)?

python - 合并多个线段

c++ - OpenGL with Qt 5 : #error gl. h 包含在 glew.h 之前