我实现了一个应用程序,它只是从摄像机视图渲染多边形网格的深度。
在顶点着色器中,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的实现方式如下。 target和source index equation用于将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图像和观察到的像素值时,我发现在多边形网格的边缘,在邻居的最小值和最大值之间存在一些像素值,如下面的屏幕截图所示。在这里,我将边缘视为多边形网格的轮廓或轮廓。
我的问题是,
我猜这些中间值是从GPU的插值器生成的。这样对吗?仅供参考,我没有使用任何其他片段着色器,例如anit-aliasing。
如果是,如何删除或禁用插值?
如果错了,那些中间值的原因是什么?
答案 0 :(得分:0)
我猜那些中间值是从插值器生成的 GPU。是不是?
没有。图形管道中的插值器与您在边缘上看到的内容无关。让我解释一下通常使用的插值。您的顶点/ tess /几何着色器最终会生成顶点数据,即它们为每个顶点设置位置,法线和其他值。例如,每个三角形(每个顶点)仅调用一次顶点着色器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);
。