Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/156.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/opengl/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么我要除以Z?_C++_Opengl_Matrix Multiplication - Fatal编程技术网

C++ 为什么我要除以Z?

C++ 为什么我要除以Z?,c++,opengl,matrix-multiplication,C++,Opengl,Matrix Multiplication,我需要在3D环境中实现“选择对象”。因此,我决定采用简单的方法,而不是像光线投射这样稳健、准确的方法。首先,我将对象的世界位置转换为屏幕坐标: glm::mat4 modelView, projection, accum; glGetFloatv(GL_PROJECTION_MATRIX, (GLfloat*)&projection); glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&modelView); accum = projecti

我需要在3D环境中实现“选择对象”。因此,我决定采用简单的方法,而不是像光线投射这样稳健、准确的方法。首先,我将对象的世界位置转换为屏幕坐标:

glm::mat4 modelView, projection, accum;
glGetFloatv(GL_PROJECTION_MATRIX, (GLfloat*)&projection);
glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&modelView);
accum = projection * modelView;
glm::mat4 transformed = accum * glm::vec4(objectLocation, 1);
接下来是一些将opengl坐标系转换为普通窗口坐标的琐碎代码,并做一个简单的距离鼠标检查但是这不太管用。为了从世界空间转换到屏幕空间,我需要在上面显示的函数末尾再添加一个计算:

transformed.x /= transformed.z;
transformed.y /= transformed.z;
我不明白我为什么要这么做。我的印象是,一旦将顶点乘以累积的modelViewProjection矩阵,就得到了屏幕坐标。但我必须除以Z才能让它正常工作。在我的openGL 3.3着色器中,我从不需要除以Z。这是为什么

编辑:从opengl坐标系转换为屏幕坐标的代码如下:

int screenX = (int)((trans.x + 1.f)*640.f); //640 = 1280/2
int screenY = (int)((-trans.y + 1.f)*360.f); //360 = 720/2
然后我通过执行以下操作来测试鼠标是否靠近该点:

float length = glm::distance(glm::vec2(screenX, screenY), glm::vec2(mouseX, mouseY));
if(length < 50) {//you can guess the rest
float length=glm::distance(glm::vec2(screenX,screenY),glm::vec2(mouseX,mouseY));
如果(长度<50){//你可以猜出其余的
编辑#2
鼠标单击事件时调用此方法:

glm::mat4 modelView;
glm::mat4 projection;
glm::mat4 accum;
glGetFloatv(GL_PROJECTION_MATRIX, (GLfloat*)&projection);
glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&modelView);
accum = projection * modelView;
float nearestDistance = 1000.f;
gameObject* nearest = NULL;
for(uint i = 0; i < objects.size(); i++) {
    gameObject* o = objects[i];
    o->selected = false;
    glm::vec4 trans = accum * glm::vec4(o->location,1);
    trans.x /= trans.z;
    trans.y /= trans.z;
    int clipX = (int)((trans.x+1.f)*640.f);
    int clipY = (int)((-trans.y+1.f)*360.f);
    float length = glm::distance(glm::vec2(clipX,clipY), glm::vec2(mouseX, mouseY));
    if(length<50) {
        nearestDistance = trans.z;
        nearest = o;
    }
}
if(nearest) {
    nearest->selected = true;
}

mouseRightPressed = true;
glm::mat4模型视图;
glm::mat4投影;
glm::mat4 accum;
glGetFloatv(GLU投影矩阵,(GLfloat*)和投影);
glGetFloatv(GL_模型视图_矩阵,(GLfloat*)和模型视图);
accum=投影*模型视图;
浮动最近距离=1000.f;
gameObject*最近=空;
对于(uint i=0;iselected=false;
glm::vec4 trans=accum*glm::vec4(o->位置,1);
trans.x/=trans.z;
trans.y/=trans.z;
int clipX=(int)((trans.x+1.f)*640.f);
int clipY=(int)(-trans.y+1.f)*360.f);
float length=glm::distance(glm::vec2(clipX,clipY),glm::vec2(mouseX,mouseY));
如果(lengthselected=true;
}
mouseRightPressed=true;

代码作为一个整体是不完整的,但与我的问题相关的部分工作正常。“对象”向量只包含我测试的一个元素,因此循环根本没有妨碍。

除以Z步骤有效地应用了透视变换。没有它,您将有一个iso视图。想象两个视图空间顶点:
a(-1,0,1)
B(-1,0100)

如果没有“除以Z”步骤,屏幕坐标等于
(-1,0)

使用Z除法时,它们是不同的:
A(-1,0)
B(-0.01,0)
。因此,在屏幕空间中,距离视图空间原点(相机)较远的物体比距离较近的物体小。例如,透视图

也就是说:如果投影矩阵(和矩阵乘法代码)是正确的,这应该已经发生了,因为投影矩阵将包含执行此操作的
1/Z
缩放组件。因此,有一些问题:

  • 您真的在使用投影变换的输出,还是仅使用视图变换

  • 您是在像素/片段着色器中执行此操作的吗?屏幕坐标是标准化的(-1,-1)到(+1,+1),而不是像素坐标,原点位于视口的中间。通常在这种情况下,您会除以
    .w
    ,而不是
    .z
    ,以获得有用的结果

  • 如果您在CPU上执行此操作,您如何将此信息返回到主机


  • 我已经弄明白了正如David Lively先生指出的

    通常在这种情况下,您需要除以
    .w
    而不是
    .z
    来获得有用的结果

    我的
    .w
    值与我的
    .z
    值非常接近,因此在我的代码中我更改了以下语句:

    transformed.x /= transformed.z;
    transformed.y /= transformed.z;
    
    致:

    它仍然像以前一样有效


    解释了w的除法将在以后的管道中进行。显然,因为我的代码只是将矩阵相乘,所以没有“后期管道”。从某种意义上说,我是幸运的,因为我的
    .z
    值与
    值非常接近。w
    值,有一种工作的错觉。

    你能展示一下这一点吗代码?1:我两者都用,正如你从我将GL_MODELVIEW_矩阵和GL_PROJECTION_矩阵组合成一个glm::mat4 2:我根本没有着色器,我想我使用的是GL 1.1?我会尝试除以w,但它按原样工作,这让我感到困惑。3:我不理解question@BWG如果你能把所有的东西都贴出来,那将非常非常有用方法。假设它不是500行长。这将是另一个问题。@BWG好的,乍看起来很好。这可能很愚蠢,但您如何创建和分配投影矩阵?我可以假设一切都画得正确吗?是的,一切都画得很好。我调用
    glMatrixMode(GL_projection);
    glLoadIdentity()
    gluPerspective(75.f,1280.f/720.f,0.1f,500.f);
    glMatrixMode(GL_MODELVIEW);
    然后分配我的相机变换。我已经解决了这个问题,并回答了我自己的问题。不过感谢您对这个问题的深入了解!
    transformed.x /= transformed.w;
    transformed.y /= transformed.w;