使用 GL_MODULATE 与顶点颜色的 alpha 时,GLKit 不显示纹理

Posted

技术标签:

【中文标题】使用 GL_MODULATE 与顶点颜色的 alpha 时,GLKit 不显示纹理【英文标题】:GLKit does not display texture when using GL_MODULATE with alpha in vertex color 【发布时间】:2015-03-12 22:23:36 【问题描述】:

我有一个与 GLKit 一起使用的纹理图像。如果我在纹理上使用 GL_MODULATE 并具有顶点 RGBA (1.0, 1.0, 1.0, 1.0),那么纹理会完全显示出来,就像在 GL_REPLACE 中一样。完全不透明。 然后,如果我将红色 (1.0, 0.0, 0.0, 1.0) 用于顶点 RGB,则纹理再次显示为红色调制纹理。 到现在为止还挺好。 但是当我改变顶点颜色的透明度并使用 RGBA(1.0, 0.0, 0.0, 0.5) 时,只能看到浅红色并且看不到纹理,因此颜色完全取代了纹理。 贴图本身没有alpha,是RGB565贴图。 我正在使用 GLKit 和 GLKTextureEnvModeModulate。

self.effect.texture2d0.envMode = GLKTextureEnvModeModulate;

当我指定 alpha 时,关于为什么纹理会消失的任何帮助?

添加快照:

这是原始纹理

RGBA (1.0, 1.0, 1.0, 1.0) - 白色,无预乘,不透明,纹理可见

RGBA (1.0, 1.0, 1.0, 0.5) - 白色,无预乘,alpha = 0.5,纹理丢失

RGBA (1.0, 0, 0, 1.0) - 红色,无预乘,不透明,纹理可见

RGBA (1.0, 0, 0, 0.5) - 红色,无预乘,alpha = 0.5,纹理丢失

RGBA (0.5, 0, 0, 0.5) - 红色,预乘,alpha = 0.5 per @andon,纹理可见,但您可能需要放大才能看到它

RGBA (0.1, 0, 0, 0.1) - 红色,预乘,每个 @andon 的 alpha = 0.1,纹理丢失,可能是因为对比度不够

RGBA (0.9, 0, 0, 0.9) - 红色,预乘,alpha = 0.9 per @andon,纹理可见,但您可能需要放大才能看到它

【问题讨论】:

纹理本身没有 Alpha。所以在加载时它会生成一个 565 RGB 图像。所以我猜这意味着 alpha 是 1 并且是预乘的。我的混合功能用于预乘 - 一,一 - Src。我正在试验 565 本身是否有问题,如果纹理 alpha 丢失,GLKit 着色器会以某种方式无法工作。所以我的下一个计划是生成一个包含 alpha 的纹理,即使它是 1,然后看看 GLKit 的工作方式是否有任何不同。 就像我说的,当您使用 565(或任何 RGB 格式)时,alpha 已经是一个常量 1.0。这只是 GL 自动为您做的事情之一,如果没有明确存储,顶点属性或颜色的第四个组件将被分配 1.0。鉴于您的混合功能,您应该相应地调整顶点颜色,这意味着将其 RGB 乘以其 A。 【参考方案1】:

贴图本身没有alpha,是RGB565贴图

RGB565 隐含恒定的 alpha(不透明 -> 1.0)。 这听起来可能并不重要,但是用纹理颜色调制顶点颜色会进行逐个乘法,如果 alpha 不是 1.0,这根本不起作用。

我的混合函数用于预乘 - One, One - Src。

这需要将顶点颜色的 RGB 分量与 A 分量进行预乘。 所有颜色都必须预乘,这包括纹素和顶点颜色。

您可以在下面看到原因:

Vtx = (1.0, 0.0, 0.0, 0.5)
Tex = (R,   G,   B,   1.0)

// Modulate Vertex and Tex
Src = Vtx * Tex = (R, 0, 0, 0.5)

// Pre-multiplied Alpha Blending (done incorrectly)
Blend_RGB = Src * 1    +  (1 - Src.a) * Dst
          = Src        +          Dst / 2.0
          = (R, 0, 0)  +          Dst / 2.0

唯一要做的就是将目标颜色除以 2,然后将未更改的源颜色添加到其中。 假定类似于线性插值(a * c + (1 - c) * b)

正确的混合应该是这样的:

// Traditional Blending
Blend_RGB = Src * Src.a   +  (1 - Src.a) * Dst
          = (0.5R, 0, 0)  +          Dst / 2.0

如果将顶点颜色的 RGB 部分乘以 A,则可以使用原始混合函数来完成。

正确的预乘 alpha 混合 (通过预乘顶点颜色):

Vtx = (0.5, 0.0, 0.0, 0.5) // Pre-multiply: RGB *= A
Tex = (R,   G,   B,   1.0)

// Modulate Vertex and Tex
Src = Vtx * Tex = (0.5R, 0, 0, 0.5)

// Pre-multiplied Alpha Blending (done correctly)
Blend_RGB = Src * 1       +  (1 - Src.a) * Dst
          = (0.5R, 0, 0)  +          Dst / 2.0

【讨论】:

这非常有用,而且解释得很好。谢谢。我完全错过了预乘顶点颜色。然而,我仍然不确定为什么纹理会消失。在我的例子中,我的纹理是浅灰色背景上的深灰色阴影线。那么在解释了它是如何工作的之后,我是否还应该看到阴影线的红色部分?那么红色背景上的某种红色阴影线?我可能没有很好地考虑这一点,所以我也将尝试预乘顶点颜色,看看是否能恢复阴影线。我会回来报告的。 好的,我想它就像你说的那样。我正在尝试使用高透明度,即低 alpha。当我这样做时,我预乘它也会拉低红色值,因此阴影线和背景之间的差异可以忽略不计。所以他们消失了。我在 R 和 A 之间尝试了多个值,并且出现了一些阴影线。因此,也许我需要从图像中较暗的阴影线开始才能使其正常工作。但是你的解释说得通。感谢您的答案(和数学)非常清晰。 我觉得我的纹理太微妙了,在调制中顶点颜色压倒了微小的差异,所以顶点颜色是调制后剩下的全部。我猜是乘法效应。 @nishant:如果你能附上截图,我可以在早上看一下。我可能需要添加一些额外的细节。如果这是用于合成多个图层,则需要讨论混合方程的 alpha 部分(您会注意到列出的混合方程仅适用于 RGB - 我这样做是为了简单)。跨度> 好的,我也试试!感谢您对此的帮助。非常感激。你教会了我如何从数学上思考 tex env + blending,这会让事情变得更容易解决。

以上是关于使用 GL_MODULATE 与顶点颜色的 alpha 时,GLKit 不显示纹理的主要内容,如果未能解决你的问题,请参考以下文章

在 width_first_search 期间设置顶点的颜色

在顶点着色器中更改顶点的颜色

OpenGL:使用着色器通过使用预先计算的颜色图来创建顶点照明?

WebGL简易教程:颜色

Unity使用顶点颜色 做混合 来实现SoftParticle 效果

Unity使用顶点颜色 做混合 来实现SoftParticle 效果