Search Unity

Is it possible to have multiple Matcaps in one material with their own masks?

Discussion in 'Shaders' started by Creiz, Jan 26, 2020.

  1. Creiz

    Creiz

    Joined:
    Jun 6, 2017
    Posts:
    130
    Consider this situation: I have a mesh of a sword. It has 3 materials. One for the Blade, one for the Hilt and one for the leather on the hilt.

    I want to combine those 3 materials into 1. I am aware that I can bake an atlas texture and be done with it but I really like the fake lighting Matcaps gives me. And since I want to drive the diffuse by color instead of textures, it really does great things.

    Basically what I have in mind is a Shader that goes like this:

    [Section 1]
    ---Diffuse Color
    ---MatCap
    ---Matcap Mask

    [Section 2]
    ---Diffuse Color
    ---MatCap
    ---Matcap Mask

    [Section 3]
    ---Diffuse Color
    ---MatCap
    ---Matcap Mask

    etc...

    The reason why I don't just use 3 different materials is because I'm using UMA and they only allow one material per slot. It's fine when you're baking textures and all but it's a no-go for my needs. The good news is that the material allowed can be almost anything.

    Unfortunately I am at a complete loss on even how to start with it. I know how to get a Matcap working. I just don't know how to make it so each section is contained in their own little bubble and only "outputs" what they're masked.
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    You‘look want to use an RGB texture with the area the different materials are painted into it. Or really you just need to use two channels. Anywhere that’s black RGB(0,0,0) is Section 1, anywhere that’s red RGB(1.0,0,0) is section 2, and anywhere that’s yellow RGB(1.0,1.0,0) or green RGB(0,1.0,0) is section 3. You can use the additional blue channel for a four section if you want. Then it’s just a matter of lerping between the colors.

    psuedo code example:
    color1 = diffuse1 * matcap1;
    color2 = diffuse2 * matcap2;
    color3 = diffuse3 * matcap3;
    color = lerp(lerp(col1, col2, mask.r), col3, mask.g);

    This is basically how terrain shaders work. It might seem like a waste to be sampling all of the matcaps all the time, but that’s kind of what GPUs are good at. Trying to refactor the code to only sample the matcap that’s needed with if statements and the like ... will still probably end up having the GPU sample all of the matcaps all of the time because if statements don’t work how you think they do on GPUs,
     
    april_4_short and Creiz like this.
  3. Creiz

    Creiz

    Joined:
    Jun 6, 2017
    Posts:
    130
    Thanks @bgolus. Yeah, I'm not trying to make if statements or anything. I just want every single section to be in their own little bubble, it doesn't matter if the GPU has to read 3000 matcaps continuously. I'm not going to have thousands of objects in my game, anyways, seriously it's at most maybe a couple hundred materials. I'm really not worried about performance.

    At the moment I'm really having difficulties telling the shader that [This section of the texture] is not part of [This other section], even though I paint it red, don't color the rest of the mesh Red. Just this little section here.

    I want to tell it something like "Look. This is the alpha mask for this section. Apply the matcap and tint it this color here and here only, don't touch the rest of the mesh."