【问题标题】:OpenGL: color value at the edge of an objectOpenGL:对象边缘的颜色值
【发布时间】:2016-09-02 06:54:30
【问题描述】:

我实现了一个应用程序,它简单地从相机视图中渲染多边形网格的深度。

在顶点着色器中,gl_Position 是使用如下简单代码设置的。

gl_Position =  MVP * vec4(vertexPosition_modelspace,1);

在片段着色器中,返回的颜色值定义如下。

color = vec3(1-gl_FragCoord.z,1-gl_FragCoord.z,1-gl_FragCoord.z);

渲染单帧后,像素值被读取为浮点数并保存为 *.pgm 图像文件。

float* pgmBuffer = new float[width*height * 3];
glReadPixels((GLint)0, (GLint)0,
                (GLint)width, (GLint)height,
                GL_RGB, GL_FLOAT, pgmBuffer);
WritePGM(width, height, pgmBuffer, imgname);

WritePGM 的实现如下所示。目标和源索引方程用于将 glReadPixel 结果的缓冲区顺序转换为 PGM 文件格式。 像素值 [0,1] 也被转换为 [0,255]。

void OpenGL_Render::WritePGM(int width, int height, float* buffer, char* outPGM)
{
    int* gbuffer = new int[width*height];
    unsigned char *cbuffer = new unsigned char[width*height*sizeof(unsigned char)];

    int line = 1;
    for (int i = 0; i < width; i++)
    {
        for (int j = 0; j < height; j++)
        {
            int target = i*width + j;
            int source = width*height * 3 - (((i+1)*width - (j+1)) * 3);

            cbuffer[target] = buffer[source]*255;
        }

    }

    ofstream fout(outPGM);
    fout << "P5\n" << width << " " << height << "\n255\n";
    fout.write((char *)cbuffer, width*height * sizeof(unsigned char));
    fout.close();
}

这就是问题所在。当我打开结果 PGM 图像并观察像素值时,我发现在多边形网格的边缘,有一些像素值介于邻居的最小值和最大值之间,如下面的屏幕截图所示。在这里,我的意思是边缘作为多边形网格的轮廓或轮廓。

我的问题是,

  1. 我猜这些中间值是从 GPU 的插值器生成的。这样对吗?仅供参考,我没有使用任何其他片段着色器,例如消除锯齿。

  2. 如果正确,如何删除或禁用插值?

  3. 如果是错误的,这些中间值的原因是什么?

【问题讨论】:

    标签: c++ opengl


    【解决方案1】:

    我猜这些中间值是从插值器生成的 显卡。对吗?

    没有。图形管道中的插值器与您在边缘看到的无关。让我解释一下插值通常用于什么。您的顶点/苔丝/几何着色器最终会产生顶点数据,即它们为每个顶点设置位置、法线和其他值。例如,每个三角形(每个顶点)只调用顶点着色器 3 次。但是片段着色器完全是另一回事。它为基元的每个片段调用(为简单起见,您可以假设片段 == 像素)。然后,如果我想获得当前片段的三角形法线向量(三角形上的点),我应该使用哪一个?一个三角形可能有三个不同的法向量!答案是:两者都不是。看,当您在顶点(以及镶嵌或几何)着色器中编写 out 变量时,片段着色器的相应 in 变量会从当前图元的所有每个顶点值中获得一个值。这允许产生以下效果:

    注意右侧球体的边缘。它没有比左边更多的多边形,但它很平滑!这种效果是可能的,因为每个顶点(四个四边形相互接触的点)中的法线是球体的 true 法线。它实际上不垂直于任何周围的四边形,但实际上它是顶点的半径矢量,因为它应该在数学上正确的球体中。但是在左边的图片中,插值被关闭了,每个四边形只有一个法线(以某种方式选择)照亮,所以同一个四边形的所有像素都有相同的法线,而在右边的图片中,每个像素都有自己的法线从四边形的角插入的向量。

    将上述内容应用于您的屏幕截图,我们看到插值只会在立方体的上产生平滑渐变,而不是边缘。没有它你会得到这样的东西:

    作为一个更原始的示例,假设您想要绘制一条线(例如,使用 GL_LINES),将其颜色从黑色平滑地更改为白色。但是您只能为线上的两个点设置颜色值:开始和结束。因此,如果您没有插值,您将获得完全黑色或完全白色的线条,具体取决于其他一些设置。例如,11 像素长的线如下所示:

    |0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|0.0|
    

    但启用插值后,像素颜色会平滑变化:

    |0.0|0.1|0.2|0.3|0.4|0.5|0.6|0.7|0.8|0.9|1.0|
    

    顶点到片段着色器变量的插值默认启用,但您可以使用 flat interpolation qualifier 禁用它。

    现在是第二个问题。

    如果是错误的,这些中间值的原因是什么?

    原因是您启用了抗锯齿功能。在不使用一些高级着色技术之前,您不需要任何额外的工作或特殊的着色器来获得抗锯齿渲染。以下是启用的抗锯齿可能来自何处的列表:

    • 您在代码中的某处调用了glEnable(GL_MULTISAMPLE);
    • 您的窗口处理库已经帮您完成了。
    • 在您的视频驱动程序选项中强制使用抗锯齿功能。据我记得,Windows 的 nVidia 驱动程序前段时间就有这样的功能。

    【讨论】:

    • 谢谢谢尔盖!只需关闭 nVidia 驱动程序中的 alaliasing 选项即可解决此问题。我认为 OpenGL API 比显卡选项“低级”......愚蠢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多