opengl - 多重采样和片段着色器

标签 opengl glsl

多重采样似乎不适用于片段着色器生成的片段。 在下面的示例中,片段着色器用于生成棋盘程序纹理。 正方形的外边缘已正确抗锯齿,但程序纹理的内边缘未正确抗锯齿。

片段着色器是否仅针对每个像素进行评估? 或者给定像素的每个片段的纹理坐标是否相同?

下面是代码和 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/

相关文章:

qt - 使用 Qt 时将键盘输入定向到小部件

opengl - 获取最大数量的帧缓冲区颜色附件?

c - Opengl 过滤器不好?

c++ - 我的 OpenGL 程序的着色器不会影响几何图形或多边形的颜色

opengl-es - 在顶点和片段着色器中访问同名统一失败

android - 如何在 Android 上加速着色器加载/编译

c++ - 转换层次结构 - 将 parent 的方向应用于其 child

opengl - 如何将 OpenGL 纹理转换为 CUDA 纹理?

c++ - 相机外的物体 OpenGL

java - 尽管链接和验证成功,为什么着色器程序无法编译?