This is an artifact of mip mapping.
GPUs calculate the mip level based on how much the texture UV changes from one screen pixel to the ones directly next to it. If the distance max change in UV in any direction is less than the width of a texel, it uses the largest mip (aka, the original texture). If it’s more than a texel width distance it calculates the appropriate mip level such that the mip map’s resolution will be roughly 1 texel between screen pixels.
When surfaces approach being parallel to the view direction, the change between one pixel and the next can reach over the entire UV. This it true even on triangles that only show a small part of the overall texture, because the GPU is extrapolating the UV for the “next pixel” even if the triangle isn’t visible in more than one. So the mip level starts going to infinity and the mip drops to the smallest 1x1 mipmap regardless of the texture size.
There are a few fixes to this.
- Disable Mip Mapping on the texture: This is usually the first option you’ll find online. Don’t do this. It does work, but it will mean aliasing and possible performance problems.
- Enable Anisotropic Filtering: Not a 100% solution, but can minimize the effect significantly. I said above that the mip level is calculated from the max of much the UV changes in any direction. That’s true for point, bilinear, and trilinear filtering. Anisotropic filtering works roughly by calculating the min change in any direction for the mip level and then samples the texture multiple times along the max change direction (how many times is controlled by the Aniso level). It’s a little more complicated than that, and at the extreme grazing angles it’ll still drop the mip level to infinity, but it should be much less apparent.
- Shrink the mesh: The cylinder mesh being used should only cover the area that’s visible. The lines will still show along the sides, but will be significantly hidden by the rest of the effect. This is a good idea regardless of what kind of effect you’re doing, as otherwise you’re wasting a lot of GPU resources rendering stuff that’s invisible. An “invisible” transparent mesh is just as expensive as a visible one.
- Fresnel Fade: Use a custom shader that fades out the mesh when the triangles are getting close to parallel with the view. This is your basic Fresnel / outline / glow shader, and really it’s a dot product between the view direction and surface normal. For double sided surfaces use the abs() of the dot product. You can then use a smoothstep() to adjust the fade point to between something like 0.05 and 0.1 so most of the cylinder is still visible.
- Fade Mip To Color: Effectively the same as using a Fresnel glow, but you have less control and it’ll fade out when you’re far away too.
- Clamp Mip Level: You can calculate the mip level in a shader and clamp it to some level above the smallest mip. Unity technically supports textures without a full mip chain so you could limit the mip level on the texture asset itself, but this only for textures created from script and not by the built in importer which makes this a bit annoying to work with.
- Add More Particles!: Really, just add a lot more stuff to the effect so no one will notice.