Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Vertex Color Splat Map Just Tinting Texture

Discussion in 'Shaders' started by tpennetta, Mar 3, 2014.

  1. tpennetta

    tpennetta

    Joined:
    Jul 25, 2013
    Posts:
    18
    Hey All,

    I am pretty new to shaders, but starting to learn. I wanted to be able to use the vertex colors from my mesh to be a splat map for textures for a mobile terrain. I have seen examples, using either Vertex Colors, or by using a Color Map texture. I have implemented both in Surface Shaders and in Vertex/Fragment approach. However, I achieve the same results, that the textures will be correctly assigned to the model but the Vertex Colors or Splat Map colors just tint completely.

    I have included the code and my result below. There must be something I am doing wrong mathematically with combining the Splat color channels and the texture assigned. In the example below I am just applying a single texture as a test.

    Code (csharp):
    1. Shader "Vertex Color Splat Surf Shader" {
    2.     Properties {
    3.         _MainTex ("Base (RGB)", 2D) = "white" {}
    4.     }
    5.     SubShader {
    6.         Tags { "RenderType"="Transparent" }
    7.         LOD 200
    8.        
    9.         CGPROGRAM
    10.         #pragma surface surf BlinnPhong
    11.        
    12.         sampler2D _MainTex;
    13.  
    14.         struct Input {
    15.             float2 uv_MainTex;
    16.             float4 color: Color; // Vertex color
    17.         };
    18.  
    19.         void surf (Input IN, inout SurfaceOutput o) {
    20.             half4 c = tex2D (_MainTex, IN.uv_MainTex);
    21.             o.Albedo = c.rgb * (IN.color.rgb); // vertex RGB
    22.         }
    23.         ENDCG
    24.     }
    25.     FallBack "Diffuse"
    26. }
    $SplatErrorOutput.PNG

    Thanks!
     
  2. tpennetta

    tpennetta

    Joined:
    Jul 25, 2013
    Posts:
    18
    Soorry I have uploaded the wrong code. But I have an update to the problem. I am getting good output except for where there is both a mix of multiple colors in the Vertex Color. It seems to blow out the color as can be seen in the attached image.

    Updated code it:

    Code (csharp):
    1.  
    2. Shader "Vertex Color Splat Surf Shader" {
    3.     Properties {
    4.         _Splat1 ("Base (RGB)", 2D) = "white" {}
    5.         _Splat2 ("Base (RGB)", 2D) = "white" {}
    6.         _Splat3 ("Base (RGB)", 2D) = "white" {}
    7.     }
    8.     SubShader {
    9.         Tags { "RenderType"="Transparent" }
    10.         LOD 200
    11.        
    12.         CGPROGRAM
    13.         #pragma surface surf BlinnPhong
    14.        
    15.         sampler2D _Splat1;
    16.         sampler2D _Splat2;
    17.         sampler2D _Splat3;
    18.  
    19.         struct Input {
    20.             float2 uv_Splat1;
    21.             float2 uv_Splat2;
    22.             float2 uv_Splat3;
    23.             float4 color: Color; // Vertex color
    24.         };
    25.  
    26.         void surf (Input IN, inout SurfaceOutput o) {
    27.             half4 splat1 = tex2D (_Splat1, IN.uv_Splat1);
    28.             half4 splat2 = tex2D (_Splat2, IN.uv_Splat2);
    29.             half4 splat3 = tex2D (_Splat3, IN.uv_Splat3);
    30.             half4 vc = normalize(IN.color);
    31.             o.Albedo = splat1.rgb * vc.r; // vertex RGB
    32.             o.Albedo += splat2.rgb * vc.g;
    33.             o.Albedo += splat3.rgb * vc.b;
    34.             o.Albedo = saturate(o.Albedo);
    35.             o.Alpha = vc.a;
    36.         }
    37.         ENDCG
    38.     }
    39.     FallBack "Diffuse"
    40. }
    41.  
    Blown Out Color in Unity:


    Correct inside of Blender using Vertex Colors


    Thanks!
     
    Last edited: Mar 3, 2014
  3. tpennetta

    tpennetta

    Joined:
    Jul 25, 2013
    Posts:
    18
    Anyone wondering about a fix for this problem, it was the blending equation. Blending based on multiplication caused the blow out. Instead, I had to lerp between each channel in the vertex color map.

    The code is below:

    Code (csharp):
    1.  
    2. Shader "Vertex Color Splat Surf Shader" {
    3.     Properties {
    4.         _Splat1 ("Base (RGB)", 2D) = "white" {}
    5.         _Splat2 ("Base (RGB)", 2D) = "white" {}
    6.         _Splat3 ("Base (RGB)", 2D) = "white" {}
    7.     }
    8.     SubShader {
    9.         Tags { "RenderType"="Transparent" }
    10.         LOD 200
    11.        
    12.         CGPROGRAM
    13.         #pragma surface surf BlinnPhong
    14.        
    15.         sampler2D _Splat1;
    16.         sampler2D _Splat2;
    17.         sampler2D _Splat3;
    18.  
    19.         struct Input {
    20.             float2 uv_Splat1;
    21.             float2 uv_Splat2;
    22.             float2 uv_Splat3;
    23.             float4 color: Color; // Vertex color
    24.         };
    25.  
    26.         void surf (Input IN, inout SurfaceOutput o) {
    27.             half4 splat1 = tex2D (_Splat1, IN.uv_Splat1);
    28.             half4 splat2 = tex2D (_Splat2, IN.uv_Splat2);
    29.             half4 splat3 = tex2D (_Splat3, IN.uv_Splat3);
    30.             fixed3 albedo = lerp(splat1.rgb, splat2.rgb, IN.color.g);
    31.             albedo = lerp(albedo, splat3.rgb, IN.color.b);
    32.            
    33.             o.Albedo = albedo;
    34.  
    35.         }
    36.         ENDCG
    37.     }
    38.     FallBack "Diffuse"
    39. }
    40.  
     
  4. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    Ideally, you'd solve this by normalizing your vertex colours. This means making sure that for every vertex, your RGB values sum to 1. Your lerp solution is slightly more expensive in the shader, and replaces the blowing out problem with a precedence one: if there is a non-normalized colour in your vertices, then the visible proportions will not be correct. For instance, if you have RGB = (1, 1, 1) then you will only see Splat3.
     
  5. tpennetta

    tpennetta

    Joined:
    Jul 25, 2013
    Posts:
    18
    Thanks Daniel. I saw that recommendation out there as well. I did my vertex painting in Blender, and was under the impression that the total RGB values could not be greater than 1 in total, but had a suspicion that they were and that this would be my problem.

    I am not sure how to correctly normalize the incoming Vertex colors as you can see in my first shader, I tried to use the CG function normalize on the Vertex colors and still had no luck...
     
  6. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    The normalization should be done in Blender. I'm not too familiar with the program, but there ought to be a way to paint only normalized colour values for exactly this purpose.

    Fixing this sort of problem in a shader means you're doing extra math every frame that could've been done once in your modelling package.
     
  7. tpennetta

    tpennetta

    Joined:
    Jul 25, 2013
    Posts:
    18
    Yea you are right there. Unfortunately Blender does not seem to have a way to normalize the colors in vertex paint mode. However it does in Weight Painting. Perhaps I can find a way to hijack that capability, or export the weight paint to vertex colors.

    Thanks!
     
  8. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    You might be able to fix the issue using an AssetPostprocessor. The OnPostprocessModel() method would be the place to do it. The only thing is that you probably have to mark the mesh as readable to allow the post processor to modify it.
     
  9. stuepfnick

    stuepfnick

    Joined:
    Apr 19, 2017
    Posts:
    18
    @ tpennetta Although this thread is old, I should mention something, if someone stumbles over this (like me):
    The color will be too bright at transitions, as in the first code snippet you apply "normalize" to the color, which I assume is meant for vectors, as i.e. RGB(0.5/0.5/0) will become RGB(0.7/0.7/0), so will get the "length" of 1 unit in 3d space. Of course there is no length for color, but as they are all the same datatype …