{
  "__type__": "cc.EffectAsset",
  "_name": "builtin-toon",
  "_objFlags": 0,
  "_native": "",
  "properties": null,
  "techniques": [
    {
      "passes": [
        {
          "rasterizerState": {
            "cullMode": 1028
          },
          "program": "builtin-toon|outline-vs:vert|outline-fs:frag",
          "depthStencilState": {
            "depthTest": true,
            "depthWrite": true
          },
          "properties": {
            "lineWidth": {
              "value": [
                10
              ],
              "type": 13
            },
            "depthBias": {
              "value": [
                0
              ],
              "type": 13
            },
            "outlineBaseColor": {
              "value": [
                0,
                0,
                0,
                1
              ],
              "inspector": {
                "type": "color"
              },
              "type": 16
            },
            "outlineBaseColorMap": {
              "value": "gray",
              "type": 29
            }
          }
        },
        {
          "program": "builtin-toon|toon-vs:vert|toon-fs:frag",
          "depthStencilState": {
            "depthTest": true,
            "depthWrite": true
          },
          "properties": {
            "tilingOffset": {
              "value": [
                1,
                1,
                0,
                0
              ],
              "type": 16
            },
            "normalMap": {
              "value": "normal",
              "type": 29
            },
            "baseColorMap": {
              "value": "white",
              "type": 29
            },
            "specular": {
              "value": [
                1,
                1,
                1,
                0.5
              ],
              "inspector": {
                "type": "color"
              },
              "type": 16
            },
            "specularMap": {
              "value": "white",
              "type": 29
            },
            "specularThreshold": {
              "value": [
                0.5
              ],
              "type": 13
            },
            "emissive": {
              "value": [
                0,
                0,
                0,
                1
              ],
              "inspector": {
                "type": "color"
              },
              "type": 16
            },
            "shadowColor": {
              "value": [
                0,
                0,
                0,
                1
              ],
              "inspector": {
                "type": "color"
              },
              "type": 16
            },
            "shadowIntensity": {
              "value": [
                0.5
              ],
              "type": 13
            },
            "highlightColor": {
              "value": [
                1,
                1,
                1,
                1
              ],
              "inspector": {
                "type": "color"
              },
              "type": 16
            },
            "lightThreshold": {
              "value": [
                0.5
              ],
              "type": 13
            },
            "lightSmoothness": {
              "value": [
                0.1
              ],
              "type": 13
            }
          }
        }
      ]
    }
  ],
  "shaders": [
    {
      "hash": 3685250997,
      "glsl3": {
        "vert": "\nprecision highp float;\nuniform CCGlobal {\n  vec4 cc_time;\n\n  vec4 cc_screenSize;\n\n  vec4 cc_screenScale;\n\n  vec4 cc_nativeSize;\n\n  mat4 cc_matView;\n  mat4 cc_matViewInv;\n  mat4 cc_matProj;\n  mat4 cc_matProjInv;\n  mat4 cc_matViewProj;\n  mat4 cc_matViewProjInv;\n  vec4 cc_cameraPos;\n\n  vec4 cc_exposure;\n\n  vec4 cc_mainLitDir;\n\n  vec4 cc_mainLitColor;\n\n  vec4 cc_ambientSky;\n  vec4 cc_ambientGround;\n};\nuniform CCLocal {\n  mat4 cc_matWorld;\n  mat4 cc_matWorldIT;\n};\n\nstruct StandardAttributes {\n  vec2 uv;\n  vec4 position;\n  vec3 normal;\n  vec4 tangent;\n  vec4 color;\n};\n\nin vec3 a_position;\n\n#if CC_USE_ATTRIBUTE_UV0\nin vec2 a_uv0;\n#endif\n\n#if CC_USE_ATTRIBUTE_COLOR\nin vec4 a_color;\n#endif\n\n#if CC_USE_ATTRIBUTE_NORMAL\nin vec3 a_normal;\n#endif\n\n#if CC_USE_ATTRIBUTE_TANGENT\nin vec4 a_tangent;\n#endif\n\nvoid CCAttribute (out StandardAttributes attr) {\n  attr.position = vec4(a_position, 1.0);\n\n  #if CC_USE_ATTRIBUTE_UV0\n    attr.uv = a_uv0;\n  #else\n    attr.uv = vec2(0.0);\n  #endif\n  \n  #if CC_USE_ATTRIBUTE_COLOR\n    attr.color = a_color;\n  #else\n    attr.color = vec4(1.0);\n  #endif\n  \n  #if CC_USE_ATTRIBUTE_NORMAL\n    attr.normal = a_normal;\n  #else\n    attr.normal = vec3(0.0, 1.0, 0.0);\n  #endif\n\n  #if CC_USE_ATTRIBUTE_TANGENT\n    attr.tangent = a_tangent;\n  #else\n    attr.tangent = vec4(1.0, 0.0, 0.0, 0.0);\n  #endif\n}\n\n#if CC_USE_SKINNING\n\n#if CC_USE_SKINNING\n\n  in vec4 a_weights;\n  in vec4 a_joints;\n\n  #if CC_USE_JOINTS_TEXTRUE\n    uniform SKINNING {\n      vec2 cc_jointsTextureSize;\n    }\n    uniform sampler2D cc_jointsTexture;\n\n    #if CC_JOINTS_TEXTURE_FLOAT32\n      mat4 getBoneMatrix(const in float i) {\n        float width = cc_jointsTextureSize.x;\n        float height = cc_jointsTextureSize.y;\n        float j = i * 4.0;\n        float x = mod(j, width);\n        float y = floor(j / width);\n\n        float dx = 1.0 / width;\n        float dy = 1.0 / height;\n\n        y = dy * (y + 0.5);\n\n        vec4 v1 = texture2D(cc_jointsTexture, vec2(dx * (x + 0.5), y));\n        vec4 v2 = texture2D(cc_jointsTexture, vec2(dx * (x + 1.5), y));\n        vec4 v3 = texture2D(cc_jointsTexture, vec2(dx * (x + 2.5), y));\n        vec4 v4 = texture2D(cc_jointsTexture, vec2(dx * (x + 3.5), y));\n\n        return mat4(v1, v2, v3, v4);\n      }\n    #else\n      float decode32(vec4 rgba) {\n        float Sign = 1.0 - step(128.0, rgba[0]) * 2.0;\n        float Exponent = 2.0 * mod(rgba[0], 128.0) + step(128.0, rgba[1]) - 127.0;\n        float Mantissa = mod(rgba[1], 128.0) * 65536.0 + rgba[2] * 256.0 + rgba[3] + 8388608.0;\n        return Sign * exp2(Exponent - 23.0) * Mantissa;\n      }\n      vec4 decodevec4 (vec4 x, vec4 y, vec4 z, vec4 w) {\n\n        return vec4(\n          decode32(x.wzyx * 255.0),\n          decode32(y.wzyx * 255.0),\n          decode32(z.wzyx * 255.0),\n          decode32(w.wzyx * 255.0)\n        );\n      }\n\n      vec4 decodevec4 (float dx, float x, float y) {\n        return decodevec4(\n          texture2D(cc_jointsTexture, vec2(dx * (x + 0.5), y)),\n          texture2D(cc_jointsTexture, vec2(dx * (x + 1.5), y)),\n          texture2D(cc_jointsTexture, vec2(dx * (x + 2.5), y)),\n          texture2D(cc_jointsTexture, vec2(dx * (x + 3.5), y))\n        );\n      }\n\n      mat4 getBoneMatrix(const in float i) {\n        float width = cc_jointsTextureSize.x;\n        float height = cc_jointsTextureSize.y;\n        float j = i * 16.0;\n        float x = mod(j, width);\n        float y = floor(j / width);\n\n        float dx = 1.0 / width;\n        float dy = 1.0 / height;\n\n        y = dy * (y + 0.5);\n\n        vec4 v1 = decodevec4(dx, x,       y);\n        vec4 v2 = decodevec4(dx, x+4.0,   y);\n        vec4 v3 = decodevec4(dx, x+8.0,   y);\n        vec4 v4 = decodevec4(dx, x+12.0,  y);\n\n        return mat4(v1, v2, v3, v4);\n      }\n    #endif\n  #else\n    uniform CC_JOINT_MATRIX {\n      mat4 cc_jointMatrices[50];\n    }\n\n    mat4 getBoneMatrix(const in float i) {\n      return cc_jointMatrices[int(i)];\n    }\n  #endif\n\n    mat4 skinMatrix() {\n      return\n        getBoneMatrix(a_joints.x) * a_weights.x +\n        getBoneMatrix(a_joints.y) * a_weights.y +\n        getBoneMatrix(a_joints.z) * a_weights.z +\n        getBoneMatrix(a_joints.w) * a_weights.w\n        ;\n    }\n#endif\n\nvoid SKIN_VERTEX(inout vec4 a1) {\n  #if CC_USE_SKINNING\n    mat4 m = skinMatrix();\n    a1 = m * a1;\n  #endif\n}\n\nvoid SKIN_VERTEX(inout vec4 a1, inout vec4 a2) {\n  #if CC_USE_SKINNING\n    mat4 m = skinMatrix();\n    a1 = m * a1;\n    a2 = m * a2;\n  #endif\n}\n\nvoid SKIN_VERTEX(inout vec4 a1, inout vec4 a2, inout vec4 a3) {\n  #if CC_USE_SKINNING\n    mat4 m = skinMatrix();\n    a1 = m * a1;\n    a2 = m * a2;\n    a3 = m * a3;\n  #endif\n}\n\n  void CCSkin(inout StandardAttributes attr) {\n    mat4 m = skinMatrix();\n    attr.position = m * attr.position;\n    attr.normal = (m * vec4(attr.normal, 0)).xyz;\n    attr.tangent = m * attr.tangent;\n  }\n#endif\n\nstruct StandardVertInput {\n  vec2 uv;\n  vec4 position;\n  vec3 normal;\n  vec4 tangent;\n  vec4 color;\n};\n\nvoid CCAttrToInput (in StandardAttributes attr, out StandardVertInput In) {\n  In.position = attr.position;\n  In.normal = attr.normal;\n  In.tangent = attr.tangent;\n  In.uv = attr.uv;\n  In.color = attr.color;\n}\n\nvoid CCVertInput (out StandardVertInput In) {\n  StandardAttributes attr;\n  CCAttribute(attr);\n  #if CC_USE_SKINNING\n    CCSkin(attr);\n  #endif\n  CCAttrToInput(attr, In);\n}\n\nout vec2 v_uv;\n\nuniform OutlineVert {\n  float lineWidth;\n  float depthBias;\n};\n\nvec4 vert () {\n  StandardVertInput In;\n  CCVertInput(In);\n\n  float width = lineWidth * 0.001;\n\n  #if USE_POSITION_SCALING\n    vec3 dir = normalize(In.position.xyz);\n    float flip = dot(dir, normalize(In.normal)) < 0.0 ? -1.0 : 1.0;\n    In.position.xyz += flip * dir * width * 2.0;\n    vec4 pos = cc_matViewProj * cc_matWorld * In.position;\n  #else\n    In.position.xyz += normalize(In.normal) * width;\n    vec4 pos = cc_matViewProj * cc_matWorld * In.position;\n  #endif\n\n  pos.z -= depthBias * 0.002;\n\n  v_uv = In.uv;\n\n  return pos;\n}\n\nvoid main() { gl_Position = vert(); }\n",
        "frag": "\nprecision highp float;\nuniform CCGlobal {\n  vec4 cc_time;\n\n  vec4 cc_screenSize;\n\n  vec4 cc_screenScale;\n\n  vec4 cc_nativeSize;\n\n  mat4 cc_matView;\n  mat4 cc_matViewInv;\n  mat4 cc_matProj;\n  mat4 cc_matProjInv;\n  mat4 cc_matViewProj;\n  mat4 cc_matViewProjInv;\n  vec4 cc_cameraPos;\n\n  vec4 cc_exposure;\n\n  vec4 cc_mainLitDir;\n\n  vec4 cc_mainLitColor;\n\n  vec4 cc_ambientSky;\n  vec4 cc_ambientGround;\n};\n\nvec3 SRGBToLinear(vec3 gamma)\n{\n\treturn pow(gamma, vec3(2.2));\n\n}\n\nvec3 LinearToSRGB(vec3 linear)\n{\n\treturn pow(linear, vec3(0.454545));\n\n}\n\nvec4 TEXEL_TO_LINEAR (in vec4 color) {\n  #if INPUT_IS_GAMMA\n    return vec4(SRGBToLinear(color.rgb), color.a);\n  #else\n    return color;\n  #endif\n}\n\nvec4 LINEAR_TO_OUTPUT_TEXEL (in vec4 color) {\n  #if OUTPUT_TO_GAMMA\n    return vec4(LinearToSRGB(color.rgb), color.a);\n  #else\n    return color;\n  #endif\n}\n\n#if CC_NUM_DIR_LIGHTS > 0 || CC_NUM_POINT_LIGHTS > 0 || CC_NUM_SPOT_LIGHTS > 0 || CC_NUM_AMBIENT_LIGHTS > 0\nuniform CCLIGHTS {\n  vec4 cc_dirLightDirection[4];\n\n  vec4 cc_dirLightColor[4];\n\n  vec4 cc_pointLightPositionAndRange[4];\n\n  vec4 cc_pointLightColor[4];\n\n  vec4 cc_spotLightPositionAndRange[4];\n\n  vec4 cc_spotLightDirection[4];\n\n  vec4 cc_spotLightColor[4];\n\n  vec4 cc_ambientColor[4];\n\n};\n\n#endif\n\nstruct LightInfo {\n  vec3 lightDir;\n  vec3 radiance;\n};\n\nLightInfo computeDirectionalLighting(\n  vec4 lightDirection,\n  vec4 lightColor\n) {\n  LightInfo ret;\n  ret.lightDir = -normalize(lightDirection.xyz);\n  ret.radiance = lightColor.rgb;\n  return ret;\n}\n\nLightInfo computePointLighting(\n  vec3 worldPosition,\n  vec4 lightPositionAndRange,\n  vec4 lightColor\n) {\n  LightInfo ret;\n  vec3 lightDir = lightPositionAndRange.xyz - worldPosition;\n  float attenuation = max(0., 1.0 - length(lightDir) / lightPositionAndRange.w);\n  \n  ret.lightDir = normalize(lightDir);\n  ret.radiance = lightColor.rgb * attenuation;\n  return ret;\n}\n\nLightInfo computeSpotLighting(\n  vec3 worldPosition,\n  vec4 lightPositionAndRange,\n  vec4 lightDirection,\n  vec4 lightColor\n) {\n  LightInfo ret;\n  vec3 lightDir = lightPositionAndRange.xyz - worldPosition;\n  float attenuation = max(0., 1.0 - length(lightDir) / lightPositionAndRange.w);\n  lightDir = normalize(lightDir);\n  float cosConeAngle = max(0., dot(lightDirection.xyz, -lightDir));\n  cosConeAngle = cosConeAngle < lightDirection.w ? 0. : cosConeAngle;\n  cosConeAngle = pow(cosConeAngle, lightColor.w);\n  \n  ret.lightDir = lightDir;\n  ret.radiance = lightColor.rgb * attenuation * cosConeAngle;\n  return ret;\n}\n\nin vec2 v_uv;\n\nuniform OutlineFrag {\n  vec4 outlineBaseColor;\n};\n\n#if USE_OUTLINE_BASE_COLOR_MAP\n  uniform sampler2D outlineBaseColorMap;\n#endif\n\nvec4 frag () {\n  vec4 color = outlineBaseColor;\n  \n  #if CC_NUM_DIR_LIGHTS > 0\n  for (int i = 0; i < CC_NUM_DIR_LIGHTS; i++) {\n      color *= cc_dirLightColor[i];\n  }\n  #endif\n\n  #if USE_OUTLINE_BASE_COLOR_MAP\n    vec4 texColor = texture(outlineBaseColorMap, v_uv);\n    texColor = TEXEL_TO_LINEAR(texColor);\n    color *= texColor;\n  #endif\n\n  return vec4(color.rgb, 1.0);\n}\n\nout vec4 cc_FragColor;\nvoid main() { cc_FragColor = frag(); }\n"
      },
      "glsl1": {
        "vert": "\nprecision highp float;\nuniform mat4 cc_matViewProj;\nuniform mat4 cc_matWorld;\n\nstruct StandardAttributes {\n  vec2 uv;\n  vec4 position;\n  vec3 normal;\n  vec4 tangent;\n  vec4 color;\n};\n\nattribute vec3 a_position;\n\n#if CC_USE_ATTRIBUTE_UV0\nattribute vec2 a_uv0;\n#endif\n\n#if CC_USE_ATTRIBUTE_COLOR\nattribute vec4 a_color;\n#endif\n\n#if CC_USE_ATTRIBUTE_NORMAL\nattribute vec3 a_normal;\n#endif\n\n#if CC_USE_ATTRIBUTE_TANGENT\nattribute vec4 a_tangent;\n#endif\n\nvoid CCAttribute (out StandardAttributes attr) {\n  attr.position = vec4(a_position, 1.0);\n\n  #if CC_USE_ATTRIBUTE_UV0\n    attr.uv = a_uv0;\n  #else\n    attr.uv = vec2(0.0);\n  #endif\n  \n  #if CC_USE_ATTRIBUTE_COLOR\n    attr.color = a_color;\n  #else\n    attr.color = vec4(1.0);\n  #endif\n  \n  #if CC_USE_ATTRIBUTE_NORMAL\n    attr.normal = a_normal;\n  #else\n    attr.normal = vec3(0.0, 1.0, 0.0);\n  #endif\n\n  #if CC_USE_ATTRIBUTE_TANGENT\n    attr.tangent = a_tangent;\n  #else\n    attr.tangent = vec4(1.0, 0.0, 0.0, 0.0);\n  #endif\n}\n\n#if CC_USE_SKINNING\n\n#if CC_USE_SKINNING\n\n  attribute vec4 a_weights;\n  attribute vec4 a_joints;\n\n  #if CC_USE_JOINTS_TEXTRUE\n    uniform vec2 cc_jointsTextureSize;\n    uniform sampler2D cc_jointsTexture;\n\n    #if CC_JOINTS_TEXTURE_FLOAT32\n      mat4 getBoneMatrix(const in float i) {\n        float width = cc_jointsTextureSize.x;\n        float height = cc_jointsTextureSize.y;\n        float j = i * 4.0;\n        float x = mod(j, width);\n        float y = floor(j / width);\n\n        float dx = 1.0 / width;\n        float dy = 1.0 / height;\n\n        y = dy * (y + 0.5);\n\n        vec4 v1 = texture2D(cc_jointsTexture, vec2(dx * (x + 0.5), y));\n        vec4 v2 = texture2D(cc_jointsTexture, vec2(dx * (x + 1.5), y));\n        vec4 v3 = texture2D(cc_jointsTexture, vec2(dx * (x + 2.5), y));\n        vec4 v4 = texture2D(cc_jointsTexture, vec2(dx * (x + 3.5), y));\n\n        return mat4(v1, v2, v3, v4);\n      }\n    #else\n      float decode32(vec4 rgba) {\n        float Sign = 1.0 - step(128.0, rgba[0]) * 2.0;\n        float Exponent = 2.0 * mod(rgba[0], 128.0) + step(128.0, rgba[1]) - 127.0;\n        float Mantissa = mod(rgba[1], 128.0) * 65536.0 + rgba[2] * 256.0 + rgba[3] + 8388608.0;\n        return Sign * exp2(Exponent - 23.0) * Mantissa;\n      }\n      vec4 decodevec4 (vec4 x, vec4 y, vec4 z, vec4 w) {\n\n        return vec4(\n          decode32(x.wzyx * 255.0),\n          decode32(y.wzyx * 255.0),\n          decode32(z.wzyx * 255.0),\n          decode32(w.wzyx * 255.0)\n        );\n      }\n\n      vec4 decodevec4 (float dx, float x, float y) {\n        return decodevec4(\n          texture2D(cc_jointsTexture, vec2(dx * (x + 0.5), y)),\n          texture2D(cc_jointsTexture, vec2(dx * (x + 1.5), y)),\n          texture2D(cc_jointsTexture, vec2(dx * (x + 2.5), y)),\n          texture2D(cc_jointsTexture, vec2(dx * (x + 3.5), y))\n        );\n      }\n\n      mat4 getBoneMatrix(const in float i) {\n        float width = cc_jointsTextureSize.x;\n        float height = cc_jointsTextureSize.y;\n        float j = i * 16.0;\n        float x = mod(j, width);\n        float y = floor(j / width);\n\n        float dx = 1.0 / width;\n        float dy = 1.0 / height;\n\n        y = dy * (y + 0.5);\n\n        vec4 v1 = decodevec4(dx, x,       y);\n        vec4 v2 = decodevec4(dx, x+4.0,   y);\n        vec4 v3 = decodevec4(dx, x+8.0,   y);\n        vec4 v4 = decodevec4(dx, x+12.0,  y);\n\n        return mat4(v1, v2, v3, v4);\n      }\n    #endif\n  #else\n    uniform mat4 cc_jointMatrices[50];\nmat4 getBoneMatrix(const in float i) {\n      return cc_jointMatrices[int(i)];\n    }\n  #endif\n\n    mat4 skinMatrix() {\n      return\n        getBoneMatrix(a_joints.x) * a_weights.x +\n        getBoneMatrix(a_joints.y) * a_weights.y +\n        getBoneMatrix(a_joints.z) * a_weights.z +\n        getBoneMatrix(a_joints.w) * a_weights.w\n        ;\n    }\n#endif\n\nvoid SKIN_VERTEX(inout vec4 a1) {\n  #if CC_USE_SKINNING\n    mat4 m = skinMatrix();\n    a1 = m * a1;\n  #endif\n}\n\nvoid SKIN_VERTEX(inout vec4 a1, inout vec4 a2) {\n  #if CC_USE_SKINNING\n    mat4 m = skinMatrix();\n    a1 = m * a1;\n    a2 = m * a2;\n  #endif\n}\n\nvoid SKIN_VERTEX(inout vec4 a1, inout vec4 a2, inout vec4 a3) {\n  #if CC_USE_SKINNING\n    mat4 m = skinMatrix();\n    a1 = m * a1;\n    a2 = m * a2;\n    a3 = m * a3;\n  #endif\n}\n\n  void CCSkin(inout StandardAttributes attr) {\n    mat4 m = skinMatrix();\n    attr.position = m * attr.position;\n    attr.normal = (m * vec4(attr.normal, 0)).xyz;\n    attr.tangent = m * attr.tangent;\n  }\n#endif\n\nstruct StandardVertInput {\n  vec2 uv;\n  vec4 position;\n  vec3 normal;\n  vec4 tangent;\n  vec4 color;\n};\n\nvoid CCAttrToInput (in StandardAttributes attr, out StandardVertInput In) {\n  In.position = attr.position;\n  In.normal = attr.normal;\n  In.tangent = attr.tangent;\n  In.uv = attr.uv;\n  In.color = attr.color;\n}\n\nvoid CCVertInput (out StandardVertInput In) {\n  StandardAttributes attr;\n  CCAttribute(attr);\n  #if CC_USE_SKINNING\n    CCSkin(attr);\n  #endif\n  CCAttrToInput(attr, In);\n}\n\nvarying vec2 v_uv;\n\nuniform float lineWidth;\nuniform float depthBias;\n\nvec4 vert () {\n  StandardVertInput In;\n  CCVertInput(In);\n\n  float width = lineWidth * 0.001;\n\n  #if USE_POSITION_SCALING\n    vec3 dir = normalize(In.position.xyz);\n    float flip = dot(dir, normalize(In.normal)) < 0.0 ? -1.0 : 1.0;\n    In.position.xyz += flip * dir * width * 2.0;\n    vec4 pos = cc_matViewProj * cc_matWorld * In.position;\n  #else\n    In.position.xyz += normalize(In.normal) * width;\n    vec4 pos = cc_matViewProj * cc_matWorld * In.position;\n  #endif\n\n  pos.z -= depthBias * 0.002;\n\n  v_uv = In.uv;\n\n  return pos;\n}\n\nvoid main() { gl_Position = vert(); }\n",
        "frag": "\nprecision highp float;\n\nvec3 SRGBToLinear(vec3 gamma)\n{\n\treturn pow(gamma, vec3(2.2));\n\n}\n\nvec3 LinearToSRGB(vec3 linear)\n{\n\treturn pow(linear, vec3(0.454545));\n\n}\n\nvec4 TEXEL_TO_LINEAR (in vec4 color) {\n  #if INPUT_IS_GAMMA\n    return vec4(SRGBToLinear(color.rgb), color.a);\n  #else\n    return color;\n  #endif\n}\n\nvec4 LINEAR_TO_OUTPUT_TEXEL (in vec4 color) {\n  #if OUTPUT_TO_GAMMA\n    return vec4(LinearToSRGB(color.rgb), color.a);\n  #else\n    return color;\n  #endif\n}\n\n#if CC_NUM_DIR_LIGHTS > 0 || CC_NUM_POINT_LIGHTS > 0 || CC_NUM_SPOT_LIGHTS > 0 || CC_NUM_AMBIENT_LIGHTS > 0\nuniform vec4 cc_dirLightColor[4];\n\n#endif\n\nstruct LightInfo {\n  vec3 lightDir;\n  vec3 radiance;\n};\n\nLightInfo computeDirectionalLighting(\n  vec4 lightDirection,\n  vec4 lightColor\n) {\n  LightInfo ret;\n  ret.lightDir = -normalize(lightDirection.xyz);\n  ret.radiance = lightColor.rgb;\n  return ret;\n}\n\nLightInfo computePointLighting(\n  vec3 worldPosition,\n  vec4 lightPositionAndRange,\n  vec4 lightColor\n) {\n  LightInfo ret;\n  vec3 lightDir = lightPositionAndRange.xyz - worldPosition;\n  float attenuation = max(0., 1.0 - length(lightDir) / lightPositionAndRange.w);\n  \n  ret.lightDir = normalize(lightDir);\n  ret.radiance = lightColor.rgb * attenuation;\n  return ret;\n}\n\nLightInfo computeSpotLighting(\n  vec3 worldPosition,\n  vec4 lightPositionAndRange,\n  vec4 lightDirection,\n  vec4 lightColor\n) {\n  LightInfo ret;\n  vec3 lightDir = lightPositionAndRange.xyz - worldPosition;\n  float attenuation = max(0., 1.0 - length(lightDir) / lightPositionAndRange.w);\n  lightDir = normalize(lightDir);\n  float cosConeAngle = max(0., dot(lightDirection.xyz, -lightDir));\n  cosConeAngle = cosConeAngle < lightDirection.w ? 0. : cosConeAngle;\n  cosConeAngle = pow(cosConeAngle, lightColor.w);\n  \n  ret.lightDir = lightDir;\n  ret.radiance = lightColor.rgb * attenuation * cosConeAngle;\n  return ret;\n}\n\nvarying vec2 v_uv;\n\nuniform vec4 outlineBaseColor;\n\n#if USE_OUTLINE_BASE_COLOR_MAP\n  uniform sampler2D outlineBaseColorMap;\n#endif\n\nvec4 frag () {\n  vec4 color = outlineBaseColor;\n  \n  #if CC_NUM_DIR_LIGHTS > 0\n  for (int i = 0; i < CC_NUM_DIR_LIGHTS; i++) {\n      color *= cc_dirLightColor[i];\n  }\n  #endif\n\n  #if USE_OUTLINE_BASE_COLOR_MAP\n    vec4 texColor = texture2D(outlineBaseColorMap, v_uv);\n    texColor = TEXEL_TO_LINEAR(texColor);\n    color *= texColor;\n  #endif\n\n  return vec4(color.rgb, 1.0);\n}\n\nvoid main() { gl_FragColor = frag(); }\n"
      },
      "builtins": {
        "globals": {
          "blocks": [
            {
              "name": "CCGlobal",
              "defines": []
            },
            {
              "name": "CCLIGHTS",
              "defines": []
            }
          ],
          "samplers": []
        },
        "locals": {
          "blocks": [
            {
              "name": "CCLocal",
              "defines": []
            },
            {
              "name": "CC_JOINT_MATRIX",
              "defines": [
                "CC_USE_SKINNING"
              ]
            }
          ],
          "samplers": [
            {
              "name": "cc_jointsTexture",
              "defines": [
                "CC_USE_SKINNING",
                "CC_USE_JOINTS_TEXTRUE"
              ]
            }
          ]
        }
      },
      "defines": [
        {
          "name": "CC_USE_ATTRIBUTE_UV0",
          "type": "boolean",
          "defines": []
        },
        {
          "name": "CC_USE_ATTRIBUTE_COLOR",
          "type": "boolean",
          "defines": []
        },
        {
          "name": "CC_USE_ATTRIBUTE_NORMAL",
          "type": "boolean",
          "defines": []
        },
        {
          "name": "CC_USE_ATTRIBUTE_TANGENT",
          "type": "boolean",
          "defines": []
        },
        {
          "name": "CC_USE_SKINNING",
          "type": "boolean",
          "defines": []
        },
        {
          "name": "CC_USE_JOINTS_TEXTRUE",
          "type": "boolean",
          "defines": [
            "CC_USE_SKINNING",
            "CC_USE_SKINNING"
          ]
        },
        {
          "name": "CC_JOINTS_TEXTURE_FLOAT32",
          "type": "boolean",
          "defines": [
            "CC_USE_SKINNING",
            "CC_USE_SKINNING",
            "CC_USE_JOINTS_TEXTRUE"
          ]
        },
        {
          "name": "USE_POSITION_SCALING",
          "type": "boolean",
          "defines": []
        },
        {
          "name": "INPUT_IS_GAMMA",
          "type": "boolean",
          "defines": []
        },
        {
          "name": "OUTPUT_TO_GAMMA",
          "type": "boolean",
          "defines": []
        },
        {
          "name": "CC_NUM_DIR_LIGHTS",
          "type": "number",
          "defines": [],
          "range": [
            0,
            3
          ]
        },
        {
          "name": "USE_OUTLINE_BASE_COLOR_MAP",
          "type": "boolean",
          "defines": []
        }
      ],
      "blocks": [
        {
          "name": "SKINNING",
          "members": [
            {
              "name": "cc_jointsTextureSize",
              "type": 14,
              "count": 1
            }
          ],
          "defines": [
            "CC_USE_SKINNING",
            "CC_USE_JOINTS_TEXTRUE"
          ],
          "binding": 0
        },
        {
          "name": "OutlineVert",
          "members": [
            {
              "name": "lineWidth",
              "type": 13,
              "count": 1
            },
            {
              "name": "depthBias",
              "type": 13,
              "count": 1
            }
          ],
          "defines": [],
          "binding": 1
        },
        {
          "name": "OutlineFrag",
          "members": [
            {
              "name": "outlineBaseColor",
              "type": 16,
              "count": 1
            }
          ],
          "defines": [],
          "binding": 2
        }
      ],
      "samplers": [
        {
          "name": "outlineBaseColorMap",
          "type": 29,
          "count": 1,
          "defines": [
            "USE_OUTLINE_BASE_COLOR_MAP"
          ],
          "binding": 30
        }
      ],
      "dependencies": {},
      "name": "builtin-toon|outline-vs:vert|outline-fs:frag"
    },
    {
      "hash": 1904275858,
      "glsl3": {
        "vert": "\nprecision highp float;\nuniform CCGlobal {\n  vec4 cc_time;\n\n  vec4 cc_screenSize;\n\n  vec4 cc_screenScale;\n\n  vec4 cc_nativeSize;\n\n  mat4 cc_matView;\n  mat4 cc_matViewInv;\n  mat4 cc_matProj;\n  mat4 cc_matProjInv;\n  mat4 cc_matViewProj;\n  mat4 cc_matViewProjInv;\n  vec4 cc_cameraPos;\n\n  vec4 cc_exposure;\n\n  vec4 cc_mainLitDir;\n\n  vec4 cc_mainLitColor;\n\n  vec4 cc_ambientSky;\n  vec4 cc_ambientGround;\n};\nuniform CCLocal {\n  mat4 cc_matWorld;\n  mat4 cc_matWorldIT;\n};\n\nstruct StandardAttributes {\n  vec2 uv;\n  vec4 position;\n  vec3 normal;\n  vec4 tangent;\n  vec4 color;\n};\n\nin vec3 a_position;\n\n#if CC_USE_ATTRIBUTE_UV0\nin vec2 a_uv0;\n#endif\n\n#if CC_USE_ATTRIBUTE_COLOR\nin vec4 a_color;\n#endif\n\n#if CC_USE_ATTRIBUTE_NORMAL\nin vec3 a_normal;\n#endif\n\n#if CC_USE_ATTRIBUTE_TANGENT\nin vec4 a_tangent;\n#endif\n\nvoid CCAttribute (out StandardAttributes attr) {\n  attr.position = vec4(a_position, 1.0);\n\n  #if CC_USE_ATTRIBUTE_UV0\n    attr.uv = a_uv0;\n  #else\n    attr.uv = vec2(0.0);\n  #endif\n  \n  #if CC_USE_ATTRIBUTE_COLOR\n    attr.color = a_color;\n  #else\n    attr.color = vec4(1.0);\n  #endif\n  \n  #if CC_USE_ATTRIBUTE_NORMAL\n    attr.normal = a_normal;\n  #else\n    attr.normal = vec3(0.0, 1.0, 0.0);\n  #endif\n\n  #if CC_USE_ATTRIBUTE_TANGENT\n    attr.tangent = a_tangent;\n  #else\n    attr.tangent = vec4(1.0, 0.0, 0.0, 0.0);\n  #endif\n}\n\n#if CC_USE_SKINNING\n\n#if CC_USE_SKINNING\n\n  in vec4 a_weights;\n  in vec4 a_joints;\n\n  #if CC_USE_JOINTS_TEXTRUE\n    uniform SKINNING {\n      vec2 cc_jointsTextureSize;\n    }\n    uniform sampler2D cc_jointsTexture;\n\n    #if CC_JOINTS_TEXTURE_FLOAT32\n      mat4 getBoneMatrix(const in float i) {\n        float width = cc_jointsTextureSize.x;\n        float height = cc_jointsTextureSize.y;\n        float j = i * 4.0;\n        float x = mod(j, width);\n        float y = floor(j / width);\n\n        float dx = 1.0 / width;\n        float dy = 1.0 / height;\n\n        y = dy * (y + 0.5);\n\n        vec4 v1 = texture2D(cc_jointsTexture, vec2(dx * (x + 0.5), y));\n        vec4 v2 = texture2D(cc_jointsTexture, vec2(dx * (x + 1.5), y));\n        vec4 v3 = texture2D(cc_jointsTexture, vec2(dx * (x + 2.5), y));\n        vec4 v4 = texture2D(cc_jointsTexture, vec2(dx * (x + 3.5), y));\n\n        return mat4(v1, v2, v3, v4);\n      }\n    #else\n      float decode32(vec4 rgba) {\n        float Sign = 1.0 - step(128.0, rgba[0]) * 2.0;\n        float Exponent = 2.0 * mod(rgba[0], 128.0) + step(128.0, rgba[1]) - 127.0;\n        float Mantissa = mod(rgba[1], 128.0) * 65536.0 + rgba[2] * 256.0 + rgba[3] + 8388608.0;\n        return Sign * exp2(Exponent - 23.0) * Mantissa;\n      }\n      vec4 decodevec4 (vec4 x, vec4 y, vec4 z, vec4 w) {\n\n        return vec4(\n          decode32(x.wzyx * 255.0),\n          decode32(y.wzyx * 255.0),\n          decode32(z.wzyx * 255.0),\n          decode32(w.wzyx * 255.0)\n        );\n      }\n\n      vec4 decodevec4 (float dx, float x, float y) {\n        return decodevec4(\n          texture2D(cc_jointsTexture, vec2(dx * (x + 0.5), y)),\n          texture2D(cc_jointsTexture, vec2(dx * (x + 1.5), y)),\n          texture2D(cc_jointsTexture, vec2(dx * (x + 2.5), y)),\n          texture2D(cc_jointsTexture, vec2(dx * (x + 3.5), y))\n        );\n      }\n\n      mat4 getBoneMatrix(const in float i) {\n        float width = cc_jointsTextureSize.x;\n        float height = cc_jointsTextureSize.y;\n        float j = i * 16.0;\n        float x = mod(j, width);\n        float y = floor(j / width);\n\n        float dx = 1.0 / width;\n        float dy = 1.0 / height;\n\n        y = dy * (y + 0.5);\n\n        vec4 v1 = decodevec4(dx, x,       y);\n        vec4 v2 = decodevec4(dx, x+4.0,   y);\n        vec4 v3 = decodevec4(dx, x+8.0,   y);\n        vec4 v4 = decodevec4(dx, x+12.0,  y);\n\n        return mat4(v1, v2, v3, v4);\n      }\n    #endif\n  #else\n    uniform CC_JOINT_MATRIX {\n      mat4 cc_jointMatrices[50];\n    }\n\n    mat4 getBoneMatrix(const in float i) {\n      return cc_jointMatrices[int(i)];\n    }\n  #endif\n\n    mat4 skinMatrix() {\n      return\n        getBoneMatrix(a_joints.x) * a_weights.x +\n        getBoneMatrix(a_joints.y) * a_weights.y +\n        getBoneMatrix(a_joints.z) * a_weights.z +\n        getBoneMatrix(a_joints.w) * a_weights.w\n        ;\n    }\n#endif\n\nvoid SKIN_VERTEX(inout vec4 a1) {\n  #if CC_USE_SKINNING\n    mat4 m = skinMatrix();\n    a1 = m * a1;\n  #endif\n}\n\nvoid SKIN_VERTEX(inout vec4 a1, inout vec4 a2) {\n  #if CC_USE_SKINNING\n    mat4 m = skinMatrix();\n    a1 = m * a1;\n    a2 = m * a2;\n  #endif\n}\n\nvoid SKIN_VERTEX(inout vec4 a1, inout vec4 a2, inout vec4 a3) {\n  #if CC_USE_SKINNING\n    mat4 m = skinMatrix();\n    a1 = m * a1;\n    a2 = m * a2;\n    a3 = m * a3;\n  #endif\n}\n\n  void CCSkin(inout StandardAttributes attr) {\n    mat4 m = skinMatrix();\n    attr.position = m * attr.position;\n    attr.normal = (m * vec4(attr.normal, 0)).xyz;\n    attr.tangent = m * attr.tangent;\n  }\n#endif\n\nstruct StandardVertInput {\n  vec2 uv;\n  vec4 position;\n  vec3 normal;\n  vec4 tangent;\n  vec4 color;\n};\n\nvoid CCAttrToInput (in StandardAttributes attr, out StandardVertInput In) {\n  In.position = attr.position;\n  In.normal = attr.normal;\n  In.tangent = attr.tangent;\n  In.uv = attr.uv;\n  In.color = attr.color;\n}\n\nvoid CCVertInput (out StandardVertInput In) {\n  StandardAttributes attr;\n  CCAttribute(attr);\n  #if CC_USE_SKINNING\n    CCSkin(attr);\n  #endif\n  CCAttrToInput(attr, In);\n}\n\nout vec3 v_position;\nout vec2 v_uv;\nout vec3 v_normal;\n\n#if USE_NORMAL_MAP\n  out vec3 v_tangent;\n  out vec3 v_bitangent;\n#endif\n\nuniform ToonVert {\n  vec4 tilingOffset;\n};\n\nvec4 vert () {\n  StandardVertInput In;\n  CCVertInput(In);\n\n  vec4 pos = cc_matWorld * In.position;\n  v_position = pos.xyz;\n  v_uv = In.uv * tilingOffset.xy + tilingOffset.zw;\n\n  v_normal = (cc_matWorldIT * vec4(In.normal, 0.0)).xyz;\n  #if USE_NORMAL_MAP\n    v_tangent = normalize((cc_matWorldIT * vec4(In.tangent.xyz, 0.0)).xyz);\n    v_bitangent = cross(v_normal, v_tangent) * In.tangent.w;\n\n  #endif\n\n  return cc_matViewProj * pos;\n}\n\nvoid main() { gl_Position = vert(); }\n",
        "frag": "\nprecision highp float;\nuniform CCGlobal {\n  vec4 cc_time;\n\n  vec4 cc_screenSize;\n\n  vec4 cc_screenScale;\n\n  vec4 cc_nativeSize;\n\n  mat4 cc_matView;\n  mat4 cc_matViewInv;\n  mat4 cc_matProj;\n  mat4 cc_matProjInv;\n  mat4 cc_matViewProj;\n  mat4 cc_matViewProjInv;\n  vec4 cc_cameraPos;\n\n  vec4 cc_exposure;\n\n  vec4 cc_mainLitDir;\n\n  vec4 cc_mainLitColor;\n\n  vec4 cc_ambientSky;\n  vec4 cc_ambientGround;\n};\n\n#if CC_NUM_DIR_LIGHTS > 0 || CC_NUM_POINT_LIGHTS > 0 || CC_NUM_SPOT_LIGHTS > 0 || CC_NUM_AMBIENT_LIGHTS > 0\nuniform CCLIGHTS {\n  vec4 cc_dirLightDirection[4];\n\n  vec4 cc_dirLightColor[4];\n\n  vec4 cc_pointLightPositionAndRange[4];\n\n  vec4 cc_pointLightColor[4];\n\n  vec4 cc_spotLightPositionAndRange[4];\n\n  vec4 cc_spotLightDirection[4];\n\n  vec4 cc_spotLightColor[4];\n\n  vec4 cc_ambientColor[4];\n\n};\n\n#endif\n\nstruct LightInfo {\n  vec3 lightDir;\n  vec3 radiance;\n};\n\nLightInfo computeDirectionalLighting(\n  vec4 lightDirection,\n  vec4 lightColor\n) {\n  LightInfo ret;\n  ret.lightDir = -normalize(lightDirection.xyz);\n  ret.radiance = lightColor.rgb;\n  return ret;\n}\n\nLightInfo computePointLighting(\n  vec3 worldPosition,\n  vec4 lightPositionAndRange,\n  vec4 lightColor\n) {\n  LightInfo ret;\n  vec3 lightDir = lightPositionAndRange.xyz - worldPosition;\n  float attenuation = max(0., 1.0 - length(lightDir) / lightPositionAndRange.w);\n  \n  ret.lightDir = normalize(lightDir);\n  ret.radiance = lightColor.rgb * attenuation;\n  return ret;\n}\n\nLightInfo computeSpotLighting(\n  vec3 worldPosition,\n  vec4 lightPositionAndRange,\n  vec4 lightDirection,\n  vec4 lightColor\n) {\n  LightInfo ret;\n  vec3 lightDir = lightPositionAndRange.xyz - worldPosition;\n  float attenuation = max(0., 1.0 - length(lightDir) / lightPositionAndRange.w);\n  lightDir = normalize(lightDir);\n  float cosConeAngle = max(0., dot(lightDirection.xyz, -lightDir));\n  cosConeAngle = cosConeAngle < lightDirection.w ? 0. : cosConeAngle;\n  cosConeAngle = pow(cosConeAngle, lightColor.w);\n  \n  ret.lightDir = lightDir;\n  ret.radiance = lightColor.rgb * attenuation * cosConeAngle;\n  return ret;\n}\n\nstruct ToonSurface {\n  vec4 baseColor;\n\n  vec3 specular;\n  float specularThreshold;\n\n  vec3 position;\n  vec3 normal;\n\n  vec3 emissive;\n\n  vec3 shadowColor;\n  float shadowIntensity;\n  vec3 highlightColor;\n\n  float lightThreshold;\n  float lightSmoothness;\n};\n\nconst float T_H = 0.25;\nfloat TreshHoldLighting(float lThreshold, float smoothness, float v) {\n  return smoothstep(lThreshold-smoothness*T_H, lThreshold+smoothness*T_H, v);\n}\n\nvec3 combined (ToonSurface s, vec3 attenuation, vec3 lightColor, float NL, float NH, float specularWeight) {\n  vec3 c = vec3(0.0);\n\n  vec3 shadowColor = mix(s.highlightColor * lightColor, s.shadowColor, s.shadowIntensity);\n  vec3 diffuse = TreshHoldLighting(s.lightThreshold, s.lightSmoothness, NL) * attenuation;\n  diffuse = mix(shadowColor, s.highlightColor * lightColor, diffuse);\n\n  c += diffuse * s.baseColor.rgb;\n\n  float specularMask = step(specularWeight, NH);\n  vec3 specular = s.specular.rgb * specularMask;\n\n  c += specular * attenuation;\n\n  return c;\n}\n\nvec4 CCToonShading (ToonSurface s) {\n  vec3 V = normalize(cc_cameraPos.xyz - s.position);\n  vec3 N = s.normal;\n\n  vec3 finalColor = vec3(0.0);\n  float specularWeight = 1.0 - pow(s.specularThreshold, 5.0);\n\n  #if CC_NUM_DIR_LIGHTS > 0\n    for (int i = 0; i < CC_NUM_DIR_LIGHTS; i++) {\n        LightInfo info = computeDirectionalLighting(cc_dirLightDirection[i], cc_dirLightColor[i]);\n\n        vec3 L = info.lightDir;\n        float NL = 0.5 * dot(N, L) + 0.5;\n        float NH = 0.5 * dot(normalize(V + L), N) + 0.5;\n\n        finalColor += combined(s, cc_dirLightColor[i].rgb, info.radiance, NL, NH, specularWeight);\n    }\n  #endif\n\n  #if CC_NUM_POINT_LIGHTS > 0\n    for (int i = 0; i < CC_NUM_POINT_LIGHTS; i++) {\n      LightInfo info = computePointLighting(s.position, cc_pointLightPositionAndRange[i], cc_pointLightColor[i]);\n\n      vec3 PL = info.lightDir;\n      vec3 PH = normalize(PL + V);\n      float NL = 0.5 * dot(N, PL) + 0.5;\n      float NH = 0.5 * dot(N, PH) + 0.5;\n\n      finalColor += combined(s, cc_pointLightColor[i].rgb, info.radiance, NL, NH, specularWeight);\n    }\n  #endif\n\n  #if CC_NUM_SPOT_LIGHTS > 0\n    for (int i = 0; i < CC_NUM_SPOT_LIGHTS; i++) {\n      LightInfo info = computeSpotLighting(s.position, cc_spotLightPositionAndRange[i], cc_spotLightDirection[i], cc_spotLightColor[i]);\n\n      vec3 SL = info.lightDir;\n      vec3 SH = normalize(SL + V);\n      float NL = 0.5 * dot(N, SL) + 0.5;\n      float NH = 0.5 * dot(N, SH) + 0.5;\n\n      finalColor += combined(s, cc_spotLightColor[i].rgb, info.radiance, NL, NH, specularWeight);\n    }\n  #endif\n\n  #if CC_NUM_AMBIENT_LIGHTS > 0\n    for (int i = 0; i < CC_NUM_AMBIENT_LIGHTS; i++) {\n      finalColor += s.baseColor.rgb * cc_ambientColor[i].rgb;\n    }\n  #endif\n\n  finalColor += s.emissive;\n  return vec4(finalColor, s.baseColor.a);\n}\n\nvec3 SRGBToLinear(vec3 gamma)\n{\n\treturn pow(gamma, vec3(2.2));\n\n}\n\nvec3 LinearToSRGB(vec3 linear)\n{\n\treturn pow(linear, vec3(0.454545));\n\n}\n\nvec4 TEXEL_TO_LINEAR (in vec4 color) {\n  #if INPUT_IS_GAMMA\n    return vec4(SRGBToLinear(color.rgb), color.a);\n  #else\n    return color;\n  #endif\n}\n\nvec4 LINEAR_TO_OUTPUT_TEXEL (in vec4 color) {\n  #if OUTPUT_TO_GAMMA\n    return vec4(LinearToSRGB(color.rgb), color.a);\n  #else\n    return color;\n  #endif\n}\n\nin vec3 v_position;\nin vec2 v_uv;\n\nin vec3 v_normal;\n#if USE_NORMAL_MAP\n  in vec3 v_tangent;\n  in vec3 v_bitangent;\n  uniform sampler2D normalMap;\n#endif\n\n#if USE_BASE_COLOR_MAP\n  uniform sampler2D baseColorMap;\n#endif\n#if USE_SPECULAR_MAP\n  uniform sampler2D specularMap;\n#endif\n#if USE_EMISSIVE_MAP\n  uniform sampler2D emissiveMap;\n#endif\n\nuniform ToonFrag {\n  vec4 colorScale;\n\n  vec4 specular;\n\n  vec4 emissive;\n  vec4 shadowColor;\n  vec4 highlightColor;\n  float specularThreshold;\n  float shadowIntensity;\n  float lightThreshold;\n  float lightSmoothness;\n};\n\nvoid surf (out ToonSurface s) {\n  #if USE_BASE_COLOR_MAP\n    s.baseColor = TEXEL_TO_LINEAR(texture(baseColorMap, v_uv));\n  #else\n    s.baseColor = highlightColor;    \n  #endif\n\n  s.normal = normalize(v_normal);\n  #if USE_NORMAL_MAP\n    vec3 nmmp = texture(normalMap, v_uv).xyz - vec3(0.5);\n    s.normal = normalize(\n      nmmp.x * normalize(v_tangent) +\n      nmmp.y * normalize(v_bitangent) +\n      nmmp.z * s.normal);\n  #endif\n\n  s.position = v_position;\n\n  s.specular = specular.rgb * specular.a;\n  #if USE_SPECULAR_MAP\n    s.specular *= TEXEL_TO_LINEAR(texture(specularMap, v_uv)).rgb;\n  #endif\n\n  s.emissive = emissive.rgb;\n  #if USE_EMISSIVE_MAP\n    s.emissive *= TEXEL_TO_LINEAR(texture(emissiveMap, v_uv)).rgb;\n  #endif\n\n  s.lightThreshold = lightThreshold;\n  s.lightSmoothness = lightSmoothness;\n  s.shadowColor = shadowColor.rgb;\n  s.highlightColor = highlightColor.rgb;\n  s.shadowIntensity = shadowIntensity;\n  s.specularThreshold = specularThreshold;\n}\n\nvec4 frag () {\n  ToonSurface s; \n  surf(s);\n  vec4 color = CCToonShading(s);\n  return LINEAR_TO_OUTPUT_TEXEL(color);\n}\n\nout vec4 cc_FragColor;\nvoid main() { cc_FragColor = frag(); }\n"
      },
      "glsl1": {
        "vert": "\nprecision highp float;\nuniform mat4 cc_matViewProj;\nuniform mat4 cc_matWorld;\nuniform mat4 cc_matWorldIT;\n\nstruct StandardAttributes {\n  vec2 uv;\n  vec4 position;\n  vec3 normal;\n  vec4 tangent;\n  vec4 color;\n};\n\nattribute vec3 a_position;\n\n#if CC_USE_ATTRIBUTE_UV0\nattribute vec2 a_uv0;\n#endif\n\n#if CC_USE_ATTRIBUTE_COLOR\nattribute vec4 a_color;\n#endif\n\n#if CC_USE_ATTRIBUTE_NORMAL\nattribute vec3 a_normal;\n#endif\n\n#if CC_USE_ATTRIBUTE_TANGENT\nattribute vec4 a_tangent;\n#endif\n\nvoid CCAttribute (out StandardAttributes attr) {\n  attr.position = vec4(a_position, 1.0);\n\n  #if CC_USE_ATTRIBUTE_UV0\n    attr.uv = a_uv0;\n  #else\n    attr.uv = vec2(0.0);\n  #endif\n  \n  #if CC_USE_ATTRIBUTE_COLOR\n    attr.color = a_color;\n  #else\n    attr.color = vec4(1.0);\n  #endif\n  \n  #if CC_USE_ATTRIBUTE_NORMAL\n    attr.normal = a_normal;\n  #else\n    attr.normal = vec3(0.0, 1.0, 0.0);\n  #endif\n\n  #if CC_USE_ATTRIBUTE_TANGENT\n    attr.tangent = a_tangent;\n  #else\n    attr.tangent = vec4(1.0, 0.0, 0.0, 0.0);\n  #endif\n}\n\n#if CC_USE_SKINNING\n\n#if CC_USE_SKINNING\n\n  attribute vec4 a_weights;\n  attribute vec4 a_joints;\n\n  #if CC_USE_JOINTS_TEXTRUE\n    uniform vec2 cc_jointsTextureSize;\n    uniform sampler2D cc_jointsTexture;\n\n    #if CC_JOINTS_TEXTURE_FLOAT32\n      mat4 getBoneMatrix(const in float i) {\n        float width = cc_jointsTextureSize.x;\n        float height = cc_jointsTextureSize.y;\n        float j = i * 4.0;\n        float x = mod(j, width);\n        float y = floor(j / width);\n\n        float dx = 1.0 / width;\n        float dy = 1.0 / height;\n\n        y = dy * (y + 0.5);\n\n        vec4 v1 = texture2D(cc_jointsTexture, vec2(dx * (x + 0.5), y));\n        vec4 v2 = texture2D(cc_jointsTexture, vec2(dx * (x + 1.5), y));\n        vec4 v3 = texture2D(cc_jointsTexture, vec2(dx * (x + 2.5), y));\n        vec4 v4 = texture2D(cc_jointsTexture, vec2(dx * (x + 3.5), y));\n\n        return mat4(v1, v2, v3, v4);\n      }\n    #else\n      float decode32(vec4 rgba) {\n        float Sign = 1.0 - step(128.0, rgba[0]) * 2.0;\n        float Exponent = 2.0 * mod(rgba[0], 128.0) + step(128.0, rgba[1]) - 127.0;\n        float Mantissa = mod(rgba[1], 128.0) * 65536.0 + rgba[2] * 256.0 + rgba[3] + 8388608.0;\n        return Sign * exp2(Exponent - 23.0) * Mantissa;\n      }\n      vec4 decodevec4 (vec4 x, vec4 y, vec4 z, vec4 w) {\n\n        return vec4(\n          decode32(x.wzyx * 255.0),\n          decode32(y.wzyx * 255.0),\n          decode32(z.wzyx * 255.0),\n          decode32(w.wzyx * 255.0)\n        );\n      }\n\n      vec4 decodevec4 (float dx, float x, float y) {\n        return decodevec4(\n          texture2D(cc_jointsTexture, vec2(dx * (x + 0.5), y)),\n          texture2D(cc_jointsTexture, vec2(dx * (x + 1.5), y)),\n          texture2D(cc_jointsTexture, vec2(dx * (x + 2.5), y)),\n          texture2D(cc_jointsTexture, vec2(dx * (x + 3.5), y))\n        );\n      }\n\n      mat4 getBoneMatrix(const in float i) {\n        float width = cc_jointsTextureSize.x;\n        float height = cc_jointsTextureSize.y;\n        float j = i * 16.0;\n        float x = mod(j, width);\n        float y = floor(j / width);\n\n        float dx = 1.0 / width;\n        float dy = 1.0 / height;\n\n        y = dy * (y + 0.5);\n\n        vec4 v1 = decodevec4(dx, x,       y);\n        vec4 v2 = decodevec4(dx, x+4.0,   y);\n        vec4 v3 = decodevec4(dx, x+8.0,   y);\n        vec4 v4 = decodevec4(dx, x+12.0,  y);\n\n        return mat4(v1, v2, v3, v4);\n      }\n    #endif\n  #else\n    uniform mat4 cc_jointMatrices[50];\nmat4 getBoneMatrix(const in float i) {\n      return cc_jointMatrices[int(i)];\n    }\n  #endif\n\n    mat4 skinMatrix() {\n      return\n        getBoneMatrix(a_joints.x) * a_weights.x +\n        getBoneMatrix(a_joints.y) * a_weights.y +\n        getBoneMatrix(a_joints.z) * a_weights.z +\n        getBoneMatrix(a_joints.w) * a_weights.w\n        ;\n    }\n#endif\n\nvoid SKIN_VERTEX(inout vec4 a1) {\n  #if CC_USE_SKINNING\n    mat4 m = skinMatrix();\n    a1 = m * a1;\n  #endif\n}\n\nvoid SKIN_VERTEX(inout vec4 a1, inout vec4 a2) {\n  #if CC_USE_SKINNING\n    mat4 m = skinMatrix();\n    a1 = m * a1;\n    a2 = m * a2;\n  #endif\n}\n\nvoid SKIN_VERTEX(inout vec4 a1, inout vec4 a2, inout vec4 a3) {\n  #if CC_USE_SKINNING\n    mat4 m = skinMatrix();\n    a1 = m * a1;\n    a2 = m * a2;\n    a3 = m * a3;\n  #endif\n}\n\n  void CCSkin(inout StandardAttributes attr) {\n    mat4 m = skinMatrix();\n    attr.position = m * attr.position;\n    attr.normal = (m * vec4(attr.normal, 0)).xyz;\n    attr.tangent = m * attr.tangent;\n  }\n#endif\n\nstruct StandardVertInput {\n  vec2 uv;\n  vec4 position;\n  vec3 normal;\n  vec4 tangent;\n  vec4 color;\n};\n\nvoid CCAttrToInput (in StandardAttributes attr, out StandardVertInput In) {\n  In.position = attr.position;\n  In.normal = attr.normal;\n  In.tangent = attr.tangent;\n  In.uv = attr.uv;\n  In.color = attr.color;\n}\n\nvoid CCVertInput (out StandardVertInput In) {\n  StandardAttributes attr;\n  CCAttribute(attr);\n  #if CC_USE_SKINNING\n    CCSkin(attr);\n  #endif\n  CCAttrToInput(attr, In);\n}\n\nvarying vec3 v_position;\nvarying vec2 v_uv;\nvarying vec3 v_normal;\n\n#if USE_NORMAL_MAP\n  varying vec3 v_tangent;\n  varying vec3 v_bitangent;\n#endif\n\nuniform vec4 tilingOffset;\n\nvec4 vert () {\n  StandardVertInput In;\n  CCVertInput(In);\n\n  vec4 pos = cc_matWorld * In.position;\n  v_position = pos.xyz;\n  v_uv = In.uv * tilingOffset.xy + tilingOffset.zw;\n\n  v_normal = (cc_matWorldIT * vec4(In.normal, 0.0)).xyz;\n  #if USE_NORMAL_MAP\n    v_tangent = normalize((cc_matWorldIT * vec4(In.tangent.xyz, 0.0)).xyz);\n    v_bitangent = cross(v_normal, v_tangent) * In.tangent.w;\n\n  #endif\n\n  return cc_matViewProj * pos;\n}\n\nvoid main() { gl_Position = vert(); }\n",
        "frag": "\nprecision highp float;\nuniform vec4 cc_cameraPos;\n\n#if CC_NUM_DIR_LIGHTS > 0 || CC_NUM_POINT_LIGHTS > 0 || CC_NUM_SPOT_LIGHTS > 0 || CC_NUM_AMBIENT_LIGHTS > 0\nuniform vec4 cc_dirLightDirection[4];\nuniform vec4 cc_dirLightColor[4];\nuniform vec4 cc_pointLightPositionAndRange[4];\nuniform vec4 cc_pointLightColor[4];\nuniform vec4 cc_spotLightPositionAndRange[4];\nuniform vec4 cc_spotLightDirection[4];\nuniform vec4 cc_spotLightColor[4];\nuniform vec4 cc_ambientColor[4];\n\n#endif\n\nstruct LightInfo {\n  vec3 lightDir;\n  vec3 radiance;\n};\n\nLightInfo computeDirectionalLighting(\n  vec4 lightDirection,\n  vec4 lightColor\n) {\n  LightInfo ret;\n  ret.lightDir = -normalize(lightDirection.xyz);\n  ret.radiance = lightColor.rgb;\n  return ret;\n}\n\nLightInfo computePointLighting(\n  vec3 worldPosition,\n  vec4 lightPositionAndRange,\n  vec4 lightColor\n) {\n  LightInfo ret;\n  vec3 lightDir = lightPositionAndRange.xyz - worldPosition;\n  float attenuation = max(0., 1.0 - length(lightDir) / lightPositionAndRange.w);\n  \n  ret.lightDir = normalize(lightDir);\n  ret.radiance = lightColor.rgb * attenuation;\n  return ret;\n}\n\nLightInfo computeSpotLighting(\n  vec3 worldPosition,\n  vec4 lightPositionAndRange,\n  vec4 lightDirection,\n  vec4 lightColor\n) {\n  LightInfo ret;\n  vec3 lightDir = lightPositionAndRange.xyz - worldPosition;\n  float attenuation = max(0., 1.0 - length(lightDir) / lightPositionAndRange.w);\n  lightDir = normalize(lightDir);\n  float cosConeAngle = max(0., dot(lightDirection.xyz, -lightDir));\n  cosConeAngle = cosConeAngle < lightDirection.w ? 0. : cosConeAngle;\n  cosConeAngle = pow(cosConeAngle, lightColor.w);\n  \n  ret.lightDir = lightDir;\n  ret.radiance = lightColor.rgb * attenuation * cosConeAngle;\n  return ret;\n}\n\nstruct ToonSurface {\n  vec4 baseColor;\n\n  vec3 specular;\n  float specularThreshold;\n\n  vec3 position;\n  vec3 normal;\n\n  vec3 emissive;\n\n  vec3 shadowColor;\n  float shadowIntensity;\n  vec3 highlightColor;\n\n  float lightThreshold;\n  float lightSmoothness;\n};\n\nconst float T_H = 0.25;\nfloat TreshHoldLighting(float lThreshold, float smoothness, float v) {\n  return smoothstep(lThreshold-smoothness*T_H, lThreshold+smoothness*T_H, v);\n}\n\nvec3 combined (ToonSurface s, vec3 attenuation, vec3 lightColor, float NL, float NH, float specularWeight) {\n  vec3 c = vec3(0.0);\n\n  vec3 shadowColor = mix(s.highlightColor * lightColor, s.shadowColor, s.shadowIntensity);\n  vec3 diffuse = TreshHoldLighting(s.lightThreshold, s.lightSmoothness, NL) * attenuation;\n  diffuse = mix(shadowColor, s.highlightColor * lightColor, diffuse);\n\n  c += diffuse * s.baseColor.rgb;\n\n  float specularMask = step(specularWeight, NH);\n  vec3 specular = s.specular.rgb * specularMask;\n\n  c += specular * attenuation;\n\n  return c;\n}\n\nvec4 CCToonShading (ToonSurface s) {\n  vec3 V = normalize(cc_cameraPos.xyz - s.position);\n  vec3 N = s.normal;\n\n  vec3 finalColor = vec3(0.0);\n  float specularWeight = 1.0 - pow(s.specularThreshold, 5.0);\n\n  #if CC_NUM_DIR_LIGHTS > 0\n    for (int i = 0; i < CC_NUM_DIR_LIGHTS; i++) {\n        LightInfo info = computeDirectionalLighting(cc_dirLightDirection[i], cc_dirLightColor[i]);\n\n        vec3 L = info.lightDir;\n        float NL = 0.5 * dot(N, L) + 0.5;\n        float NH = 0.5 * dot(normalize(V + L), N) + 0.5;\n\n        finalColor += combined(s, cc_dirLightColor[i].rgb, info.radiance, NL, NH, specularWeight);\n    }\n  #endif\n\n  #if CC_NUM_POINT_LIGHTS > 0\n    for (int i = 0; i < CC_NUM_POINT_LIGHTS; i++) {\n      LightInfo info = computePointLighting(s.position, cc_pointLightPositionAndRange[i], cc_pointLightColor[i]);\n\n      vec3 PL = info.lightDir;\n      vec3 PH = normalize(PL + V);\n      float NL = 0.5 * dot(N, PL) + 0.5;\n      float NH = 0.5 * dot(N, PH) + 0.5;\n\n      finalColor += combined(s, cc_pointLightColor[i].rgb, info.radiance, NL, NH, specularWeight);\n    }\n  #endif\n\n  #if CC_NUM_SPOT_LIGHTS > 0\n    for (int i = 0; i < CC_NUM_SPOT_LIGHTS; i++) {\n      LightInfo info = computeSpotLighting(s.position, cc_spotLightPositionAndRange[i], cc_spotLightDirection[i], cc_spotLightColor[i]);\n\n      vec3 SL = info.lightDir;\n      vec3 SH = normalize(SL + V);\n      float NL = 0.5 * dot(N, SL) + 0.5;\n      float NH = 0.5 * dot(N, SH) + 0.5;\n\n      finalColor += combined(s, cc_spotLightColor[i].rgb, info.radiance, NL, NH, specularWeight);\n    }\n  #endif\n\n  #if CC_NUM_AMBIENT_LIGHTS > 0\n    for (int i = 0; i < CC_NUM_AMBIENT_LIGHTS; i++) {\n      finalColor += s.baseColor.rgb * cc_ambientColor[i].rgb;\n    }\n  #endif\n\n  finalColor += s.emissive;\n  return vec4(finalColor, s.baseColor.a);\n}\n\nvec3 SRGBToLinear(vec3 gamma)\n{\n\treturn pow(gamma, vec3(2.2));\n\n}\n\nvec3 LinearToSRGB(vec3 linear)\n{\n\treturn pow(linear, vec3(0.454545));\n\n}\n\nvec4 TEXEL_TO_LINEAR (in vec4 color) {\n  #if INPUT_IS_GAMMA\n    return vec4(SRGBToLinear(color.rgb), color.a);\n  #else\n    return color;\n  #endif\n}\n\nvec4 LINEAR_TO_OUTPUT_TEXEL (in vec4 color) {\n  #if OUTPUT_TO_GAMMA\n    return vec4(LinearToSRGB(color.rgb), color.a);\n  #else\n    return color;\n  #endif\n}\n\nvarying vec3 v_position;\nvarying vec2 v_uv;\n\nvarying vec3 v_normal;\n#if USE_NORMAL_MAP\n  varying vec3 v_tangent;\n  varying vec3 v_bitangent;\n  uniform sampler2D normalMap;\n#endif\n\n#if USE_BASE_COLOR_MAP\n  uniform sampler2D baseColorMap;\n#endif\n#if USE_SPECULAR_MAP\n  uniform sampler2D specularMap;\n#endif\n#if USE_EMISSIVE_MAP\n  uniform sampler2D emissiveMap;\n#endif\n\nuniform vec4 specular;\nuniform vec4 emissive;\nuniform vec4 shadowColor;\nuniform vec4 highlightColor;\nuniform float specularThreshold;\nuniform float shadowIntensity;\nuniform float lightThreshold;\nuniform float lightSmoothness;\n\nvoid surf (out ToonSurface s) {\n  #if USE_BASE_COLOR_MAP\n    s.baseColor = TEXEL_TO_LINEAR(texture2D(baseColorMap, v_uv));\n  #else\n    s.baseColor = highlightColor;    \n  #endif\n\n  s.normal = normalize(v_normal);\n  #if USE_NORMAL_MAP\n    vec3 nmmp = texture2D(normalMap, v_uv).xyz - vec3(0.5);\n    s.normal = normalize(\n      nmmp.x * normalize(v_tangent) +\n      nmmp.y * normalize(v_bitangent) +\n      nmmp.z * s.normal);\n  #endif\n\n  s.position = v_position;\n\n  s.specular = specular.rgb * specular.a;\n  #if USE_SPECULAR_MAP\n    s.specular *= TEXEL_TO_LINEAR(texture2D(specularMap, v_uv)).rgb;\n  #endif\n\n  s.emissive = emissive.rgb;\n  #if USE_EMISSIVE_MAP\n    s.emissive *= TEXEL_TO_LINEAR(texture2D(emissiveMap, v_uv)).rgb;\n  #endif\n\n  s.lightThreshold = lightThreshold;\n  s.lightSmoothness = lightSmoothness;\n  s.shadowColor = shadowColor.rgb;\n  s.highlightColor = highlightColor.rgb;\n  s.shadowIntensity = shadowIntensity;\n  s.specularThreshold = specularThreshold;\n}\n\nvec4 frag () {\n  ToonSurface s; \n  surf(s);\n  vec4 color = CCToonShading(s);\n  return LINEAR_TO_OUTPUT_TEXEL(color);\n}\n\nvoid main() { gl_FragColor = frag(); }\n"
      },
      "builtins": {
        "globals": {
          "blocks": [
            {
              "name": "CCGlobal",
              "defines": []
            },
            {
              "name": "CCLIGHTS",
              "defines": []
            }
          ],
          "samplers": []
        },
        "locals": {
          "blocks": [
            {
              "name": "CCLocal",
              "defines": []
            },
            {
              "name": "CC_JOINT_MATRIX",
              "defines": [
                "CC_USE_SKINNING"
              ]
            }
          ],
          "samplers": [
            {
              "name": "cc_jointsTexture",
              "defines": [
                "CC_USE_SKINNING",
                "CC_USE_JOINTS_TEXTRUE"
              ]
            }
          ]
        }
      },
      "defines": [
        {
          "name": "CC_USE_ATTRIBUTE_UV0",
          "type": "boolean",
          "defines": []
        },
        {
          "name": "CC_USE_ATTRIBUTE_COLOR",
          "type": "boolean",
          "defines": []
        },
        {
          "name": "CC_USE_ATTRIBUTE_NORMAL",
          "type": "boolean",
          "defines": []
        },
        {
          "name": "CC_USE_ATTRIBUTE_TANGENT",
          "type": "boolean",
          "defines": []
        },
        {
          "name": "CC_USE_SKINNING",
          "type": "boolean",
          "defines": []
        },
        {
          "name": "CC_USE_JOINTS_TEXTRUE",
          "type": "boolean",
          "defines": [
            "CC_USE_SKINNING",
            "CC_USE_SKINNING"
          ]
        },
        {
          "name": "CC_JOINTS_TEXTURE_FLOAT32",
          "type": "boolean",
          "defines": [
            "CC_USE_SKINNING",
            "CC_USE_SKINNING",
            "CC_USE_JOINTS_TEXTRUE"
          ]
        },
        {
          "name": "USE_NORMAL_MAP",
          "type": "boolean",
          "defines": []
        },
        {
          "name": "CC_NUM_DIR_LIGHTS",
          "type": "number",
          "defines": [],
          "range": [
            0,
            3
          ]
        },
        {
          "name": "CC_NUM_POINT_LIGHTS",
          "type": "number",
          "defines": [],
          "range": [
            0,
            3
          ]
        },
        {
          "name": "CC_NUM_SPOT_LIGHTS",
          "type": "number",
          "defines": [],
          "range": [
            0,
            3
          ]
        },
        {
          "name": "CC_NUM_AMBIENT_LIGHTS",
          "type": "number",
          "defines": [],
          "range": [
            0,
            3
          ]
        },
        {
          "name": "INPUT_IS_GAMMA",
          "type": "boolean",
          "defines": []
        },
        {
          "name": "OUTPUT_TO_GAMMA",
          "type": "boolean",
          "defines": []
        },
        {
          "name": "USE_BASE_COLOR_MAP",
          "type": "boolean",
          "defines": []
        },
        {
          "name": "USE_SPECULAR_MAP",
          "type": "boolean",
          "defines": []
        },
        {
          "name": "USE_EMISSIVE_MAP",
          "type": "boolean",
          "defines": []
        }
      ],
      "blocks": [
        {
          "name": "SKINNING",
          "members": [
            {
              "name": "cc_jointsTextureSize",
              "type": 14,
              "count": 1
            }
          ],
          "defines": [
            "CC_USE_SKINNING",
            "CC_USE_JOINTS_TEXTRUE"
          ],
          "binding": 0
        },
        {
          "name": "ToonVert",
          "members": [
            {
              "name": "tilingOffset",
              "type": 16,
              "count": 1
            }
          ],
          "defines": [],
          "binding": 1
        },
        {
          "name": "ToonFrag",
          "members": [
            {
              "name": "colorScale",
              "type": 16,
              "count": 1
            },
            {
              "name": "specular",
              "type": 16,
              "count": 1
            },
            {
              "name": "emissive",
              "type": 16,
              "count": 1
            },
            {
              "name": "shadowColor",
              "type": 16,
              "count": 1
            },
            {
              "name": "highlightColor",
              "type": 16,
              "count": 1
            },
            {
              "name": "specularThreshold",
              "type": 13,
              "count": 1
            },
            {
              "name": "shadowIntensity",
              "type": 13,
              "count": 1
            },
            {
              "name": "lightThreshold",
              "type": 13,
              "count": 1
            },
            {
              "name": "lightSmoothness",
              "type": 13,
              "count": 1
            }
          ],
          "defines": [],
          "binding": 2
        }
      ],
      "samplers": [
        {
          "name": "normalMap",
          "type": 29,
          "count": 1,
          "defines": [
            "USE_NORMAL_MAP"
          ],
          "binding": 30
        },
        {
          "name": "baseColorMap",
          "type": 29,
          "count": 1,
          "defines": [
            "USE_BASE_COLOR_MAP"
          ],
          "binding": 31
        },
        {
          "name": "specularMap",
          "type": 29,
          "count": 1,
          "defines": [
            "USE_SPECULAR_MAP"
          ],
          "binding": 32
        },
        {
          "name": "emissiveMap",
          "type": 29,
          "count": 1,
          "defines": [
            "USE_EMISSIVE_MAP"
          ],
          "binding": 33
        }
      ],
      "dependencies": {},
      "name": "builtin-toon|toon-vs:vert|toon-fs:frag"
    }
  ]
}