【问题标题】:OpenGL: How to render perfect rectangular gradient?OpenGL:如何渲染完美的矩形渐变?
【发布时间】:2011-03-19 00:56:41
【问题描述】:

我可以只用一个三角形渲染三角形渐变,并为每个角使用 glColor。

但是如何渲染完美的矩形渐变呢?我试过一个四边形,但中间会出现难看的接缝。我也尝试使用 2x2 大小的纹理,就像应该这样做:从每个角落适当混合,但是当拉伸太多时纹理采样精度变得不精确(我开始看到大于 1x1 大小的像素)。

也许有一些方法可以在着色器中计算这个?

--

编辑:图片链接已损坏(已删除)。

【问题讨论】:

  • 您使用的是什么版本的 OpenGL?前向还是兼容上下文?
  • 我希望它与尽可能低的版本兼容。
  • 这看起来像两个三角形而不是一个四边形(中心插在两个角之间,而不是全部四个。
  • @ben,是的...四边形由两个三角形组成,我怎样才能在opengl中没有三角形...?顺便说一句,我在那里使用了 GL_QUADS。
  • @Ben Voigt,现在看看我的新图像,它根本不起作用。

标签: c++ opengl gradient glsl


【解决方案1】:

确实,您想要的渐变类型依赖于每个像素的 4 种颜色,而 OpenGL 通常只在三角形上插入输入(因此 3 个输入)。仅使用标准插值无法获得完美的渐变。

现在,正如您所提到的,2x2 纹理可以做到这一点。如果您确实看到了精度问题,我建议您将纹理格式切换为通常需要更高精度的格式(例如浮动纹理)。

最后,正如您在问题中提到的那样,您可以使用着色器解决此问题。假设您将对应于 (u,v) = (0,0) (0,1) (1,0) (1,0) 的每个顶点的额外属性一直传递到像素着色器(使用顶点着色器只是做一个传递)。

您可以在像素着色器中执行以下操作(注意,这里的想法是合理的,但我没有测试代码):

顶点着色器sn-p:

varying vec2 uv;
attribute vec2 uvIn;

uv = uvIn;

片段着色器:

uniform vec3 color0;
uniform vec3 color1;
varying vec2 uv;

// from wikipedia on bilinear interpolation on unit square:
// f(x,y) = f(0,0)(1-x)(1-y) + f(1,0)x(1-y) + f(0,1)(1-x)y + f(1,1) xy. 
// applied here:
// gl_FragColor = color0 * ((1-x)*(1-y) + x*y) + color1*(x*(1-y) + (1-x)*y)
// gl_FragColor = color0 * (1 - x - y + 2 * x * y) + color1 * (x + y - 2 * x * y)
// after simplification:
// float temp = (x + y - 2 * x * y);
// gl_FragColor = color0 * (1-temp) + color1 * temp;
gl_FragColor = mix(color0, color1, uv.u + uv.v - 2 * uv.u * uv.v);

【讨论】:

  • 不应该是gl_FragColor = mix(...) 吗?那些float3和float2也不应该是vec3vec2吗?你能展示我如何传递额外的属性,以及我需要在顶点着色器中进行哪些更改吗?我不太关注这个...
  • @Rookie:确实。我玩的语言太多了……修复了你提到的那些,并在顶点着色器上添加​​了一些。你到底不遵循什么?我们的想法是在着色器中实现您所追求的双线性过滤,使用我们传入的 uv 来确定感兴趣的像素在正方形中的位置。
  • 如果我理解正确,我必须使用 glTexCoord2f() 和 glColor3f() 和 glVertex2f() 吗?但是代码的哪一部分知道 uvIn 意味着纹理坐标……那部分我不明白
  • 我也不明白如何用顶点着色器(或其他地方?)的相应值填充 color0 和 color1
  • 哦,我明白了.. 好吧,您应该告诉您的代码在您的答案中没有计算完美的梯度,(以防其他人想知道为什么它不起作用)。那我就自己算算了……(真的看不懂那个公式XD)
【解决方案2】:

问题是因为您使用了四边形。四边形是使用两个三角形绘制的,但三角形的方向不是您需要的。

如果我将四边形顶点定义为:

  • A:左下顶点
  • B:右下顶点
  • C:右上角的顶点
  • D:左上顶点

我会说四边形由以下三角形组成:

  • A B D
  • DB C

分配给每个顶点的颜色是:

  • A:黄色
  • B:红色
  • C:黄色
  • D:红色

记住几何形状(两个三角形),DB 之间的像素是红色和红色之间插值的结果:确实,红色!

解决方案是具有两个三角形的几何图形,但方向不同:

  • A B C
  • A C D

但可能你不会得到准确的渐变,因为在四边形的中间你会得到一个完整的黄色,而不是黄色和红色的混合。所以,我想你可以使用 4 个三角形(或三角形扇形)来获得确切的结果,其中居中的顶点是黄色和红色之间的插值。


哇!有效地结果不是我所期望的。我认为渐变是由颜色之间的线性插值产生的,但肯定不是(我真的需要设置 LCD 色彩空间!)。事实上,最具可扩展性的解决方案是使用片段着色器进行渲染。

保留Bahbar 提出的解决方案。我建议开始实现直通顶点/片段着色器(仅指定顶点和颜色,您应该得到以前的结果);然后,开始使用 mix 函数并将纹理坐标传递给顶点着色器。

你真的需要了解可编程着色器的渲染管道:顶点着色器每个顶点调用一次,片段着色器每个片段调用一次(没有多重采样,片段是一个像素;使用多重采样,一个像素由许多片段组成,这些片段被插值以获得像素颜色)。

顶点着色器采用输入参数(制服和输入;制服对于在 glBegin/glEnd 之间发出的所有顶点都是恒定的;输入是每个顶点着色器实例的特征(4 个顶点,4 个顶点着色器实例)。

片段着色器将产生片段的顶点着色器输出作为输入(由于三角形、线和点的光栅化)。在 Bahbar 答案中,唯一的输出是 uv 变量(两个着色器源通用)。

在您的情况下,顶点着色器输出顶点纹理坐标 UV(“按原样”传递)。这些 UV 坐标可用于每个片段,它们是通过根据片段位置对顶点着色器输出的值进行插值来计算的。

一旦你有了这些坐标,你只需要两种颜色:红色和黄色(在 Bahbar 中,答案对应于 color0color1 制服)。然后,根据特定片段的 UV 坐标混合这些颜色。 (*)

(*) 这是着色器的强大之处:您可以通过简单地修改着色器源来指定不同的插值方法。线性、双线性或样条插值是通过为片段着色器指定额外的统一来实现的。

好习惯!

【讨论】:

  • 我尝试了任意数量的三角形,即使是您建议的“4 个角和 1 个中间额外点”,但结果始终与使用两个三角形相同(除了形状略有变化,但它仍然显示“接缝”,我仍然不会像我想要的那样完美地得到它)。你能帮我用着色器做这个吗?我在想我可以自己计算渐变,但我遇到的问题是:如何发送片段着色器的 4 个角颜色值(如果这甚至是我应该怎么做?,所以我也需要这方面的建议。 ..)
  • 添加了您建议的版本示例,它仍然无法正常工作,请查看图片(或我留下的链接,以防图片无法正常工作)
【解决方案3】:

您的所有顶点是否都具有相同的深度 (Z) 值,并且您的所有三角形都完全在屏幕上吗?如果是这样,那么在由两个三角形组成的四边形上使用 glColor 获得“完美”的颜色渐变应该没有问题。如果不是,那么您的 OpenGL 实现可能对颜色处理不佳。

这让我怀疑您可能有一个非常古老或奇怪的 OpenGL 实现。我建议您告诉我们您使用的是什么平台,以及您拥有的 OpenGL 版本...?

如果没有更多信息,我建议您尝试编写着色器,并避免告诉 OpenGL 您需要“颜色”。如果可能的话,告诉它你想要一个“texcoord”,但无论如何都要把它当作一种颜色。这个技巧在某些颜色准确度太低的情况下很有效。

【讨论】:

  • 是的,它是 2d。是的,它们完全在屏幕上(为什么这很重要?虽然,如果三角形部分超出屏幕,我看到 opengl 渲染在没有驱动程序的情况下变得丑陋,但我为使用 opengl 驱动程序的人这样做)
  • hmm,通过将texcoord视为颜色,您的意思是我会使用它的数值通过使用4个角颜色来混合颜色?你能给我一些建议我该怎么做吗?我不知道,我只知道如何获取纹理颜色值或 glColor 值...但我不知道如何将 4 个颜色值发送到片段着色器(我也不确定这是否应该这样做) .
  • 我现在添加了问题的示例图片。
  • @Rookie:我没有看到任何图像。您没有足够的代表将它们直接添加到您的问题中,因此请粘贴链接,我们中的一个可以添加图像。
  • 啊,它不应该显示给我,如果没有其他人可以看到它...现在添加一个链接。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多