【问题标题】:GLSL : Object translation with fragment shaderGLSL:使用片段着色器进行对象翻译
【发布时间】:2015-01-28 16:26:32
【问题描述】:

如下图所示,我试图通过多画两次来表达轮廓:左右移动1个像素。

但是,我不知道这应该在顶点着色器还是片段着色器中运行。

是否可以在片段着色器中移动顶点(像素)?

如果不是,我应该在每一帧计算顶点的屏幕空间坐标吗?

【问题讨论】:

    标签: opengl glsl


    【解决方案1】:

    对于传统的片段着色器输出,答案是明确而响亮的。片段着色器无法决定要渲染哪个像素。顶点着色器和片段着色器之间的固定函数步骤(光栅化)确定哪些片段被图元覆盖。然后为这些片段中的每一个调用片段着色器。它可以决定在这个片段位置写入输出缓冲区的值(颜色等),或者它可以决定根本不写任何东西(discard)。但它不会改变位置。

    以下是我想到的一些选项。

    图片

    OpenGL 4.2 及更高版本中有一项功能在此区域添加了新选项:图像。您可以将纹理绑定为图像,然后使用内置的imageStore() 函数在着色器代码中写入它们。该函数将坐标和值作为参数,因此您可以将值写入图像中的任意位置。

    使用它,您可以使用图像作为输出而不是传统的片段着色器输出,并向其写入多个值。或者使用混合,您仍然使用片段着色器输出进行主要渲染,将阴影部分写入图像,然后将两者与额外的渲染通道结合起来。

    多个绘图调用

    对于更传统的功能,您通常需要多次渲染几何图形,使用深度或模板测试将主要渲染与阴影效果相结合。例如,使用深度测试,您可以将形状以原始颜色渲染一次,然后再渲染两次,稍微左/右偏移,同时稍微增加深度,使阴影位于原始形状的后面。

    几何着色器

    我相信您可以使用几何着色器来生成每个图元的 3 个实例。因此,每个图元仍会渲染 3 次,但您不必实际进行 3 次不同的绘制调用。

    图像后处理

    为了达到您想要的效果,您可以将没有阴影的整个物体渲染到 FBO 中,从而在纹理中生成帧。然后你进行另一个绘制通道,在其中绘制一个窗口大小的四边形,并从包含你的帧的纹理中采样。您对纹理进行 3 次采样,然后将 3 个结果结合起来产生阴影效果。

    只是为了勾勒这个(代码完全未经测试)。如果您使用带有 alpha 组件的纹理作为渲染目标,您可以检查 alpha 值以查看在渲染期间是否命中了给定像素。

    // Texture produced as output from original render pass.
    uniform texture2D Tex;
    // Offset to add one pixel to texture coordinates, should be
    // 1.0 / width of render target.
    uniform float PixelOffset;
    // Incoming texture coordinate from rendering window sized quad.
    in vec2 TexCoord;
    // Output.
    out vec4 FragColor;
    
    void main() {
        vec4 centerColor = texture(Tex, TexCoord);
        vec4 leftColor = texture(Tex, vec2(TexCoord.s, TexCoord.t - PixelOffset));
        vec4 rightColor = texture(Tex, vec2(TexCoord.s, TexCoord.t + PixelOffset));
    
        if (centerColor.a > 0.0) {
            // Fragment was rendered, use its color as output.
            FragColor = centerColor;
        } else if (leftColor.a + rightColor.a > 0.0) {
            // Fragment is within 1 pixel left/right of rendered fragment,
            // color it black.
            FragColor = vec4(0.0, 0.0, 0.0, 1.0);
        } else {
            // Neither rendered nor in shadow. Set output to background color,
            // or discard it. This would be for white background.
            FragColor = vec4(1.0, 1.0, 1.0, 1.0);
        }
    }
    

    结论/建议

    直观地说,我自己喜欢图像后处理方法。我可能会先尝试一下。我认为下一个最优雅的解决方案是使用几何着色器复制图元。

    【讨论】:

    • 谢谢。我通过图像后处理解决了。顺便说一句,我可以在几何着色器中设置对象的绘制顺序吗?如果我使用几何着色器复制,它会显示深度测试问题。
    【解决方案2】:

    不,一旦您进入片段着色器,输出位置已经被光栅化过程固定。

    【讨论】:

      【解决方案3】:

      由于像素的位置已经由您在片段着色器中的时间确定,所以这不是一个选项。顶点着色器也帮不了你,因为它只能为每个传入的顶点推送一个输出顶点。

      然而,几何着色器阶段可以为每个传入的顶点发射多个顶点。这可以让您克隆两个额外的顶点,每个顶点都有一个平移到原始顶点的左侧或右侧。

      此资源有一些详细的现代示例:https://open.gl/geometry

      【讨论】:

      • 感谢几何着色器示例。我找到another example 了解更多信息。
      猜你喜欢
      • 1970-01-01
      • 2021-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-30
      • 2017-04-12
      • 1970-01-01
      • 2013-07-30
      相关资源
      最近更新 更多