Closed thayerandrews closed 3 years ago
Interesting... I tried looking into this once, but as far as I could tell the sample positions and weights were correct. I hadn't considered it was a sub-pixel alignment problem.
Yeah, I've completely mismanaged my time for the last couple days trying to figure this one out. I started working on the Metal implementation of CCEffectBlur, made the mistake of asking myself, "Why has this never looking right?", and now here I am without a Metal implementation yet but at least some idea of how this goes wrong under certain circumstances.
I've got a scrap of notebook paper that shows the way the optimized sample offsets and weights can yield incorrect results depending on the position of the center point of the filter. I'm going to convert it into something more readable and I'll attach it here too (maybe not until I actually implement Metal blur though).
And interestingly, I can reproduce the problem in one of the GPUImage sample apps if I hack their rendering code to adjust vertex positions to NPOT values (i.e. adding something like 0.1 to all the vertex positions).
I guess there really are no free lunches :) I actually encountered this, many years ago. I think the problem is, that when forcing the texture reader to fixed positions, you get a discrepancy between what is read from the texture, and what should actually be displayed on the screen. If so, the problem should be reduced if increasing texture resolution, and vice verse. So I guess using linear texture filtering to reduce texture fetches should be disabled for textures below 1:1, and I guess you should be able to adjust position slightly in the vertex shader, for textures above.
Especially when scaling, all effects which uses some kind of blur function, starts to create very visible artefacts. I am afraid there is not much we can do at this point, so despite this being a serious issue, I will give it low priority.
Background: CCEffectBlur is implemented using the linear sampling optimization described by Daniel Rakos. Much of its implementation comes from GPUImage's gaussian blur filter here.
Problem description: When drawing sprites with CCEffect, "stair stepping" becomes visible depending on the sprite's position on the screen. This is visible in the following enlarged comparison of CCBlur and CCBlurReference (which does not have the linear filtering optimization):
At other positions, the artifacts disappear and CCEffectBlur looks identical to CCEffectBlurReference.
Suggested fix: More investigation is needed but either CCEffectBlur needs to be modified so the linear filtering optimization does not have this position dependent artifact or the optimization should be removed.