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

Custom toon shader not compiling on mobile.

Discussion in 'Shaders' started by melong, Jul 31, 2012.

  1. melong

    melong

    Joined:
    Sep 2, 2011
    Posts:
    22
    Hi !
    I am currently working on this GLSL toon shader which combine features i couldn't find in other available shaders online.
    Although i am still quite a newbie in shader programming i did manage to get it working fine in the unity editor.
    The problem is that the shader wouldn't compile on android and i lack the programmer's knowledge to be able to debug this by myself, so maybe you could help me point out what obvious mistake i may have done.

    To sum it up, it uses two color textures (lit and unlit) that render according to a normal map and a ramp map (stored in the lit color texture's alpha channel). There is an addtional rim effect (masked through model's vertex red color) and specular effect on metallic parts (with a specular map stored in the unlit color texture's alpha channel) .
    Here's the shader code:

    Code (csharp):
    1.  
    2. Shader "GLSL/ToonDetailRampRimSpecular"
    3. {
    4.    Properties
    5.    {
    6.       _LitColor ("Lit Color Map(RGB) Ramp(A)", 2D) = "black" {}
    7.       _UnlitColor ("Unlit Color Map(RGB) Specular(A)", 2D) = "black" {}
    8.       _BumpMap ("Normal Map", 2D) = "bump" {}
    9.       _RimColor ("Rim Color", Color) = (0.97,0.88,1,0.75)
    10.       _RimPower ("Rim Power", Float) = 2.5
    11.       _RimDirection ("Rim Direction Vector (XYZ)", Vector) = (1, 0, 0, 0)
    12.       _SpecColor ("Specular Color", Color) = (1,1,1,1)
    13.       _Shininess ("Shininess", Float) = 10
    14.    }
    15.    SubShader
    16.    {
    17.       Pass
    18.       {      
    19.          Tags { "LightMode" = "ForwardBase" }
    20.  
    21.          GLSLPROGRAM
    22.  
    23.          // User-specified properties
    24.          uniform mediump sampler2D _LitColor;
    25.          uniform mediump sampler2D _UnlitColor;
    26.          uniform mediump sampler2D _BumpMap;
    27.          uniform vec4 _BumpMap_ST;
    28.          uniform vec4 _RimColor;
    29.          uniform float _RimPower;
    30.          uniform vec4 _RimDirection;
    31.          uniform vec4 _SpecColor;
    32.          uniform float _Shininess;
    33.  
    34.          // Built-in properties
    35.          uniform vec3 _WorldSpaceCameraPos; // camera position in world space
    36.          uniform mat4 _Object2World; // model matrix
    37.          uniform mat4 _World2Object; // inverse model matrix
    38.          uniform vec4 _WorldSpaceLightPos0; // direction to or position of light source
    39.          uniform vec4 _LightColor0; // color of light source
    40.  
    41.          // Varying variables for passing data from vertex to fragment
    42.          varying vec4 position; // position of the vertex (and fragment) in world space
    43.          varying mediump vec4 vertexColor; // vertex color
    44.          varying mediump vec4 uv; // uv coordinates
    45.          varying mat3 localSurface2World; // mapping from local surface coordinates to world coordinates
    46.  
    47.          #ifdef VERTEX
    48.  
    49.          attribute vec4 Tangent;
    50.  
    51.          void main()
    52.          {                                
    53.             mat4 modelMatrix = _Object2World;
    54.             mat4 modelMatrixInverse = _World2Object;
    55.  
    56.             localSurface2World[0] = normalize(vec3(modelMatrix * vec4(vec3(Tangent), 0.0)));
    57.             localSurface2World[2] = normalize(vec3(vec4(gl_Normal, 0.0) * modelMatrixInverse));
    58.             localSurface2World[1] = normalize(cross(localSurface2World[2], localSurface2World[0]) * Tangent.w);
    59.  
    60.             position = modelMatrix * gl_Vertex; // vertex position in world space
    61.             vertexColor = gl_Color; // get vertex color from model
    62.             uv = gl_MultiTexCoord0; // get uv coordinates from model
    63.             gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; //vertex position in screen space
    64.          }
    65.  
    66.          #endif
    67.  
    68.          #ifdef FRAGMENT
    69.  
    70.          void main()
    71.          {
    72.             // maps
    73.             vec4 diffuseunlit = texture2D(_UnlitColor, uv.xy);
    74.             vec4 diffuselit = texture2D(_LitColor, uv.xy);
    75.             vec4 encodedNormal = texture2D(_BumpMap, _BumpMap_ST.xy * uv.xy + _BumpMap_ST.zw);
    76.  
    77.             // normal direction from normal map
    78.             vec3 localCoords = vec3(2.0 * encodedNormal.ag - vec2(1.0), 0.0);
    79.             localCoords.z = sqrt(1.0 - dot(localCoords, localCoords));
    80.             vec3 normalDirection = normalize(localSurface2World * localCoords);
    81.  
    82.             // view direction
    83.             vec3 viewDirection = normalize(_WorldSpaceCameraPos - vec3(position));
    84.  
    85.             // light direction and attenuation
    86.             vec3 lightDirection;
    87.             float attenuation;
    88.             // directional light?
    89.             if (0.0 == _WorldSpaceLightPos0.w)
    90.             {
    91.                attenuation = 1.0; // no attenuation
    92.                lightDirection = normalize(vec3(_WorldSpaceLightPos0));
    93.             }
    94.             // point or spot light
    95.             else
    96.             {
    97.                vec3 vertexToLightSource = vec3(_WorldSpaceLightPos0 - position);
    98.                float distance = length(vertexToLightSource);
    99.                attenuation = 1.0 / distance; // linear attenuation
    100.                lightDirection = normalize(vertexToLightSource);
    101.             }
    102.  
    103.             // ramp texture coordinates
    104.             float NdotL = dot(normalDirection, lightDirection) * 0.5 + 0.5;
    105.             vec4 ramp = texture2D(_LitColor, vec2(NdotL * attenuation, 0.0));
    106.  
    107.             // rim light
    108.             vec3 rim = pow(max(0, dot(vec3(_RimDirection), normalDirection)), _RimPower) * _RimColor.rgb;
    109.  
    110.             // diffuse
    111.             vec3 fragmentColor = mix(vec3(diffuseunlit), vec3(diffuselit), ramp.a) + rim * vertexColor.r;
    112.  
    113.             // specular
    114.             float specularPower;
    115.             if (dot(normalDirection, lightDirection) > 0.0)
    116.             {
    117.                specularPower = pow(max(0.0, dot(reflect(-lightDirection, normalDirection), viewDirection)), _Shininess) * 0.5 + 0.5;
    118.                vec4 specularReflection = texture2D(_LitColor, vec2(specularPower * attenuation, 0.0));
    119.                fragmentColor = fragmentColor + vec3(_SpecColor) * specularReflection.a * diffuseunlit.a;
    120.             }
    121.            
    122.             // final color
    123.             gl_FragColor = vec4(fragmentColor, 1.0);
    124.          }
    125.  
    126.          #endif
    127.  
    128.          ENDGLSL
    129.       }
    130.    }
    131. }
    132.  
    I know that the unity "official" shader language to be used is CG and i did a few attempt at converting it to cg but untill now i failed as lack knowledge of this language to reproduce all the good stuff i have in my GLSL shader :)

    Thanks!


    EDIT: I just isolated what is actually making this shader to not compile on my phone. It is the max() function in the rim light.
    I rewrote the line as follows:
    Code (csharp):
    1.  
    2.             vec3 rimVector = vec3(_RimDirection);
    3.             float RDotN = dot(rimVector, normalDirection);
    4.             float maxRDotN = max(0, RDotN);
    5.             float powerRim = pow(maxRDotN, _RimPower);
    6.             vec3 rim = powerRim * _RimColor.rgb;
    7.  
    then commented out the max function like here:
    Code (csharp):
    1.  
    2.             vec3 rimVector = vec3(_RimDirection);
    3.             float RDotN = dot(rimVector, normalDirection);
    4.             //float maxRDotN = max(0, RDotN);
    5.             float powerRim = pow(RDotN, _RimPower);
    6.             vec3 rim = powerRim * _RimColor.rgb;
    7.  
    And now the shader compile on my phone (i have other problems though, but one at a time ^^)
    Any thought of what could cause this ?
     
    Last edited: Jul 31, 2012