1
\$\begingroup\$

The first thing that comes in mind is masking using RGBA values. With this you can obtain this kind of textures and this kind of results.

enter image description here enter image description here

But with this, you can only store up to 4 masks inside a texture and blend between maximum 4 textures.

I am wondering if there's a way to store more than 4 masks inside a texture and being able to blend more than 4 textures using this mask texture. The aim would be to store as much as possible masking data inside a texture.

Is it possible ? How ?

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

If you use a point sampler for your mask texture, then you can store as many IDs as bits in your texture: for a 32-bit RGBA texture you'd be able to store 128 different IDs. In such a case though, as you have a single bit per ID, there's virtually no blending as you have only 0 or 1.

The more bits you devote per ID, the greater the blending granularity, but of course that reduces the number of total IDs. If you go with RGBA32 textures, you have 128 bits at your disposal. You can store 128 IDs with blending value "full" or "none", or 64 IDs with "full", "half", "none" and so on - it's up to you what you write to those 128 bits and how you interpret them.

I can't point you to a whitepaper/link, as this is something that I'd do (and might have done in the past). I will also not provide any detailed code, as it's just bit fiddling; nothing else. The function that you'd need in your shader would be like:

    /* Extract the bits that refer to a particular texture id and return the blend factor. 
    E.g. if you have 4 bits per id and the bits in the texture are 1001, 
    then the blend value would be 9/15 */
    float unpack_id_blend_factor_from_texture_value( uint4 lookup_value, int id, int bits_per_id)
{
    const int total_ids = 128/bits_per_id;
    const int total_ids_per_component = total_ids / 4;
    // get the component that contains the id, and modify 
    int value = 0;
    if( id < total_ids_per_component )
    {
        value = lookup_value.x;
    }
    else if( id < (2*total_ids_per_component) )
    {
        value = lookup_value.y;
        id -= total_ids_per_component;
    }
    else if( id < (3*total_ids_per_component) )
    {
        value = lookup_value.z;
        id -= 2*total_ids_per_component;
    }
    else
    {
        value = lookup_value.w;
        id -= 3*total_ids_per_component;
    }

    // shift the value data so that the bits used by the id are in the front
    uint used_bits = value >> (bits_per_id*id);
    // make the rest of the bits -- after the used ones -- zero
    used_bits &= (1 << bits_per_id) -1;
    // get and return the blend value
    return used_bits / float((1 << bits_per_id) -1);
}

Now the above should give you an idea how you extract the bits. You use the inverse process to fill the lookup texture.

\$\endgroup\$
5
  • \$\begingroup\$ Thank you for your answer, could you develop your solution ? Do you have some tutorials or white papers ? Does this allows blending ? \$\endgroup\$
    – MaT
    Jan 13, 2015 at 13:57
  • 1
    \$\begingroup\$ updated my answer - it allows blending at the cost of potential IDs. the authoring of the lookup will be bit-fiddly though, in any case \$\endgroup\$
    – Babis
    Jan 13, 2015 at 14:29
  • \$\begingroup\$ Thank you for your update and you very understandable answer. I'll try to find some informations about this kind of bit fiddling as this is the first time I try to do such effect. \$\endgroup\$
    – MaT
    Jan 13, 2015 at 15:02
  • 1
    \$\begingroup\$ Ok I added some example code which I hope makes it a bit clearer, can't guarantee that it's error free of course :) \$\endgroup\$
    – Babis
    Jan 13, 2015 at 15:40
  • \$\begingroup\$ Oh thank you very much for this example, it will help me understand the process ! Thank you again ! \$\endgroup\$
    – MaT
    Jan 13, 2015 at 15:46

You must log in to answer this question.

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