I’m currently working on a project where I’m using HISCM to generate a custom tile map where selecting different tile types alters the per instance material scaling to show different things. The issue I seem to be running into is that the scaling per instance doesn’t seem to be uniform in my material, and I’m trying to understand why.
Here is a quick rundown of the specs before the details:
My object is a plane that is scaled to 32x32 units exported from Blender
The texture I’m applying to each tile should be a scaled value of my material size that essentially equates to 32x32. For example, I may have a single texture that has 4 32x32 tiles in a square with no spacing. The size of the texture is 64x64. Per instance, I’m scaling the U, V (texture coordinates) of my material to (0.5, 0.5) (0.5, 1) (1, 0.5) or (1,1) which “divides” the material into what should be a 32x32 space, or 1/4 of the total texture.
I have 3 HISMC objects (static, animated, and layer tiles), and all 3 texture files are not an even square, but are an even scale of 32x32. Though I have tested this issue with a perfect square that divides into a single decimal number and I get the same issue.
This project is targeted towards minimum specs, so the materials are unlit, the textures are basic and set to User Interface 2D for compression. Aside from being set up to handle custom data and UV scaling, there is nothing else added to the material.
This is happening on 4.27.2
The issue:
Based on the description above, I’m seeing this issue where depending on my camera position, or the specific scale, the texture coordinates will become incorrect and will bleed into the texture beside it causes lines to appear and disappear on the object.
Here is an example where all my grass is the same HISMC object and UV scaling, but in some areas it’s broken and in some it’s completely fine. It can also be seen in the lava, which is a different HISMC, and it varies per frame of animation, despite the frame of animation moving the UV scaling a uniform 1/3 each frame.
Here is another example where the bleeding into the next part of texture appears and disappears based on camera movement:
At this point I’ve spent a large amount of time trying to research this and understand it. I’ve tried making my texture tiles square. I’ve tried to make them divided such that the number is as accurate as 0.25, 0.5, 0.75, 1. I’ve tried different material settings to increase precision. I’ve messed around with the texture’s compression settings. Different sizes other than 32x32 tiles. Nothing has worked. I’d be very grateful for any extra input on the matter. I also have a very basic project example I put together that I can share if need be.
Thanks, mate! That’d be great if you wouldn’t mind. I wrote this example project, so I don’t mind sharing a public link for others in the community.
This project is a very simplified version of what I’m doing. You should be able to play and go.
To make it easy to follow:
Tile generation actions & movement are linked to the player controller.
Tile generation methods are linked to a custom event dispatcher in the level BP which uses a custom “map” object named “Example_Map” you can find in the Content folder. This object is placed in the scene and holds the HISMC objects we’re adding instances to along with an associated method to do so.
In the Tiles folder, you can find the HISMC bases I’ve created that are added to the “map” object as components.
In the Tiles folder you can find the materials and textures being used. I’ve set them up exactly as I have them in my game, but scaled back and not all my custom data inputs are used here (just the important ones). I apologize the textures aren’t great as I whipped them up very quickly to showcase this issue. Feel free to replace the textures as you like.
In the materials view, this is the most accurate way I find to view the material
At a certain point of generation / distance from the center, culling will kick in and you can start to see some visual issues of entire tiles disappearing. This is fine and isn’t an issue in my main project, but I didn’t want to spend the time to tie culling into my camera movement for this example.
Yes, I actually noticed the same thing, and I think that’s on the right track for sure! It’s interesting because the texture itself doesn’t appear to have those edges in photoshop, the .png export, or the UE4 texture editor / import. Only in the material / implementation. I did some greater research last night on texture vs material settings, compression, mipping, and texture sizing. I think I have an idea of what may be wrong. If it’s correct I will provide a greater update later this evening with a breakdown.
Ok, so I think I understand what’s going on here. The results aren’t exactly ideal for me, but I suppose it comes with the territory when working with something you’re not entirely familiar with.
If anyone in the future ever needs a greater detailed explanation I can certainly provide it. But for now, just note that is a consequence of trying to be too performance-oriented, while not fully understanding graphics rendering pipeline.
The issue of the wonky lines where it looked like the texture wasn’t fully stretched on the plane or face of the cube is a combination of the texture size and the texture compression.
I was using a single texture file (let’s call it a texture atlas), to hold all my individual textures (let’s call these tile textures). The tile textures were drawn at 32x32 pixels, and in the example above were put into a square texture atlas file that was 64x64 pixels, which is what my material was using. So I had 4 tile textures to work with when diving up the texture atlas by scaling my material’s UV. The texture’s compression, filtering, and mipping settings were causing the edges of each tile texture to bleed into eachother, causing that “line” we see above. In addition to that, I also had some anti-aliasing and camera distance trickery at play which caused the line flickering showcased in the video I posted.
After playing around with the settings and doing some research, I found that generally for the most accurate reflection of my texture export in engine, my compression settings should be set to User Interface. My texture filtering should be Nearest. And my level of detail texture group should either be UI or 2D. These of course come with their own costs, but this did completely solve the line issue. However, it produced another problem entirely. After applying these settings, the textures became incredibly pixelated and low quality, which was not what I wanted to see.
After more testing, I decided I was going to double my texture size to see if perhaps using a higher quality texture would resolve this. This actually did work, and made the above find irrelevant because this solution also fixed the line issue by itself with the default texture settings. I guess the compression on the edges just became less noticeable or more accurate? The only problem I have now is the added cost of increasing my textures from 32x32 to 64x64, and subsequently my atlas size from 64x64 to 128x128. In the example project this doesn’t matter, but I think it does matter in my main project which takes my atlases to 2k and in some cases 4k which isn’t viable for what I’m doing. My solution will be to likely further break these out into more HISMC objects and managing those individually so I can reduce the texture atlas sizes.
This kind of mip-map bleeding is usually solved by adding a border to the tiles by duplicating the pixels at the edges. So instead of 32x32 tiles you now have 33x33 (but you could also do 34x34, so a 2-pixel border, remember than the further you zoom out the higher mipmap level is taken so the bigger the border needs to be). The downside of this is that the math to pick the correct tile in the material gets more complicated. It is also more work to make the texture atlases, but some tools like Texture Packer have an option to add this border automatically.
Aha, well I am trying to target mobile devices in the low end, hence the likely over-concern for keeping things smaller. But really, with the implementation I’m going with, the issue becomes the texture atlas’ size rather than the individual textures themselves. I’ve created nearly 1,000 unique tile pieces, so grouping those together such that they can be used by a minimal number of ISMC objects that will allow me to draw a lot for very little becomes the justification for texture size.
@Pjotr that’s very interesting I will look more into the borders implementation this week and report back my findings for reference, thanks! I did attempt to use it, but didn’t seem to have luck with it. So I was obviously missing something that I’ll read up more on.
I’ve read that the max texture size for a mobile device is 2k, though I’m not really sure what happens if you try to use textures above that size anyways. I think regardless I will end up doubling my atlas size, as I’ve also read the cost of a texture in the engine is scaled up to the nearest power of 2 as a square. So the extra spacing in my atlases will likely push my dimensions to a number where it would be upscaled to 2k or 4k in one of the cases.