【问题标题】:multisampling and fragment shader多重采样和片段着色器
【发布时间】:2015-04-17 12:46:41
【问题描述】:

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

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

下面是代码,image 显示了它的输出(请注意,程序边缘 - 白色和灰色正方形之间 - 没有抗锯齿,而几何边缘 - 黑色和白色/灰色之间 - 是):

#!/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()  

【问题讨论】:

  • 那是什么语言?
  • python/python3 与 pyopengl,但问题与语言无关。如果有帮助,我可以添加一个 C 版本。
  • 好的,看起来我需要sample_shading 扩展:“在标准多样本渲染中,允许实现为每个样本分配相同的颜色和纹理坐标值,然后允许优化着色器只评估一次,然后分发到已确定被当前正在光栅化的图元覆盖的样本。"

标签: opengl glsl


【解决方案1】:

这是 MSAA(多重采样抗锯齿)的基本思想。片段着色器每个片段只执行一次。然后使用样本掩码来控制将生成的片段写入哪些样本。

假设您使用 4x MSAA,其中每个片段由 2x2 样本组成。如果三角形的边穿过片段,则只有边内侧的样本会更新为新颜色。因此,如果片段仅部分位于三角形内部,则可能会更新 4 个样本中的 1、2 或 3 个。但是更新的样本都更新为相同的颜色。因此,片段着色器只需要评估一次。

这种方法的最大优点是非常有效。与没有 MSAA 的渲染相比,它通常只会增加非常少的开销。正如已经确定的,着色器执行的次数没有改变。渲染目标理论上会增大 4 倍,这可能会大幅增加内存使用量。但该内存通常可以被有效地压缩,所以它并不像听起来那么糟糕。显然在渲染帧结束时有一个下采样步骤,这确实增加了开销。

缺点是 MSAA 仅有助于平滑三角形边界和交叉点。如果您在三角形内有尖锐的过渡,例如由于纹理内容,或由于程序纹理,它根本无济于事。 Mipmapping 可以减少纹理的锯齿状边缘,而程序纹理可以通过考虑渐变来减少锐利的过渡。但是 MSAA 没有帮助。

如果您想要消除锐利过渡的所有锯齿来源的抗锯齿,您可以全力以赴并使用超级采样。这意味着您可以以更高的分辨率渲染整个场景。例如,如果最终渲染目标的大小是w 乘以h,则您渲染到大小为2 * w 乘以2 * h 的表面,最后进行下采样。这明显更加昂贵,因为您现在执行片段着色器的频率是原来的 4 倍,而且在较大表面上的压缩也不会像在 MSAA 表面上那样有效。

我没有使用你找到的ARB_sample_shading extension。但据我了解,它试图接近超级采样的视觉质量,同时至少保持 MSAA 的一些性能优势。

【讨论】:

  • 如果一个片段位于多个三角形中怎么办?例如,如果样本 1 和 2 位于三角形 A 中,样本 3 和 4 位于三角形 B 中,是否意味着必须调用片段着色器两次,每个三角形调用一次?
【解决方案2】:

需要sample_shading 扩展:“在标准多样本渲染中,允许实现为每个样本分配相同的颜色和纹理坐标值,然后允许优化着色器只评估一次然后分发到已确定被当前正在栅格化的图元覆盖的样本。”

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-15
    • 1970-01-01
    • 1970-01-01
    • 2013-09-17
    • 1970-01-01
    • 2011-05-24
    相关资源
    最近更新 更多