GLSL:使用片段着色器进行对象翻译
Posted
技术标签:
【中文标题】GLSL:使用片段着色器进行对象翻译【英文标题】:GLSL : Object translation with fragment shader 【发布时间】:2015-01-28 16:26:32 【问题描述】:如下图所示,我试图通过多画两次来表达轮廓:左右移动1个像素。
但是,我不知道这应该在顶点着色器还是片段着色器中运行。
是否可以在片段着色器中移动顶点(像素)?
如果不是,我应该在每一帧计算顶点的屏幕空间坐标吗?
【问题讨论】:
【参考方案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 了解更多信息。以上是关于GLSL:使用片段着色器进行对象翻译的主要内容,如果未能解决你的问题,请参考以下文章