繁体   English   中英

GLSL:使用片段着色器进行对象翻译

[英]GLSL : Object translation with fragment shader

如下图所示,我试图通过绘制对象两倍以上来表示轮廓:每个像素左右移动1个像素。

三圈重复

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

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

如果没有,我是否应该计算每帧顶点的屏幕空间坐标?

一旦您处于片段着色器中,就不会通过光栅化过程固定输出位置。

使用传统的片段着色器输出,答案是明确而响亮的NO 片段着色器无法确定要渲染的像素。 顶点着色器和片段着色器之间的固定功能步骤(栅格化)确定了哪些片段被图元覆盖。 然后为每个片段调用片段着色器。 它可以决定在此片段位置写入输出缓冲区的值(颜色等),也可以决定根本不写入任何内容( discard )。 但这并不能改变立场。

以下是一些想到的选项。

图片

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

使用此功能,您可以将图像用作输出,而不是传统的片段着色器输出,然后向其中写入多个值。 或使用混合方法,在该方法中,仍将片段着色器输出用于主要渲染,将阴影部分写入图像,然后将两者与其他渲染过程结合在一起。

多次抽奖

使用更传统的功能时,通常必须使用深度或模板测试将主要渲染与阴影效果结合在一起,多次渲染几何图形。 例如,使用深度测试,可以以原始颜色渲染一次形状,然后以略有左右偏移和深度稍微增加的方式渲染两次,以使阴影在原始形状后面。

几何着色器

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

图像后处理

为了获得所需的效果,您可以将没有阴影的整个对象渲染到FBO中,该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);
    }
}

结论/建议

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

由于像素的位置已经由您进入片段着色器的时间确定,因此这不是一个选择。 顶点着色器也无济于事,因为它只能为每个传入的顶点推送一个输出顶点。

但是,几何着色器阶段可以为每个传入的顶点发出多个顶点。 这可以允许您克隆两个额外的顶点,每个顶点在原始对象的左侧或右侧都有平移。

该资源提供了一些详细的现代示例: https : //open.gl/geometry

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM