我想渲染一个灰色的颜色纹理。使用着色器在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);
现在,它太黑了。我无法做对。尝试过但没有工作:
由于DOT3_RGB
中的偏见和乘法,我开始怀疑它是不可能的。在组合器中执行此操作的正确方法是:
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并非用于此目的,更可能只用于碰撞或其他东西。太糟糕了。我希望我错了,但我不明白。
答案 0 :(得分: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有一个名为 combiner 的纹理环境,这个组合环境具有点积模式:
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合并器中指定GL_COMBINE_ALPHA中的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; FTFY。
答案 1 :(得分:5)
使用2个或3个纹理合成器可以实现这一点。您很可能希望支持仅支持2个纹理合并器的旧设备(例如iPhone 3G)。您可以使用以下代码确定设备支持的纹理合成器数量:
int maxTextureUnits;
glGetIntegerv(GL_MAX_TEXTURE_UNITS, &maxTextureUnits);
在没有着色器的情况下实现渲染灰度纹理的基本步骤是:
现在,可以使用Texture Combiner执行每个步骤。或者,您也可以只使用两个纹理合并器,将第1步替换为自定义代码,以便在读取纹理时调整像素值。如果您选择仅使用两个纹理合成器,您仍然可以使用颜色渲染调整后的纹理,则只需要一个纹理合并器,在渲染之前将RGB值加倍。
我们为所有像素值添加.5的原因是因为我们用来计算亮度的GL_DOT3_RGB方程将从每个像素值中减去.5。
我们将所有像素值除以2的原因是,当从步骤2移动到步骤3时,我们的值不会被钳制。如果我们的RGB值为(.5,.6,.7)并且我们添加了.5对于每个RGB值,我们得到的RGB值进入步骤3将是(1.0,1.0,1.0)。在DOT3方程从每个值中减去.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);
答案 2 :(得分: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);