多重采样似乎不适用于片段着色器生成的片段。 在下面的示例中,片段着色器用于生成棋盘程序纹理。 正方形的外边缘已正确抗锯齿,但程序纹理的内边缘未正确抗锯齿。
片段着色器是否仅针对每个像素进行评估? 或者给定像素的每个片段的纹理坐标是否相同?
下面是代码和 image显示其输出(请注意,程序边缘(白色和灰色方 block 之间)没有抗锯齿,而几何边缘(黑色和白色/灰色之间)是抗锯齿的):
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# imports ####################################################################
import sys
from OpenGL.GLUT import *
from OpenGL.GL import *
# display ####################################################################
def reshape(width, height):
"""window reshape callback."""
glViewport(0, 0, width, height)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
r = float(min(width, height))
w, h = 2*width/r, 2*height/r
glOrtho(-w, w, -h, h, -1, 1)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glRotate(45, 0, 0, 1)
def display():
"""window redisplay callback."""
glClear(GL_COLOR_BUFFER_BIT)
glBegin(GL_TRIANGLE_STRIP)
for x in [-1, 1]:
for y in [-1, 1]:
glTexCoord(x, y)
glVertex(x, y)
glEnd()
glutSwapBuffers()
# setup ######################################################################
glutInit(sys.argv)
glutInitDisplayString(b"rgba double samples=4")
glutInitWindowSize(100, 100)
glutCreateWindow(sys.argv[0].encode())
glutReshapeFunc(reshape)
glutDisplayFunc(display)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
shader = glCreateShader(GL_FRAGMENT_SHADER)
glShaderSource(shader, """
void main() {
vec2 c = gl_TexCoord[0].xy;
vec4 color = gl_Color;
if(c.x*c.y < 0.) color.a *= .5;
gl_FragColor = color;
}
""")
glCompileShader(shader)
program = glCreateProgram()
glAttachShader(program, shader)
glLinkProgram(program)
glUseProgram(program)
glutMainLoop()
最佳答案
这就是MSAA(多重采样抗锯齿)的基本思想。片段着色器每个片段仅执行一次。然后使用样本掩码来控制将结果片段写入哪些样本。
假设您使用 4x MSAA,其中每个片段由 2x2 样本组成。如果三角形的边穿过片段,则仅将边内部的样本更新为新颜色。因此,如果片段仅部分位于三角形内,则可以更新 4 个样本中的 1、2 或 3 个。但更新的样本均以相同颜色更新。因此,片段着色器只需要评估一次。
这种方法的一大优点是非常高效。与不使用 MSAA 的渲染相比,它通常只会增加非常少量的开销。正如已经确定的,着色器执行的数量没有变化。渲染目标理论上会变大 4 倍,这可能会大幅增加内存使用量。但该内存通常可以被有效压缩,因此它并不像听起来那么糟糕。显然,在渲染帧的最后有一个下采样步骤,这确实增加了开销。
缺点是 MSAA 仅有助于平滑三角形边界和交叉点。如果三角形内有急剧的过渡,例如由于纹理内容或程序纹理,它根本没有帮助。 Mipmapping 可以减少纹理中的锯齿状边缘,而程序纹理可以通过考虑梯度来减少尖锐的过渡。但 MSAA 没有帮助。
如果您希望抗锯齿能够解决锐过渡造成的所有锯齿源问题,您可以全力以赴并使用 super 采样。这意味着您可以以更高的分辨率渲染整个场景。例如,如果最终渲染目标的大小为 w
乘以 h
,则渲染到大小为 2 * w
乘以 的表面>2 * h
,最后进行下采样。这显着更加昂贵,因为您现在执行片段着色器的频率是原来的 4 倍,并且较大表面上的压缩也不会像 MSAA 表面上那样有效。
我没有使用过 ARB_sample_shading extension你发现了。但据我了解,它试图接近 super 采样的视觉质量,同时至少保持 MSAA 的一些性能优势。
关于opengl - 多重采样和片段着色器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21109931/