I think at least part of your problem is due to rounding errors that are causing your texture to unintentionally wrap. Does this Playground solve the issue on top?
Basically the only thing I did was to set the texture’s vertical wrap mode to “clamp” on line 18. With this change, when the shader looks for pixels that are slightly above the strict v = 0 to 1 range (because of floating point error, etc.) it’ll clamp to the transparent pixels at v = 1 instead of wrapping around to sample the green pixels at v = 0.
Surprisingly, I still see an artifact along the bottom of the grass, which seems odd; I wouldn’t have expected there to be two unrelated issues causing these artifacts, and I’m not sure what to conclude from that. I’ll let you know if I think of something that might explain that better. However, since it’s grass, as long as the top looks good, hopefully the bottom won’t be too much of an issue.
Basically the default sampling mode was causing the shader to handle partial pixels as combinations of the pixels in the vicinity, which near the boundary between your transparent and opaque areas was creating “half-way” pixels, which looked weird.
Speaking of weird, the method I used to set the sampling mode—in the constructor—was the only one of the ways I tried that worked. Strangely, manually calling setUpdateMode on the texture didn’t seem to have the same effect even with the same argument. Not quite sure how I feel about that, but at least we know what was making the grass look strange.
Yes, I think this is also due to rounding errors; it shows up this way because the edge between one sub-texture’s transparency and the next sub-texture’s opacity is rather harsh and precise.
You can work around this issue by fiddling with the scales to avoid having the edge of the color be so close to then edge of the texture that’s supposed to be rendered, as demonstrated in the Playground above. Another option would be to “flip” the top half of the sheet so that the transparent parts of the textures are adjacent, eliminating this problem.
There might be other things to try as well, but ultimately as long as you have pixels that look drastically different very near to each other in pixel space, you risk having difficulty keeping one from leaking into the other. @PatrickRyan likely knows some good ways to avoid/deal with issues like this.
@Yann_S, I agree with @syntheticmagus that creating a texture where you want to be able to snap the bottom of the grass, yet start that at 0.5 V will always give you problems, especially when mip mapping. The only real way to combat that is to not snap the secondary texture to 0.5 V and use a custom offset to ensure that you aren’t pulling pixels from the texture above.
The way I would solve this problem is a little different. Rather than setting up the texture like above and needing to rotate the UVs to get to the other texture, I created a new tiling texture from your source (the grey background is just for illustration of proportions here, it is a transparent png).
This is a 2048x256 pixel map that tiles in U. The reason to use a non-square texture is so that you can limit the overdraw on the grass and save on file size. Your original 1024x1024 texture was 518K. This reformatted verision is 512K so you don’t pay a higher file size cost while retaining the same texel density. I am not sure how you are using this for final, but noticed that your original texture did not tile so I assume it is used so that the edges aren’t seen. In this case, you can get a unique look just by offsetting the U position.
I am tiling in U and clamping in V with a non-uniform scale for U and V to retain the same proportions as in the original art. I updated your playground with this new asset and added a GUI slider so you can see the effect of offsetting the U position on the texture. This should give you flexibility while not causing any stray pixels to appear.