1
$\begingroup$

https://www.youtube.com/watch?v=Q60cdwZDyjE

I'm used to working with texture atlases, where multiple images are compiled into islands or a regular grid within one single image. An example follows: enter image description here

The individual textures within the main image are chosen through UV coords via the shader and applied to the 3D surface. This is useful for game development as using a single texture for multiple objects can help reduce drawcalls.

In the linked video, the tutor explains a different methodology where the user converts the atlas into a 2d Texture Array, where the images are no longer accessed by UV coords, but are instead indexed solely by the W coord. With this system (it appears!), texture bleed seems to be eliminated and the textures can be repeated / scrolled by increasing / changing the UV values.

I'm not an especially technical person, so I'm leaving a couple of links I've found while researching the topic:

https://www.khronos.org/opengl/wiki/Array_Texture

https://docs.unity3d.com/Manual/class-Texture2DArray.html

https://derivative.ca/UserGuide/2D_Texture_Array

This seems like a very useful technique, especially if I could use it in my 3D modelling program and then use the output models in Unity. Does anybody have an idea of how to make this work in Blender?

$\endgroup$
2
  • $\begingroup$ While files, images, and external videos or links may be helpful additions they should not be the only way to obtain information about your issue. Don't make understanding your question rely on downloading a file, watching a video or visiting an external site. Use the builtin tools to upload images or gifs, along with thoroughly explaining the problem in written form so it can be indexed and searched for thus helping future visitors with similar issues. $\endgroup$ Dec 10, 2021 at 9:39
  • $\begingroup$ Point taken, I'll attempt to add further clarifying text. $\endgroup$ Dec 10, 2021 at 10:21

1 Answer 1

2
$\begingroup$

You could set up a material to do a "texture array" in Blender. There would be no advantage to doing so. Texture arrays as you're talking about are intended as a replacement for texture atlasing, which is a technique intended to reduce the number of draw calls that game engines need. But Blender is not significantly bottlenecked by draw calls-- it is not optimized as a game engine, but as a "slow" rendering engine, and there are bottlenecks far more significant than draw calls in Blender! I'm unsure of the performance impact of texture arrays in something like Unity, but in Blender, use of a texture array is probably more likely to lead to a reduction in performance.

And setting up either a texture atlas or a texture array in Blender does nothing to set it up in a desired game engine. Your Blender materials won't have anything to do with your Unity materials.

So given all that, how can we implement?

First problem is 3D UV. Blender doesn't natively support it. But one bit of vertex data is just like another bit of vertex data. We can use one channel of a second UV map to create 3D UV:

enter image description here

UVMap, not shown, is your basic Suzanne UVMap. But I've created another UV map, UVMap.001, which is different: all the UV lies on the left margin. When we combine vectors as shown in the shader nodes, we're appending the U of UVMap.001 as a Z component onto the XY provided by UVMap's UV. So right now, that value is 0. (You can treat this as XYZ coords, you can treat it as UVW coords, it's the same thing. What it is is what matters, not what we call it.)

In later views, I'll collapse this shader structure into a node group to be able to focus on the other elements.

So then we can use this Z coordinate to specify which "layer" of a texture array we want to call. But how are we going to set up that texture array?

enter image description here

Notice especially the leftmost Suzanne, where I've rotated UV.Z so you can see how this mixes between elements in our texture array.

We can read all the textures, and then mix between them on the basis of UV.Z is greater than some fixed value. Here, I've made an interval of 0.33 to specify, since I'm doing it with a texture array that is 3 images thick. If you want, you can use some other thickness; and there's really no reason to limit ourselves to the 0,1 range for UV.Z, since we're not using it for tiling or anything.

BTW, in this particular case, we're sampling the array as if our Z component was being sampled on "closest" mode-- no texture filtering. So we get all one image, or all another. It's not necessary to do that; we could, for example, sample two images and interpolate between them to do texture filtering between array layers. If we were to do that, we'd see a smoother interpolation between textures on the leftmost Suzanne rather than hard borders where the texture switched.

And if we want, we can cleanly node group our texture array, so that we can use a different array for our normals, for our roughnesses, etc. The only thing that we need for the node group is a 3D vector input.

$\endgroup$
2
  • $\begingroup$ That is a phenomenal answer, cannot wait to try it out tomorrow! I will say that my hope was to be able to export a model from Blender with the W value for specific faces set to certain integer values and have those values per face picked up by Unity on import. I'm not looking to improve performance in Blender, but instead to author content with this method for use in Unity, where the performance (and other) benefits would be found without having to explicitly set the W integer per shader, per face. Do you think this would be possible? Again, great answer, excited to try it out! $\endgroup$ Dec 11, 2021 at 0:37
  • 1
    $\begingroup$ @ReverendSpeed phenomenal answer but you did not give an upvote for Nathan's time and effort. sad. $\endgroup$ Oct 14, 2022 at 7:15

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .