Search Unity

  1. If you have experience with import & exporting custom (.unitypackage) packages, please help complete a survey (open until May 15, 2024).
    Dismiss Notice
  2. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice

iPhone Shaders: Simple diffuse with alpha and Lightmap

Discussion in 'iOS and tvOS' started by MatthewScott, Sep 16, 2009.

  1. MatthewScott

    MatthewScott

    Joined:
    Aug 25, 2008
    Posts:
    40
    Hi all,

    To make sure we're as optimized as possible, we've put together all of our own shaders for the iPhone. Sometimes the layers of fallback shaders make it hard to know if you're getting the most efficient shader for the iPhone. These are cobbled together from various samples, so I didn't create them from scratch.

    One is a simple diffuse texture for unlit characters with baked lighting in their diffuse texture that supports alpha testing. The other is a lightmap shader.

    I'm struggling to write a shader for our lightmapped objects that require alpha testing or alpha blending. The lightmap alpha testing shader would be a combination of these two shaders below. Any help would be appreciated.

    Otherwise, I've seen requests for these two shaders elsewhere. Enjoy.

    Here is our simple "no lighting" diffuse texture shader that supports alpha testing (cutout).

    Code (csharp):
    1.  
    2. Shader "Unlit Diffuse Alpha" {
    3. Properties {
    4.     _Color ("Color Tint", Color) = (1,1,1,1)
    5.     _MainTex ("Base (RGB) Alpha (A)", 2D) = "white" {}
    6.     _Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
    7. }
    8.  
    9. SubShader {
    10.     Cull Off
    11.     Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="TransparentCutoff"}
    12.     Pass {
    13.         Alphatest Greater [_Cutoff]
    14.         AlphaToMask True
    15.         ColorMask RGB
    16.  
    17.         SetTexture [_MainTex] {
    18.             Combine texture, texture
    19.         }
    20.     }
    21. }
    22.  
    23. }
    24.  
    And here is our simple lightmap diffuse shader that we use for lightmaping our scenes. This is a two pass shader that multiplies the lightmap texture with the color constant and the diffuse text.

    Code (csharp):
    1.  
    2. Shader "Unlit Lightmap Diffuse" {
    3.  
    4. Properties {
    5.     _Color ("Main Color", Color) = (1,1,1,1)
    6.     _MainTex ("Base (RGB)", 2D) = "white"
    7.     _LightMap ("Lightmap (RGB)", 2D) = "white"
    8. }
    9.    
    10. SubShader {
    11.     Cull Back
    12.    
    13.    // Base pass: lightmap
    14.    Pass {
    15.       Name "LIGHTMAP"
    16.       Tags {"LightMode" = "Always"}
    17.       BindChannels {
    18.          Bind "Vertex", vertex
    19.          Bind "texcoord1", texcoord0 // lightmap uses 2nd uv
    20.       }
    21.       SetTexture [_LightMap] { constantColor [_Color] combine texture * constant DOUBLE }
    22.    }
    23.    
    24.    // Second pass: modulate with texture
    25.    Pass {
    26.       Name "BASE"
    27.       Tags {"LightMode" = "Always"}
    28.       BindChannels {
    29.          Bind "Vertex", vertex
    30.          Bind "texcoord", texcoord0 // main uses 1st uv
    31.       }
    32.       Blend Zero SrcColor
    33.       SetTexture [_MainTex] { combine texture }
    34.    }
    35. }  
    36. }
    37.  
    Thanks,
    Matthew Scott
    Manifest Games
     
  2. moctezumagames

    moctezumagames

    Joined:
    Jun 9, 2009
    Posts:
    395
    thank you a lot!
    are those on unitedWiki? If not... it may be a better place for the resource!
     
  3. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    I didn't go deep enough into shader lab stuff, so this might sound noobish:
    Thats about the 3rd shader I've seen that uses two passes for lightmap. I've worked with DX7 and FFP for a long time and there you could put that all into a single pass.

    The iphone has 2 texture units which allows 2 textures in parallel so something like lightmapping theoretically should work in 1 pass shouldn't it? (don't see how the color influences it as it ends on the vertex color, at least I really hope that it does not introduce a virtual 1x1 texture to tint)

    Am I missing something on that thinking?
     
  4. MatthewScott

    MatthewScott

    Joined:
    Aug 25, 2008
    Posts:
    40
    You're right. There are 2 texture units.
    But I don't know if you can have two different blend settings in the same pass. You'll notice that the 2nd pass uses Blend Zero SrcColor to blend the main texture with the lightmap.

    I'll see if I can optimize it, but so far I'm not taking a rendering hit on the device.

    Any ideas for how to do the lightmap shader with alpha testing?

    Thanks,
    Matthew Scott
    Manifest Games
     
  5. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    Don't use alpha testing on the iphone but alpha blending.
    Alpha testing is considerably slower than blending.

    As for the rendering hit: each pass renders the object once again, which means another draw call and another time its geometry. But you might be low enough on both to not feel the impact or not have one of the normal devices but a high speed one (3GS or itouch 2nd gen)
     
  6. n0mad

    n0mad

    Joined:
    Jan 27, 2009
    Posts:
    3,732
    Actually, you are forced to use Alpha testing, because Alpha blending can't manage depth properly.

    In short, with alpha blending, you'll have perfect alpha blends, with no "cut edges" on your textures, but all the objects using semi-transparency will mask other parts of the same texture if it's placed behind.

    Here is the doc explaining it : http://unity3d.com/support/documentation/Components/SL-AlphaTest.html

    That's why in order to use lightmaps, or self illuminated maps, with integrated semi transparent
    zones, you'll have to make it 2 pass, alpha test. :)

    Here is one I wrote, putting 2 pass self illum + alpha, based on Aras ones :

    Code (csharp):
    1. Shader "_SelfIllumAlpha" {
    2.   Properties {
    3.         _Color ("Main Color", Color) = (1,1,1,1)
    4.    _SpecColor ("Spec Color", Color) = (1,1,1,1)
    5.    _Shininess ("Shininess", Range (0.1, 1)) = 0.8
    6.    _MainTex ("Base (RGB)", 2D) = "white" {}
    7.    _SelfIllum ("Illumin (A)", 2D) = "bump" {}
    8.    _Cutoff ("Base Alpha cutoff", Range (0,.9)) = .95
    9.     }
    10.  
    11.   SubShader {
    12.   Tags {"RenderType"="Transparent" "Queue"="Transparent" "IgnoreProjector"="True"}
    13.        SeparateSpecular On
    14.       Lighting On
    15.  
    16.      
    17.    // Vertex lights
    18.    Pass {
    19.      
    20.       Tags {"LightMode" = "Vertex"}
    21.       Material {
    22.          Diffuse [_Color]
    23.          Emission [_PPLAmbient]
    24.          Shininess [_Shininess]
    25.          Specular [_SpecColor]
    26.       }
    27.      
    28.       ZWrite On
    29.       AlphaTest GEqual [_Cutoff]
    30.  
    31.       SetTexture [_SelfIllum] {
    32.          constantColor (.5,.5,.5)
    33.          combine constant lerp (texture) primary
    34.       }
    35.       SetTexture [_MainTex] {
    36.          Combine texture * previous DOUBLE, texture
    37.       }
    38.    }
    39.    
    40.    Pass {
    41.        
    42.          ZWrite off
    43.          AlphaTest Less [_Cutoff]
    44.  
    45.          // Set up alpha blending
    46.          Blend SrcAlpha OneMinusSrcAlpha
    47.  
    48.          
    49.      SetTexture [_SelfIllum] {
    50.          constantColor (.5,.5,.5)
    51.          combine constant lerp (texture) primary
    52.       }
    53.       SetTexture [_MainTex] {
    54.          Combine texture * previous DOUBLE, texture
    55.       }
    56.  
    57.       }
    58. }
    59.  
    60.  
    61.  
    62. }
    My selfillum process takes the alpha layer of a separate map, but could work with black white, using addition instead of lerping in the selfillum texture pass. But I found lerping more realistic than black white.

    Another difference is this shader don't use 2 UVs, as the selfillum map don't require high pixel precision, it can be based on the base texture positions, and resized to 256x256 pixels.
    I prefer this method because of the faster workflow, but it could be better for some other cases to set 2 separate UVs.


    I can't access my home macbook now, but I remember having jumped to a more optimized than this one. I will update it tonight.

    Still, it works.

    But actually, if a better solution exists, I'm really interested !
     
  7. rooney

    rooney

    Joined:
    Nov 9, 2009
    Posts:
    3
    Hi, all. First of all, I'm a newbie and thanks to MatthewScott.
    I needed a shader of lightmap + cutoff for trees, buildings, etc.
    The alpha value is in main texture.
    I mixed a shader and It seems to work.
    But I'm worried about the shader's performance and properness.
    Or another good solution is welcome.

    Code (csharp):
    1.  
    2. Shader "Tree" {
    3.     Properties {
    4.         _Color ("Main Color", Color) = (1,1,1,1)
    5.         _MainTex ("Base (RGB)", 2D) = "white" {}
    6.         _Cutoff ("Alpha Cutoff", Range(0,1)) = 0.5
    7.         _LightMap ("Lightmap (RGB)", 2D) = "white" {}
    8.     }
    9.     SubShader {
    10.         Cull Off
    11.         Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="TransparentCutoff"}
    12.  
    13.         Pass {
    14.           Name "LIGHTMAP"
    15.           Tags {"LightMode" = "Always"}
    16.           BindChannels {
    17.              Bind "Vertex", vertex
    18.              Bind "texcoord1", texcoord0 // lightmap uses 2nd uv
    19.              Bind "texcoord", texcoord1 // alphamap uses 1nd uv
    20.           }
    21.            
    22.           Alphatest Greater [_Cutoff]
    23.           AlphaToMask True
    24.           ColorMask RGB
    25.          
    26.           SetTexture [_LightMap] { constantColor [_Color] combine texture * constant DOUBLE }
    27.           SetTexture [_MainTex] { combine previous * texture, texture }
    28.          
    29.         }
    30.     }
    31. }
    32.  
     
  8. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    AlphaTest generally isn't a good idea unless its really needed because the iphone gpu is opted for alpha blending, not testing.

    Also the Lightmode Tag isn't required as you only have vertex.
     
  9. rooney

    rooney

    Joined:
    Nov 9, 2009
    Posts:
    3
    Thanks dreamora.
    I removed Lightmode. and tried removing AlphaTest.
    But because of depth, trees seems to need AlphaTest.
    So, I decided separate the shader.
    Basically most uses AlphaBlend shader, and the rest uses AlphaTest shader.
    How about this?

    Code (csharp):
    1.  
    2. Shader "Tree" {
    3.     Properties {
    4.         _Color ("Main Color", Color) = (1,1,1,1)
    5.         _MainTex ("Base (RGB)", 2D) = "white" {}
    6.         _Cutoff ("Alpha Cutoff", Range(0,1)) = 0.5
    7.         _LightMap ("Lightmap (RGB)", 2D) = "white" {}
    8.     }
    9.     SubShader {
    10.         Cull Off
    11.         Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="TransparentCutoff"}
    12.         Pass {
    13.           BindChannels {
    14.              Bind "Vertex", vertex
    15.              Bind "texcoord1", texcoord0 // lightmap uses 2nd uv
    16.              Bind "texcoord", texcoord1 // alphamap uses 1nd uv
    17.           }
    18.            
    19.           Alphatest Greater [_Cutoff]
    20.           AlphaToMask True
    21.           ColorMask RGB
    22.          
    23.           SetTexture [_LightMap] { constantColor [_Color] combine texture * constant DOUBLE }
    24.           SetTexture [_MainTex] { combine previous * texture, texture }
    25.          
    26.         }
    27.     }
    28. }
    29.  
    Code (csharp):
    1.  
    2. Shader "Building" {
    3.     Properties {
    4.         _Color ("Main Color", Color) = (1,1,1,1)
    5.         _MainTex ("Base (RGB)", 2D) = "white" {}
    6.         _LightMap ("Lightmap (RGB)", 2D) = "white" {}
    7.     }
    8.     SubShader {
    9.         Tags {"Queue"="Transparent" "IgnoreProjector"="True"}
    10.         Pass {
    11.           BindChannels {
    12.              Bind "Vertex", vertex
    13.              Bind "texcoord1", texcoord0 // lightmap uses 2nd uv
    14.              Bind "texcoord", texcoord1 // alphamap uses 1nd uv
    15.           }
    16.            
    17.           Blend SrcAlpha OneMinusSrcAlpha
    18.          
    19.           SetTexture [_LightMap] { constantColor [_Color] combine texture * constant DOUBLE }
    20.           SetTexture [_MainTex] { combine previous * texture, texture }
    21.         }
    22.     }
    23. }
    24.