在集成一款产品的SDK时遇到以下问题:
SDK使用了QOpenGLWidget编写,目的是绘制二维图形。现在想要在QOpenGLWidget上增加鼠标交互,需要获取鼠标点击的位置在QOpenGLWidget绘制的二维区域对应的世界坐标。
SDK的paintGL代码:
//观察矩阵view
QMatrix4x4 camera;
camera.lookAt(QVector3D(0, 0, 1.3f * cameraZoom), QVector3D(0, 0, 0), QVector3D(0, 1, 0));
camera.translate(0.0f, -0.5f, 0.0f);
camera.scale(1.0f, 1.0f, 1.0f);
// 投影矩阵project
QMatrix4x4 projection;
projection.setToIdentity();//初始化为单位矩阵
projection.perspective(45.f, (float)width / (float)height, 0.01f, 100.0f);
QMatrix4x4 m = projection * camera;
paintSonarImage(m.constData(), glfLogger);/
...
// bind matrix
glUniformMatrix4fv(m_matrixUniform, 1, GL_FALSE, mvp);
...
SDK添加了两个矩阵,传入了shader,在这种情况下,如何获取正确的鼠标位置在二维世界中的投影
下面是我尝试的代码,但是结果并不对
QMatrix4x4 m = projection * camera;
paintSonarImage(m.constData(), glfLogger);
#if 1
{
float winZ;
QPointF pos = line.p1();
glReadPixels((int)pos.x(), (int)pos.y(),
1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ);
float x = (2.f * pos.x()) / width - 1.f;
float y = 1.f - (2.0f * pos.y()) / height;
float z = winZ * 2.f - 1.f;
float w = (2.f * 0.01f * 100.0f) / (100.0f + 0.01f - z * (100.0f - 0.01f));
QVector4D worldPos(x, y, z , 1);
qDebug() << "worldPos1 = " << worldPos;
worldPos *= w;
worldPos = camera.inverted() * projection.inverted() * worldPos;
qDebug() << "pos = " << pos;
qDebug() << "worldPos2 = " << worldPos;
}
#endif
“Devil组”引证GPT后的撰写:
可以通过以下步骤实现:
注意:glReadPixels函数获取的深度值范围为[0,1],需要将其转换为[-1,1]的范围。
float x_ndc = (2.0f * x) / width - 1.0f;
float y_ndc = 1.0f - (2.0f * y) / height;
QVector4D clipPos(x_ndc, y_ndc, winZ, 1.0f);
QVector4D viewportPos = mvpMatrix.inverted() * clipPos;
float w_viewport = viewportPos.w();
float x_viewport = viewportPos.x() / w_viewport;
float y_viewport = viewportPos.y() / w_viewport;
float z_viewport = viewportPos.z() / w_viewport;
QVector3D worldPos = cameraMatrix.inverted() * QVector3D(x_viewport, y_viewport, z_viewport);
这个是提问的我,还是我被推荐回答了。你好提问者,不知道你有没有使用过glut库,这个是opengl的第三方库,上面的转换代码是一个基础射线转换代码,如果是二维的话你可以用glut的函数来获取。代码如下:
double modelview[16], projection[16];//模型投影矩阵
int viewport[4];//视口
float ScreenZ = 1;//深度值
double objx,objy,objz;//获得的世界坐标值
glGetDoublev( GL_PROJECTION_MATRIX, projection );//获得投影矩阵
glGetDoublev( GL_MODELVIEW_MATRIX, modelview );//获得模型矩阵
glGetIntegerv( GL_VIEWPORT, viewport ); //获得视口
glReadPixels( x, viewport[3]-y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &ScreenZ ); //获得屏幕像素对应的世界坐标深度值
gluUnProject( x, viewport[3]-y, ScreenZ , modelview, projection, viewport, &objx, &objy, &objz );//获得屏幕坐标对应的世界坐标
std::cout << " x:" << objx << " y:" << objy << " z:" << objz << std::endl;
你可以试一试,对了这个里面的参数可能和你的有冲突,别忘了修改.
如果你需要库文件的话可以找我或者是在网上下载。这个里面还有好多的计算,自己研究哈