OpenGL - 在 NDC 中计算位置适用于着色器,但不适用于“常规”程序

Posted

技术标签:

【中文标题】OpenGL - 在 NDC 中计算位置适用于着色器,但不适用于“常规”程序【英文标题】:OpenGL - calculating position in NDC works in shader but not in 'regular' program 【发布时间】:2020-07-02 09:23:24 【问题描述】:

我目前正在使用 opengl 进行 2d-sicescrolling jump'n'run。我目前想检查我的敌人是否在屏幕上渲染,以停止对不可见敌人的碰撞计算。为此,如果 NDC 中的位置在 x 轴和 y 轴的 [-1, 1] 之间,我会检查每一帧。 这是通过以下方法完成的:

bool Enemy::checkWithCameraArea(glm::mat4 cameraView, glm::mat4 proj, glm::vec3 scale) 
    glm::mat4 model = glm::mat4(1.0f);
    model = glm::translate(model, position);
    model = glm::scale(model, scale);
    glm::vec4 posInClip = proj * cameraView * model * glm::vec4(position, 1.0f);
    glm::vec3 posDehom = glm::vec3(posInClip.x / posInClip.w, posInClip.y / posInClip.w, posInClip.z / posInClip.w);

    if (posDehom.x <= 1.0f && posDehom.x >= -1.0f &&
        posDehom.y <= 1.0f && posDehom.y >= -1.0f) 
        return true;
    

    return false;

视图矩阵计算如下:glm::lookAt(_position, _position + _front, _up); 和这样的投影矩阵:glm::perspective(45.0f, (float)Width / (float)Height, 5.0f, 15.0f); 这些值会根据相机向右的移动在每一帧中更新。

在我的顶点着色器中使用相同的值将位置转换为剪辑空间,从渲染的角度来看,一切正常。但是每个敌人的计算似乎只在一开始就起作用。如果相机向右移动,我的“checkWithCameraArea”方法计算的区域似乎落后了。所以左边屏幕外的敌人还在计算,从右边进入屏幕的敌人还没有计算。请帮助我,我不知道我的错误在哪里。

编辑#1

删除了缩放线,因为这对于单个位置没有意义(如 cmets 中所指出的)。由于有人问,我检查的位置是左下角。但是当整个对象在屏幕上时,我的问题也仍然存在,可以看到here。在此视频中,我将问题可视化: checkWithCameraArea-Method 的结果确定是绘制了敌人纹理(为真)还是绿色框(为假)

【问题讨论】:

我猜你的敌人有一些音量。如果你只检查一个点,那么你会遇到问题,因为这一点可能是不可见的,而敌人的其他部分已经可见。难道你测试的点是每个敌人最右边的点? @BDL 我已经检查过了,点在最左边。当整个敌人都在屏幕上时,甚至会出现问题 为什么需要一个尺度矩阵来计算单点 @DraykoonD 好点,我不需要它。谢谢,但这并没有改变我的问题 刚刚注意到您申请了两次position。一次是使用模型矩阵,一次是因为您使用glm::vec4(position, 1.0f)。你不应该计算proj * cameraView * model * glm::vec4(0.0f, 0.0f, 0.0f, 1.0f);proj * cameraView * glm::vec4(position, 1.0f); 吗? 【参考方案1】:

正如用户 BDL 在 cmets 中指出的那样,我应用了两次该位置(一次在翻译中,一次在与 MVP 相乘时)。我还删除了缩放,因为它不是单点所必需的。 该方法现在看起来像这样,并且可以按我的意愿工作:

bool Enemy::checkWithCameraArea(glm::mat4 view, glm::mat4 proj) 
    glm::vec4 posInClip = proj * view * glm::vec4(position, 1.0f);
    glm::vec3 posDehom = glm::vec3(posInClip.x / posInClip.w, posInClip.y / posInClip.w, posInClip.z / posInClip.w);

    if (posDehom.x <= 1.0f && posDehom.x >= -1.0f &&
        posDehom.y <= 1.0f && posDehom.y >= -1.0f) 
        return true;
    

    return false;

【讨论】:

以上是关于OpenGL - 在 NDC 中计算位置适用于着色器,但不适用于“常规”程序的主要内容,如果未能解决你的问题,请参考以下文章

着色器存储缓冲区中的 OpenGL 顶点

OpenGL坐标系统

OpenGL:使用着色器通过使用预先计算的颜色图来创建顶点照明?

OpenGL在可分离着色器程序中改变不同的位置

哪些 OpenGL 函数在顶点着色器之前修改顶点位置?

OpenGL:在着色器中执行 TexCoord 计算,不好的做法?