1

我想用灰色渲染颜色纹理。在 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:

点计算

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

我怀疑 DOT 不是为此目的而设计的,更有可能仅用于凹凸贴图之类的。太糟糕了。我希望我错了,但我不明白怎么做。

4

3 回答 3

5

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

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 combiner中指定对 alpha 通道的操作,令牌 GL_COMBINE_ALPHA。在您的情况下,您只想使用源 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 以他们当时所谓的“注册组合器”开始这一切,后来成为纹理组合器。

EDIT2 由于问题的附录

您必须在其自己的组合器阶段(=纹理单元)中执行第二部分。你用 切换纹理单位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;自由贸易区。

于 2011-08-03T12:06:14.683 回答
5

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

int maxTextureUnits;
glGetIntegerv(GL_MAX_TEXTURE_UNITS, &maxTextureUnits);

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

  1. 将所有像素 RGB 值除以 2
  2. 从所有像素 RGB 值中减去 0.5
  3. 使用自定义加权值计算每个 RGB 值的 GL_DOT3_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);
于 2012-03-13T18:47:13.033 回答
1

在将纹理上传到 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);
于 2011-08-03T10:55:17.503 回答