Overview: Indexed Material Mapping Tecnique

Artem Krizhanovskiy demonstrated the Indexed Material Mapping approach that allowed him to increase detail without memory loss by sampling all material data from pre-defined LUT.

In case you missed it

You might find these articles interesting

Introduction

The main idea of this approach is to reduce compression artifacts, increase detail in all PBR channels, get highly customizable shading without any changes in the content, and in the end reduce the memory. 

Approach

Instead of using direct texturing approach, I rely on a material-based approach in which using a gradient (wear or condition) and material we can sample all material data from pre-defined LUT.

The only input is:

- 4-channel full-sized gradient-ID map, compressed

- Full-sized Tangent or object-space normal map, compressed

- 16x16 albedo, repaint LUT, uncompressed

- 16x16 metallic, roughness LUT, uncompressed

1 of 4

Gradient Texture: R - Ambient Occlusion, G - material ID, B - detail ID, A - gradient

1 of 2

Material LUT1: RGB - albedo, A - repaint mask | uncompressed, no mip-map

Material LUT2: R - metallic, G - roughness, BA - empty | uncompressed, no mip-map

Basically, gradient serves as U and material ID map serves as V in reading Material LUT textures: texture(materialLUT_sampler, vec2(gradient, material_ID))

Schematically, it looks like this:

The process is pretty straightforward and can be reproduced with code or node-based editors like Substance Designer or Unreal Engine:

This model consists of 16 materials:

Repaint:

1 of 2

In this case, additional camo pattern texture is used as a repaint color.

The very idea of repaint is based on reversed blending. As we know, trivial linear interpolation looks like this:

Result =  C_base*(1-alpha) + C_paint*alpha

We can derive C_base:

C_base = (Result -  C_paint*alpha) /(1-alpha) 

And blend it with a new color:

Result =  C_base*(1-alpha) + C_repaint*alpha

The Devil Is in the Detail

The detailed (top) image has 16 times greater texel density while it is only ~11% heavier on memory.

1 of 2

The procedural nature of this approach allows me to apply a full-PBR set of detail to the model which works fine with all materials and repaint options. The detail map consists of 16 tiles with a set of detail normal and detail gradient. Detail_ID map is used to define which tile is used for detail. I would recommend using BC7 texture format with normal R and G channel in RG, and gradient in B. Further restoration of normal B channel is required in code. You may notice that some of the details are blank, that's because I don’t need 16 details on this model.

You can see how changing detail_ID affects the surface:

Artem Krizhanovskiy, Technical Artist at Wargaming

Keep reading

You may find this article interesting

Join discussion

Comments 8

  • M-C Alej

    Quite interesting! I got a couple of questions if you don’t mind:
    - So if I understand correctly from other comments and the textures, if the “gradient” base starts from curvature peaks/valleys, edge wears, etc then it means that chipped away metallic parts have to be towards the right end side of the texture? the middle gets a bit artistic and have to carefully play with gradients grayscale level there? (some of the ID line-strips around the middle levels have transitions from a brighter color back to a dark).
    - Detail normal maps can do a lot more too thanks to having a gradient in B channel, but how do you mix the gradients? is it something like the max or avg of the two gradients?
    - The repaint part is probable the most head-scratching for me... first of all, is it triplanar mapping? Or maybe the detail pattern tile-able uvs? (it’s not quite clear what are the uv requirements for the model, I’m assuming at least two: one unique UVs unwrap for the AO/normals/gradient and another for detail normals (which are tiled-repeated by shader code to a single quadrant of the 16x16 tiles).
    If you assumed premultiplied alpha blending would it simplify the math (assuming that it is possible)? As c_result = c_source + c_dest * (1 - srcAlpha).

    Nevertheless, thanks a lot for sharing this, it does indeed looks great! and will probably open the door to see materials in a more “indexed” clever ways.

    2

    M-C Alej

    ·3 years ago·
  • M-C Alej

    Just wanted to leave a late thank you note for going through the questions and giving answers, more pointers and insight.
    (just realized that 80.lv doesn’t have a reply button and looks like no notifications on comments at least for me).

    0

    M-C Alej

    ·3 years ago·
  • Krizhanovskiy Artem

    M-C Alej
    gradients blend as sum of waves, just get them into -1 to +1 range and blend
    - one model uv is used, tiles are just tiled:)
    - repaint is probably the easiest part, it's just blend of initial color with a new one(or texture) with an alpha from LUT, the only trick is the correct blending. Simplifying single ALU instructions on modern hardware, sacrificing the code and algorithm understanding is pointless from my point of view.

    1

    Krizhanovskiy Artem

    ·3 years ago·
  • Krizhanovskiy Artem

    M-C Alej

    - Yeah you are correct. for example for the paint material, the darkest part would be dirty concave parts, middle the paint, next is oxidized steel and brightest part is the convex chipped or polished bare metal.
    - For the normals: if you are using tangent space, use any of this to blend: https://blog.selfshadow.com/publications/blending-in-detail/
    I prefer to use object space normals, in this case you will need to create a new basis, using OS normal and tangents from vertex, with Gramm-Schmidt process and apply TS detail normal over OS normal.

    1

    Krizhanovskiy Artem

    ·3 years ago·
  • Krizhanovskiy Artem

    "how do you actually paint/generate the full-rez gradient ID texture?"

    This one is done in Substance Painter. ID is straightforward fill(for UV.y of LUT), while gradient  itself(UV.x of LUT) representing more of wear and curvature, so curvature bake works really great for the start. I've also wrote myself a viewport shader for SP and marmoset to actually see what I am painting.

    1

    Krizhanovskiy Artem

    ·3 years ago·
  • Anonymous user

    how do you actually paint/generate the full-rez gradient ID texture?

    0

    Anonymous user

    ·3 years ago·
  • Krizhanovskiy Artem

    Łyczkowski Paweł

    each material is a pixel in 16x16(in this case, can be any) LUT.
    model base map(4k) and detail (2k) and normal(4k) are all of this projects resources.
    You can see it as tiled texturing, but this approach has key differences:
    - only 1 texture per tile instead of normally 3(albedo, roughness/metallic)
    - 2 textures main set instead of 3
    - detail affects main textures in a more complex, natural way, based on material wear and curvature more than a trivial blending

    1

    Krizhanovskiy Artem

    ·3 years ago·
  • Łyczkowski Paweł

    I don't get it. Is each material a set of maps? Then why doesn't it use 16 times the normal amount of memory?

    0

    Łyczkowski Paweł

    ·3 years ago·

You might also like

We need your consent

We use cookies on this website to make your browsing experience better. By using the site you agree to our use of cookies.Learn more