Strange artifacts from blending textures

So I’ve tried to add another texture into my texture mixing machine(cough The shader). However, being a noob in this area, I can’t understand the logic error in my code. I seem to be getting very bad alpha artifacts? My script works, with two textures. I simply can’t transfer that logic into three.

SEE NEXT POST FOR UPDATE

Here is a screen shot and the code:
Large Picture

Shader Code

Shader "Hexagon"
{
    Properties
    {
        _MainTex ("Base (RGB)", 2D) = "white" {}
        _GridTex("Grid Texture", 2D) = "white" {}
        _BorderTex ("Border Texture", 2D) = "white" {}
        _UseGrid("Show Grid", Range (0, 1)) = 0
        _FOWTex("Fog of War Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags {"IgnoreProjector"="True" "RenderType"="Opaque"}
        LOD 200
        ZWrite Off
        Blend SrcAlpha OneMinusSrcAlpha
        CGPROGRAM
// Upgrade NOTE: excluded shader from OpenGL ES 2.0 because it does not contain a surface program or both vertex and fragment programs.
        #pragma exclude_renderers gles
        #pragma surface surf Lambert vertex:vert
      
        float4 BlendMethod( float4 a, float4 b ){
     
            return a * b;                     // Default
//            return (a+b-1);                 // Severe.
//            return (1-(1-a)*b);                // Nice effect (keeps white border) but inverts & lightens colors.
         
        }
     
        sampler2D _MainTex;
        sampler2D _GridTex;
        sampler2D _BlendTex;
        float _UseGrid;
        sampler2D _FOWTex;
        

        struct Input
        {
            float2 uv_MainTex;
            float2 uv2_BlendTex;
            float4 tangent;
            float4 color: Color; // Vertex color
            fixed underFOW;
        };

        void vert(inout appdata_full v, out Input o)
        {
            o.tangent = v.tangent;
         
         
            //determine FOW setting for this vertex
            o.underFOW = (fixed)v.tangent.z;
        }
       void surf (Input IN, inout SurfaceOutput o)
       {
         fixed4 mainCol = tex2D(_MainTex, IN.uv_MainTex);
          fixed4 texTwoCol = BlendMethod( tex2D(_BlendTex, IN.uv2_BlendTex), IN.color.rgba );
          fixed4 FOWCol = tex2D(_FOWTex, IN.tangent.xy);
  
          //FOWCol.a *= 1.3;
          
         fixed4 mainOutput = mainCol.rgba * (1.0 - texTwoCol.a);
         fixed4 blendOutput = texTwoCol.rgba * (1.0 - FOWCol.a);
         fixed4 FOWOutput = FOWCol.rgba * FOWCol.a;
      
         if(_UseGrid == 1)
         {
             fixed4 gridCol = tex2D(_GridTex, IN.tangent.xy);
             fixed4 gridOutput = gridCol.rgba;           
          
             if(IN.underFOW == 1)
             {
                 o.Albedo =  mainOutput.rgb + blendOutput.rgb + gridOutput.rgb +  FOWOutput.rgb;
                 o.Alpha = mainOutput.a + blendOutput.a + gridOutput.a + FOWOutput.a;
             }
             else
            {
                o.Albedo = ( mainOutput.rgb + blendOutput.rgb + gridOutput.rgb);
                 o.Alpha = ( mainOutput.a + blendOutput.a + gridOutput.a);
             }
         }
         else
         {
             if(IN.underFOW == 1)
             {
                 o.Albedo =  mainOutput.rgb + blendOutput.rgb +  FOWOutput.rgb;
                 o.Alpha = mainOutput.a + blendOutput.a + FOWOutput.a;
             }
             else
             {
                 o.Albedo = ( mainOutput.rgb + blendOutput.rgb);
                 o.Alpha = mainOutput.a + blendOutput.a;
             }
         }
       }
        ENDCG
    }
    FallBack "Diffuse"
}

Thank you guys, in advance! Sorry for being a noob, I just really have no clue what is going wrong and been at it all day.

LanDog :slight_smile:

After some more work, I’ve gotten it to work in the scene view, and the artifacts are now only in the game view.

Here is a screenshot and code:

Large Picture

Shader Code

Shader "Hexagon"
{
    Properties
    {
        _MainTex ("Base (RGB)", 2D) = "white" {}
        _GridTex("Grid Texture", 2D) = "white" {}
        _BorderTex ("Border Texture", 2D) = "white" {}
        _UseGrid("Show Grid", Range (0, 1)) = 0
        _FOWTex("Fog of War Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags {"IgnoreProjector"="True" "RenderType"="Opaque"}
        LOD 200
        ZWrite Off
        Blend SrcAlpha OneMinusSrcAlpha
        CGPROGRAM
// Upgrade NOTE: excluded shader from OpenGL ES 2.0 because it does not contain a surface program or both vertex and fragment programs.
        #pragma exclude_renderers gles
        #pragma surface surf Lambert vertex:vert
        
        float4 BlendMethod( float4 a, float4 b ){
       
            return a * b;                     // Default
//            return (a+b-1);                 // Severe.
//            return (1-(1-a)*b);                // Nice effect (keeps white border) but inverts & lightens colors.
           
        }
       
        sampler2D _MainTex;
        sampler2D _GridTex;
        sampler2D _BlendTex;
        float _UseGrid;
        sampler2D _FOWTex;
          

        struct Input
        {
            float2 uv_MainTex;
            float2 uv2_BlendTex;
            float4 tangent;
            float4 color: Color; // Vertex color
            fixed underFOW;
        };

        void vert(inout appdata_full v, out Input o)
        {
            o.tangent = v.tangent;
           
           
            //determine FOW setting for this vertex
            o.underFOW = (fixed)v.tangent.z;
        }
       void surf (Input IN, inout SurfaceOutput o)
       {
         fixed4 mainCol = tex2D(_MainTex, IN.uv_MainTex);
          fixed4 texTwoCol = BlendMethod( tex2D(_BlendTex, IN.uv2_BlendTex), IN.color.rgba );

         fixed4 mainOutput = mainCol.rgba * (1.0 - texTwoCol.a);
         fixed4 blendOutput = texTwoCol.rgba * texTwoCol.a;
        
         if(_UseGrid == 1)
         {
             fixed4 gridCol = tex2D(_GridTex, IN.tangent.xy);
             fixed4 gridOutput = gridCol.rgba * gridCol.a;             
            
             if(IN.underFOW == 1)
             {
                 fixed4 FOWCol = tex2D(_FOWTex, IN.tangent.xy);
                 fixed4 FOWOutput = FOWCol.rgba;
            
                 o.Albedo =  mainOutput.rgb + blendOutput.rgb + gridOutput.rgb + FOWOutput.rgb;
                 o.Alpha = mainOutput.a + blendOutput.a + gridOutput.a;// + FOWOutput.a;
             }
             else
            {
                o.Albedo = ( mainOutput.rgb + blendOutput.rgb + gridOutput.rgb);
                 o.Alpha = ( mainOutput.a + blendOutput.a + gridOutput.a);
             }
         }
         else
         {
             if(IN.underFOW == 1)
             {
                 fixed4 FOWCol = tex2D(_FOWTex, IN.tangent.xy);
                 fixed4 FOWOutput = FOWCol.rgba;
        
                 o.Albedo =  mainOutput.rgb + blendOutput.rgb + FOWOutput.rgb;
                 o.Alpha = mainOutput.a + blendOutput.a;// + FOWOutput.a;
             }
             else
             {
                 o.Albedo = ( mainOutput.rgb + blendOutput.rgb);
                 o.Alpha = mainOutput.a + blendOutput.a;
             }
         }
       }
        ENDCG
    }
    FallBack "Diffuse"
}

I just made some tiny little changes, not sure why and where it’s being effected.

What’s the FOWCol value?

If they’re tangents, they’ll get modified as the batching comes into play (they get rotated along with the normals - as if they were vectors, regardless of what you’re storing in there) and so might not show what you’re after in-game…

1 Like

I’m trying to use tangents as an extra uv channel. Is there anyway to counter-act or disable the batching?

You could disable batching, yeah. It’s in your build settings I think.

There’s static and dynamic batching.

Any reason you’re not using UV channel 2 as extra UVs?

1 Like

Ok, thanks I’ll try that tonight.

I’m using the uv channels as such:

UV: Location of diffuse texture in texture atlas.
UV2: Location of border texture in its own texture atlas.
Tangent: Standard mapped to cover a standard texture.

Would it possibly be better to say, attempt to convert the first one into the second, in the shader? I would think it’d be better to cache it one the mono side, and send it in.

You might be able to use vertex colour for the border texture location?

If it’s an atlas and there’s not many tiles in the atlas, you might be alright (vertex colours are clamped 0-1 and only use 8bit precision rather than floating point).

1 Like

Oops, forgot to mention that vertex colors are used to color the borders. Sorry, about that!

Tangents and normals are the only things left, that is standard. I think normals are needed for the surface shader? So I was trying to use tangents four values to pass some extra data in. Is there a better way?

I don’t think so, sounds like you’ve used everything up!

So yeah, disabling batching sounds like your best bet there - or I think that ensuring that your tiles remain unrotated should mean that the batching doesn’t touch the normals or tangents (moving them around should be fine… scaling should be ok, I think?).

1 Like

Hmm, well this is disappointing. This work is for a framework, and so I can’t expect customers to disable batching. I saw in Unity 5.0 that there are 4 uv channels, but the framework is nearing completion in a few weeks. Not a few months.

On topic, where do you disable batching? I couldn’t find it, just trying to determine if thats the problem indeed.

I think it’s in the player settings for the project.

By default, non-Pro version only has dynamic batching (game spends time at run-time combining meshes together).
Pro version has static batching (objects marked as static are combined into a big mesh at build-time, so you don’t waste time later combining them during run-time).

1 Like

Is there no way to do this with two mapping channels?

I can imagine each tile simply has a flat mapping in channel 1. With just a diffuse texture applied all tiles will look the same to start out with.

Then you replace the simple diffuse texture with a texture atlas that contains all the different tiles. This can go for a normal map or others in the same way.

A secondary texture contains offsets in the atlas. Each tile is mapped to a single pixel in this secondary texture in channel 2.

// No filtering or mipmaps on the offset texture!
float2 offset = tex2D(offset_sampler, input.uv1);
float3 diffuse = tex2D(diffuse_sampler, offset + 0.25 * input.uv0);

It would even be possible to place the offsets in channel 2 directly.

float3 diffuse = tex2D(diffuse_sampler, input.uv1 + 0.25 * input.uv0);

I don’t think we are on the same page here. I use one channel for the diffuse mapping. The first uv channel contains the uv mapping for the diffuse texture in the texture atlas. The second channel has the mapping for the border texture atlas. This is mapped completely different. Vertex colors are used to tint the border texture. Now, I’m trying to use tangents are a third channel, to hold the 1:1 mapping where the uv fills the entire area.

@Aras

Would it be possible to have a patch release of the four uv channels?

Regress it back to 4.6 or such? It’s really a feature that can’t be worked around.

Doing that required rewriting all of vertex buffer code for someone (since it was, uhm, not terribly clever before), and was several months of work. It’s not something that can be easily brought back to 4.x :frowning: