是否可以在 OpenGL ES 1.0 中进行去饱和以及如何进行?

发布于 2024-11-28 04:28:24 字数 2148 浏览 1 评论 0原文

我想用灰色渲染颜色纹理。在 ES 2.0 中使用着色器来做这件事是小菜一碟,但是在 ES 1.x 中可以做到吗?

更新

感谢@datenwolf,我这样做:

GLfloat weights_vector[4] = {0.2126, 0.7152, 0.0722, 1.0};
GLfloat additions_vector[4] = {0.5, 0.5, 0.5, 0.0};

glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);

/* First part */
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_DOT3_RGB);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, weights_vector);

/* Second part */
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, additions_vector);

如果我将其单独保留,第一部分渲染得很好,但如果我添加第二部分,它会使用“黑色”作为前一个颜色,所以我只得到灰色像素。我在这里做错了吗?

第二次更新

如果我尝试使用GL_TEXTURE0而不是GL_PREVIOUS,我确实得到了与GL_TEXTURE相同的结果。但是,如果我使用 GL_TEXTURE1 ,我什至不会得到灰色像素,而是黑色。我在这里迷路了......

第三次更新

第二部分现在正在工作。应该按照 @datenwolf 的建议使用先前纹理的名称!

然而,输出仍然不正确,因为它是颠倒的。我通过添加以下内容解决了这个问题:

glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_ONE_MINUS_SRC_COLOR);

现在,天太黑了。我无法把它做好。尝试过但没有成功:

  • 将权重乘以 2
  • 加 0.5
  • 将整个图像调制为 2
  • 将权重乘以 2 然后减去 0.5

第四次更新(抱歉有这么多)

我开始怀疑由于偏差这是不可能的以及 DOT3_RGB 中的乘法。在组合器中执行此操作的正确方法是:

  1. 将 0.5 添加到输入纹理
  2. 计算权重因子:weight_new = (weight_real + 2.0) / (4.0);
  3. 执行 GL_DOT3_RGB

例如,

GLfloat weights_vector[4] = {0.30, 0.59, 0.11, 0.0};

,而不是使用:使用:

GLfloat weights_vector[4] = {0.575, 0.6475, 0.5275, 0.0};

这确实得到了几乎正确的结果,但是由于第一步和事实上,数字被限制在 [-1.0, 1.0] 范围内,

为什么要进行计算?好吧,根据 API:

Dot Calculation

所以我没有看到任何其他与我展示的不同的方式,因为的精度限制。当然,我可以首先将输入除以 2.0,然后加 0.5,执行 dot3,然后再次乘以 2,从而有效地使所有值都在 [-1.0, 0.0] 范围内。但我担心它仍然会因为划分而失去准确性。

我怀疑 DOT 并不是用于此目的,更可能仅用于凹凸贴图或其他用途。太糟糕了。我希望我错了,但我不明白怎么办。

I'd like to render a colour texture in gray. Doing it in ES 2.0 by using a shader is a piece of cake, but is it possible to do in ES 1.x?

UPDATE

Thanks to @datenwolf, I'm doing it like that:

GLfloat weights_vector[4] = {0.2126, 0.7152, 0.0722, 1.0};
GLfloat additions_vector[4] = {0.5, 0.5, 0.5, 0.0};

glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);

/* First part */
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_DOT3_RGB);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, weights_vector);

/* Second part */
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, additions_vector);

The first part renders fine if I leave it on its own, but if I add the second one, it uses "black" as the previous colour and so I get only gray pixels. Am I doing it wrong here?

SECOND UPDATE

If I try to use GL_TEXTURE0 instead of GL_PREVIOUS I indeed get the same result as GL_TEXTURE. However, if I used GL_TEXTURE1 I get not even gray pixels, but black. I'm getting lost here...

THIRD UPDATE

The second part is working now. Should've just used the name of the previous texture as @datenwolf had suggested!

However, the output was still not correct as it was inverted. I fixed that by adding:

glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_ONE_MINUS_SRC_COLOR);

Now, it's too dark. And I can't get it right. Tried and didn't work:

  • multiplying the weights by two
  • adding 0.5
  • modulating the whole image by 2
  • multiplying the weights by 2 and then subtracting by 0.5

FOURTH UPDATE (Sorry there are so many)

I begin to suspect it's not possible due to the bias and multiplication in DOT3_RGB. The correct way to do it in a combiner is:

  1. Add 0.5 to the input texture
  2. Calculate to weighting factors: weight_new = (weight_real + 2.0) / (4.0);
  3. Do a GL_DOT3_RGB

For instance, instead of using:

GLfloat weights_vector[4] = {0.30, 0.59, 0.11, 0.0};

Use:

GLfloat weights_vector[4] = {0.575, 0.6475, 0.5275, 0.0};

This is indeed getting almost the right result, but some of the contrast is lost, due to the first step and the fact that numbers are clamped in the range [-1.0, 1.0]

Why the calculations? Well, according to the API:

Dot calculation

So I don't see any other way different from the one I showed and because of the accuracy limitation. Of course, I could first divide the input by 2.0, then add 0.5, do a dot3 and then again multiply by 2, thus effectively having all values in the range [-1.0, 0.0]. But I fear it would still loose accuracy because of the division.

I suspect that the DOT wasn't intended for this purpose, more likely only for bumpmapping or something. Too bad. I hope I'm wrong, but I don't see how.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

等风来 2024-12-05 04:28:25

这可以使用 2 个或 3 个纹理组合器来实现。您很可能希望支持仅支持 2 个纹理组合器的旧设备(例如 iPhone 3G)。您可以使用以下代码确定您的设备支持多少个纹理组合器:

int maxTextureUnits;
glGetIntegerv(GL_MAX_TEXTURE_UNITS, &maxTextureUnits);

在没有着色器的情况下实现渲染灰度纹理的基本步骤如下:

  1. 将所有像素 RGB 值除以 2
  2. 从所有像素 RGB 值中减去 0.5
  3. 计算 GL_DOT3_RGB使用自定义加权值的每个 RGB 值

现在,每个步骤都可以使用纹理组合器来执行。或者,您也可以仅使用两个纹理组合器,将步骤 1 替换为自定义代码,在读取纹理时调整像素值。如果您选择仅使用两个纹理组合器,您仍然可以以颜色渲染调整后的纹理,您只需要一个纹理组合器,在渲染之前将 RGB 值加倍。

我们向所有像素值添加 0.5 的原因是因为我们用于计算亮度的 GL_DOT3_RGB 方程将从每个像素值中减去 0.5。

我们将所有像素值除以 2 的原因是,当从步骤 2 移动到步骤 3 时,我们的值不会受到限制。如果我们的 RGB 值为 (.5, .6, .7),并且我们将 0.5 添加到对于每个 RGB 值,进入步骤 3 时得到的 RGB 值将是 (1.0, 1.0, 1.0)。 DOT3 方程从每个值中减去 0.5 后,将根据 (.5, .5, .5) 计算亮度。

以下是使用 3 个纹理单元渲染纹理灰度的示例代码:

//Enable texture unit 0 to divide RGB values in our texture by 2
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, m_textureId);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glClientActiveTexture(GL_TEXTURE0);

//GL_MODULATE is Arg0 * Arg1    
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);

//Configure Arg0
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);

//Configure Arg1
float multipliers[4] = {.5, .5, .5, 0.0};
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, (GLfloat*)&multipliers);

//Remember to set your texture coordinates if you need them
//glEnableClientState(GL_TEXTURE_COORD_ARRAY);
//glTexCoordPointer...

//Enable texture unit 1 to increase RGB values by .5
glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, m_textureId);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glClientActiveTexture(GL_TEXTURE1);

//GL_ADD is Arg0 + Arg1
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD);

//Configure Arg0
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);

//Configure Arg1
GLfloat additions[4] = {.5, .5, .5, 0.0};
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, (GLfloat*)&additions);

//Set your texture coordinates if you need them
//glEnableClientState(GL_TEXTURE_COORD_ARRAY);
//glTexCoordPointer...

//Enable texture combiner 2 to get a DOT3_RGB product of your RGB values
glActiveTexture(GL_TEXTURE2);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, m_textureId);
glClientActiveTexture(GL_TEXTURE2);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);

//GL_DOT3_RGB is 4*((Arg0r - 0.5) * (Arg1r - 0.5) + (Arg0g - 0.5) * (Arg1g - 0.5) + (Arg0b - 0.5) * (Arg1b - 0.5))
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_DOT3_RGB);   

//Configure Arg0
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);

//Configure Arg1
//We want this to adjust our DOT3 by R*0.3 + G*0.59 + B*0.11
//So, our actual adjustment will need to take into consideration
//the fact that OpenGL will subtract .5 from our Arg1
//and we need to also take into consideration that we have divided 
//our RGB values by 2 and we are multiplying the entire
//DOT3 product by 4
//So, for Red adjustment you will get :
//   .65 = (4*(0.3))/2 + 0.5  = (0.3/2) + 0.5
GLfloat weights[4] = {.65, .795, .555, 1.};
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, (GLfloat*)&weights);

//Set your texture coordinates if you need them
//glEnableClientState(GL_TEXTURE_COORD_ARRAY);
//glTexCoordPointer...

//Render your objects or sprite

//Clean up by disabling your texture combiners or texture units. 
glActiveTexture(GL_TEXTURE2);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glDisable(GL_TEXTURE_2D);

glActiveTexture(GL_TEXTURE1);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glDisable(GL_TEXTURE_2D);

glActiveTexture(GL_TEXTURE0);
glClientActiveTexture(GL_TEXTURE0);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

This is possible using either 2 or 3 texture combiners. Most likely you are looking to support an older device (such as the iPhone 3G) which only supports 2 texture combiners. You can determine how many texture combiners your device supports using the following code:

int maxTextureUnits;
glGetIntegerv(GL_MAX_TEXTURE_UNITS, &maxTextureUnits);

The basic steps to achieve rendering a grayscale texture without shaders is this:

  1. Divide all your pixel RGB values by 2
  2. Subtract .5 from all of your pixel RGB values
  3. Calculate the GL_DOT3_RGB value for each RGB value using custom weighted values

Now, each of these steps can be performed with a Texture Combiner. Or, alternatively, you can use only two texture combiners by replacing step 1 with custom code that adjusts your pixel values when you read in the texture. If you choose to use only two texture combiners you can still render your adjusted texture in color, you will just need a single texture combiner that doubles your RGB values before rendering.

The reason we are adding .5 to all of our pixel values is because the GL_DOT3_RGB equation we are using to calculate luminance will subtract .5 from each of our pixel values.

The reason we are dividing all pixel values by 2 is so that our values are not clamped when moving from step 2 to step 3. If we had a RGB value of (.5, .6, .7) and we added .5 to each of the RGB values, our resulting RGB value going into step 3 would be (1.0, 1.0, 1.0). After the DOT3 equation subtracts .5 from each value, it will be calculating luminance based on (.5, .5, .5).

Here is sample code that will render a texture grayscale using 3 texture units:

//Enable texture unit 0 to divide RGB values in our texture by 2
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, m_textureId);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glClientActiveTexture(GL_TEXTURE0);

//GL_MODULATE is Arg0 * Arg1    
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);

//Configure Arg0
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);

//Configure Arg1
float multipliers[4] = {.5, .5, .5, 0.0};
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, (GLfloat*)&multipliers);

//Remember to set your texture coordinates if you need them
//glEnableClientState(GL_TEXTURE_COORD_ARRAY);
//glTexCoordPointer...

//Enable texture unit 1 to increase RGB values by .5
glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, m_textureId);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glClientActiveTexture(GL_TEXTURE1);

//GL_ADD is Arg0 + Arg1
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD);

//Configure Arg0
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);

//Configure Arg1
GLfloat additions[4] = {.5, .5, .5, 0.0};
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, (GLfloat*)&additions);

//Set your texture coordinates if you need them
//glEnableClientState(GL_TEXTURE_COORD_ARRAY);
//glTexCoordPointer...

//Enable texture combiner 2 to get a DOT3_RGB product of your RGB values
glActiveTexture(GL_TEXTURE2);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, m_textureId);
glClientActiveTexture(GL_TEXTURE2);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);

//GL_DOT3_RGB is 4*((Arg0r - 0.5) * (Arg1r - 0.5) + (Arg0g - 0.5) * (Arg1g - 0.5) + (Arg0b - 0.5) * (Arg1b - 0.5))
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_DOT3_RGB);   

//Configure Arg0
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);

//Configure Arg1
//We want this to adjust our DOT3 by R*0.3 + G*0.59 + B*0.11
//So, our actual adjustment will need to take into consideration
//the fact that OpenGL will subtract .5 from our Arg1
//and we need to also take into consideration that we have divided 
//our RGB values by 2 and we are multiplying the entire
//DOT3 product by 4
//So, for Red adjustment you will get :
//   .65 = (4*(0.3))/2 + 0.5  = (0.3/2) + 0.5
GLfloat weights[4] = {.65, .795, .555, 1.};
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, (GLfloat*)&weights);

//Set your texture coordinates if you need them
//glEnableClientState(GL_TEXTURE_COORD_ARRAY);
//glTexCoordPointer...

//Render your objects or sprite

//Clean up by disabling your texture combiners or texture units. 
glActiveTexture(GL_TEXTURE2);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glDisable(GL_TEXTURE_2D);

glActiveTexture(GL_TEXTURE1);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glDisable(GL_TEXTURE_2D);

glActiveTexture(GL_TEXTURE0);
glClientActiveTexture(GL_TEXTURE0);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
蓝色星空 2024-12-05 04:28:25

您可以为此使用点(标量)积纹理环境。请记住,矢量的点积是

dot(v1, v2) = v1[0]*v2[0] + v1[1]*v2[1] + ... + v1[n]*v2[n]

去饱和度是通过将每个通道与加权因子相加来实现的,

L{r,g,b} = w_r * R + w_g * G + w_b * B

但这只不过是颜色与加权矢量的点积。 OpenGL-1.5 有一个称为组合器的纹理环境,该组合器环境具有点积模式:

GLfloat weighting_vector[4];
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_DOT3_RGB);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, weighting_vector);

根据注释进行编辑

您可以指定对alpha 组合器中的 Alpha 通道,标记 GL_COMBINE_ALPHA。在你的情况下,你只想使用源阿尔法。添加这些配置:

glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE);

我忘记的是,点积模式引入了 0.5 的偏差。但这没问题,因为您至少有 3 个组合器阶段,因此您可以使用 GL_SUBSTRACT 阶段减去每个通道的 0.5 并将权重乘以 2.0 来补偿这一点。

查看 glTexEnv 手册页 http:// /www.opengl.org/sdk/docs/man/xhtml/glTexEnv.xml 和原始扩展规范http://www.opengl.org/registry/specs/ARB/texture_env_combine.txt(这是扩展时的时间)。我承认,如果您是新手,纹理组合器会有点令人费解。从历史上看,它们是片段着色器的前身; NVidia 从他们当时所谓的“寄存器组合器”开始,后来成为纹理组合器。

由于问题附录而编辑2

您必须在其自己的组合器阶段(=纹理单元)中执行第二部分。您可以使用glActiveTexture切换纹理单位。像这样修改你的代码:

GLfloat weights_vector[4] = {0.2126, 0.7152, 0.0722, 1.0};
GLfloat additions_vector[4] = {0.5, 0.5, 0.5, 0.0};

glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texID);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);

/* First part */
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_DOT3_RGB);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, weights_vector);

glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texID); // we need some dummy texture active
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);

/* Second part */
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_SUBTRACT);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, additions_vector);

另外我认为你打算减去,以补偿 0.5 偏差而不是添加 0.5; FTFY。

You can use dot (scalar) product texture environment for this. Remember that the dot product of vectors is

dot(v1, v2) = v1[0]*v2[0] + v1[1]*v2[1] + ... + v1[n]*v2[n]

Desaturation is achieved by summing the channels with a weighting factor each

L{r,g,b} = w_r * R + w_g * G + w_b * B

But this is nothing else than a dot product of the colour with a weighting vector. OpenGL-1.5 has a texture environment called combiner and this combiner environment features a dot product mode:

GLfloat weighting_vector[4];
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_DOT3_RGB);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, weighting_vector);

EDIT due to comment

You can specify the operation on the alpha channel in the alpha combiner, token GL_COMBINE_ALPHA. In your case you simply want to use source alpha. Adding these configuration:

glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE);

What I forgot was, that the dot product mode introduces a 0.5 bias. But this is no problem, as you are provided with at lease 3 combiner stages, so you conclude with a GL_SUBSTRACT stage subtracting 0.5 of each channel and multiply your weighting by 2.0 to compensate for this.

Take a look at the glTexEnv manpage http://www.opengl.org/sdk/docs/man/xhtml/glTexEnv.xml and the original extension specification http://www.opengl.org/registry/specs/ARB/texture_env_combine.txt (of the time when this was an extension). I admit that texture combiners are a bit mind twisting if you're new to them. Historically they are the predecessors of fragment shaders; NVidia started it all with what they then called "register combiners", which later became texture combiners.

EDIT2 due to addendum to question

You must do the second part in its own combiner stage (=texture unit). You switch texture units with glActiveTexture. Modify your code like this:

GLfloat weights_vector[4] = {0.2126, 0.7152, 0.0722, 1.0};
GLfloat additions_vector[4] = {0.5, 0.5, 0.5, 0.0};

glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texID);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);

/* First part */
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_DOT3_RGB);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, weights_vector);

glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texID); // we need some dummy texture active
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);

/* Second part */
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_SUBTRACT);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, additions_vector);

Also I think you intend to subtract, to compensate the 0.5 bias instead of adding 0.5; FTFY.

静若繁花 2024-12-05 04:28:25

在将纹理上传到 OpenGL 之前,使用 ColorMatrix 对其进行去饱和处理

Paint paint = new Paint();
ColorMatrix matrix = new ColorMatrix();
matrix.setSaturation(0);
paint.setColorFilter(new ColorMatrixColorFilter(matrix));

Bitmap bmp = Bitmap.createBitmap(resource.getWidth(), resource.getHeight(), resource.getConfig());
Canvas canvas = new Canvas(bmp);
canvas.drawBitmap(resource, null, paint);

Before uploading your texture to OpenGL, desaturate it using a ColorMatrix

Paint paint = new Paint();
ColorMatrix matrix = new ColorMatrix();
matrix.setSaturation(0);
paint.setColorFilter(new ColorMatrixColorFilter(matrix));

Bitmap bmp = Bitmap.createBitmap(resource.getWidth(), resource.getHeight(), resource.getConfig());
Canvas canvas = new Canvas(bmp);
canvas.drawBitmap(resource, null, paint);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文