我正在尝试使用我们自己的Atkinson dithering algorithm的Brad Larson框架在GLSL中的片段着色器中实现GPUImage。 (这可能是那些不可能完成的事情之一,但我还不知道如何确定这一点,所以我只是继续这样做。)
Atkinson algo将灰度图像调整为纯黑色和白色,如原始Macintosh上所示。基本上,我需要研究像素周围的几个像素,并确定每个像素与纯黑或白的距离,并使用它来计算累积“误差”;该误差值加上给定像素的原始值确定它应该是黑色还是白色。问题在于,据我所知,误差值(几乎?)始终为零或不知不觉地靠近它。我正在想的可能是我正在采样的纹理与我正在编写的纹理相同,因此错误最终为零(或接近它)因为大多数/所有像素我'采样已经是黑色或白色。
这是正确的,还是我正在采样并写入不同的纹理?如果是前者,有没有办法避免这种情况?如果是后者,那么您是否能够发现此代码的任何其他错误? “因为我很难过,也许不知道如何正确调试它。
varying highp vec2 textureCoordinate;
uniform sampler2D inputImageTexture;
uniform highp vec3 dimensions;
void main()
{
highp vec2 relevantPixels[6];
relevantPixels[0] = vec2(textureCoordinate.x, textureCoordinate.y - 2.0);
relevantPixels[1] = vec2(textureCoordinate.x - 1.0, textureCoordinate.y - 1.0);
relevantPixels[2] = vec2(textureCoordinate.x, textureCoordinate.y - 1.0);
relevantPixels[3] = vec2(textureCoordinate.x + 1.0, textureCoordinate.y - 1.0);
relevantPixels[4] = vec2(textureCoordinate.x - 2.0, textureCoordinate.y);
relevantPixels[5] = vec2(textureCoordinate.x - 1.0, textureCoordinate.y);
highp float err = 0.0;
for (mediump int i = 0; i < 6; i++) {
highp vec2 relevantPixel = relevantPixels[i];
// @todo Make sure we're not sampling a pixel out of scope. For now this
// doesn't seem to be a failure (?!).
lowp vec4 pointColor = texture2D(inputImageTexture, relevantPixel);
err += ((pointColor.r - step(.5, pointColor.r)) / 8.0);
}
lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
lowp float hue = step(.5, textureColor.r + err);
gl_FragColor = vec4(hue, hue, hue, 1.0);
}
答案 0 :(得分:2)
这里存在一些问题,但最大的问题是Atkinson抖动无法在片段着色器中以有效的方式执行。这种抖动是一个顺序过程,取决于它上面和后面的片段的结果。片段着色器只能写入OpenGL ES中的一个片段,而不是您指向的Python实现中所需的相邻片段。
对于潜在的着色器友好抖动实现,请参阅问题"Floyd–Steinberg dithering alternatives for pixel shader."
你通常也不能写入和读取相同的纹理,虽然Apple确实在iOS 6.0中添加了一些扩展,让你可以写入帧缓冲区并在相同的渲染过程中读取该写入的值。
至于为什么你会看到奇怪的错误结果,GPUImage过滤器中的坐标系统被标准化为0.0 - 1.0的范围。当您尝试通过添加1.0来偏移纹理坐标时,您将读取纹理的末尾(默认情况下会将其限制为边缘处的值)。这就是为什么你看到我使用texelWidth和texelHeight值作为需要从相邻像素采样的其他滤镜中的制服。这些计算为整个图像宽度和高度的一部分。
我也不建议在片段着色器中进行纹理坐标计算,因为这将导致依赖纹理读取并真正减慢渲染速度。如果可以的话,将其移动到顶点着色器。
最后,为了回答您的标题问题,通常您无法在读取时修改纹理,但iOS纹理缓存机制有时允许您在着色器正在通过场景时覆盖纹理值。这通常会导致严重的撕裂伪影。
答案 1 :(得分:1)