0

I've got a textured mesh with a specific list of triangles that correspond to faces on the mesh that get recolored at runtime using code like this:

        _mesh = GetComponent<MeshFilter>().mesh;
        ...
        var colors = _mesh.colors;
        foreach (int n in trianglesIndexList)
        {
            colors[n] = Color.blue;
        }
        _mesh.colors = colors;

It works great but I had originally intended these faces to be a bright blue. Unfortunately the coloration seems to be blending with the material's texture that I've assigned to the mesh in Unity. Here you can see that the green grass on the texture is mixed with the rather green looking "blue":

enter image description here

I've tried playing with the lighting but that does not seem to be the issue. The mesh coloration that I've got requires use of specific shaders, so I've assigned the Particles / Standard Surface shader to the mesh.

Is there any way to recolor subsections of the texture at runtime and make these faces look bright blue?

Mir
  • 305
  • 8
  • 24
  • 1
    Can you remap the texture?, if you change the texture mapping for example to a white texture, you should get the blue when you set the color, or just put a blue texture into your mapping. – DomCR Aug 27 '19 at 09:20
  • The color blending is intentional. That's what is supposed to happen, if you don't want that to happen then either (a) use a grayscale texture (b) don't use color tinting that way or (c) write your own shader. – Draco18s no longer trusts SE Aug 27 '19 at 13:21
  • Yes, previously the mesh had no texture and the coloration looked perfect. It's too bad there isn't an easy way to recolor faces additively. It seems like the best solution would be to store one normally colored texture and one blue colored texture and remap it at runtime for only those select few faces rather than setting mesh colors, but I have no idea how to do that or if it's even possible. @Draco18s write my own shader that does what exactly? – Mir Aug 27 '19 at 16:29
  • One texture that's grayscale will be the easiest. As for the custom shader, that's how you could make the color additive instead of multiplicative. – Draco18s no longer trusts SE Aug 27 '19 at 20:01
  • @Draco18s Yes, but how? I would think that I need to pass coordinates (or some such) for a subset of mesh faces into the shader and then let the shader render the uv texture normally and somehow add the blue on top of that only for those coordinates? Am I think along the correct lines? Also, I don't want to use greyscale textures here, I would like to preserve the normally colored textures and 2d art where the blue isn't present. – Mir Aug 27 '19 at 22:12
  • Shaders already operate on either a per-pixel or per-vertex loop. You don't need to deal with "passing coordinates for a subset of the mesh" level of detail, that part's done for you. https://docs.unity3d.com/Manual/Shaders.html – Draco18s no longer trusts SE Aug 28 '19 at 00:03
  • In that case, how will the shader know which portions of the mesh to recolor at runtime? I'm looking to dynamically recolor certain faces, not recolor the entire mesh. – Mir Aug 28 '19 at 00:16

1 Answers1

0

Ok, nevermind, I found my own solution by learning how shader code works within about 3 hours and writing a custom shader. Simply use Unity's default standard shader as a starting point and add worldNormal and worldPos inputs like this:

struct Input
{
   float2 uv_MainTex;
   float3 worldNormal;
   float3 worldPos;
};

Then inside the surf function you can filter to just the upward facing normals (which is what I want in this case) and filter these mesh coordinates once again by the world space coordinates.

void surf(Input IN, inout SurfaceOutputStandard o)
                {
                float2 UV;
                fixed4 c;

                if (abs(IN.worldNormal.x) > 0.5)
                {
                    // normals facing the left and right side
                    UV = IN.worldPos.yz; 
                    c = tex2D(_MainTex, IN.uv_MainTex);
                }
                else if (abs(IN.worldNormal.z) > 0.5)
                {
                    // normals facing forward and backward
                    UV = IN.worldPos.xy; 
                    c = tex2D(_MainTex, IN.uv_MainTex);
                }
                else
                {
                    // normals facing up and down
                    if (abs(IN.worldPos.x) > 0.5)
                    {
                        UV = IN.worldPos.xz;
                        // COLOR IT BLUE
                        c = tex2D(_MainTex, IN.uv_MainTex) + (_Color * _SinTime.y);
                    }
                    else
                    {
                        UV = IN.worldPos.xz;
                        c = tex2D(_MainTex, IN.uv_MainTex);
                    }
                }

Can obviously simplify this quite a bit, but this is all I wanted to know how to do. I even figured out how to recolor over time using the built in SinTime variable. Super easy.

Mir
  • 305
  • 8
  • 24