From c99525cb7f30f14b99418081edc0d472891f7c3d Mon Sep 17 00:00:00 2001 From: troublemaker52025 Date: Thu, 27 Aug 2020 22:14:16 -0500 Subject: [PATCH] Repair shadow matrix for 3d-v1.2 (#7223) * calculate sphere * calculate shadowCamera matirx * update * add pcf shadow * update * Modify shadowUI style * Solve the error * use else if * add pcf sampler to x25 times --- cocos/core/3d/builtin/effects.ts | 24 +++---- cocos/core/geometry/sphere.ts | 43 +++++++++++- cocos/core/pipeline/define.ts | 6 +- .../core/pipeline/forward/forward-pipeline.ts | 22 +++++- cocos/core/pipeline/forward/scene-culling.ts | 6 +- cocos/core/renderer/scene/shadows.ts | 70 ++++++++++++++++++- cocos/core/scene-graph/scene-globals.ts | 18 ++++- editor/assets/chunks/cc-shadow-map-fs.chunk | 47 ++++++++++++- editor/assets/chunks/cc-shadow.chunk | 2 + editor/assets/chunks/shading-standard.chunk | 9 ++- 10 files changed, 223 insertions(+), 24 deletions(-) diff --git a/cocos/core/3d/builtin/effects.ts b/cocos/core/3d/builtin/effects.ts index b0cc6dda728..23f3d0061f8 100644 --- a/cocos/core/3d/builtin/effects.ts +++ b/cocos/core/3d/builtin/effects.ts @@ -353,18 +353,18 @@ export default [ "shaders": [ { "name": "builtin-standard|standard-vs:vert|standard-fs:frag", - "hash": 1919679594, + "hash": 313692231, "glsl3": { - "vert": `\nprecision highp float;\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nin vec3 a_position;\nin vec3 a_normal;\nin vec2 a_texCoord;\nin vec4 a_tangent;\n#if CC_USE_MORPH\n int getVertexId() {\n return gl_VertexID;\n }\nlayout(std140) uniform CCMorph {\n vec4 cc_displacementWeights[15];\n vec4 cc_displacementTextureInfo;\n};\n vec4 fetchVec3ArrayFromTexture(sampler2D tex, int pixelIndex) {\n ivec2 texSize = textureSize(tex, 0);\n return texelFetch(tex, ivec2(pixelIndex % texSize.x, pixelIndex / texSize.x), 0);\n }\nfloat getDisplacementWeight(int index) {\n float m = mod(float(index), 4.0);\n if (m < 1.0) {\n return cc_displacementWeights[index / 4].x;\n } else if (m < 2.0) {\n return cc_displacementWeights[index / 4].y;\n } else if (m < 3.0) {\n return cc_displacementWeights[index / 4].z;\n } else {\n return cc_displacementWeights[index / 4].w;\n }\n}\nvec3 getVec3DisplacementFromTexture(sampler2D tex, int vertexIndex) {\n#if CC_MORPH_PRECOMPUTED\n return fetchVec3ArrayFromTexture(tex, vertexIndex).rgb;\n#else\n vec3 result = vec3(0, 0, 0);\n for (int iTarget = 0; iTarget < CC_MORPH_TARGET_COUNT; ++iTarget) {\n int dataPixelStart = int(fetchVec3ArrayFromTexture(tex, iTarget).r);\n result += (fetchVec3ArrayFromTexture(tex, dataPixelStart + vertexIndex).rgb * getDisplacementWeight(iTarget));\n }\n return result;\n#endif\n}\n#if CC_MORPH_TARGET_HAS_POSITION\n uniform sampler2D cc_PositionDisplacements;\n vec3 getPositionDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_PositionDisplacements, vertexId);\n }\n#endif\n#if CC_MORPH_TARGET_HAS_NORMAL\n uniform sampler2D cc_NormalDisplacements;\n vec3 getNormalDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_NormalDisplacements, vertexId);\n }\n#endif\n#if CC_MORPH_TARGET_HAS_TANGENT\n uniform sampler2D cc_TangentDisplacements;\n vec3 getTangentDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_TangentDisplacements, vertexId);\n }\n#endif\nvoid applyMorph (inout StandardVertInput attr) {\n int vertexId = getVertexId();\n#if CC_MORPH_TARGET_HAS_POSITION\n attr.position.xyz = attr.position.xyz + getPositionDisplacement(vertexId);\n#endif\n#if CC_MORPH_TARGET_HAS_NORMAL\n attr.normal.xyz = attr.normal.xyz + getNormalDisplacement(vertexId);\n#endif\n#if CC_MORPH_TARGET_HAS_TANGENT\n attr.tangent.xyz = attr.tangent.xyz + getTangentDisplacement(vertexId);\n#endif\n}\nvoid applyMorph (inout vec4 position) {\n#if CC_MORPH_TARGET_HAS_POSITION\n position.xyz = position.xyz + getPositionDisplacement(getVertexId());\n#endif\n}\n#endif\n#if CC_USE_SKINNING\nin vec4 a_joints;\nin vec4 a_weights;\n#if CC_USE_BAKED_ANIMATION\n #if USE_INSTANCING\n in highp vec4 a_jointAnimInfo;\n #endif\n layout(std140) uniform CCSkinningTexture {\n highp vec4 cc_jointTextureInfo;\n };\n layout(std140) uniform CCSkinningAnimation {\n highp vec4 cc_jointAnimInfo;\n };\n uniform highp sampler2D cc_jointTexture;\n #if !CC_SUPPORT_FLOAT_TEXTURE\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n #endif\n#else\n layout(std140) uniform CCSkinning {\n highp vec4 cc_joints[30 * 3];\n };\n#endif\n#if CC_USE_BAKED_ANIMATION\n #if CC_SUPPORT_FLOAT_TEXTURE\n mat4 getJointMatrix (float i) {\n #if USE_INSTANCING\n highp float j = 3.0 * (a_jointAnimInfo.x * a_jointAnimInfo.y + i) + a_jointAnimInfo.z;\n #else\n highp float j = 3.0 * (cc_jointAnimInfo.x * cc_jointTextureInfo.y + i) + cc_jointTextureInfo.z;\n #endif\n highp float invSize = cc_jointTextureInfo.w;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture(cc_jointTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture(cc_jointTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture(cc_jointTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n #else\n mat4 getJointMatrix (float i) {\n #if USE_INSTANCING\n highp float j = 12.0 * (a_jointAnimInfo.x * a_jointAnimInfo.y + i) + a_jointAnimInfo.z;\n #else\n highp float j = 12.0 * (cc_jointAnimInfo.x * cc_jointTextureInfo.y + i) + cc_jointTextureInfo.z;\n #endif\n highp float invSize = cc_jointTextureInfo.w;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n #endif\n#else\n mat4 getJointMatrix (float i) {\n int idx = int(i);\n vec4 v1 = cc_joints[idx * 3];\n vec4 v2 = cc_joints[idx * 3 + 1];\n vec4 v3 = cc_joints[idx * 3 + 2];\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y\n + getJointMatrix(a_joints.z) * a_weights.z\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\nlayout(std140) uniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n mediump vec4 cc_fogColor;\n mediump vec4 cc_fogBase;\n mediump vec4 cc_fogAdd;\n};\n#if USE_INSTANCING\n in vec4 a_matWorld0;\n in vec4 a_matWorld1;\n in vec4 a_matWorld2;\n #if USE_LIGHTMAP\n in vec4 a_lightingMapUVParam;\n #endif\n#elif USE_BATCHING\n in float a_dyn_batch_id;\n layout(std140) uniform CCLocalBatched {\n highp mat4 cc_matWorlds[10];\n };\n#else\nlayout(std140) uniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n highp vec4 cc_lightingMapUVParam;\n};\n#endif\nlayout(std140) uniform Constants {\n vec4 tilingOffset;\n vec4 albedo;\n vec4 albedoScaleAndCutoff;\n vec4 pbrParams;\n vec4 emissive;\n vec4 emissiveScaleParam;\n};\nfloat LinearFog(vec4 pos) {\n vec4 wPos = pos;\n float cam_dis = distance(cc_cameraPos, wPos);\n float fogStart = cc_fogBase.x;\n float fogEnd = cc_fogBase.y;\n return clamp((fogEnd - cam_dis) / (fogEnd - fogStart), 0., 1.);\n}\nfloat ExpFog(vec4 pos) {\n vec4 wPos = pos;\n float fogAtten = cc_fogAdd.z;\n float fogDensity = cc_fogBase.z;\n float cam_dis = distance(cc_cameraPos, wPos) / fogAtten * 4.;\n float f = exp(-cam_dis * fogDensity);\n return f;\n}\nfloat ExpSquaredFog(vec4 pos) {\n vec4 wPos = pos;\n float fogAtten = cc_fogAdd.z;\n float fogDensity = cc_fogBase.z;\n float cam_dis = distance(cc_cameraPos, wPos) / fogAtten * 4.;\n float f = exp(-cam_dis * cam_dis * fogDensity * fogDensity);\n return f;\n}\nfloat LayeredFog(vec4 pos) {\n vec4 wPos = pos;\n float fogAtten = cc_fogAdd.z;\n float _FogTop = cc_fogAdd.x;\n float _FogRange = cc_fogAdd.y;\n vec3 camWorldProj = cc_cameraPos.xyz;\n camWorldProj.y = 0.;\n vec3 worldPosProj = wPos.xyz;\n worldPosProj.y = 0.;\n float fDeltaD = distance(worldPosProj, camWorldProj) / fogAtten * 2.0;\n float fDeltaY, fDensityIntegral;\n if (cc_cameraPos.y > _FogTop) {\n if (wPos.y < _FogTop) {\n fDeltaY = (_FogTop - wPos.y) / _FogRange * 2.0;\n fDensityIntegral = fDeltaY * fDeltaY * 0.5;\n } else {\n fDeltaY = 0.;\n fDensityIntegral = 0.;\n }\n } else {\n if (wPos.y < _FogTop) {\n float fDeltaA = (_FogTop - cc_cameraPos.y) / _FogRange * 2.;\n float fDeltaB = (_FogTop - wPos.y) / _FogRange * 2.;\n fDeltaY = abs(fDeltaA - fDeltaB);\n fDensityIntegral = abs((fDeltaA * fDeltaA * 0.5) - (fDeltaB * fDeltaB * 0.5));\n } else {\n fDeltaY = abs(_FogTop - cc_cameraPos.y) / _FogRange * 2.;\n fDensityIntegral = abs(fDeltaY * fDeltaY * 0.5);\n }\n }\n float fDensity;\n if (fDeltaY != 0.) {\n fDensity = (sqrt(1.0 + ((fDeltaD / fDeltaY) * (fDeltaD / fDeltaY)))) * fDensityIntegral;\n } else {\n fDensity = 0.;\n }\n float f = exp(-fDensity);\n return f;\n}\nfloat CC_TRANSFER_FOG(vec4 pos) {\n #if CC_USE_FOG == 1\n return LinearFog(pos);\n #elif CC_USE_FOG == 2\n return ExpFog(pos);\n #elif CC_USE_FOG == 3\n return ExpSquaredFog(pos);\n #elif CC_USE_FOG == 4\n return LayeredFog(pos);\n #endif\n return 1.;\n}\nout vec4 v_shadowPos;\nlayout(std140) uniform CCShadow {\n highp mat4 cc_matLightPlaneProj;\n highp mat4 cc_matLightViewProj;\n lowp vec4 cc_shadowColor;\n};\n#if USE_VERTEX_COLOR\n in vec3 a_color;\n out vec3 v_color;\n#endif\nout vec3 v_position;\nout vec3 v_normal;\nout vec2 v_uv;\nout vec2 v_uv1;\nout float factor_fog;\n#if USE_NORMAL_MAP\n out vec3 v_tangent;\n out vec3 v_bitangent;\n#endif\n#if HAS_SECOND_UV || USE_LIGHTMAP\n in vec2 a_texCoord1;\n#endif\n#if USE_LIGHTMAP && !USE_BATCHING && !CC_FORWARD_ADD\n out vec2 v_luv;\nvoid CCLightingMapCaclUV()\n{\n#if !USE_INSTANCING\n v_luv = cc_lightingMapUVParam.xy + a_texCoord1 * cc_lightingMapUVParam.zw;\n#else\n v_luv = a_lightingMapUVParam.xy + a_texCoord1 * a_lightingMapUVParam.zw;\n#endif\n}\n#endif\nvec4 vert () {\n StandardVertInput In;\n In.position = vec4(a_position, 1.0);\n In.normal = a_normal;\n In.tangent = a_tangent;\n #if CC_USE_MORPH\n applyMorph(In);\n #endif\n #if CC_USE_SKINNING\n CCSkin(In);\n #endif\n mat4 matWorld, matWorldIT;\n #if USE_INSTANCING\n matWorld = mat4(\n vec4(a_matWorld0.xyz, 0.0),\n vec4(a_matWorld1.xyz, 0.0),\n vec4(a_matWorld2.xyz, 0.0),\n vec4(a_matWorld0.w, a_matWorld1.w, a_matWorld2.w, 1.0)\n );\n matWorldIT = matWorld;\n #elif USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id)];\n matWorldIT = matWorld;\n #else\n matWorld = cc_matWorld;\n matWorldIT = cc_matWorldIT;\n #endif\n vec4 pos = matWorld * In.position;\n v_position = pos.xyz;\n v_normal = normalize((matWorldIT * vec4(In.normal, 0.0)).xyz);\n #if USE_NORMAL_MAP\n v_tangent = normalize((matWorld * vec4(In.tangent.xyz, 0.0)).xyz);\n v_bitangent = cross(v_normal, v_tangent) * In.tangent.w;\n #endif\n v_uv = a_texCoord * tilingOffset.xy + tilingOffset.zw;\n #if HAS_SECOND_UV\n v_uv1 = a_texCoord1 * tilingOffset.xy + tilingOffset.zw;\n #endif\n #if USE_VERTEX_COLOR\n v_color = a_color;\n #endif\n factor_fog = CC_TRANSFER_FOG(matWorld * In.position);\n #if USE_LIGHTMAP && !USE_BATCHING && !CC_FORWARD_ADD\n CCLightingMapCaclUV();\n #endif\n v_shadowPos = cc_matLightViewProj * pos;\n return cc_matProj * (cc_matView * matWorld) * In.position;\n}\nvoid main() { gl_Position = vert(); }`, - "frag": `\nprecision highp float;\nlayout(std140) uniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n mediump vec4 cc_fogColor;\n mediump vec4 cc_fogBase;\n mediump vec4 cc_fogAdd;\n};\n#if CC_USE_IBL\nuniform samplerCube cc_environment;\nvec3 unpackRGBE (vec4 rgbe) {\n return rgbe.rgb * pow(2.0, rgbe.a * 255.0 - 128.0);\n}\nvec4 fragTextureLod (sampler2D tex, vec2 coord, float lod) {\n return textureLod(tex, coord, lod);\n}\nvec4 fragTextureLod (samplerCube tex, vec3 coord, float lod) {\n return textureLod(tex, coord, lod);\n}\n#endif\n#if USE_LIGHTMAP && !USE_BATCHING && !CC_FORWARD_ADD\n in vec2 v_luv;\nuniform sampler2D cc_lightingMap;\n#endif\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nfloat GGXMobile (float roughness, float NoH, vec3 H, vec3 N) {\n vec3 NxH = cross(N, H);\n float OneMinusNoHSqr = dot(NxH, NxH);\n float a = roughness * roughness;\n float n = NoH * a;\n float p = a / (OneMinusNoHSqr + n * n);\n return p * p;\n}\nfloat CalcSpecular (float roughness, float NoH, vec3 H, vec3 N) {\n return (roughness*0.25 + 0.25) * GGXMobile(roughness, NoH, H, N);\n}\nvec3 BRDFApprox (vec3 specular, float roughness, float NoV) {\n const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);\n const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);\n vec4 r = roughness * c0 + c1;\n float a004 = min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y;\n vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\n AB.y *= clamp(50.0 * specular.g, 0.0, 1.0);\n return specular * AB.x + AB.y;\n}\nstruct StandardSurface {\n vec4 albedo;\n vec3 position;\n vec3 normal;\n vec3 emissive;\n float roughness;\n float metallic;\n float occlusion;\n};\n#if CC_FORWARD_ADD\nlayout(std140) uniform CCForwardLight {\n highp vec4 cc_lightPos[1];\n vec4 cc_lightColor[1];\n vec4 cc_lightSizeRangeAngle[1];\n vec4 cc_lightDir[1];\n};\nfloat SmoothDistAtt (float distSqr, float invSqrAttRadius) {\n float factor = distSqr * invSqrAttRadius;\n float smoothFactor = clamp(1.0 - factor * factor, 0.0, 1.0);\n return smoothFactor * smoothFactor;\n}\nfloat GetDistAtt (float distSqr, float invSqrAttRadius) {\n float attenuation = 1.0 / max(distSqr, 0.01*0.01);\n attenuation *= SmoothDistAtt(distSqr , invSqrAttRadius);\n return attenuation;\n}\nfloat GetAngleAtt (vec3 L, vec3 litDir, float litAngleScale, float litAngleOffset) {\n float cd = dot(litDir, L);\n float attenuation = clamp(cd * litAngleScale + litAngleOffset, 0.0, 1.0);\n return (attenuation * attenuation);\n}\n vec4 CCStandardShading (StandardSurface s) {\n vec3 diffuse = s.albedo.rgb * (1.0 - s.metallic);\n vec3 specular = mix(vec3(0.04), s.albedo.rgb, s.metallic);\n vec3 diffuseContrib = diffuse / 3.14159265359;\n vec3 N = normalize(s.normal);\n vec3 V = normalize(cc_cameraPos.xyz - s.position);\n float NV = max(abs(dot(N, V)), 0.001);\n specular = BRDFApprox(specular, s.roughness, NV);\n vec3 finalColor = vec3(0.0);\n for (int i = 0; i < 1; i++) {\n vec3 SLU = cc_lightPos[i].xyz - s.position;\n vec3 SL = normalize(SLU);\n vec3 SH = normalize(SL + V);\n float SNL = max(dot(N, SL), 0.001);\n float SNH = max(dot(N, SH), 0.0);\n float distSqr = dot(SLU, SLU);\n float litRadius = cc_lightSizeRangeAngle[i].x;\n float litRadiusSqr = litRadius * litRadius;\n float illum = 3.14159265359 * (litRadiusSqr / max(litRadiusSqr , distSqr));\n float attRadiusSqrInv = 1.0 / max(cc_lightSizeRangeAngle[i].y, 0.01);\n attRadiusSqrInv *= attRadiusSqrInv;\n float att = GetDistAtt(distSqr, attRadiusSqrInv);\n vec3 lspec = specular * CalcSpecular(s.roughness, SNH, SH, N);\n if (cc_lightPos[i].w > 0.0) {\n float cosInner = max(dot(-cc_lightDir[i].xyz, SL), 0.01);\n float cosOuter = cc_lightSizeRangeAngle[i].z;\n float litAngleScale = 1.0 / max(0.001, cosInner - cosOuter);\n float litAngleOffset = -cosOuter * litAngleScale;\n att *= GetAngleAtt(SL, -cc_lightDir[i].xyz, litAngleScale, litAngleOffset);\n }\n finalColor += SNL * cc_lightColor[i].rgb * cc_lightColor[i].w * illum * att * (diffuseContrib + lspec);\n }\n finalColor = finalColor * s.occlusion;\n return vec4(finalColor, 0.0);\n }\n#else\n #if CC_RECEIVE_SHADOW\nin vec4 v_shadowPos;\nlayout(std140) uniform CCShadow {\n highp mat4 cc_matLightPlaneProj;\n highp mat4 cc_matLightViewProj;\n lowp vec4 cc_shadowColor;\n};\nuniform sampler2D cc_shadowMap;\nvec4 CCGetShadowFactor () {\n vec3 clipPos = v_shadowPos.xyz / v_shadowPos.w * 0.5 + 0.5;\n float depth = dot(texture(cc_shadowMap, clipPos.xy), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n if (depth < (clipPos.z - 0.001)) return cc_shadowColor;\n else return vec4(0);\n}\n #endif\n vec4 CCStandardShading (StandardSurface s) {\n vec3 diffuse = s.albedo.rgb * (1.0 - s.metallic);\n vec3 specular = mix(vec3(0.04), s.albedo.rgb, s.metallic);\n vec3 N = normalize(s.normal);\n vec3 V = normalize(cc_cameraPos.xyz - s.position);\n float NV = max(abs(dot(N, V)), 0.001);\n specular = BRDFApprox(specular, s.roughness, NV);\n vec3 L = normalize(-cc_mainLitDir.xyz);\n vec3 H = normalize(L+V);\n float NH = max(dot(N, H), 0.0);\n float NL = max(dot(N, L), 0.001);\n vec3 finalColor = NL * cc_mainLitColor.rgb * cc_mainLitColor.w;\n #if USE_LIGHTMAP && !USE_BATCHING && !CC_FORWARD_ADD\n vec4 lightmap = texture(cc_lightingMap, v_luv);\n finalColor = lightmap.a * lightmap.rgb + (1.0 - lightmap.a) * finalColor;\n #endif\n vec3 diffuseContrib = diffuse / 3.14159265359;\n vec3 specularContrib = specular * CalcSpecular(s.roughness, NH, H, N);\n finalColor *= (diffuseContrib + specularContrib);\n float fAmb = 0.5 - N.y * 0.5;\n vec3 ambDiff = mix(cc_ambientSky.rgb, cc_ambientGround.rgb, fAmb) * cc_ambientSky.w;\n finalColor += (ambDiff.rgb * diffuse);\n #if CC_USE_IBL\n vec3 R = normalize(reflect(-V, N));\n vec4 envmap = fragTextureLod(cc_environment, R, s.roughness * cc_ambientGround.w);\n #if CC_USE_IBL == 2\n vec3 env = unpackRGBE(envmap);\n #else\n vec3 env = SRGBToLinear(envmap.rgb);\n #endif\n finalColor += env * cc_ambientSky.w * specular;\n #endif\n finalColor = finalColor * s.occlusion;\n #if CC_USE_HDR\n s.emissive *= cc_exposure.w;\n #endif\n finalColor += s.emissive;\n #if CC_RECEIVE_SHADOW\n vec4 shadow = CCGetShadowFactor();\n finalColor = shadow.rgb * shadow.a + finalColor * (1.0 - shadow.a);\n #endif\n return vec4(finalColor, s.albedo.a);\n }\n#endif\nvec3 ACESToneMap (vec3 color) {\n color = min(color, vec3(8.0));\n const float A = 2.51;\n const float B = 0.03;\n const float C = 2.43;\n const float D = 0.59;\n const float E = 0.14;\n return (color * (A * color + B)) / (color * (C * color + D) + E);\n}\nvec4 CCFragOutput (vec4 color) {\n #if !CC_USE_HDR\n color.rgb = sqrt(ACESToneMap(color.rgb));\n #endif\n return color;\n}\nlayout(std140) uniform Constants {\n vec4 tilingOffset;\n vec4 albedo;\n vec4 albedoScaleAndCutoff;\n vec4 pbrParams;\n vec4 emissive;\n vec4 emissiveScaleParam;\n};\nin vec3 v_position;\nin vec2 v_uv;\nin vec2 v_uv1;\nin vec3 v_normal;\n#if USE_VERTEX_COLOR\n in vec3 v_color;\n#endif\n#if USE_ALBEDO_MAP\n uniform sampler2D albedoMap;\n#endif\n#if USE_NORMAL_MAP\n in vec3 v_tangent;\n in vec3 v_bitangent;\n uniform sampler2D normalMap;\n#endif\n#if USE_PBR_MAP\n uniform sampler2D pbrMap;\n#endif\n#if USE_METALLIC_ROUGHNESS_MAP\n uniform sampler2D metallicRoughnessMap;\n#endif\n#if USE_OCCLUSION_MAP\n uniform sampler2D occlusionMap;\n#endif\n#if USE_EMISSIVE_MAP\n uniform sampler2D emissiveMap;\n#endif\n#if USE_ALPHA_TEST\n#endif\nin float factor_fog;\nvoid surf (out StandardSurface s) {\n vec4 baseColor = albedo;\n #if USE_VERTEX_COLOR\n baseColor.rgb *= v_color;\n #endif\n #if USE_ALBEDO_MAP\n vec4 texColor = texture(albedoMap, ALBEDO_UV);\n texColor.rgb = SRGBToLinear(texColor.rgb);\n baseColor *= texColor;\n #endif\n s.albedo = baseColor;\n s.albedo.rgb *= albedoScaleAndCutoff.xyz;\n #if USE_ALPHA_TEST\n if (s.albedo.ALPHA_TEST_CHANNEL < albedoScaleAndCutoff.w) discard;\n #endif\n s.normal = v_normal;\n #if USE_NORMAL_MAP\n vec3 nmmp = texture(normalMap, NORMAL_UV).xyz - vec3(0.5);\n s.normal =\n (nmmp.x * pbrParams.w) * normalize(v_tangent) +\n (nmmp.y * pbrParams.w) * normalize(v_bitangent) +\n nmmp.z * normalize(s.normal);\n #endif\n s.position = v_position;\n vec4 pbr = pbrParams;\n #if USE_PBR_MAP\n vec4 res = texture(pbrMap, PBR_UV);\n pbr.x *= res.r;\n pbr.y *= res.g;\n pbr.z *= res.b;\n #endif\n #if USE_METALLIC_ROUGHNESS_MAP\n vec4 metallicRoughness = texture(metallicRoughnessMap, PBR_UV);\n pbr.z *= metallicRoughness.b;\n pbr.y *= metallicRoughness.g;\n #endif\n #if USE_OCCLUSION_MAP\n pbr.x *= texture(occlusionMap, PBR_UV).r;\n #endif\n s.occlusion = clamp(pbr.x, 0.0, 0.96);\n s.roughness = clamp(pbr.y, 0.04, 1.0);\n s.metallic = pbr.z;\n s.emissive = emissive.rgb * emissiveScaleParam.xyz;\n #if USE_EMISSIVE_MAP\n s.emissive *= SRGBToLinear(texture(emissiveMap, EMISSIVE_UV).rgb);\n #endif\n}\nvec4 frag () {\n StandardSurface s; surf(s);\n vec4 color = CCStandardShading(s);\n color = vec4(mix(CC_FORWARD_ADD > 0 ? vec3(0.0) : cc_fogColor.rgb, color.rgb, factor_fog), color.a);\n return CCFragOutput(color);\n}\nout vec4 cc_FragColor;\nvoid main() { cc_FragColor = frag(); }` + "vert": `\nprecision highp float;\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nin vec3 a_position;\nin vec3 a_normal;\nin vec2 a_texCoord;\nin vec4 a_tangent;\n#if CC_USE_MORPH\n int getVertexId() {\n return gl_VertexID;\n }\nlayout(std140) uniform CCMorph {\n vec4 cc_displacementWeights[15];\n vec4 cc_displacementTextureInfo;\n};\n vec4 fetchVec3ArrayFromTexture(sampler2D tex, int pixelIndex) {\n ivec2 texSize = textureSize(tex, 0);\n return texelFetch(tex, ivec2(pixelIndex % texSize.x, pixelIndex / texSize.x), 0);\n }\nfloat getDisplacementWeight(int index) {\n float m = mod(float(index), 4.0);\n if (m < 1.0) {\n return cc_displacementWeights[index / 4].x;\n } else if (m < 2.0) {\n return cc_displacementWeights[index / 4].y;\n } else if (m < 3.0) {\n return cc_displacementWeights[index / 4].z;\n } else {\n return cc_displacementWeights[index / 4].w;\n }\n}\nvec3 getVec3DisplacementFromTexture(sampler2D tex, int vertexIndex) {\n#if CC_MORPH_PRECOMPUTED\n return fetchVec3ArrayFromTexture(tex, vertexIndex).rgb;\n#else\n vec3 result = vec3(0, 0, 0);\n for (int iTarget = 0; iTarget < CC_MORPH_TARGET_COUNT; ++iTarget) {\n int dataPixelStart = int(fetchVec3ArrayFromTexture(tex, iTarget).r);\n result += (fetchVec3ArrayFromTexture(tex, dataPixelStart + vertexIndex).rgb * getDisplacementWeight(iTarget));\n }\n return result;\n#endif\n}\n#if CC_MORPH_TARGET_HAS_POSITION\n uniform sampler2D cc_PositionDisplacements;\n vec3 getPositionDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_PositionDisplacements, vertexId);\n }\n#endif\n#if CC_MORPH_TARGET_HAS_NORMAL\n uniform sampler2D cc_NormalDisplacements;\n vec3 getNormalDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_NormalDisplacements, vertexId);\n }\n#endif\n#if CC_MORPH_TARGET_HAS_TANGENT\n uniform sampler2D cc_TangentDisplacements;\n vec3 getTangentDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_TangentDisplacements, vertexId);\n }\n#endif\nvoid applyMorph (inout StandardVertInput attr) {\n int vertexId = getVertexId();\n#if CC_MORPH_TARGET_HAS_POSITION\n attr.position.xyz = attr.position.xyz + getPositionDisplacement(vertexId);\n#endif\n#if CC_MORPH_TARGET_HAS_NORMAL\n attr.normal.xyz = attr.normal.xyz + getNormalDisplacement(vertexId);\n#endif\n#if CC_MORPH_TARGET_HAS_TANGENT\n attr.tangent.xyz = attr.tangent.xyz + getTangentDisplacement(vertexId);\n#endif\n}\nvoid applyMorph (inout vec4 position) {\n#if CC_MORPH_TARGET_HAS_POSITION\n position.xyz = position.xyz + getPositionDisplacement(getVertexId());\n#endif\n}\n#endif\n#if CC_USE_SKINNING\nin vec4 a_joints;\nin vec4 a_weights;\n#if CC_USE_BAKED_ANIMATION\n #if USE_INSTANCING\n in highp vec4 a_jointAnimInfo;\n #endif\n layout(std140) uniform CCSkinningTexture {\n highp vec4 cc_jointTextureInfo;\n };\n layout(std140) uniform CCSkinningAnimation {\n highp vec4 cc_jointAnimInfo;\n };\n uniform highp sampler2D cc_jointTexture;\n #if !CC_SUPPORT_FLOAT_TEXTURE\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n #endif\n#else\n layout(std140) uniform CCSkinning {\n highp vec4 cc_joints[30 * 3];\n };\n#endif\n#if CC_USE_BAKED_ANIMATION\n #if CC_SUPPORT_FLOAT_TEXTURE\n mat4 getJointMatrix (float i) {\n #if USE_INSTANCING\n highp float j = 3.0 * (a_jointAnimInfo.x * a_jointAnimInfo.y + i) + a_jointAnimInfo.z;\n #else\n highp float j = 3.0 * (cc_jointAnimInfo.x * cc_jointTextureInfo.y + i) + cc_jointTextureInfo.z;\n #endif\n highp float invSize = cc_jointTextureInfo.w;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture(cc_jointTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture(cc_jointTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture(cc_jointTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n #else\n mat4 getJointMatrix (float i) {\n #if USE_INSTANCING\n highp float j = 12.0 * (a_jointAnimInfo.x * a_jointAnimInfo.y + i) + a_jointAnimInfo.z;\n #else\n highp float j = 12.0 * (cc_jointAnimInfo.x * cc_jointTextureInfo.y + i) + cc_jointTextureInfo.z;\n #endif\n highp float invSize = cc_jointTextureInfo.w;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n #endif\n#else\n mat4 getJointMatrix (float i) {\n int idx = int(i);\n vec4 v1 = cc_joints[idx * 3];\n vec4 v2 = cc_joints[idx * 3 + 1];\n vec4 v3 = cc_joints[idx * 3 + 2];\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y\n + getJointMatrix(a_joints.z) * a_weights.z\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\nlayout(std140) uniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n mediump vec4 cc_fogColor;\n mediump vec4 cc_fogBase;\n mediump vec4 cc_fogAdd;\n};\n#if USE_INSTANCING\n in vec4 a_matWorld0;\n in vec4 a_matWorld1;\n in vec4 a_matWorld2;\n #if USE_LIGHTMAP\n in vec4 a_lightingMapUVParam;\n #endif\n#elif USE_BATCHING\n in float a_dyn_batch_id;\n layout(std140) uniform CCLocalBatched {\n highp mat4 cc_matWorlds[10];\n };\n#else\nlayout(std140) uniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n highp vec4 cc_lightingMapUVParam;\n};\n#endif\nlayout(std140) uniform Constants {\n vec4 tilingOffset;\n vec4 albedo;\n vec4 albedoScaleAndCutoff;\n vec4 pbrParams;\n vec4 emissive;\n vec4 emissiveScaleParam;\n};\nfloat LinearFog(vec4 pos) {\n vec4 wPos = pos;\n float cam_dis = distance(cc_cameraPos, wPos);\n float fogStart = cc_fogBase.x;\n float fogEnd = cc_fogBase.y;\n return clamp((fogEnd - cam_dis) / (fogEnd - fogStart), 0., 1.);\n}\nfloat ExpFog(vec4 pos) {\n vec4 wPos = pos;\n float fogAtten = cc_fogAdd.z;\n float fogDensity = cc_fogBase.z;\n float cam_dis = distance(cc_cameraPos, wPos) / fogAtten * 4.;\n float f = exp(-cam_dis * fogDensity);\n return f;\n}\nfloat ExpSquaredFog(vec4 pos) {\n vec4 wPos = pos;\n float fogAtten = cc_fogAdd.z;\n float fogDensity = cc_fogBase.z;\n float cam_dis = distance(cc_cameraPos, wPos) / fogAtten * 4.;\n float f = exp(-cam_dis * cam_dis * fogDensity * fogDensity);\n return f;\n}\nfloat LayeredFog(vec4 pos) {\n vec4 wPos = pos;\n float fogAtten = cc_fogAdd.z;\n float _FogTop = cc_fogAdd.x;\n float _FogRange = cc_fogAdd.y;\n vec3 camWorldProj = cc_cameraPos.xyz;\n camWorldProj.y = 0.;\n vec3 worldPosProj = wPos.xyz;\n worldPosProj.y = 0.;\n float fDeltaD = distance(worldPosProj, camWorldProj) / fogAtten * 2.0;\n float fDeltaY, fDensityIntegral;\n if (cc_cameraPos.y > _FogTop) {\n if (wPos.y < _FogTop) {\n fDeltaY = (_FogTop - wPos.y) / _FogRange * 2.0;\n fDensityIntegral = fDeltaY * fDeltaY * 0.5;\n } else {\n fDeltaY = 0.;\n fDensityIntegral = 0.;\n }\n } else {\n if (wPos.y < _FogTop) {\n float fDeltaA = (_FogTop - cc_cameraPos.y) / _FogRange * 2.;\n float fDeltaB = (_FogTop - wPos.y) / _FogRange * 2.;\n fDeltaY = abs(fDeltaA - fDeltaB);\n fDensityIntegral = abs((fDeltaA * fDeltaA * 0.5) - (fDeltaB * fDeltaB * 0.5));\n } else {\n fDeltaY = abs(_FogTop - cc_cameraPos.y) / _FogRange * 2.;\n fDensityIntegral = abs(fDeltaY * fDeltaY * 0.5);\n }\n }\n float fDensity;\n if (fDeltaY != 0.) {\n fDensity = (sqrt(1.0 + ((fDeltaD / fDeltaY) * (fDeltaD / fDeltaY)))) * fDensityIntegral;\n } else {\n fDensity = 0.;\n }\n float f = exp(-fDensity);\n return f;\n}\nfloat CC_TRANSFER_FOG(vec4 pos) {\n #if CC_USE_FOG == 1\n return LinearFog(pos);\n #elif CC_USE_FOG == 2\n return ExpFog(pos);\n #elif CC_USE_FOG == 3\n return ExpSquaredFog(pos);\n #elif CC_USE_FOG == 4\n return LayeredFog(pos);\n #endif\n return 1.;\n}\nout vec4 v_shadowPos;\nlayout(std140) uniform CCShadow {\n highp mat4 cc_matLightPlaneProj;\n highp mat4 cc_matLightViewProj;\n lowp vec4 cc_shadowColor;\n lowp vec4 cc_shadowPCF;\n lowp vec4 cc_shadowSize;\n};\n#if USE_VERTEX_COLOR\n in vec3 a_color;\n out vec3 v_color;\n#endif\nout vec3 v_position;\nout vec3 v_normal;\nout vec2 v_uv;\nout vec2 v_uv1;\nout float factor_fog;\n#if USE_NORMAL_MAP\n out vec3 v_tangent;\n out vec3 v_bitangent;\n#endif\n#if HAS_SECOND_UV || USE_LIGHTMAP\n in vec2 a_texCoord1;\n#endif\n#if USE_LIGHTMAP && !USE_BATCHING && !CC_FORWARD_ADD\n out vec2 v_luv;\nvoid CCLightingMapCaclUV()\n{\n#if !USE_INSTANCING\n v_luv = cc_lightingMapUVParam.xy + a_texCoord1 * cc_lightingMapUVParam.zw;\n#else\n v_luv = a_lightingMapUVParam.xy + a_texCoord1 * a_lightingMapUVParam.zw;\n#endif\n}\n#endif\nvec4 vert () {\n StandardVertInput In;\n In.position = vec4(a_position, 1.0);\n In.normal = a_normal;\n In.tangent = a_tangent;\n #if CC_USE_MORPH\n applyMorph(In);\n #endif\n #if CC_USE_SKINNING\n CCSkin(In);\n #endif\n mat4 matWorld, matWorldIT;\n #if USE_INSTANCING\n matWorld = mat4(\n vec4(a_matWorld0.xyz, 0.0),\n vec4(a_matWorld1.xyz, 0.0),\n vec4(a_matWorld2.xyz, 0.0),\n vec4(a_matWorld0.w, a_matWorld1.w, a_matWorld2.w, 1.0)\n );\n matWorldIT = matWorld;\n #elif USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id)];\n matWorldIT = matWorld;\n #else\n matWorld = cc_matWorld;\n matWorldIT = cc_matWorldIT;\n #endif\n vec4 pos = matWorld * In.position;\n v_position = pos.xyz;\n v_normal = normalize((matWorldIT * vec4(In.normal, 0.0)).xyz);\n #if USE_NORMAL_MAP\n v_tangent = normalize((matWorld * vec4(In.tangent.xyz, 0.0)).xyz);\n v_bitangent = cross(v_normal, v_tangent) * In.tangent.w;\n #endif\n v_uv = a_texCoord * tilingOffset.xy + tilingOffset.zw;\n #if HAS_SECOND_UV\n v_uv1 = a_texCoord1 * tilingOffset.xy + tilingOffset.zw;\n #endif\n #if USE_VERTEX_COLOR\n v_color = a_color;\n #endif\n factor_fog = CC_TRANSFER_FOG(matWorld * In.position);\n #if USE_LIGHTMAP && !USE_BATCHING && !CC_FORWARD_ADD\n CCLightingMapCaclUV();\n #endif\n v_shadowPos = cc_matLightViewProj * pos;\n return cc_matProj * (cc_matView * matWorld) * In.position;\n}\nvoid main() { gl_Position = vert(); }`, + "frag": `\nprecision highp float;\nlayout(std140) uniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n mediump vec4 cc_fogColor;\n mediump vec4 cc_fogBase;\n mediump vec4 cc_fogAdd;\n};\nlayout(std140) uniform CCShadow {\n highp mat4 cc_matLightPlaneProj;\n highp mat4 cc_matLightViewProj;\n lowp vec4 cc_shadowColor;\n lowp vec4 cc_shadowPCF;\n lowp vec4 cc_shadowSize;\n};\n#if CC_USE_IBL\nuniform samplerCube cc_environment;\nvec3 unpackRGBE (vec4 rgbe) {\n return rgbe.rgb * pow(2.0, rgbe.a * 255.0 - 128.0);\n}\nvec4 fragTextureLod (sampler2D tex, vec2 coord, float lod) {\n return textureLod(tex, coord, lod);\n}\nvec4 fragTextureLod (samplerCube tex, vec3 coord, float lod) {\n return textureLod(tex, coord, lod);\n}\n#endif\n#if USE_LIGHTMAP && !USE_BATCHING && !CC_FORWARD_ADD\n in vec2 v_luv;\nuniform sampler2D cc_lightingMap;\n#endif\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nfloat GGXMobile (float roughness, float NoH, vec3 H, vec3 N) {\n vec3 NxH = cross(N, H);\n float OneMinusNoHSqr = dot(NxH, NxH);\n float a = roughness * roughness;\n float n = NoH * a;\n float p = a / (OneMinusNoHSqr + n * n);\n return p * p;\n}\nfloat CalcSpecular (float roughness, float NoH, vec3 H, vec3 N) {\n return (roughness*0.25 + 0.25) * GGXMobile(roughness, NoH, H, N);\n}\nvec3 BRDFApprox (vec3 specular, float roughness, float NoV) {\n const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);\n const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);\n vec4 r = roughness * c0 + c1;\n float a004 = min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y;\n vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\n AB.y *= clamp(50.0 * specular.g, 0.0, 1.0);\n return specular * AB.x + AB.y;\n}\nstruct StandardSurface {\n vec4 albedo;\n vec3 position;\n vec3 normal;\n vec3 emissive;\n float roughness;\n float metallic;\n float occlusion;\n};\n#if CC_FORWARD_ADD\nlayout(std140) uniform CCForwardLight {\n highp vec4 cc_lightPos[1];\n vec4 cc_lightColor[1];\n vec4 cc_lightSizeRangeAngle[1];\n vec4 cc_lightDir[1];\n};\nfloat SmoothDistAtt (float distSqr, float invSqrAttRadius) {\n float factor = distSqr * invSqrAttRadius;\n float smoothFactor = clamp(1.0 - factor * factor, 0.0, 1.0);\n return smoothFactor * smoothFactor;\n}\nfloat GetDistAtt (float distSqr, float invSqrAttRadius) {\n float attenuation = 1.0 / max(distSqr, 0.01*0.01);\n attenuation *= SmoothDistAtt(distSqr , invSqrAttRadius);\n return attenuation;\n}\nfloat GetAngleAtt (vec3 L, vec3 litDir, float litAngleScale, float litAngleOffset) {\n float cd = dot(litDir, L);\n float attenuation = clamp(cd * litAngleScale + litAngleOffset, 0.0, 1.0);\n return (attenuation * attenuation);\n}\n vec4 CCStandardShading (StandardSurface s) {\n vec3 diffuse = s.albedo.rgb * (1.0 - s.metallic);\n vec3 specular = mix(vec3(0.04), s.albedo.rgb, s.metallic);\n vec3 diffuseContrib = diffuse / 3.14159265359;\n vec3 N = normalize(s.normal);\n vec3 V = normalize(cc_cameraPos.xyz - s.position);\n float NV = max(abs(dot(N, V)), 0.001);\n specular = BRDFApprox(specular, s.roughness, NV);\n vec3 finalColor = vec3(0.0);\n for (int i = 0; i < 1; i++) {\n vec3 SLU = cc_lightPos[i].xyz - s.position;\n vec3 SL = normalize(SLU);\n vec3 SH = normalize(SL + V);\n float SNL = max(dot(N, SL), 0.001);\n float SNH = max(dot(N, SH), 0.0);\n float distSqr = dot(SLU, SLU);\n float litRadius = cc_lightSizeRangeAngle[i].x;\n float litRadiusSqr = litRadius * litRadius;\n float illum = 3.14159265359 * (litRadiusSqr / max(litRadiusSqr , distSqr));\n float attRadiusSqrInv = 1.0 / max(cc_lightSizeRangeAngle[i].y, 0.01);\n attRadiusSqrInv *= attRadiusSqrInv;\n float att = GetDistAtt(distSqr, attRadiusSqrInv);\n vec3 lspec = specular * CalcSpecular(s.roughness, SNH, SH, N);\n if (cc_lightPos[i].w > 0.0) {\n float cosInner = max(dot(-cc_lightDir[i].xyz, SL), 0.01);\n float cosOuter = cc_lightSizeRangeAngle[i].z;\n float litAngleScale = 1.0 / max(0.001, cosInner - cosOuter);\n float litAngleOffset = -cosOuter * litAngleScale;\n att *= GetAngleAtt(SL, -cc_lightDir[i].xyz, litAngleScale, litAngleOffset);\n }\n finalColor += SNL * cc_lightColor[i].rgb * cc_lightColor[i].w * illum * att * (diffuseContrib + lspec);\n }\n finalColor = finalColor * s.occlusion;\n return vec4(finalColor, 0.0);\n }\n#else\n #if CC_RECEIVE_SHADOW\nin vec4 v_shadowPos;\nuniform sampler2D cc_shadowMap;\nvec4 CCGetShadowFactorEasy () {\n vec3 clipPos = v_shadowPos.xyz / v_shadowPos.w * 0.5 + 0.5;\n float depth = dot(texture(cc_shadowMap, clipPos.xy), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n if (depth < (clipPos.z - 0.001)) return cc_shadowColor;\n else return vec4(0);\n}\nvec4 CCGetShadowFactorHard () {\n vec3 clipPos = v_shadowPos.xyz / v_shadowPos.w * 0.5 + 0.5;\n float offsetx = 1.0 / cc_shadowSize.x;\n float offsety = 1.0 / cc_shadowSize.y;\n float depth = 0.0;\n depth += dot(texture(cc_shadowMap, vec2(clipPos.x - offsetx, clipPos.y - offsety)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture(cc_shadowMap, vec2(clipPos.x, clipPos.y - offsety)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture(cc_shadowMap, vec2(clipPos.x + offsetx, clipPos.y - offsety)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture(cc_shadowMap, vec2(clipPos.x - offsetx, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture(cc_shadowMap, vec2(clipPos.x, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture(cc_shadowMap, vec2(clipPos.x + offsetx, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture(cc_shadowMap, vec2(clipPos.x - offsetx, clipPos.y + offsety)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture(cc_shadowMap, vec2(clipPos.x, clipPos.y + offsety)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture(cc_shadowMap, vec2(clipPos.x + offsetx, clipPos.y + offsety)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth /= 9.0;\n if (depth < (clipPos.z - 0.001)) return cc_shadowColor;\n else return vec4(0);\n}\nvec4 CCGetShadowFactorCommon () {\n vec3 clipPos = v_shadowPos.xyz / v_shadowPos.w * 0.5 + 0.5;\n float offsetx = 1.0 / cc_shadowSize.x;\n float offsety = 1.0 / cc_shadowSize.y;\n float depth = 0.0;\n depth += dot(texture(cc_shadowMap, vec2(clipPos.x - offsetx, clipPos.y - offsety)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture(cc_shadowMap, vec2(clipPos.x - offsetx, clipPos.y + offsety)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture(cc_shadowMap, vec2(clipPos.x, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture(cc_shadowMap, vec2(clipPos.x + offsetx, clipPos.y - offsety)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture(cc_shadowMap, vec2(clipPos.x + offsetx, clipPos.y + offsety)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth /= 5.0;\n if (depth < (clipPos.z - 0.001)) return cc_shadowColor;\n else return vec4(0);\n}\n #endif\n vec4 CCStandardShading (StandardSurface s) {\n vec3 diffuse = s.albedo.rgb * (1.0 - s.metallic);\n vec3 specular = mix(vec3(0.04), s.albedo.rgb, s.metallic);\n vec3 N = normalize(s.normal);\n vec3 V = normalize(cc_cameraPos.xyz - s.position);\n float NV = max(abs(dot(N, V)), 0.001);\n specular = BRDFApprox(specular, s.roughness, NV);\n vec3 L = normalize(-cc_mainLitDir.xyz);\n vec3 H = normalize(L+V);\n float NH = max(dot(N, H), 0.0);\n float NL = max(dot(N, L), 0.001);\n vec3 finalColor = NL * cc_mainLitColor.rgb * cc_mainLitColor.w;\n #if USE_LIGHTMAP && !USE_BATCHING && !CC_FORWARD_ADD\n vec4 lightmap = texture(cc_lightingMap, v_luv);\n finalColor = lightmap.a * lightmap.rgb + (1.0 - lightmap.a) * finalColor;\n #endif\n vec3 diffuseContrib = diffuse / 3.14159265359;\n vec3 specularContrib = specular * CalcSpecular(s.roughness, NH, H, N);\n finalColor *= (diffuseContrib + specularContrib);\n float fAmb = 0.5 - N.y * 0.5;\n vec3 ambDiff = mix(cc_ambientSky.rgb, cc_ambientGround.rgb, fAmb) * cc_ambientSky.w;\n finalColor += (ambDiff.rgb * diffuse);\n #if CC_USE_IBL\n vec3 R = normalize(reflect(-V, N));\n vec4 envmap = fragTextureLod(cc_environment, R, s.roughness * cc_ambientGround.w);\n #if CC_USE_IBL == 2\n vec3 env = unpackRGBE(envmap);\n #else\n vec3 env = SRGBToLinear(envmap.rgb);\n #endif\n finalColor += env * cc_ambientSky.w * specular;\n #endif\n finalColor = finalColor * s.occlusion;\n #if CC_USE_HDR\n s.emissive *= cc_exposure.w;\n #endif\n finalColor += s.emissive;\n #if CC_RECEIVE_SHADOW\n vec4 shadow = vec4(1.0);\n float pcf = cc_shadowPCF.x + 0.001;\n if (pcf > 2.0) {shadow = CCGetShadowFactorEasy();}\n if (2.0 > pcf && pcf > 1.0) {shadow = CCGetShadowFactorCommon();}\n if (1.0 > pcf && pcf > 0.0) {shadow = CCGetShadowFactorHard();}\n finalColor = shadow.rgb * shadow.a + finalColor * (1.0 - shadow.a);\n #endif\n return vec4(finalColor, s.albedo.a);\n }\n#endif\nvec3 ACESToneMap (vec3 color) {\n color = min(color, vec3(8.0));\n const float A = 2.51;\n const float B = 0.03;\n const float C = 2.43;\n const float D = 0.59;\n const float E = 0.14;\n return (color * (A * color + B)) / (color * (C * color + D) + E);\n}\nvec4 CCFragOutput (vec4 color) {\n #if !CC_USE_HDR\n color.rgb = sqrt(ACESToneMap(color.rgb));\n #endif\n return color;\n}\nlayout(std140) uniform Constants {\n vec4 tilingOffset;\n vec4 albedo;\n vec4 albedoScaleAndCutoff;\n vec4 pbrParams;\n vec4 emissive;\n vec4 emissiveScaleParam;\n};\nin vec3 v_position;\nin vec2 v_uv;\nin vec2 v_uv1;\nin vec3 v_normal;\n#if USE_VERTEX_COLOR\n in vec3 v_color;\n#endif\n#if USE_ALBEDO_MAP\n uniform sampler2D albedoMap;\n#endif\n#if USE_NORMAL_MAP\n in vec3 v_tangent;\n in vec3 v_bitangent;\n uniform sampler2D normalMap;\n#endif\n#if USE_PBR_MAP\n uniform sampler2D pbrMap;\n#endif\n#if USE_METALLIC_ROUGHNESS_MAP\n uniform sampler2D metallicRoughnessMap;\n#endif\n#if USE_OCCLUSION_MAP\n uniform sampler2D occlusionMap;\n#endif\n#if USE_EMISSIVE_MAP\n uniform sampler2D emissiveMap;\n#endif\n#if USE_ALPHA_TEST\n#endif\nin float factor_fog;\nvoid surf (out StandardSurface s) {\n vec4 baseColor = albedo;\n #if USE_VERTEX_COLOR\n baseColor.rgb *= v_color;\n #endif\n #if USE_ALBEDO_MAP\n vec4 texColor = texture(albedoMap, ALBEDO_UV);\n texColor.rgb = SRGBToLinear(texColor.rgb);\n baseColor *= texColor;\n #endif\n s.albedo = baseColor;\n s.albedo.rgb *= albedoScaleAndCutoff.xyz;\n #if USE_ALPHA_TEST\n if (s.albedo.ALPHA_TEST_CHANNEL < albedoScaleAndCutoff.w) discard;\n #endif\n s.normal = v_normal;\n #if USE_NORMAL_MAP\n vec3 nmmp = texture(normalMap, NORMAL_UV).xyz - vec3(0.5);\n s.normal =\n (nmmp.x * pbrParams.w) * normalize(v_tangent) +\n (nmmp.y * pbrParams.w) * normalize(v_bitangent) +\n nmmp.z * normalize(s.normal);\n #endif\n s.position = v_position;\n vec4 pbr = pbrParams;\n #if USE_PBR_MAP\n vec4 res = texture(pbrMap, PBR_UV);\n pbr.x *= res.r;\n pbr.y *= res.g;\n pbr.z *= res.b;\n #endif\n #if USE_METALLIC_ROUGHNESS_MAP\n vec4 metallicRoughness = texture(metallicRoughnessMap, PBR_UV);\n pbr.z *= metallicRoughness.b;\n pbr.y *= metallicRoughness.g;\n #endif\n #if USE_OCCLUSION_MAP\n pbr.x *= texture(occlusionMap, PBR_UV).r;\n #endif\n s.occlusion = clamp(pbr.x, 0.0, 0.96);\n s.roughness = clamp(pbr.y, 0.04, 1.0);\n s.metallic = pbr.z;\n s.emissive = emissive.rgb * emissiveScaleParam.xyz;\n #if USE_EMISSIVE_MAP\n s.emissive *= SRGBToLinear(texture(emissiveMap, EMISSIVE_UV).rgb);\n #endif\n}\nvec4 frag () {\n StandardSurface s; surf(s);\n vec4 color = CCStandardShading(s);\n color = vec4(mix(CC_FORWARD_ADD > 0 ? vec3(0.0) : cc_fogColor.rgb, color.rgb, factor_fog), color.a);\n return CCFragOutput(color);\n}\nout vec4 cc_FragColor;\nvoid main() { cc_FragColor = frag(); }` }, "glsl1": { "vert": `\nprecision highp float;\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nattribute vec3 a_position;\nattribute vec3 a_normal;\nattribute vec2 a_texCoord;\nattribute vec4 a_tangent;\n#if CC_USE_MORPH\n attribute float a_vertexId;\n int getVertexId() {\n return int(a_vertexId);\n }\nuniform vec4 cc_displacementWeights[15];\nuniform vec4 cc_displacementTextureInfo;\n vec2 getPixelLocation(vec2 textureResolution, int pixelIndex) {\n float pixelIndexF = float(pixelIndex);\n float x = mod(pixelIndexF, textureResolution.x);\n float y = floor(pixelIndexF / textureResolution.x);\n return vec2(x, y);\n }\n vec2 getPixelCoordFromLocation(vec2 location, vec2 textureResolution) {\n return (vec2(location.x, location.y) + .5) / textureResolution;\n }\n #if CC_SUPPORT_FLOAT_TEXTURE\n vec4 fetchVec3ArrayFromTexture(sampler2D tex, int elementIndex) {\n int pixelIndex = elementIndex;\n vec2 location = getPixelLocation(cc_displacementTextureInfo.xy, pixelIndex);\n vec2 uv = getPixelCoordFromLocation(location, cc_displacementTextureInfo.xy);\n return texture2D(tex, uv);\n }\n #else\n vec4 fetchVec3ArrayFromTexture(sampler2D tex, int elementIndex) {\n int pixelIndex = elementIndex * 4;\n vec2 location = getPixelLocation(cc_displacementTextureInfo.xy, pixelIndex);\n vec2 x = getPixelCoordFromLocation(location + vec2(0.0, 0.0), cc_displacementTextureInfo.xy);\n vec2 y = getPixelCoordFromLocation(location + vec2(1.0, 0.0), cc_displacementTextureInfo.xy);\n vec2 z = getPixelCoordFromLocation(location + vec2(2.0, 0.0), cc_displacementTextureInfo.xy);\n return vec4(\n decode32(texture2D(tex, x)),\n decode32(texture2D(tex, y)),\n decode32(texture2D(tex, z)),\n 1.0\n );\n }\n #endif\nfloat getDisplacementWeight(int index) {\n float m = mod(float(index), 4.0);\n if (m < 1.0) {\n return cc_displacementWeights[index / 4].x;\n } else if (m < 2.0) {\n return cc_displacementWeights[index / 4].y;\n } else if (m < 3.0) {\n return cc_displacementWeights[index / 4].z;\n } else {\n return cc_displacementWeights[index / 4].w;\n }\n}\nvec3 getVec3DisplacementFromTexture(sampler2D tex, int vertexIndex) {\n#if CC_MORPH_PRECOMPUTED\n return fetchVec3ArrayFromTexture(tex, vertexIndex).rgb;\n#else\n vec3 result = vec3(0, 0, 0);\n for (int iTarget = 0; iTarget < CC_MORPH_TARGET_COUNT; ++iTarget) {\n int dataPixelStart = int(fetchVec3ArrayFromTexture(tex, iTarget).r);\n result += (fetchVec3ArrayFromTexture(tex, dataPixelStart + vertexIndex).rgb * getDisplacementWeight(iTarget));\n }\n return result;\n#endif\n}\n#if CC_MORPH_TARGET_HAS_POSITION\n uniform sampler2D cc_PositionDisplacements;\n vec3 getPositionDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_PositionDisplacements, vertexId);\n }\n#endif\n#if CC_MORPH_TARGET_HAS_NORMAL\n uniform sampler2D cc_NormalDisplacements;\n vec3 getNormalDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_NormalDisplacements, vertexId);\n }\n#endif\n#if CC_MORPH_TARGET_HAS_TANGENT\n uniform sampler2D cc_TangentDisplacements;\n vec3 getTangentDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_TangentDisplacements, vertexId);\n }\n#endif\nvoid applyMorph (inout StandardVertInput attr) {\n int vertexId = getVertexId();\n#if CC_MORPH_TARGET_HAS_POSITION\n attr.position.xyz = attr.position.xyz + getPositionDisplacement(vertexId);\n#endif\n#if CC_MORPH_TARGET_HAS_NORMAL\n attr.normal.xyz = attr.normal.xyz + getNormalDisplacement(vertexId);\n#endif\n#if CC_MORPH_TARGET_HAS_TANGENT\n attr.tangent.xyz = attr.tangent.xyz + getTangentDisplacement(vertexId);\n#endif\n}\nvoid applyMorph (inout vec4 position) {\n#if CC_MORPH_TARGET_HAS_POSITION\n position.xyz = position.xyz + getPositionDisplacement(getVertexId());\n#endif\n}\n#endif\n#if CC_USE_SKINNING\nattribute vec4 a_joints;\nattribute vec4 a_weights;\n#if CC_USE_BAKED_ANIMATION\n #if USE_INSTANCING\n attribute highp vec4 a_jointAnimInfo;\n #endif\n uniform highp vec4 cc_jointTextureInfo;\n uniform highp vec4 cc_jointAnimInfo;\n uniform highp sampler2D cc_jointTexture;\n #if !CC_SUPPORT_FLOAT_TEXTURE\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n #endif\n#else\n uniform highp vec4 cc_joints[90];\n#endif\n#if CC_USE_BAKED_ANIMATION\n #if CC_SUPPORT_FLOAT_TEXTURE\n mat4 getJointMatrix (float i) {\n #if USE_INSTANCING\n highp float j = 3.0 * (a_jointAnimInfo.x * a_jointAnimInfo.y + i) + a_jointAnimInfo.z;\n #else\n highp float j = 3.0 * (cc_jointAnimInfo.x * cc_jointTextureInfo.y + i) + cc_jointTextureInfo.z;\n #endif\n highp float invSize = cc_jointTextureInfo.w;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture2D(cc_jointTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture2D(cc_jointTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture2D(cc_jointTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n #else\n mat4 getJointMatrix (float i) {\n #if USE_INSTANCING\n highp float j = 12.0 * (a_jointAnimInfo.x * a_jointAnimInfo.y + i) + a_jointAnimInfo.z;\n #else\n highp float j = 12.0 * (cc_jointAnimInfo.x * cc_jointTextureInfo.y + i) + cc_jointTextureInfo.z;\n #endif\n highp float invSize = cc_jointTextureInfo.w;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture2D(cc_jointTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture2D(cc_jointTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture2D(cc_jointTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture2D(cc_jointTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture2D(cc_jointTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture2D(cc_jointTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture2D(cc_jointTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture2D(cc_jointTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture2D(cc_jointTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture2D(cc_jointTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture2D(cc_jointTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture2D(cc_jointTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n #endif\n#else\n mat4 getJointMatrix (float i) {\n int idx = int(i);\n vec4 v1 = cc_joints[idx * 3];\n vec4 v2 = cc_joints[idx * 3 + 1];\n vec4 v3 = cc_joints[idx * 3 + 2];\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y\n + getJointMatrix(a_joints.z) * a_weights.z\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\nuniform highp mat4 cc_matView;\nuniform highp mat4 cc_matProj;\nuniform highp vec4 cc_cameraPos;\nuniform mediump vec4 cc_fogBase;\nuniform mediump vec4 cc_fogAdd;\n#if USE_INSTANCING\n attribute vec4 a_matWorld0;\n attribute vec4 a_matWorld1;\n attribute vec4 a_matWorld2;\n #if USE_LIGHTMAP\n attribute vec4 a_lightingMapUVParam;\n #endif\n#elif USE_BATCHING\n attribute float a_dyn_batch_id;\n uniform highp mat4 cc_matWorlds[10];\n#else\nuniform highp mat4 cc_matWorld;\nuniform highp mat4 cc_matWorldIT;\nuniform highp vec4 cc_lightingMapUVParam;\n#endif\nuniform vec4 tilingOffset;\nfloat LinearFog(vec4 pos) {\n vec4 wPos = pos;\n float cam_dis = distance(cc_cameraPos, wPos);\n float fogStart = cc_fogBase.x;\n float fogEnd = cc_fogBase.y;\n return clamp((fogEnd - cam_dis) / (fogEnd - fogStart), 0., 1.);\n}\nfloat ExpFog(vec4 pos) {\n vec4 wPos = pos;\n float fogAtten = cc_fogAdd.z;\n float fogDensity = cc_fogBase.z;\n float cam_dis = distance(cc_cameraPos, wPos) / fogAtten * 4.;\n float f = exp(-cam_dis * fogDensity);\n return f;\n}\nfloat ExpSquaredFog(vec4 pos) {\n vec4 wPos = pos;\n float fogAtten = cc_fogAdd.z;\n float fogDensity = cc_fogBase.z;\n float cam_dis = distance(cc_cameraPos, wPos) / fogAtten * 4.;\n float f = exp(-cam_dis * cam_dis * fogDensity * fogDensity);\n return f;\n}\nfloat LayeredFog(vec4 pos) {\n vec4 wPos = pos;\n float fogAtten = cc_fogAdd.z;\n float _FogTop = cc_fogAdd.x;\n float _FogRange = cc_fogAdd.y;\n vec3 camWorldProj = cc_cameraPos.xyz;\n camWorldProj.y = 0.;\n vec3 worldPosProj = wPos.xyz;\n worldPosProj.y = 0.;\n float fDeltaD = distance(worldPosProj, camWorldProj) / fogAtten * 2.0;\n float fDeltaY, fDensityIntegral;\n if (cc_cameraPos.y > _FogTop) {\n if (wPos.y < _FogTop) {\n fDeltaY = (_FogTop - wPos.y) / _FogRange * 2.0;\n fDensityIntegral = fDeltaY * fDeltaY * 0.5;\n } else {\n fDeltaY = 0.;\n fDensityIntegral = 0.;\n }\n } else {\n if (wPos.y < _FogTop) {\n float fDeltaA = (_FogTop - cc_cameraPos.y) / _FogRange * 2.;\n float fDeltaB = (_FogTop - wPos.y) / _FogRange * 2.;\n fDeltaY = abs(fDeltaA - fDeltaB);\n fDensityIntegral = abs((fDeltaA * fDeltaA * 0.5) - (fDeltaB * fDeltaB * 0.5));\n } else {\n fDeltaY = abs(_FogTop - cc_cameraPos.y) / _FogRange * 2.;\n fDensityIntegral = abs(fDeltaY * fDeltaY * 0.5);\n }\n }\n float fDensity;\n if (fDeltaY != 0.) {\n fDensity = (sqrt(1.0 + ((fDeltaD / fDeltaY) * (fDeltaD / fDeltaY)))) * fDensityIntegral;\n } else {\n fDensity = 0.;\n }\n float f = exp(-fDensity);\n return f;\n}\nfloat CC_TRANSFER_FOG(vec4 pos) {\n #if CC_USE_FOG == 1\n return LinearFog(pos);\n #elif CC_USE_FOG == 2\n return ExpFog(pos);\n #elif CC_USE_FOG == 3\n return ExpSquaredFog(pos);\n #elif CC_USE_FOG == 4\n return LayeredFog(pos);\n #endif\n return 1.;\n}\nvarying vec4 v_shadowPos;\nuniform highp mat4 cc_matLightViewProj;\n#if USE_VERTEX_COLOR\n attribute vec3 a_color;\n varying vec3 v_color;\n#endif\nvarying vec3 v_position;\nvarying vec3 v_normal;\nvarying vec2 v_uv;\nvarying vec2 v_uv1;\nvarying float factor_fog;\n#if USE_NORMAL_MAP\n varying vec3 v_tangent;\n varying vec3 v_bitangent;\n#endif\n#if HAS_SECOND_UV || USE_LIGHTMAP\n attribute vec2 a_texCoord1;\n#endif\n#if USE_LIGHTMAP && !USE_BATCHING && !CC_FORWARD_ADD\n varying vec2 v_luv;\nvoid CCLightingMapCaclUV()\n{\n#if !USE_INSTANCING\n v_luv = cc_lightingMapUVParam.xy + a_texCoord1 * cc_lightingMapUVParam.zw;\n#else\n v_luv = a_lightingMapUVParam.xy + a_texCoord1 * a_lightingMapUVParam.zw;\n#endif\n}\n#endif\nvec4 vert () {\n StandardVertInput In;\n In.position = vec4(a_position, 1.0);\n In.normal = a_normal;\n In.tangent = a_tangent;\n #if CC_USE_MORPH\n applyMorph(In);\n #endif\n #if CC_USE_SKINNING\n CCSkin(In);\n #endif\n mat4 matWorld, matWorldIT;\n #if USE_INSTANCING\n matWorld = mat4(\n vec4(a_matWorld0.xyz, 0.0),\n vec4(a_matWorld1.xyz, 0.0),\n vec4(a_matWorld2.xyz, 0.0),\n vec4(a_matWorld0.w, a_matWorld1.w, a_matWorld2.w, 1.0)\n );\n matWorldIT = matWorld;\n #elif USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id)];\n matWorldIT = matWorld;\n #else\n matWorld = cc_matWorld;\n matWorldIT = cc_matWorldIT;\n #endif\n vec4 pos = matWorld * In.position;\n v_position = pos.xyz;\n v_normal = normalize((matWorldIT * vec4(In.normal, 0.0)).xyz);\n #if USE_NORMAL_MAP\n v_tangent = normalize((matWorld * vec4(In.tangent.xyz, 0.0)).xyz);\n v_bitangent = cross(v_normal, v_tangent) * In.tangent.w;\n #endif\n v_uv = a_texCoord * tilingOffset.xy + tilingOffset.zw;\n #if HAS_SECOND_UV\n v_uv1 = a_texCoord1 * tilingOffset.xy + tilingOffset.zw;\n #endif\n #if USE_VERTEX_COLOR\n v_color = a_color;\n #endif\n factor_fog = CC_TRANSFER_FOG(matWorld * In.position);\n #if USE_LIGHTMAP && !USE_BATCHING && !CC_FORWARD_ADD\n CCLightingMapCaclUV();\n #endif\n v_shadowPos = cc_matLightViewProj * pos;\n return cc_matProj * (cc_matView * matWorld) * In.position;\n}\nvoid main() { gl_Position = vert(); }`, - "frag": `\n#ifdef GL_EXT_shader_texture_lod\n#extension GL_EXT_shader_texture_lod: enable\n#endif\nprecision highp float;\nuniform highp vec4 cc_cameraPos;\nuniform mediump vec4 cc_exposure;\nuniform mediump vec4 cc_mainLitDir;\nuniform mediump vec4 cc_mainLitColor;\nuniform mediump vec4 cc_ambientSky;\nuniform mediump vec4 cc_ambientGround;\nuniform mediump vec4 cc_fogColor;\n#if CC_USE_IBL\nuniform samplerCube cc_environment;\nvec3 unpackRGBE (vec4 rgbe) {\n return rgbe.rgb * pow(2.0, rgbe.a * 255.0 - 128.0);\n}\nvec4 fragTextureLod (sampler2D tex, vec2 coord, float lod) {\n #ifdef GL_EXT_shader_texture_lod\n return texture2DLodEXT(tex, coord, lod);\n #else\n return texture2D(tex, coord, lod);\n #endif\n}\nvec4 fragTextureLod (samplerCube tex, vec3 coord, float lod) {\n #ifdef GL_EXT_shader_texture_lod\n return textureCubeLodEXT(tex, coord, lod);\n #else\n return textureCube(tex, coord, lod);\n #endif\n}\n#endif\n#if USE_LIGHTMAP && !USE_BATCHING && !CC_FORWARD_ADD\n varying vec2 v_luv;\nuniform sampler2D cc_lightingMap;\n#endif\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nfloat GGXMobile (float roughness, float NoH, vec3 H, vec3 N) {\n vec3 NxH = cross(N, H);\n float OneMinusNoHSqr = dot(NxH, NxH);\n float a = roughness * roughness;\n float n = NoH * a;\n float p = a / (OneMinusNoHSqr + n * n);\n return p * p;\n}\nfloat CalcSpecular (float roughness, float NoH, vec3 H, vec3 N) {\n return (roughness*0.25 + 0.25) * GGXMobile(roughness, NoH, H, N);\n}\nvec3 BRDFApprox (vec3 specular, float roughness, float NoV) {\n const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);\n const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);\n vec4 r = roughness * c0 + c1;\n float a004 = min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y;\n vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\n AB.y *= clamp(50.0 * specular.g, 0.0, 1.0);\n return specular * AB.x + AB.y;\n}\nstruct StandardSurface {\n vec4 albedo;\n vec3 position;\n vec3 normal;\n vec3 emissive;\n float roughness;\n float metallic;\n float occlusion;\n};\n#if CC_FORWARD_ADD\nuniform highp vec4 cc_lightPos[1];\nuniform vec4 cc_lightColor[1];\nuniform vec4 cc_lightSizeRangeAngle[1];\nuniform vec4 cc_lightDir[1];\nfloat SmoothDistAtt (float distSqr, float invSqrAttRadius) {\n float factor = distSqr * invSqrAttRadius;\n float smoothFactor = clamp(1.0 - factor * factor, 0.0, 1.0);\n return smoothFactor * smoothFactor;\n}\nfloat GetDistAtt (float distSqr, float invSqrAttRadius) {\n float attenuation = 1.0 / max(distSqr, 0.01*0.01);\n attenuation *= SmoothDistAtt(distSqr , invSqrAttRadius);\n return attenuation;\n}\nfloat GetAngleAtt (vec3 L, vec3 litDir, float litAngleScale, float litAngleOffset) {\n float cd = dot(litDir, L);\n float attenuation = clamp(cd * litAngleScale + litAngleOffset, 0.0, 1.0);\n return (attenuation * attenuation);\n}\n vec4 CCStandardShading (StandardSurface s) {\n vec3 diffuse = s.albedo.rgb * (1.0 - s.metallic);\n vec3 specular = mix(vec3(0.04), s.albedo.rgb, s.metallic);\n vec3 diffuseContrib = diffuse / 3.14159265359;\n vec3 N = normalize(s.normal);\n vec3 V = normalize(cc_cameraPos.xyz - s.position);\n float NV = max(abs(dot(N, V)), 0.001);\n specular = BRDFApprox(specular, s.roughness, NV);\n vec3 finalColor = vec3(0.0);\n for (int i = 0; i < 1; i++) {\n vec3 SLU = cc_lightPos[i].xyz - s.position;\n vec3 SL = normalize(SLU);\n vec3 SH = normalize(SL + V);\n float SNL = max(dot(N, SL), 0.001);\n float SNH = max(dot(N, SH), 0.0);\n float distSqr = dot(SLU, SLU);\n float litRadius = cc_lightSizeRangeAngle[i].x;\n float litRadiusSqr = litRadius * litRadius;\n float illum = 3.14159265359 * (litRadiusSqr / max(litRadiusSqr , distSqr));\n float attRadiusSqrInv = 1.0 / max(cc_lightSizeRangeAngle[i].y, 0.01);\n attRadiusSqrInv *= attRadiusSqrInv;\n float att = GetDistAtt(distSqr, attRadiusSqrInv);\n vec3 lspec = specular * CalcSpecular(s.roughness, SNH, SH, N);\n if (cc_lightPos[i].w > 0.0) {\n float cosInner = max(dot(-cc_lightDir[i].xyz, SL), 0.01);\n float cosOuter = cc_lightSizeRangeAngle[i].z;\n float litAngleScale = 1.0 / max(0.001, cosInner - cosOuter);\n float litAngleOffset = -cosOuter * litAngleScale;\n att *= GetAngleAtt(SL, -cc_lightDir[i].xyz, litAngleScale, litAngleOffset);\n }\n finalColor += SNL * cc_lightColor[i].rgb * cc_lightColor[i].w * illum * att * (diffuseContrib + lspec);\n }\n finalColor = finalColor * s.occlusion;\n return vec4(finalColor, 0.0);\n }\n#else\n #if CC_RECEIVE_SHADOW\nvarying vec4 v_shadowPos;\nuniform lowp vec4 cc_shadowColor;\nuniform sampler2D cc_shadowMap;\nvec4 CCGetShadowFactor () {\n vec3 clipPos = v_shadowPos.xyz / v_shadowPos.w * 0.5 + 0.5;\n float depth = dot(texture2D(cc_shadowMap, clipPos.xy), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n if (depth < (clipPos.z - 0.001)) return cc_shadowColor;\n else return vec4(0);\n}\n #endif\n vec4 CCStandardShading (StandardSurface s) {\n vec3 diffuse = s.albedo.rgb * (1.0 - s.metallic);\n vec3 specular = mix(vec3(0.04), s.albedo.rgb, s.metallic);\n vec3 N = normalize(s.normal);\n vec3 V = normalize(cc_cameraPos.xyz - s.position);\n float NV = max(abs(dot(N, V)), 0.001);\n specular = BRDFApprox(specular, s.roughness, NV);\n vec3 L = normalize(-cc_mainLitDir.xyz);\n vec3 H = normalize(L+V);\n float NH = max(dot(N, H), 0.0);\n float NL = max(dot(N, L), 0.001);\n vec3 finalColor = NL * cc_mainLitColor.rgb * cc_mainLitColor.w;\n #if USE_LIGHTMAP && !USE_BATCHING && !CC_FORWARD_ADD\n vec4 lightmap = texture2D(cc_lightingMap, v_luv);\n finalColor = lightmap.a * lightmap.rgb + (1.0 - lightmap.a) * finalColor;\n #endif\n vec3 diffuseContrib = diffuse / 3.14159265359;\n vec3 specularContrib = specular * CalcSpecular(s.roughness, NH, H, N);\n finalColor *= (diffuseContrib + specularContrib);\n float fAmb = 0.5 - N.y * 0.5;\n vec3 ambDiff = mix(cc_ambientSky.rgb, cc_ambientGround.rgb, fAmb) * cc_ambientSky.w;\n finalColor += (ambDiff.rgb * diffuse);\n #if CC_USE_IBL\n vec3 R = normalize(reflect(-V, N));\n vec4 envmap = fragTextureLod(cc_environment, R, s.roughness * cc_ambientGround.w);\n #if CC_USE_IBL == 2\n vec3 env = unpackRGBE(envmap);\n #else\n vec3 env = SRGBToLinear(envmap.rgb);\n #endif\n finalColor += env * cc_ambientSky.w * specular;\n #endif\n finalColor = finalColor * s.occlusion;\n #if CC_USE_HDR\n s.emissive *= cc_exposure.w;\n #endif\n finalColor += s.emissive;\n #if CC_RECEIVE_SHADOW\n vec4 shadow = CCGetShadowFactor();\n finalColor = shadow.rgb * shadow.a + finalColor * (1.0 - shadow.a);\n #endif\n return vec4(finalColor, s.albedo.a);\n }\n#endif\nvec3 ACESToneMap (vec3 color) {\n color = min(color, vec3(8.0));\n const float A = 2.51;\n const float B = 0.03;\n const float C = 2.43;\n const float D = 0.59;\n const float E = 0.14;\n return (color * (A * color + B)) / (color * (C * color + D) + E);\n}\nvec4 CCFragOutput (vec4 color) {\n #if !CC_USE_HDR\n color.rgb = sqrt(ACESToneMap(color.rgb));\n #endif\n return color;\n}\nuniform vec4 albedo;\nuniform vec4 albedoScaleAndCutoff;\nuniform vec4 pbrParams;\nuniform vec4 emissive;\nuniform vec4 emissiveScaleParam;\nvarying vec3 v_position;\nvarying vec2 v_uv;\nvarying vec2 v_uv1;\nvarying vec3 v_normal;\n#if USE_VERTEX_COLOR\n varying vec3 v_color;\n#endif\n#if USE_ALBEDO_MAP\n uniform sampler2D albedoMap;\n#endif\n#if USE_NORMAL_MAP\n varying vec3 v_tangent;\n varying vec3 v_bitangent;\n uniform sampler2D normalMap;\n#endif\n#if USE_PBR_MAP\n uniform sampler2D pbrMap;\n#endif\n#if USE_METALLIC_ROUGHNESS_MAP\n uniform sampler2D metallicRoughnessMap;\n#endif\n#if USE_OCCLUSION_MAP\n uniform sampler2D occlusionMap;\n#endif\n#if USE_EMISSIVE_MAP\n uniform sampler2D emissiveMap;\n#endif\n#if USE_ALPHA_TEST\n#endif\nvarying float factor_fog;\nvoid surf (out StandardSurface s) {\n vec4 baseColor = albedo;\n #if USE_VERTEX_COLOR\n baseColor.rgb *= v_color;\n #endif\n #if USE_ALBEDO_MAP\n vec4 texColor = texture2D(albedoMap, ALBEDO_UV);\n texColor.rgb = SRGBToLinear(texColor.rgb);\n baseColor *= texColor;\n #endif\n s.albedo = baseColor;\n s.albedo.rgb *= albedoScaleAndCutoff.xyz;\n #if USE_ALPHA_TEST\n if (s.albedo.ALPHA_TEST_CHANNEL < albedoScaleAndCutoff.w) discard;\n #endif\n s.normal = v_normal;\n #if USE_NORMAL_MAP\n vec3 nmmp = texture2D(normalMap, NORMAL_UV).xyz - vec3(0.5);\n s.normal =\n (nmmp.x * pbrParams.w) * normalize(v_tangent) +\n (nmmp.y * pbrParams.w) * normalize(v_bitangent) +\n nmmp.z * normalize(s.normal);\n #endif\n s.position = v_position;\n vec4 pbr = pbrParams;\n #if USE_PBR_MAP\n vec4 res = texture2D(pbrMap, PBR_UV);\n pbr.x *= res.r;\n pbr.y *= res.g;\n pbr.z *= res.b;\n #endif\n #if USE_METALLIC_ROUGHNESS_MAP\n vec4 metallicRoughness = texture2D(metallicRoughnessMap, PBR_UV);\n pbr.z *= metallicRoughness.b;\n pbr.y *= metallicRoughness.g;\n #endif\n #if USE_OCCLUSION_MAP\n pbr.x *= texture2D(occlusionMap, PBR_UV).r;\n #endif\n s.occlusion = clamp(pbr.x, 0.0, 0.96);\n s.roughness = clamp(pbr.y, 0.04, 1.0);\n s.metallic = pbr.z;\n s.emissive = emissive.rgb * emissiveScaleParam.xyz;\n #if USE_EMISSIVE_MAP\n s.emissive *= SRGBToLinear(texture2D(emissiveMap, EMISSIVE_UV).rgb);\n #endif\n}\nvec4 frag () {\n StandardSurface s; surf(s);\n vec4 color = CCStandardShading(s);\n color = vec4(mix(CC_FORWARD_ADD > 0 ? vec3(0.0) : cc_fogColor.rgb, color.rgb, factor_fog), color.a);\n return CCFragOutput(color);\n}\nvoid main() { gl_FragColor = frag(); }` + "frag": `\n#ifdef GL_EXT_shader_texture_lod\n#extension GL_EXT_shader_texture_lod: enable\n#endif\nprecision highp float;\nuniform highp vec4 cc_cameraPos;\nuniform mediump vec4 cc_exposure;\nuniform mediump vec4 cc_mainLitDir;\nuniform mediump vec4 cc_mainLitColor;\nuniform mediump vec4 cc_ambientSky;\nuniform mediump vec4 cc_ambientGround;\nuniform mediump vec4 cc_fogColor;\nuniform lowp vec4 cc_shadowColor;\nuniform lowp vec4 cc_shadowPCF;\nuniform lowp vec4 cc_shadowSize;\n#if CC_USE_IBL\nuniform samplerCube cc_environment;\nvec3 unpackRGBE (vec4 rgbe) {\n return rgbe.rgb * pow(2.0, rgbe.a * 255.0 - 128.0);\n}\nvec4 fragTextureLod (sampler2D tex, vec2 coord, float lod) {\n #ifdef GL_EXT_shader_texture_lod\n return texture2DLodEXT(tex, coord, lod);\n #else\n return texture2D(tex, coord, lod);\n #endif\n}\nvec4 fragTextureLod (samplerCube tex, vec3 coord, float lod) {\n #ifdef GL_EXT_shader_texture_lod\n return textureCubeLodEXT(tex, coord, lod);\n #else\n return textureCube(tex, coord, lod);\n #endif\n}\n#endif\n#if USE_LIGHTMAP && !USE_BATCHING && !CC_FORWARD_ADD\n varying vec2 v_luv;\nuniform sampler2D cc_lightingMap;\n#endif\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nfloat GGXMobile (float roughness, float NoH, vec3 H, vec3 N) {\n vec3 NxH = cross(N, H);\n float OneMinusNoHSqr = dot(NxH, NxH);\n float a = roughness * roughness;\n float n = NoH * a;\n float p = a / (OneMinusNoHSqr + n * n);\n return p * p;\n}\nfloat CalcSpecular (float roughness, float NoH, vec3 H, vec3 N) {\n return (roughness*0.25 + 0.25) * GGXMobile(roughness, NoH, H, N);\n}\nvec3 BRDFApprox (vec3 specular, float roughness, float NoV) {\n const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);\n const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);\n vec4 r = roughness * c0 + c1;\n float a004 = min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y;\n vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\n AB.y *= clamp(50.0 * specular.g, 0.0, 1.0);\n return specular * AB.x + AB.y;\n}\nstruct StandardSurface {\n vec4 albedo;\n vec3 position;\n vec3 normal;\n vec3 emissive;\n float roughness;\n float metallic;\n float occlusion;\n};\n#if CC_FORWARD_ADD\nuniform highp vec4 cc_lightPos[1];\nuniform vec4 cc_lightColor[1];\nuniform vec4 cc_lightSizeRangeAngle[1];\nuniform vec4 cc_lightDir[1];\nfloat SmoothDistAtt (float distSqr, float invSqrAttRadius) {\n float factor = distSqr * invSqrAttRadius;\n float smoothFactor = clamp(1.0 - factor * factor, 0.0, 1.0);\n return smoothFactor * smoothFactor;\n}\nfloat GetDistAtt (float distSqr, float invSqrAttRadius) {\n float attenuation = 1.0 / max(distSqr, 0.01*0.01);\n attenuation *= SmoothDistAtt(distSqr , invSqrAttRadius);\n return attenuation;\n}\nfloat GetAngleAtt (vec3 L, vec3 litDir, float litAngleScale, float litAngleOffset) {\n float cd = dot(litDir, L);\n float attenuation = clamp(cd * litAngleScale + litAngleOffset, 0.0, 1.0);\n return (attenuation * attenuation);\n}\n vec4 CCStandardShading (StandardSurface s) {\n vec3 diffuse = s.albedo.rgb * (1.0 - s.metallic);\n vec3 specular = mix(vec3(0.04), s.albedo.rgb, s.metallic);\n vec3 diffuseContrib = diffuse / 3.14159265359;\n vec3 N = normalize(s.normal);\n vec3 V = normalize(cc_cameraPos.xyz - s.position);\n float NV = max(abs(dot(N, V)), 0.001);\n specular = BRDFApprox(specular, s.roughness, NV);\n vec3 finalColor = vec3(0.0);\n for (int i = 0; i < 1; i++) {\n vec3 SLU = cc_lightPos[i].xyz - s.position;\n vec3 SL = normalize(SLU);\n vec3 SH = normalize(SL + V);\n float SNL = max(dot(N, SL), 0.001);\n float SNH = max(dot(N, SH), 0.0);\n float distSqr = dot(SLU, SLU);\n float litRadius = cc_lightSizeRangeAngle[i].x;\n float litRadiusSqr = litRadius * litRadius;\n float illum = 3.14159265359 * (litRadiusSqr / max(litRadiusSqr , distSqr));\n float attRadiusSqrInv = 1.0 / max(cc_lightSizeRangeAngle[i].y, 0.01);\n attRadiusSqrInv *= attRadiusSqrInv;\n float att = GetDistAtt(distSqr, attRadiusSqrInv);\n vec3 lspec = specular * CalcSpecular(s.roughness, SNH, SH, N);\n if (cc_lightPos[i].w > 0.0) {\n float cosInner = max(dot(-cc_lightDir[i].xyz, SL), 0.01);\n float cosOuter = cc_lightSizeRangeAngle[i].z;\n float litAngleScale = 1.0 / max(0.001, cosInner - cosOuter);\n float litAngleOffset = -cosOuter * litAngleScale;\n att *= GetAngleAtt(SL, -cc_lightDir[i].xyz, litAngleScale, litAngleOffset);\n }\n finalColor += SNL * cc_lightColor[i].rgb * cc_lightColor[i].w * illum * att * (diffuseContrib + lspec);\n }\n finalColor = finalColor * s.occlusion;\n return vec4(finalColor, 0.0);\n }\n#else\n #if CC_RECEIVE_SHADOW\nvarying vec4 v_shadowPos;\nuniform sampler2D cc_shadowMap;\nvec4 CCGetShadowFactorEasy () {\n vec3 clipPos = v_shadowPos.xyz / v_shadowPos.w * 0.5 + 0.5;\n float depth = dot(texture2D(cc_shadowMap, clipPos.xy), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n if (depth < (clipPos.z - 0.001)) return cc_shadowColor;\n else return vec4(0);\n}\nvec4 CCGetShadowFactorHard () {\n vec3 clipPos = v_shadowPos.xyz / v_shadowPos.w * 0.5 + 0.5;\n float offsetx = 1.0 / cc_shadowSize.x;\n float offsety = 1.0 / cc_shadowSize.y;\n float depth = 0.0;\n depth += dot(texture2D(cc_shadowMap, vec2(clipPos.x - offsetx, clipPos.y - offsety)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture2D(cc_shadowMap, vec2(clipPos.x, clipPos.y - offsety)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture2D(cc_shadowMap, vec2(clipPos.x + offsetx, clipPos.y - offsety)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture2D(cc_shadowMap, vec2(clipPos.x - offsetx, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture2D(cc_shadowMap, vec2(clipPos.x, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture2D(cc_shadowMap, vec2(clipPos.x + offsetx, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture2D(cc_shadowMap, vec2(clipPos.x - offsetx, clipPos.y + offsety)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture2D(cc_shadowMap, vec2(clipPos.x, clipPos.y + offsety)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture2D(cc_shadowMap, vec2(clipPos.x + offsetx, clipPos.y + offsety)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth /= 9.0;\n if (depth < (clipPos.z - 0.001)) return cc_shadowColor;\n else return vec4(0);\n}\nvec4 CCGetShadowFactorCommon () {\n vec3 clipPos = v_shadowPos.xyz / v_shadowPos.w * 0.5 + 0.5;\n float offsetx = 1.0 / cc_shadowSize.x;\n float offsety = 1.0 / cc_shadowSize.y;\n float depth = 0.0;\n depth += dot(texture2D(cc_shadowMap, vec2(clipPos.x - offsetx, clipPos.y - offsety)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture2D(cc_shadowMap, vec2(clipPos.x - offsetx, clipPos.y + offsety)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture2D(cc_shadowMap, vec2(clipPos.x, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture2D(cc_shadowMap, vec2(clipPos.x + offsetx, clipPos.y - offsety)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture2D(cc_shadowMap, vec2(clipPos.x + offsetx, clipPos.y + offsety)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth /= 5.0;\n if (depth < (clipPos.z - 0.001)) return cc_shadowColor;\n else return vec4(0);\n}\n #endif\n vec4 CCStandardShading (StandardSurface s) {\n vec3 diffuse = s.albedo.rgb * (1.0 - s.metallic);\n vec3 specular = mix(vec3(0.04), s.albedo.rgb, s.metallic);\n vec3 N = normalize(s.normal);\n vec3 V = normalize(cc_cameraPos.xyz - s.position);\n float NV = max(abs(dot(N, V)), 0.001);\n specular = BRDFApprox(specular, s.roughness, NV);\n vec3 L = normalize(-cc_mainLitDir.xyz);\n vec3 H = normalize(L+V);\n float NH = max(dot(N, H), 0.0);\n float NL = max(dot(N, L), 0.001);\n vec3 finalColor = NL * cc_mainLitColor.rgb * cc_mainLitColor.w;\n #if USE_LIGHTMAP && !USE_BATCHING && !CC_FORWARD_ADD\n vec4 lightmap = texture2D(cc_lightingMap, v_luv);\n finalColor = lightmap.a * lightmap.rgb + (1.0 - lightmap.a) * finalColor;\n #endif\n vec3 diffuseContrib = diffuse / 3.14159265359;\n vec3 specularContrib = specular * CalcSpecular(s.roughness, NH, H, N);\n finalColor *= (diffuseContrib + specularContrib);\n float fAmb = 0.5 - N.y * 0.5;\n vec3 ambDiff = mix(cc_ambientSky.rgb, cc_ambientGround.rgb, fAmb) * cc_ambientSky.w;\n finalColor += (ambDiff.rgb * diffuse);\n #if CC_USE_IBL\n vec3 R = normalize(reflect(-V, N));\n vec4 envmap = fragTextureLod(cc_environment, R, s.roughness * cc_ambientGround.w);\n #if CC_USE_IBL == 2\n vec3 env = unpackRGBE(envmap);\n #else\n vec3 env = SRGBToLinear(envmap.rgb);\n #endif\n finalColor += env * cc_ambientSky.w * specular;\n #endif\n finalColor = finalColor * s.occlusion;\n #if CC_USE_HDR\n s.emissive *= cc_exposure.w;\n #endif\n finalColor += s.emissive;\n #if CC_RECEIVE_SHADOW\n vec4 shadow = vec4(1.0);\n float pcf = cc_shadowPCF.x + 0.001;\n if (pcf > 2.0) {shadow = CCGetShadowFactorEasy();}\n if (2.0 > pcf && pcf > 1.0) {shadow = CCGetShadowFactorCommon();}\n if (1.0 > pcf && pcf > 0.0) {shadow = CCGetShadowFactorHard();}\n finalColor = shadow.rgb * shadow.a + finalColor * (1.0 - shadow.a);\n #endif\n return vec4(finalColor, s.albedo.a);\n }\n#endif\nvec3 ACESToneMap (vec3 color) {\n color = min(color, vec3(8.0));\n const float A = 2.51;\n const float B = 0.03;\n const float C = 2.43;\n const float D = 0.59;\n const float E = 0.14;\n return (color * (A * color + B)) / (color * (C * color + D) + E);\n}\nvec4 CCFragOutput (vec4 color) {\n #if !CC_USE_HDR\n color.rgb = sqrt(ACESToneMap(color.rgb));\n #endif\n return color;\n}\nuniform vec4 albedo;\nuniform vec4 albedoScaleAndCutoff;\nuniform vec4 pbrParams;\nuniform vec4 emissive;\nuniform vec4 emissiveScaleParam;\nvarying vec3 v_position;\nvarying vec2 v_uv;\nvarying vec2 v_uv1;\nvarying vec3 v_normal;\n#if USE_VERTEX_COLOR\n varying vec3 v_color;\n#endif\n#if USE_ALBEDO_MAP\n uniform sampler2D albedoMap;\n#endif\n#if USE_NORMAL_MAP\n varying vec3 v_tangent;\n varying vec3 v_bitangent;\n uniform sampler2D normalMap;\n#endif\n#if USE_PBR_MAP\n uniform sampler2D pbrMap;\n#endif\n#if USE_METALLIC_ROUGHNESS_MAP\n uniform sampler2D metallicRoughnessMap;\n#endif\n#if USE_OCCLUSION_MAP\n uniform sampler2D occlusionMap;\n#endif\n#if USE_EMISSIVE_MAP\n uniform sampler2D emissiveMap;\n#endif\n#if USE_ALPHA_TEST\n#endif\nvarying float factor_fog;\nvoid surf (out StandardSurface s) {\n vec4 baseColor = albedo;\n #if USE_VERTEX_COLOR\n baseColor.rgb *= v_color;\n #endif\n #if USE_ALBEDO_MAP\n vec4 texColor = texture2D(albedoMap, ALBEDO_UV);\n texColor.rgb = SRGBToLinear(texColor.rgb);\n baseColor *= texColor;\n #endif\n s.albedo = baseColor;\n s.albedo.rgb *= albedoScaleAndCutoff.xyz;\n #if USE_ALPHA_TEST\n if (s.albedo.ALPHA_TEST_CHANNEL < albedoScaleAndCutoff.w) discard;\n #endif\n s.normal = v_normal;\n #if USE_NORMAL_MAP\n vec3 nmmp = texture2D(normalMap, NORMAL_UV).xyz - vec3(0.5);\n s.normal =\n (nmmp.x * pbrParams.w) * normalize(v_tangent) +\n (nmmp.y * pbrParams.w) * normalize(v_bitangent) +\n nmmp.z * normalize(s.normal);\n #endif\n s.position = v_position;\n vec4 pbr = pbrParams;\n #if USE_PBR_MAP\n vec4 res = texture2D(pbrMap, PBR_UV);\n pbr.x *= res.r;\n pbr.y *= res.g;\n pbr.z *= res.b;\n #endif\n #if USE_METALLIC_ROUGHNESS_MAP\n vec4 metallicRoughness = texture2D(metallicRoughnessMap, PBR_UV);\n pbr.z *= metallicRoughness.b;\n pbr.y *= metallicRoughness.g;\n #endif\n #if USE_OCCLUSION_MAP\n pbr.x *= texture2D(occlusionMap, PBR_UV).r;\n #endif\n s.occlusion = clamp(pbr.x, 0.0, 0.96);\n s.roughness = clamp(pbr.y, 0.04, 1.0);\n s.metallic = pbr.z;\n s.emissive = emissive.rgb * emissiveScaleParam.xyz;\n #if USE_EMISSIVE_MAP\n s.emissive *= SRGBToLinear(texture2D(emissiveMap, EMISSIVE_UV).rgb);\n #endif\n}\nvec4 frag () {\n StandardSurface s; surf(s);\n vec4 color = CCStandardShading(s);\n color = vec4(mix(CC_FORWARD_ADD > 0 ? vec3(0.0) : cc_fogColor.rgb, color.rgb, factor_fog), color.a);\n return CCFragOutput(color);\n}\nvoid main() { gl_FragColor = frag(); }` }, "glsl4": { - "vert": `\n#ifdef GL_EXT_shader_explicit_arithmetic_types_int16\n#extension GL_EXT_shader_explicit_arithmetic_types_int16: enable\n#endif\nprecision highp float;\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nlayout(location = 0) in vec3 a_position;\nlayout(location = 1) in vec3 a_normal;\nlayout(location = 2) in vec2 a_texCoord;\nlayout(location = 3) in vec4 a_tangent;\n#if CC_USE_MORPH\n int getVertexId() {\n return gl_VertexID;\n }\nlayout(set = 2, binding = 4) uniform CCMorph {\n vec4 cc_displacementWeights[15];\n vec4 cc_displacementTextureInfo;\n};\n vec4 fetchVec3ArrayFromTexture(sampler2D tex, int pixelIndex) {\n ivec2 texSize = textureSize(tex, 0);\n return texelFetch(tex, ivec2(pixelIndex % texSize.x, pixelIndex / texSize.x), 0);\n }\nfloat getDisplacementWeight(int index) {\n float m = mod(float(index), 4.0);\n if (m < 1.0) {\n return cc_displacementWeights[index / 4].x;\n } else if (m < 2.0) {\n return cc_displacementWeights[index / 4].y;\n } else if (m < 3.0) {\n return cc_displacementWeights[index / 4].z;\n } else {\n return cc_displacementWeights[index / 4].w;\n }\n}\nvec3 getVec3DisplacementFromTexture(sampler2D tex, int vertexIndex) {\n#if CC_MORPH_PRECOMPUTED\n return fetchVec3ArrayFromTexture(tex, vertexIndex).rgb;\n#else\n vec3 result = vec3(0, 0, 0);\n for (int iTarget = 0; iTarget < CC_MORPH_TARGET_COUNT; ++iTarget) {\n int dataPixelStart = int(fetchVec3ArrayFromTexture(tex, iTarget).r);\n result += (fetchVec3ArrayFromTexture(tex, dataPixelStart + vertexIndex).rgb * getDisplacementWeight(iTarget));\n }\n return result;\n#endif\n}\n#if CC_MORPH_TARGET_HAS_POSITION\n layout(set = 2, binding = 6) uniform sampler2D cc_PositionDisplacements;\n vec3 getPositionDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_PositionDisplacements, vertexId);\n }\n#endif\n#if CC_MORPH_TARGET_HAS_NORMAL\n layout(set = 2, binding = 7) uniform sampler2D cc_NormalDisplacements;\n vec3 getNormalDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_NormalDisplacements, vertexId);\n }\n#endif\n#if CC_MORPH_TARGET_HAS_TANGENT\n layout(set = 2, binding = 8) uniform sampler2D cc_TangentDisplacements;\n vec3 getTangentDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_TangentDisplacements, vertexId);\n }\n#endif\nvoid applyMorph (inout StandardVertInput attr) {\n int vertexId = getVertexId();\n#if CC_MORPH_TARGET_HAS_POSITION\n attr.position.xyz = attr.position.xyz + getPositionDisplacement(vertexId);\n#endif\n#if CC_MORPH_TARGET_HAS_NORMAL\n attr.normal.xyz = attr.normal.xyz + getNormalDisplacement(vertexId);\n#endif\n#if CC_MORPH_TARGET_HAS_TANGENT\n attr.tangent.xyz = attr.tangent.xyz + getTangentDisplacement(vertexId);\n#endif\n}\nvoid applyMorph (inout vec4 position) {\n#if CC_MORPH_TARGET_HAS_POSITION\n position.xyz = position.xyz + getPositionDisplacement(getVertexId());\n#endif\n}\n#endif\n#if CC_USE_SKINNING\nlayout(location = 4) in u16vec4 a_joints;\nlayout(location = 5) in vec4 a_weights;\n#if CC_USE_BAKED_ANIMATION\n #if USE_INSTANCING\n layout(location = 7) in highp vec4 a_jointAnimInfo;\n #endif\n layout(set = 2, binding = 3) uniform CCSkinningTexture {\n highp vec4 cc_jointTextureInfo;\n };\n layout(set = 2, binding = 2) uniform CCSkinningAnimation {\n highp vec4 cc_jointAnimInfo;\n };\n layout(set = 2, binding = 5) uniform highp sampler2D cc_jointTexture;\n #if !CC_SUPPORT_FLOAT_TEXTURE\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n #endif\n#else\n layout(set = 2, binding = 3) uniform CCSkinning {\n highp vec4 cc_joints[30 * 3];\n };\n#endif\n#if CC_USE_BAKED_ANIMATION\n #if CC_SUPPORT_FLOAT_TEXTURE\n mat4 getJointMatrix (float i) {\n #if USE_INSTANCING\n highp float j = 3.0 * (a_jointAnimInfo.x * a_jointAnimInfo.y + i) + a_jointAnimInfo.z;\n #else\n highp float j = 3.0 * (cc_jointAnimInfo.x * cc_jointTextureInfo.y + i) + cc_jointTextureInfo.z;\n #endif\n highp float invSize = cc_jointTextureInfo.w;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture(cc_jointTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture(cc_jointTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture(cc_jointTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n #else\n mat4 getJointMatrix (float i) {\n #if USE_INSTANCING\n highp float j = 12.0 * (a_jointAnimInfo.x * a_jointAnimInfo.y + i) + a_jointAnimInfo.z;\n #else\n highp float j = 12.0 * (cc_jointAnimInfo.x * cc_jointTextureInfo.y + i) + cc_jointTextureInfo.z;\n #endif\n highp float invSize = cc_jointTextureInfo.w;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n #endif\n#else\n mat4 getJointMatrix (float i) {\n int idx = int(i);\n vec4 v1 = cc_joints[idx * 3];\n vec4 v2 = cc_joints[idx * 3 + 1];\n vec4 v3 = cc_joints[idx * 3 + 2];\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y\n + getJointMatrix(a_joints.z) * a_weights.z\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\nlayout(set = 0, binding = 0) uniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n mediump vec4 cc_fogColor;\n mediump vec4 cc_fogBase;\n mediump vec4 cc_fogAdd;\n};\n#if USE_INSTANCING\n layout(location = 8) in vec4 a_matWorld0;\n layout(location = 9) in vec4 a_matWorld1;\n layout(location = 10) in vec4 a_matWorld2;\n #if USE_LIGHTMAP\n layout(location = 11) in vec4 a_lightingMapUVParam;\n #endif\n#elif USE_BATCHING\n layout(location = 12) in float a_dyn_batch_id;\n layout(set = 2, binding = 0) uniform CCLocalBatched {\n highp mat4 cc_matWorlds[10];\n };\n#else\nlayout(set = 2, binding = 0) uniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n highp vec4 cc_lightingMapUVParam;\n};\n#endif\nlayout(set = 1, binding = 0) uniform Constants {\n vec4 tilingOffset;\n vec4 albedo;\n vec4 albedoScaleAndCutoff;\n vec4 pbrParams;\n vec4 emissive;\n vec4 emissiveScaleParam;\n};\nfloat LinearFog(vec4 pos) {\n vec4 wPos = pos;\n float cam_dis = distance(cc_cameraPos, wPos);\n float fogStart = cc_fogBase.x;\n float fogEnd = cc_fogBase.y;\n return clamp((fogEnd - cam_dis) / (fogEnd - fogStart), 0., 1.);\n}\nfloat ExpFog(vec4 pos) {\n vec4 wPos = pos;\n float fogAtten = cc_fogAdd.z;\n float fogDensity = cc_fogBase.z;\n float cam_dis = distance(cc_cameraPos, wPos) / fogAtten * 4.;\n float f = exp(-cam_dis * fogDensity);\n return f;\n}\nfloat ExpSquaredFog(vec4 pos) {\n vec4 wPos = pos;\n float fogAtten = cc_fogAdd.z;\n float fogDensity = cc_fogBase.z;\n float cam_dis = distance(cc_cameraPos, wPos) / fogAtten * 4.;\n float f = exp(-cam_dis * cam_dis * fogDensity * fogDensity);\n return f;\n}\nfloat LayeredFog(vec4 pos) {\n vec4 wPos = pos;\n float fogAtten = cc_fogAdd.z;\n float _FogTop = cc_fogAdd.x;\n float _FogRange = cc_fogAdd.y;\n vec3 camWorldProj = cc_cameraPos.xyz;\n camWorldProj.y = 0.;\n vec3 worldPosProj = wPos.xyz;\n worldPosProj.y = 0.;\n float fDeltaD = distance(worldPosProj, camWorldProj) / fogAtten * 2.0;\n float fDeltaY, fDensityIntegral;\n if (cc_cameraPos.y > _FogTop) {\n if (wPos.y < _FogTop) {\n fDeltaY = (_FogTop - wPos.y) / _FogRange * 2.0;\n fDensityIntegral = fDeltaY * fDeltaY * 0.5;\n } else {\n fDeltaY = 0.;\n fDensityIntegral = 0.;\n }\n } else {\n if (wPos.y < _FogTop) {\n float fDeltaA = (_FogTop - cc_cameraPos.y) / _FogRange * 2.;\n float fDeltaB = (_FogTop - wPos.y) / _FogRange * 2.;\n fDeltaY = abs(fDeltaA - fDeltaB);\n fDensityIntegral = abs((fDeltaA * fDeltaA * 0.5) - (fDeltaB * fDeltaB * 0.5));\n } else {\n fDeltaY = abs(_FogTop - cc_cameraPos.y) / _FogRange * 2.;\n fDensityIntegral = abs(fDeltaY * fDeltaY * 0.5);\n }\n }\n float fDensity;\n if (fDeltaY != 0.) {\n fDensity = (sqrt(1.0 + ((fDeltaD / fDeltaY) * (fDeltaD / fDeltaY)))) * fDensityIntegral;\n } else {\n fDensity = 0.;\n }\n float f = exp(-fDensity);\n return f;\n}\nfloat CC_TRANSFER_FOG(vec4 pos) {\n #if CC_USE_FOG == 1\n return LinearFog(pos);\n #elif CC_USE_FOG == 2\n return ExpFog(pos);\n #elif CC_USE_FOG == 3\n return ExpSquaredFog(pos);\n #elif CC_USE_FOG == 4\n return LayeredFog(pos);\n #endif\n return 1.;\n}\nlayout(location = 0) out vec4 v_shadowPos;\nlayout(set = 0, binding = 1) uniform CCShadow {\n highp mat4 cc_matLightPlaneProj;\n highp mat4 cc_matLightViewProj;\n lowp vec4 cc_shadowColor;\n};\n#if USE_VERTEX_COLOR\n layout(location = 13) in vec3 a_color;\n layout(location = 1) out vec3 v_color;\n#endif\nlayout(location = 2) out vec3 v_position;\nlayout(location = 3) out vec3 v_normal;\nlayout(location = 4) out vec2 v_uv;\nlayout(location = 5) out vec2 v_uv1;\nlayout(location = 6) out float factor_fog;\n#if USE_NORMAL_MAP\n layout(location = 7) out vec3 v_tangent;\n layout(location = 8) out vec3 v_bitangent;\n#endif\n#if HAS_SECOND_UV || USE_LIGHTMAP\n layout(location = 14) in vec2 a_texCoord1;\n#endif\n#if USE_LIGHTMAP && !USE_BATCHING && !CC_FORWARD_ADD\n layout(location = 9) out vec2 v_luv;\nvoid CCLightingMapCaclUV()\n{\n#if !USE_INSTANCING\n v_luv = cc_lightingMapUVParam.xy + a_texCoord1 * cc_lightingMapUVParam.zw;\n#else\n v_luv = a_lightingMapUVParam.xy + a_texCoord1 * a_lightingMapUVParam.zw;\n#endif\n}\n#endif\nvec4 vert () {\n StandardVertInput In;\n In.position = vec4(a_position, 1.0);\n In.normal = a_normal;\n In.tangent = a_tangent;\n #if CC_USE_MORPH\n applyMorph(In);\n #endif\n #if CC_USE_SKINNING\n CCSkin(In);\n #endif\n mat4 matWorld, matWorldIT;\n #if USE_INSTANCING\n matWorld = mat4(\n vec4(a_matWorld0.xyz, 0.0),\n vec4(a_matWorld1.xyz, 0.0),\n vec4(a_matWorld2.xyz, 0.0),\n vec4(a_matWorld0.w, a_matWorld1.w, a_matWorld2.w, 1.0)\n );\n matWorldIT = matWorld;\n #elif USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id)];\n matWorldIT = matWorld;\n #else\n matWorld = cc_matWorld;\n matWorldIT = cc_matWorldIT;\n #endif\n vec4 pos = matWorld * In.position;\n v_position = pos.xyz;\n v_normal = normalize((matWorldIT * vec4(In.normal, 0.0)).xyz);\n #if USE_NORMAL_MAP\n v_tangent = normalize((matWorld * vec4(In.tangent.xyz, 0.0)).xyz);\n v_bitangent = cross(v_normal, v_tangent) * In.tangent.w;\n #endif\n v_uv = a_texCoord * tilingOffset.xy + tilingOffset.zw;\n #if HAS_SECOND_UV\n v_uv1 = a_texCoord1 * tilingOffset.xy + tilingOffset.zw;\n #endif\n #if USE_VERTEX_COLOR\n v_color = a_color;\n #endif\n factor_fog = CC_TRANSFER_FOG(matWorld * In.position);\n #if USE_LIGHTMAP && !USE_BATCHING && !CC_FORWARD_ADD\n CCLightingMapCaclUV();\n #endif\n v_shadowPos = cc_matLightViewProj * pos;\n return cc_matProj * (cc_matView * matWorld) * In.position;\n}\nvoid main() { gl_Position = vert(); }`, - "frag": `\nprecision highp float;\nlayout(set = 0, binding = 0) uniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n mediump vec4 cc_fogColor;\n mediump vec4 cc_fogBase;\n mediump vec4 cc_fogAdd;\n};\n#if CC_USE_IBL\nlayout(set = 0, binding = 3) uniform samplerCube cc_environment;\nvec3 unpackRGBE (vec4 rgbe) {\n return rgbe.rgb * pow(2.0, rgbe.a * 255.0 - 128.0);\n}\nvec4 fragTextureLod (sampler2D tex, vec2 coord, float lod) {\n return textureLod(tex, coord, lod);\n}\nvec4 fragTextureLod (samplerCube tex, vec3 coord, float lod) {\n return textureLod(tex, coord, lod);\n}\n#endif\n#if USE_LIGHTMAP && !USE_BATCHING && !CC_FORWARD_ADD\n layout(location = 9) in vec2 v_luv;\nlayout(set = 2, binding = 9) uniform sampler2D cc_lightingMap;\n#endif\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nfloat GGXMobile (float roughness, float NoH, vec3 H, vec3 N) {\n vec3 NxH = cross(N, H);\n float OneMinusNoHSqr = dot(NxH, NxH);\n float a = roughness * roughness;\n float n = NoH * a;\n float p = a / (OneMinusNoHSqr + n * n);\n return p * p;\n}\nfloat CalcSpecular (float roughness, float NoH, vec3 H, vec3 N) {\n return (roughness*0.25 + 0.25) * GGXMobile(roughness, NoH, H, N);\n}\nvec3 BRDFApprox (vec3 specular, float roughness, float NoV) {\n const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);\n const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);\n vec4 r = roughness * c0 + c1;\n float a004 = min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y;\n vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\n AB.y *= clamp(50.0 * specular.g, 0.0, 1.0);\n return specular * AB.x + AB.y;\n}\nstruct StandardSurface {\n vec4 albedo;\n vec3 position;\n vec3 normal;\n vec3 emissive;\n float roughness;\n float metallic;\n float occlusion;\n};\n#if CC_FORWARD_ADD\nlayout(set = 2, binding = 1) uniform CCForwardLight {\n highp vec4 cc_lightPos[1];\n vec4 cc_lightColor[1];\n vec4 cc_lightSizeRangeAngle[1];\n vec4 cc_lightDir[1];\n};\nfloat SmoothDistAtt (float distSqr, float invSqrAttRadius) {\n float factor = distSqr * invSqrAttRadius;\n float smoothFactor = clamp(1.0 - factor * factor, 0.0, 1.0);\n return smoothFactor * smoothFactor;\n}\nfloat GetDistAtt (float distSqr, float invSqrAttRadius) {\n float attenuation = 1.0 / max(distSqr, 0.01*0.01);\n attenuation *= SmoothDistAtt(distSqr , invSqrAttRadius);\n return attenuation;\n}\nfloat GetAngleAtt (vec3 L, vec3 litDir, float litAngleScale, float litAngleOffset) {\n float cd = dot(litDir, L);\n float attenuation = clamp(cd * litAngleScale + litAngleOffset, 0.0, 1.0);\n return (attenuation * attenuation);\n}\n vec4 CCStandardShading (StandardSurface s) {\n vec3 diffuse = s.albedo.rgb * (1.0 - s.metallic);\n vec3 specular = mix(vec3(0.04), s.albedo.rgb, s.metallic);\n vec3 diffuseContrib = diffuse / 3.14159265359;\n vec3 N = normalize(s.normal);\n vec3 V = normalize(cc_cameraPos.xyz - s.position);\n float NV = max(abs(dot(N, V)), 0.001);\n specular = BRDFApprox(specular, s.roughness, NV);\n vec3 finalColor = vec3(0.0);\n for (int i = 0; i < 1; i++) {\n vec3 SLU = cc_lightPos[i].xyz - s.position;\n vec3 SL = normalize(SLU);\n vec3 SH = normalize(SL + V);\n float SNL = max(dot(N, SL), 0.001);\n float SNH = max(dot(N, SH), 0.0);\n float distSqr = dot(SLU, SLU);\n float litRadius = cc_lightSizeRangeAngle[i].x;\n float litRadiusSqr = litRadius * litRadius;\n float illum = 3.14159265359 * (litRadiusSqr / max(litRadiusSqr , distSqr));\n float attRadiusSqrInv = 1.0 / max(cc_lightSizeRangeAngle[i].y, 0.01);\n attRadiusSqrInv *= attRadiusSqrInv;\n float att = GetDistAtt(distSqr, attRadiusSqrInv);\n vec3 lspec = specular * CalcSpecular(s.roughness, SNH, SH, N);\n if (cc_lightPos[i].w > 0.0) {\n float cosInner = max(dot(-cc_lightDir[i].xyz, SL), 0.01);\n float cosOuter = cc_lightSizeRangeAngle[i].z;\n float litAngleScale = 1.0 / max(0.001, cosInner - cosOuter);\n float litAngleOffset = -cosOuter * litAngleScale;\n att *= GetAngleAtt(SL, -cc_lightDir[i].xyz, litAngleScale, litAngleOffset);\n }\n finalColor += SNL * cc_lightColor[i].rgb * cc_lightColor[i].w * illum * att * (diffuseContrib + lspec);\n }\n finalColor = finalColor * s.occlusion;\n return vec4(finalColor, 0.0);\n }\n#else\n #if CC_RECEIVE_SHADOW\nlayout(location = 0) in vec4 v_shadowPos;\nlayout(set = 0, binding = 1) uniform CCShadow {\n highp mat4 cc_matLightPlaneProj;\n highp mat4 cc_matLightViewProj;\n lowp vec4 cc_shadowColor;\n};\nlayout(set = 0, binding = 4) uniform sampler2D cc_shadowMap;\nvec4 CCGetShadowFactor () {\n vec3 clipPos = v_shadowPos.xyz / v_shadowPos.w * 0.5 + 0.5;\n float depth = dot(texture(cc_shadowMap, clipPos.xy), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n if (depth < (clipPos.z - 0.001)) return cc_shadowColor;\n else return vec4(0);\n}\n #endif\n vec4 CCStandardShading (StandardSurface s) {\n vec3 diffuse = s.albedo.rgb * (1.0 - s.metallic);\n vec3 specular = mix(vec3(0.04), s.albedo.rgb, s.metallic);\n vec3 N = normalize(s.normal);\n vec3 V = normalize(cc_cameraPos.xyz - s.position);\n float NV = max(abs(dot(N, V)), 0.001);\n specular = BRDFApprox(specular, s.roughness, NV);\n vec3 L = normalize(-cc_mainLitDir.xyz);\n vec3 H = normalize(L+V);\n float NH = max(dot(N, H), 0.0);\n float NL = max(dot(N, L), 0.001);\n vec3 finalColor = NL * cc_mainLitColor.rgb * cc_mainLitColor.w;\n #if USE_LIGHTMAP && !USE_BATCHING && !CC_FORWARD_ADD\n vec4 lightmap = texture(cc_lightingMap, v_luv);\n finalColor = lightmap.a * lightmap.rgb + (1.0 - lightmap.a) * finalColor;\n #endif\n vec3 diffuseContrib = diffuse / 3.14159265359;\n vec3 specularContrib = specular * CalcSpecular(s.roughness, NH, H, N);\n finalColor *= (diffuseContrib + specularContrib);\n float fAmb = 0.5 - N.y * 0.5;\n vec3 ambDiff = mix(cc_ambientSky.rgb, cc_ambientGround.rgb, fAmb) * cc_ambientSky.w;\n finalColor += (ambDiff.rgb * diffuse);\n #if CC_USE_IBL\n vec3 R = normalize(reflect(-V, N));\n vec4 envmap = fragTextureLod(cc_environment, R, s.roughness * cc_ambientGround.w);\n #if CC_USE_IBL == 2\n vec3 env = unpackRGBE(envmap);\n #else\n vec3 env = SRGBToLinear(envmap.rgb);\n #endif\n finalColor += env * cc_ambientSky.w * specular;\n #endif\n finalColor = finalColor * s.occlusion;\n #if CC_USE_HDR\n s.emissive *= cc_exposure.w;\n #endif\n finalColor += s.emissive;\n #if CC_RECEIVE_SHADOW\n vec4 shadow = CCGetShadowFactor();\n finalColor = shadow.rgb * shadow.a + finalColor * (1.0 - shadow.a);\n #endif\n return vec4(finalColor, s.albedo.a);\n }\n#endif\nvec3 ACESToneMap (vec3 color) {\n color = min(color, vec3(8.0));\n const float A = 2.51;\n const float B = 0.03;\n const float C = 2.43;\n const float D = 0.59;\n const float E = 0.14;\n return (color * (A * color + B)) / (color * (C * color + D) + E);\n}\nvec4 CCFragOutput (vec4 color) {\n #if !CC_USE_HDR\n color.rgb = sqrt(ACESToneMap(color.rgb));\n #endif\n return color;\n}\nlayout(set = 1, binding = 0) uniform Constants {\n vec4 tilingOffset;\n vec4 albedo;\n vec4 albedoScaleAndCutoff;\n vec4 pbrParams;\n vec4 emissive;\n vec4 emissiveScaleParam;\n};\nlayout(location = 2) in vec3 v_position;\nlayout(location = 4) in vec2 v_uv;\nlayout(location = 5) in vec2 v_uv1;\nlayout(location = 3) in vec3 v_normal;\n#if USE_VERTEX_COLOR\n layout(location = 1) in vec3 v_color;\n#endif\n#if USE_ALBEDO_MAP\n layout(set = 1, binding = 1) uniform sampler2D albedoMap;\n#endif\n#if USE_NORMAL_MAP\n layout(location = 7) in vec3 v_tangent;\n layout(location = 8) in vec3 v_bitangent;\n layout(set = 1, binding = 2) uniform sampler2D normalMap;\n#endif\n#if USE_PBR_MAP\n layout(set = 1, binding = 3) uniform sampler2D pbrMap;\n#endif\n#if USE_METALLIC_ROUGHNESS_MAP\n layout(set = 1, binding = 4) uniform sampler2D metallicRoughnessMap;\n#endif\n#if USE_OCCLUSION_MAP\n layout(set = 1, binding = 5) uniform sampler2D occlusionMap;\n#endif\n#if USE_EMISSIVE_MAP\n layout(set = 1, binding = 6) uniform sampler2D emissiveMap;\n#endif\n#if USE_ALPHA_TEST\n#endif\nlayout(location = 6) in float factor_fog;\nvoid surf (out StandardSurface s) {\n vec4 baseColor = albedo;\n #if USE_VERTEX_COLOR\n baseColor.rgb *= v_color;\n #endif\n #if USE_ALBEDO_MAP\n vec4 texColor = texture(albedoMap, ALBEDO_UV);\n texColor.rgb = SRGBToLinear(texColor.rgb);\n baseColor *= texColor;\n #endif\n s.albedo = baseColor;\n s.albedo.rgb *= albedoScaleAndCutoff.xyz;\n #if USE_ALPHA_TEST\n if (s.albedo.ALPHA_TEST_CHANNEL < albedoScaleAndCutoff.w) discard;\n #endif\n s.normal = v_normal;\n #if USE_NORMAL_MAP\n vec3 nmmp = texture(normalMap, NORMAL_UV).xyz - vec3(0.5);\n s.normal =\n (nmmp.x * pbrParams.w) * normalize(v_tangent) +\n (nmmp.y * pbrParams.w) * normalize(v_bitangent) +\n nmmp.z * normalize(s.normal);\n #endif\n s.position = v_position;\n vec4 pbr = pbrParams;\n #if USE_PBR_MAP\n vec4 res = texture(pbrMap, PBR_UV);\n pbr.x *= res.r;\n pbr.y *= res.g;\n pbr.z *= res.b;\n #endif\n #if USE_METALLIC_ROUGHNESS_MAP\n vec4 metallicRoughness = texture(metallicRoughnessMap, PBR_UV);\n pbr.z *= metallicRoughness.b;\n pbr.y *= metallicRoughness.g;\n #endif\n #if USE_OCCLUSION_MAP\n pbr.x *= texture(occlusionMap, PBR_UV).r;\n #endif\n s.occlusion = clamp(pbr.x, 0.0, 0.96);\n s.roughness = clamp(pbr.y, 0.04, 1.0);\n s.metallic = pbr.z;\n s.emissive = emissive.rgb * emissiveScaleParam.xyz;\n #if USE_EMISSIVE_MAP\n s.emissive *= SRGBToLinear(texture(emissiveMap, EMISSIVE_UV).rgb);\n #endif\n}\nvec4 frag () {\n StandardSurface s; surf(s);\n vec4 color = CCStandardShading(s);\n color = vec4(mix(CC_FORWARD_ADD > 0 ? vec3(0.0) : cc_fogColor.rgb, color.rgb, factor_fog), color.a);\n return CCFragOutput(color);\n}\nlayout(location = 0) out vec4 cc_FragColor;\nvoid main() { cc_FragColor = frag(); }` + "vert": `\n#ifdef GL_EXT_shader_explicit_arithmetic_types_int16\n#extension GL_EXT_shader_explicit_arithmetic_types_int16: enable\n#endif\nprecision highp float;\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nlayout(location = 0) in vec3 a_position;\nlayout(location = 1) in vec3 a_normal;\nlayout(location = 2) in vec2 a_texCoord;\nlayout(location = 3) in vec4 a_tangent;\n#if CC_USE_MORPH\n int getVertexId() {\n return gl_VertexID;\n }\nlayout(set = 2, binding = 4) uniform CCMorph {\n vec4 cc_displacementWeights[15];\n vec4 cc_displacementTextureInfo;\n};\n vec4 fetchVec3ArrayFromTexture(sampler2D tex, int pixelIndex) {\n ivec2 texSize = textureSize(tex, 0);\n return texelFetch(tex, ivec2(pixelIndex % texSize.x, pixelIndex / texSize.x), 0);\n }\nfloat getDisplacementWeight(int index) {\n float m = mod(float(index), 4.0);\n if (m < 1.0) {\n return cc_displacementWeights[index / 4].x;\n } else if (m < 2.0) {\n return cc_displacementWeights[index / 4].y;\n } else if (m < 3.0) {\n return cc_displacementWeights[index / 4].z;\n } else {\n return cc_displacementWeights[index / 4].w;\n }\n}\nvec3 getVec3DisplacementFromTexture(sampler2D tex, int vertexIndex) {\n#if CC_MORPH_PRECOMPUTED\n return fetchVec3ArrayFromTexture(tex, vertexIndex).rgb;\n#else\n vec3 result = vec3(0, 0, 0);\n for (int iTarget = 0; iTarget < CC_MORPH_TARGET_COUNT; ++iTarget) {\n int dataPixelStart = int(fetchVec3ArrayFromTexture(tex, iTarget).r);\n result += (fetchVec3ArrayFromTexture(tex, dataPixelStart + vertexIndex).rgb * getDisplacementWeight(iTarget));\n }\n return result;\n#endif\n}\n#if CC_MORPH_TARGET_HAS_POSITION\n layout(set = 2, binding = 6) uniform sampler2D cc_PositionDisplacements;\n vec3 getPositionDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_PositionDisplacements, vertexId);\n }\n#endif\n#if CC_MORPH_TARGET_HAS_NORMAL\n layout(set = 2, binding = 7) uniform sampler2D cc_NormalDisplacements;\n vec3 getNormalDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_NormalDisplacements, vertexId);\n }\n#endif\n#if CC_MORPH_TARGET_HAS_TANGENT\n layout(set = 2, binding = 8) uniform sampler2D cc_TangentDisplacements;\n vec3 getTangentDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_TangentDisplacements, vertexId);\n }\n#endif\nvoid applyMorph (inout StandardVertInput attr) {\n int vertexId = getVertexId();\n#if CC_MORPH_TARGET_HAS_POSITION\n attr.position.xyz = attr.position.xyz + getPositionDisplacement(vertexId);\n#endif\n#if CC_MORPH_TARGET_HAS_NORMAL\n attr.normal.xyz = attr.normal.xyz + getNormalDisplacement(vertexId);\n#endif\n#if CC_MORPH_TARGET_HAS_TANGENT\n attr.tangent.xyz = attr.tangent.xyz + getTangentDisplacement(vertexId);\n#endif\n}\nvoid applyMorph (inout vec4 position) {\n#if CC_MORPH_TARGET_HAS_POSITION\n position.xyz = position.xyz + getPositionDisplacement(getVertexId());\n#endif\n}\n#endif\n#if CC_USE_SKINNING\nlayout(location = 4) in u16vec4 a_joints;\nlayout(location = 5) in vec4 a_weights;\n#if CC_USE_BAKED_ANIMATION\n #if USE_INSTANCING\n layout(location = 7) in highp vec4 a_jointAnimInfo;\n #endif\n layout(set = 2, binding = 3) uniform CCSkinningTexture {\n highp vec4 cc_jointTextureInfo;\n };\n layout(set = 2, binding = 2) uniform CCSkinningAnimation {\n highp vec4 cc_jointAnimInfo;\n };\n layout(set = 2, binding = 5) uniform highp sampler2D cc_jointTexture;\n #if !CC_SUPPORT_FLOAT_TEXTURE\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n #endif\n#else\n layout(set = 2, binding = 3) uniform CCSkinning {\n highp vec4 cc_joints[30 * 3];\n };\n#endif\n#if CC_USE_BAKED_ANIMATION\n #if CC_SUPPORT_FLOAT_TEXTURE\n mat4 getJointMatrix (float i) {\n #if USE_INSTANCING\n highp float j = 3.0 * (a_jointAnimInfo.x * a_jointAnimInfo.y + i) + a_jointAnimInfo.z;\n #else\n highp float j = 3.0 * (cc_jointAnimInfo.x * cc_jointTextureInfo.y + i) + cc_jointTextureInfo.z;\n #endif\n highp float invSize = cc_jointTextureInfo.w;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture(cc_jointTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture(cc_jointTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture(cc_jointTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n #else\n mat4 getJointMatrix (float i) {\n #if USE_INSTANCING\n highp float j = 12.0 * (a_jointAnimInfo.x * a_jointAnimInfo.y + i) + a_jointAnimInfo.z;\n #else\n highp float j = 12.0 * (cc_jointAnimInfo.x * cc_jointTextureInfo.y + i) + cc_jointTextureInfo.z;\n #endif\n highp float invSize = cc_jointTextureInfo.w;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n #endif\n#else\n mat4 getJointMatrix (float i) {\n int idx = int(i);\n vec4 v1 = cc_joints[idx * 3];\n vec4 v2 = cc_joints[idx * 3 + 1];\n vec4 v3 = cc_joints[idx * 3 + 2];\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y\n + getJointMatrix(a_joints.z) * a_weights.z\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\nlayout(set = 0, binding = 0) uniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n mediump vec4 cc_fogColor;\n mediump vec4 cc_fogBase;\n mediump vec4 cc_fogAdd;\n};\n#if USE_INSTANCING\n layout(location = 8) in vec4 a_matWorld0;\n layout(location = 9) in vec4 a_matWorld1;\n layout(location = 10) in vec4 a_matWorld2;\n #if USE_LIGHTMAP\n layout(location = 11) in vec4 a_lightingMapUVParam;\n #endif\n#elif USE_BATCHING\n layout(location = 12) in float a_dyn_batch_id;\n layout(set = 2, binding = 0) uniform CCLocalBatched {\n highp mat4 cc_matWorlds[10];\n };\n#else\nlayout(set = 2, binding = 0) uniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n highp vec4 cc_lightingMapUVParam;\n};\n#endif\nlayout(set = 1, binding = 0) uniform Constants {\n vec4 tilingOffset;\n vec4 albedo;\n vec4 albedoScaleAndCutoff;\n vec4 pbrParams;\n vec4 emissive;\n vec4 emissiveScaleParam;\n};\nfloat LinearFog(vec4 pos) {\n vec4 wPos = pos;\n float cam_dis = distance(cc_cameraPos, wPos);\n float fogStart = cc_fogBase.x;\n float fogEnd = cc_fogBase.y;\n return clamp((fogEnd - cam_dis) / (fogEnd - fogStart), 0., 1.);\n}\nfloat ExpFog(vec4 pos) {\n vec4 wPos = pos;\n float fogAtten = cc_fogAdd.z;\n float fogDensity = cc_fogBase.z;\n float cam_dis = distance(cc_cameraPos, wPos) / fogAtten * 4.;\n float f = exp(-cam_dis * fogDensity);\n return f;\n}\nfloat ExpSquaredFog(vec4 pos) {\n vec4 wPos = pos;\n float fogAtten = cc_fogAdd.z;\n float fogDensity = cc_fogBase.z;\n float cam_dis = distance(cc_cameraPos, wPos) / fogAtten * 4.;\n float f = exp(-cam_dis * cam_dis * fogDensity * fogDensity);\n return f;\n}\nfloat LayeredFog(vec4 pos) {\n vec4 wPos = pos;\n float fogAtten = cc_fogAdd.z;\n float _FogTop = cc_fogAdd.x;\n float _FogRange = cc_fogAdd.y;\n vec3 camWorldProj = cc_cameraPos.xyz;\n camWorldProj.y = 0.;\n vec3 worldPosProj = wPos.xyz;\n worldPosProj.y = 0.;\n float fDeltaD = distance(worldPosProj, camWorldProj) / fogAtten * 2.0;\n float fDeltaY, fDensityIntegral;\n if (cc_cameraPos.y > _FogTop) {\n if (wPos.y < _FogTop) {\n fDeltaY = (_FogTop - wPos.y) / _FogRange * 2.0;\n fDensityIntegral = fDeltaY * fDeltaY * 0.5;\n } else {\n fDeltaY = 0.;\n fDensityIntegral = 0.;\n }\n } else {\n if (wPos.y < _FogTop) {\n float fDeltaA = (_FogTop - cc_cameraPos.y) / _FogRange * 2.;\n float fDeltaB = (_FogTop - wPos.y) / _FogRange * 2.;\n fDeltaY = abs(fDeltaA - fDeltaB);\n fDensityIntegral = abs((fDeltaA * fDeltaA * 0.5) - (fDeltaB * fDeltaB * 0.5));\n } else {\n fDeltaY = abs(_FogTop - cc_cameraPos.y) / _FogRange * 2.;\n fDensityIntegral = abs(fDeltaY * fDeltaY * 0.5);\n }\n }\n float fDensity;\n if (fDeltaY != 0.) {\n fDensity = (sqrt(1.0 + ((fDeltaD / fDeltaY) * (fDeltaD / fDeltaY)))) * fDensityIntegral;\n } else {\n fDensity = 0.;\n }\n float f = exp(-fDensity);\n return f;\n}\nfloat CC_TRANSFER_FOG(vec4 pos) {\n #if CC_USE_FOG == 1\n return LinearFog(pos);\n #elif CC_USE_FOG == 2\n return ExpFog(pos);\n #elif CC_USE_FOG == 3\n return ExpSquaredFog(pos);\n #elif CC_USE_FOG == 4\n return LayeredFog(pos);\n #endif\n return 1.;\n}\nlayout(location = 0) out vec4 v_shadowPos;\nlayout(set = 0, binding = 1) uniform CCShadow {\n highp mat4 cc_matLightPlaneProj;\n highp mat4 cc_matLightViewProj;\n lowp vec4 cc_shadowColor;\n lowp vec4 cc_shadowPCF;\n lowp vec4 cc_shadowSize;\n};\n#if USE_VERTEX_COLOR\n layout(location = 13) in vec3 a_color;\n layout(location = 1) out vec3 v_color;\n#endif\nlayout(location = 2) out vec3 v_position;\nlayout(location = 3) out vec3 v_normal;\nlayout(location = 4) out vec2 v_uv;\nlayout(location = 5) out vec2 v_uv1;\nlayout(location = 6) out float factor_fog;\n#if USE_NORMAL_MAP\n layout(location = 7) out vec3 v_tangent;\n layout(location = 8) out vec3 v_bitangent;\n#endif\n#if HAS_SECOND_UV || USE_LIGHTMAP\n layout(location = 14) in vec2 a_texCoord1;\n#endif\n#if USE_LIGHTMAP && !USE_BATCHING && !CC_FORWARD_ADD\n layout(location = 9) out vec2 v_luv;\nvoid CCLightingMapCaclUV()\n{\n#if !USE_INSTANCING\n v_luv = cc_lightingMapUVParam.xy + a_texCoord1 * cc_lightingMapUVParam.zw;\n#else\n v_luv = a_lightingMapUVParam.xy + a_texCoord1 * a_lightingMapUVParam.zw;\n#endif\n}\n#endif\nvec4 vert () {\n StandardVertInput In;\n In.position = vec4(a_position, 1.0);\n In.normal = a_normal;\n In.tangent = a_tangent;\n #if CC_USE_MORPH\n applyMorph(In);\n #endif\n #if CC_USE_SKINNING\n CCSkin(In);\n #endif\n mat4 matWorld, matWorldIT;\n #if USE_INSTANCING\n matWorld = mat4(\n vec4(a_matWorld0.xyz, 0.0),\n vec4(a_matWorld1.xyz, 0.0),\n vec4(a_matWorld2.xyz, 0.0),\n vec4(a_matWorld0.w, a_matWorld1.w, a_matWorld2.w, 1.0)\n );\n matWorldIT = matWorld;\n #elif USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id)];\n matWorldIT = matWorld;\n #else\n matWorld = cc_matWorld;\n matWorldIT = cc_matWorldIT;\n #endif\n vec4 pos = matWorld * In.position;\n v_position = pos.xyz;\n v_normal = normalize((matWorldIT * vec4(In.normal, 0.0)).xyz);\n #if USE_NORMAL_MAP\n v_tangent = normalize((matWorld * vec4(In.tangent.xyz, 0.0)).xyz);\n v_bitangent = cross(v_normal, v_tangent) * In.tangent.w;\n #endif\n v_uv = a_texCoord * tilingOffset.xy + tilingOffset.zw;\n #if HAS_SECOND_UV\n v_uv1 = a_texCoord1 * tilingOffset.xy + tilingOffset.zw;\n #endif\n #if USE_VERTEX_COLOR\n v_color = a_color;\n #endif\n factor_fog = CC_TRANSFER_FOG(matWorld * In.position);\n #if USE_LIGHTMAP && !USE_BATCHING && !CC_FORWARD_ADD\n CCLightingMapCaclUV();\n #endif\n v_shadowPos = cc_matLightViewProj * pos;\n return cc_matProj * (cc_matView * matWorld) * In.position;\n}\nvoid main() { gl_Position = vert(); }`, + "frag": `\nprecision highp float;\nlayout(set = 0, binding = 0) uniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n mediump vec4 cc_fogColor;\n mediump vec4 cc_fogBase;\n mediump vec4 cc_fogAdd;\n};\nlayout(set = 0, binding = 1) uniform CCShadow {\n highp mat4 cc_matLightPlaneProj;\n highp mat4 cc_matLightViewProj;\n lowp vec4 cc_shadowColor;\n lowp vec4 cc_shadowPCF;\n lowp vec4 cc_shadowSize;\n};\n#if CC_USE_IBL\nlayout(set = 0, binding = 3) uniform samplerCube cc_environment;\nvec3 unpackRGBE (vec4 rgbe) {\n return rgbe.rgb * pow(2.0, rgbe.a * 255.0 - 128.0);\n}\nvec4 fragTextureLod (sampler2D tex, vec2 coord, float lod) {\n return textureLod(tex, coord, lod);\n}\nvec4 fragTextureLod (samplerCube tex, vec3 coord, float lod) {\n return textureLod(tex, coord, lod);\n}\n#endif\n#if USE_LIGHTMAP && !USE_BATCHING && !CC_FORWARD_ADD\n layout(location = 9) in vec2 v_luv;\nlayout(set = 2, binding = 9) uniform sampler2D cc_lightingMap;\n#endif\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nfloat GGXMobile (float roughness, float NoH, vec3 H, vec3 N) {\n vec3 NxH = cross(N, H);\n float OneMinusNoHSqr = dot(NxH, NxH);\n float a = roughness * roughness;\n float n = NoH * a;\n float p = a / (OneMinusNoHSqr + n * n);\n return p * p;\n}\nfloat CalcSpecular (float roughness, float NoH, vec3 H, vec3 N) {\n return (roughness*0.25 + 0.25) * GGXMobile(roughness, NoH, H, N);\n}\nvec3 BRDFApprox (vec3 specular, float roughness, float NoV) {\n const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);\n const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);\n vec4 r = roughness * c0 + c1;\n float a004 = min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y;\n vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\n AB.y *= clamp(50.0 * specular.g, 0.0, 1.0);\n return specular * AB.x + AB.y;\n}\nstruct StandardSurface {\n vec4 albedo;\n vec3 position;\n vec3 normal;\n vec3 emissive;\n float roughness;\n float metallic;\n float occlusion;\n};\n#if CC_FORWARD_ADD\nlayout(set = 2, binding = 1) uniform CCForwardLight {\n highp vec4 cc_lightPos[1];\n vec4 cc_lightColor[1];\n vec4 cc_lightSizeRangeAngle[1];\n vec4 cc_lightDir[1];\n};\nfloat SmoothDistAtt (float distSqr, float invSqrAttRadius) {\n float factor = distSqr * invSqrAttRadius;\n float smoothFactor = clamp(1.0 - factor * factor, 0.0, 1.0);\n return smoothFactor * smoothFactor;\n}\nfloat GetDistAtt (float distSqr, float invSqrAttRadius) {\n float attenuation = 1.0 / max(distSqr, 0.01*0.01);\n attenuation *= SmoothDistAtt(distSqr , invSqrAttRadius);\n return attenuation;\n}\nfloat GetAngleAtt (vec3 L, vec3 litDir, float litAngleScale, float litAngleOffset) {\n float cd = dot(litDir, L);\n float attenuation = clamp(cd * litAngleScale + litAngleOffset, 0.0, 1.0);\n return (attenuation * attenuation);\n}\n vec4 CCStandardShading (StandardSurface s) {\n vec3 diffuse = s.albedo.rgb * (1.0 - s.metallic);\n vec3 specular = mix(vec3(0.04), s.albedo.rgb, s.metallic);\n vec3 diffuseContrib = diffuse / 3.14159265359;\n vec3 N = normalize(s.normal);\n vec3 V = normalize(cc_cameraPos.xyz - s.position);\n float NV = max(abs(dot(N, V)), 0.001);\n specular = BRDFApprox(specular, s.roughness, NV);\n vec3 finalColor = vec3(0.0);\n for (int i = 0; i < 1; i++) {\n vec3 SLU = cc_lightPos[i].xyz - s.position;\n vec3 SL = normalize(SLU);\n vec3 SH = normalize(SL + V);\n float SNL = max(dot(N, SL), 0.001);\n float SNH = max(dot(N, SH), 0.0);\n float distSqr = dot(SLU, SLU);\n float litRadius = cc_lightSizeRangeAngle[i].x;\n float litRadiusSqr = litRadius * litRadius;\n float illum = 3.14159265359 * (litRadiusSqr / max(litRadiusSqr , distSqr));\n float attRadiusSqrInv = 1.0 / max(cc_lightSizeRangeAngle[i].y, 0.01);\n attRadiusSqrInv *= attRadiusSqrInv;\n float att = GetDistAtt(distSqr, attRadiusSqrInv);\n vec3 lspec = specular * CalcSpecular(s.roughness, SNH, SH, N);\n if (cc_lightPos[i].w > 0.0) {\n float cosInner = max(dot(-cc_lightDir[i].xyz, SL), 0.01);\n float cosOuter = cc_lightSizeRangeAngle[i].z;\n float litAngleScale = 1.0 / max(0.001, cosInner - cosOuter);\n float litAngleOffset = -cosOuter * litAngleScale;\n att *= GetAngleAtt(SL, -cc_lightDir[i].xyz, litAngleScale, litAngleOffset);\n }\n finalColor += SNL * cc_lightColor[i].rgb * cc_lightColor[i].w * illum * att * (diffuseContrib + lspec);\n }\n finalColor = finalColor * s.occlusion;\n return vec4(finalColor, 0.0);\n }\n#else\n #if CC_RECEIVE_SHADOW\nlayout(location = 0) in vec4 v_shadowPos;\nlayout(set = 0, binding = 4) uniform sampler2D cc_shadowMap;\nvec4 CCGetShadowFactorEasy () {\n vec3 clipPos = v_shadowPos.xyz / v_shadowPos.w * 0.5 + 0.5;\n float depth = dot(texture(cc_shadowMap, clipPos.xy), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n if (depth < (clipPos.z - 0.001)) return cc_shadowColor;\n else return vec4(0);\n}\nvec4 CCGetShadowFactorHard () {\n vec3 clipPos = v_shadowPos.xyz / v_shadowPos.w * 0.5 + 0.5;\n float offsetx = 1.0 / cc_shadowSize.x;\n float offsety = 1.0 / cc_shadowSize.y;\n float depth = 0.0;\n depth += dot(texture(cc_shadowMap, vec2(clipPos.x - offsetx, clipPos.y - offsety)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture(cc_shadowMap, vec2(clipPos.x, clipPos.y - offsety)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture(cc_shadowMap, vec2(clipPos.x + offsetx, clipPos.y - offsety)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture(cc_shadowMap, vec2(clipPos.x - offsetx, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture(cc_shadowMap, vec2(clipPos.x, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture(cc_shadowMap, vec2(clipPos.x + offsetx, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture(cc_shadowMap, vec2(clipPos.x - offsetx, clipPos.y + offsety)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture(cc_shadowMap, vec2(clipPos.x, clipPos.y + offsety)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture(cc_shadowMap, vec2(clipPos.x + offsetx, clipPos.y + offsety)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth /= 9.0;\n if (depth < (clipPos.z - 0.001)) return cc_shadowColor;\n else return vec4(0);\n}\nvec4 CCGetShadowFactorCommon () {\n vec3 clipPos = v_shadowPos.xyz / v_shadowPos.w * 0.5 + 0.5;\n float offsetx = 1.0 / cc_shadowSize.x;\n float offsety = 1.0 / cc_shadowSize.y;\n float depth = 0.0;\n depth += dot(texture(cc_shadowMap, vec2(clipPos.x - offsetx, clipPos.y - offsety)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture(cc_shadowMap, vec2(clipPos.x - offsetx, clipPos.y + offsety)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture(cc_shadowMap, vec2(clipPos.x, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture(cc_shadowMap, vec2(clipPos.x + offsetx, clipPos.y - offsety)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth += dot(texture(cc_shadowMap, vec2(clipPos.x + offsetx, clipPos.y + offsety)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0));\n depth /= 5.0;\n if (depth < (clipPos.z - 0.001)) return cc_shadowColor;\n else return vec4(0);\n}\n #endif\n vec4 CCStandardShading (StandardSurface s) {\n vec3 diffuse = s.albedo.rgb * (1.0 - s.metallic);\n vec3 specular = mix(vec3(0.04), s.albedo.rgb, s.metallic);\n vec3 N = normalize(s.normal);\n vec3 V = normalize(cc_cameraPos.xyz - s.position);\n float NV = max(abs(dot(N, V)), 0.001);\n specular = BRDFApprox(specular, s.roughness, NV);\n vec3 L = normalize(-cc_mainLitDir.xyz);\n vec3 H = normalize(L+V);\n float NH = max(dot(N, H), 0.0);\n float NL = max(dot(N, L), 0.001);\n vec3 finalColor = NL * cc_mainLitColor.rgb * cc_mainLitColor.w;\n #if USE_LIGHTMAP && !USE_BATCHING && !CC_FORWARD_ADD\n vec4 lightmap = texture(cc_lightingMap, v_luv);\n finalColor = lightmap.a * lightmap.rgb + (1.0 - lightmap.a) * finalColor;\n #endif\n vec3 diffuseContrib = diffuse / 3.14159265359;\n vec3 specularContrib = specular * CalcSpecular(s.roughness, NH, H, N);\n finalColor *= (diffuseContrib + specularContrib);\n float fAmb = 0.5 - N.y * 0.5;\n vec3 ambDiff = mix(cc_ambientSky.rgb, cc_ambientGround.rgb, fAmb) * cc_ambientSky.w;\n finalColor += (ambDiff.rgb * diffuse);\n #if CC_USE_IBL\n vec3 R = normalize(reflect(-V, N));\n vec4 envmap = fragTextureLod(cc_environment, R, s.roughness * cc_ambientGround.w);\n #if CC_USE_IBL == 2\n vec3 env = unpackRGBE(envmap);\n #else\n vec3 env = SRGBToLinear(envmap.rgb);\n #endif\n finalColor += env * cc_ambientSky.w * specular;\n #endif\n finalColor = finalColor * s.occlusion;\n #if CC_USE_HDR\n s.emissive *= cc_exposure.w;\n #endif\n finalColor += s.emissive;\n #if CC_RECEIVE_SHADOW\n vec4 shadow = vec4(1.0);\n float pcf = cc_shadowPCF.x + 0.001;\n if (pcf > 2.0) {shadow = CCGetShadowFactorEasy();}\n if (2.0 > pcf && pcf > 1.0) {shadow = CCGetShadowFactorCommon();}\n if (1.0 > pcf && pcf > 0.0) {shadow = CCGetShadowFactorHard();}\n finalColor = shadow.rgb * shadow.a + finalColor * (1.0 - shadow.a);\n #endif\n return vec4(finalColor, s.albedo.a);\n }\n#endif\nvec3 ACESToneMap (vec3 color) {\n color = min(color, vec3(8.0));\n const float A = 2.51;\n const float B = 0.03;\n const float C = 2.43;\n const float D = 0.59;\n const float E = 0.14;\n return (color * (A * color + B)) / (color * (C * color + D) + E);\n}\nvec4 CCFragOutput (vec4 color) {\n #if !CC_USE_HDR\n color.rgb = sqrt(ACESToneMap(color.rgb));\n #endif\n return color;\n}\nlayout(set = 1, binding = 0) uniform Constants {\n vec4 tilingOffset;\n vec4 albedo;\n vec4 albedoScaleAndCutoff;\n vec4 pbrParams;\n vec4 emissive;\n vec4 emissiveScaleParam;\n};\nlayout(location = 2) in vec3 v_position;\nlayout(location = 4) in vec2 v_uv;\nlayout(location = 5) in vec2 v_uv1;\nlayout(location = 3) in vec3 v_normal;\n#if USE_VERTEX_COLOR\n layout(location = 1) in vec3 v_color;\n#endif\n#if USE_ALBEDO_MAP\n layout(set = 1, binding = 1) uniform sampler2D albedoMap;\n#endif\n#if USE_NORMAL_MAP\n layout(location = 7) in vec3 v_tangent;\n layout(location = 8) in vec3 v_bitangent;\n layout(set = 1, binding = 2) uniform sampler2D normalMap;\n#endif\n#if USE_PBR_MAP\n layout(set = 1, binding = 3) uniform sampler2D pbrMap;\n#endif\n#if USE_METALLIC_ROUGHNESS_MAP\n layout(set = 1, binding = 4) uniform sampler2D metallicRoughnessMap;\n#endif\n#if USE_OCCLUSION_MAP\n layout(set = 1, binding = 5) uniform sampler2D occlusionMap;\n#endif\n#if USE_EMISSIVE_MAP\n layout(set = 1, binding = 6) uniform sampler2D emissiveMap;\n#endif\n#if USE_ALPHA_TEST\n#endif\nlayout(location = 6) in float factor_fog;\nvoid surf (out StandardSurface s) {\n vec4 baseColor = albedo;\n #if USE_VERTEX_COLOR\n baseColor.rgb *= v_color;\n #endif\n #if USE_ALBEDO_MAP\n vec4 texColor = texture(albedoMap, ALBEDO_UV);\n texColor.rgb = SRGBToLinear(texColor.rgb);\n baseColor *= texColor;\n #endif\n s.albedo = baseColor;\n s.albedo.rgb *= albedoScaleAndCutoff.xyz;\n #if USE_ALPHA_TEST\n if (s.albedo.ALPHA_TEST_CHANNEL < albedoScaleAndCutoff.w) discard;\n #endif\n s.normal = v_normal;\n #if USE_NORMAL_MAP\n vec3 nmmp = texture(normalMap, NORMAL_UV).xyz - vec3(0.5);\n s.normal =\n (nmmp.x * pbrParams.w) * normalize(v_tangent) +\n (nmmp.y * pbrParams.w) * normalize(v_bitangent) +\n nmmp.z * normalize(s.normal);\n #endif\n s.position = v_position;\n vec4 pbr = pbrParams;\n #if USE_PBR_MAP\n vec4 res = texture(pbrMap, PBR_UV);\n pbr.x *= res.r;\n pbr.y *= res.g;\n pbr.z *= res.b;\n #endif\n #if USE_METALLIC_ROUGHNESS_MAP\n vec4 metallicRoughness = texture(metallicRoughnessMap, PBR_UV);\n pbr.z *= metallicRoughness.b;\n pbr.y *= metallicRoughness.g;\n #endif\n #if USE_OCCLUSION_MAP\n pbr.x *= texture(occlusionMap, PBR_UV).r;\n #endif\n s.occlusion = clamp(pbr.x, 0.0, 0.96);\n s.roughness = clamp(pbr.y, 0.04, 1.0);\n s.metallic = pbr.z;\n s.emissive = emissive.rgb * emissiveScaleParam.xyz;\n #if USE_EMISSIVE_MAP\n s.emissive *= SRGBToLinear(texture(emissiveMap, EMISSIVE_UV).rgb);\n #endif\n}\nvec4 frag () {\n StandardSurface s; surf(s);\n vec4 color = CCStandardShading(s);\n color = vec4(mix(CC_FORWARD_ADD > 0 ? vec3(0.0) : cc_fogColor.rgb, color.rgb, factor_fog), color.a);\n return CCFragOutput(color);\n}\nlayout(location = 0) out vec4 cc_FragColor;\nvoid main() { cc_FragColor = frag(); }` }, "builtins": { "globals": { "blocks": [{ "name": "CCGlobal", "defines": [] }, { "name": "CCShadow", "defines": [] }], "samplers": [{ "name": "cc_environment", "defines": ["CC_USE_IBL"] }, { "name": "cc_shadowMap", "defines": ["!CC_FORWARD_ADD", "CC_RECEIVE_SHADOW"] }] }, @@ -443,7 +443,7 @@ export default [ "name": "builtin-standard|shadowMap-vs:vert|shadowMap-fs:frag", "hash": 832800683, "glsl3": { - "vert": `\nprecision highp float;\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nin vec3 a_position;\nin vec3 a_normal;\nin vec2 a_texCoord;\nin vec4 a_tangent;\n#if CC_USE_MORPH\n int getVertexId() {\n return gl_VertexID;\n }\nlayout(std140) uniform CCMorph {\n vec4 cc_displacementWeights[15];\n vec4 cc_displacementTextureInfo;\n};\n vec4 fetchVec3ArrayFromTexture(sampler2D tex, int pixelIndex) {\n ivec2 texSize = textureSize(tex, 0);\n return texelFetch(tex, ivec2(pixelIndex % texSize.x, pixelIndex / texSize.x), 0);\n }\nfloat getDisplacementWeight(int index) {\n float m = mod(float(index), 4.0);\n if (m < 1.0) {\n return cc_displacementWeights[index / 4].x;\n } else if (m < 2.0) {\n return cc_displacementWeights[index / 4].y;\n } else if (m < 3.0) {\n return cc_displacementWeights[index / 4].z;\n } else {\n return cc_displacementWeights[index / 4].w;\n }\n}\nvec3 getVec3DisplacementFromTexture(sampler2D tex, int vertexIndex) {\n#if CC_MORPH_PRECOMPUTED\n return fetchVec3ArrayFromTexture(tex, vertexIndex).rgb;\n#else\n vec3 result = vec3(0, 0, 0);\n for (int iTarget = 0; iTarget < CC_MORPH_TARGET_COUNT; ++iTarget) {\n int dataPixelStart = int(fetchVec3ArrayFromTexture(tex, iTarget).r);\n result += (fetchVec3ArrayFromTexture(tex, dataPixelStart + vertexIndex).rgb * getDisplacementWeight(iTarget));\n }\n return result;\n#endif\n}\n#if CC_MORPH_TARGET_HAS_POSITION\n uniform sampler2D cc_PositionDisplacements;\n vec3 getPositionDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_PositionDisplacements, vertexId);\n }\n#endif\n#if CC_MORPH_TARGET_HAS_NORMAL\n uniform sampler2D cc_NormalDisplacements;\n vec3 getNormalDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_NormalDisplacements, vertexId);\n }\n#endif\n#if CC_MORPH_TARGET_HAS_TANGENT\n uniform sampler2D cc_TangentDisplacements;\n vec3 getTangentDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_TangentDisplacements, vertexId);\n }\n#endif\nvoid applyMorph (inout StandardVertInput attr) {\n int vertexId = getVertexId();\n#if CC_MORPH_TARGET_HAS_POSITION\n attr.position.xyz = attr.position.xyz + getPositionDisplacement(vertexId);\n#endif\n#if CC_MORPH_TARGET_HAS_NORMAL\n attr.normal.xyz = attr.normal.xyz + getNormalDisplacement(vertexId);\n#endif\n#if CC_MORPH_TARGET_HAS_TANGENT\n attr.tangent.xyz = attr.tangent.xyz + getTangentDisplacement(vertexId);\n#endif\n}\nvoid applyMorph (inout vec4 position) {\n#if CC_MORPH_TARGET_HAS_POSITION\n position.xyz = position.xyz + getPositionDisplacement(getVertexId());\n#endif\n}\n#endif\n#if CC_USE_SKINNING\nin vec4 a_joints;\nin vec4 a_weights;\n#if CC_USE_BAKED_ANIMATION\n #if USE_INSTANCING\n in highp vec4 a_jointAnimInfo;\n #endif\n layout(std140) uniform CCSkinningTexture {\n highp vec4 cc_jointTextureInfo;\n };\n layout(std140) uniform CCSkinningAnimation {\n highp vec4 cc_jointAnimInfo;\n };\n uniform highp sampler2D cc_jointTexture;\n #if !CC_SUPPORT_FLOAT_TEXTURE\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n #endif\n#else\n layout(std140) uniform CCSkinning {\n highp vec4 cc_joints[30 * 3];\n };\n#endif\n#if CC_USE_BAKED_ANIMATION\n #if CC_SUPPORT_FLOAT_TEXTURE\n mat4 getJointMatrix (float i) {\n #if USE_INSTANCING\n highp float j = 3.0 * (a_jointAnimInfo.x * a_jointAnimInfo.y + i) + a_jointAnimInfo.z;\n #else\n highp float j = 3.0 * (cc_jointAnimInfo.x * cc_jointTextureInfo.y + i) + cc_jointTextureInfo.z;\n #endif\n highp float invSize = cc_jointTextureInfo.w;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture(cc_jointTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture(cc_jointTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture(cc_jointTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n #else\n mat4 getJointMatrix (float i) {\n #if USE_INSTANCING\n highp float j = 12.0 * (a_jointAnimInfo.x * a_jointAnimInfo.y + i) + a_jointAnimInfo.z;\n #else\n highp float j = 12.0 * (cc_jointAnimInfo.x * cc_jointTextureInfo.y + i) + cc_jointTextureInfo.z;\n #endif\n highp float invSize = cc_jointTextureInfo.w;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n #endif\n#else\n mat4 getJointMatrix (float i) {\n int idx = int(i);\n vec4 v1 = cc_joints[idx * 3];\n vec4 v2 = cc_joints[idx * 3 + 1];\n vec4 v3 = cc_joints[idx * 3 + 2];\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y\n + getJointMatrix(a_joints.z) * a_weights.z\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\nlayout(std140) uniform CCShadow {\n highp mat4 cc_matLightPlaneProj;\n highp mat4 cc_matLightViewProj;\n lowp vec4 cc_shadowColor;\n};\n#if USE_INSTANCING\n in vec4 a_matWorld0;\n in vec4 a_matWorld1;\n in vec4 a_matWorld2;\n #if USE_LIGHTMAP\n in vec4 a_lightingMapUVParam;\n #endif\n#elif USE_BATCHING\n in float a_dyn_batch_id;\n layout(std140) uniform CCLocalBatched {\n highp mat4 cc_matWorlds[10];\n };\n#else\nlayout(std140) uniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n highp vec4 cc_lightingMapUVParam;\n};\n#endif\nout vec4 vTexCoord;\nvec4 vert () {\n StandardVertInput In;\n In.position = vec4(a_position, 1.0);\n In.normal = a_normal;\n In.tangent = a_tangent;\n #if CC_USE_MORPH\n applyMorph(In);\n #endif\n #if CC_USE_SKINNING\n CCSkin(In);\n #endif\n mat4 matWorld, matWorldIT;\n #if USE_INSTANCING\n matWorld = mat4(\n vec4(a_matWorld0.xyz, 0.0),\n vec4(a_matWorld1.xyz, 0.0),\n vec4(a_matWorld2.xyz, 0.0),\n vec4(a_matWorld0.w, a_matWorld1.w, a_matWorld2.w, 1.0)\n );\n matWorldIT = matWorld;\n #elif USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id)];\n matWorldIT = matWorld;\n #else\n matWorld = cc_matWorld;\n matWorldIT = cc_matWorldIT;\n #endif\n vec4 worldPos = matWorld * In.position;\n vec4 clipPos = cc_matLightViewProj * worldPos;\n vTexCoord = vec4(a_texCoord, clipPos.z, clipPos.w);\n return clipPos;\n}\nvoid main() { gl_Position = vert(); }`, + "vert": `\nprecision highp float;\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nin vec3 a_position;\nin vec3 a_normal;\nin vec2 a_texCoord;\nin vec4 a_tangent;\n#if CC_USE_MORPH\n int getVertexId() {\n return gl_VertexID;\n }\nlayout(std140) uniform CCMorph {\n vec4 cc_displacementWeights[15];\n vec4 cc_displacementTextureInfo;\n};\n vec4 fetchVec3ArrayFromTexture(sampler2D tex, int pixelIndex) {\n ivec2 texSize = textureSize(tex, 0);\n return texelFetch(tex, ivec2(pixelIndex % texSize.x, pixelIndex / texSize.x), 0);\n }\nfloat getDisplacementWeight(int index) {\n float m = mod(float(index), 4.0);\n if (m < 1.0) {\n return cc_displacementWeights[index / 4].x;\n } else if (m < 2.0) {\n return cc_displacementWeights[index / 4].y;\n } else if (m < 3.0) {\n return cc_displacementWeights[index / 4].z;\n } else {\n return cc_displacementWeights[index / 4].w;\n }\n}\nvec3 getVec3DisplacementFromTexture(sampler2D tex, int vertexIndex) {\n#if CC_MORPH_PRECOMPUTED\n return fetchVec3ArrayFromTexture(tex, vertexIndex).rgb;\n#else\n vec3 result = vec3(0, 0, 0);\n for (int iTarget = 0; iTarget < CC_MORPH_TARGET_COUNT; ++iTarget) {\n int dataPixelStart = int(fetchVec3ArrayFromTexture(tex, iTarget).r);\n result += (fetchVec3ArrayFromTexture(tex, dataPixelStart + vertexIndex).rgb * getDisplacementWeight(iTarget));\n }\n return result;\n#endif\n}\n#if CC_MORPH_TARGET_HAS_POSITION\n uniform sampler2D cc_PositionDisplacements;\n vec3 getPositionDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_PositionDisplacements, vertexId);\n }\n#endif\n#if CC_MORPH_TARGET_HAS_NORMAL\n uniform sampler2D cc_NormalDisplacements;\n vec3 getNormalDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_NormalDisplacements, vertexId);\n }\n#endif\n#if CC_MORPH_TARGET_HAS_TANGENT\n uniform sampler2D cc_TangentDisplacements;\n vec3 getTangentDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_TangentDisplacements, vertexId);\n }\n#endif\nvoid applyMorph (inout StandardVertInput attr) {\n int vertexId = getVertexId();\n#if CC_MORPH_TARGET_HAS_POSITION\n attr.position.xyz = attr.position.xyz + getPositionDisplacement(vertexId);\n#endif\n#if CC_MORPH_TARGET_HAS_NORMAL\n attr.normal.xyz = attr.normal.xyz + getNormalDisplacement(vertexId);\n#endif\n#if CC_MORPH_TARGET_HAS_TANGENT\n attr.tangent.xyz = attr.tangent.xyz + getTangentDisplacement(vertexId);\n#endif\n}\nvoid applyMorph (inout vec4 position) {\n#if CC_MORPH_TARGET_HAS_POSITION\n position.xyz = position.xyz + getPositionDisplacement(getVertexId());\n#endif\n}\n#endif\n#if CC_USE_SKINNING\nin vec4 a_joints;\nin vec4 a_weights;\n#if CC_USE_BAKED_ANIMATION\n #if USE_INSTANCING\n in highp vec4 a_jointAnimInfo;\n #endif\n layout(std140) uniform CCSkinningTexture {\n highp vec4 cc_jointTextureInfo;\n };\n layout(std140) uniform CCSkinningAnimation {\n highp vec4 cc_jointAnimInfo;\n };\n uniform highp sampler2D cc_jointTexture;\n #if !CC_SUPPORT_FLOAT_TEXTURE\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n #endif\n#else\n layout(std140) uniform CCSkinning {\n highp vec4 cc_joints[30 * 3];\n };\n#endif\n#if CC_USE_BAKED_ANIMATION\n #if CC_SUPPORT_FLOAT_TEXTURE\n mat4 getJointMatrix (float i) {\n #if USE_INSTANCING\n highp float j = 3.0 * (a_jointAnimInfo.x * a_jointAnimInfo.y + i) + a_jointAnimInfo.z;\n #else\n highp float j = 3.0 * (cc_jointAnimInfo.x * cc_jointTextureInfo.y + i) + cc_jointTextureInfo.z;\n #endif\n highp float invSize = cc_jointTextureInfo.w;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture(cc_jointTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture(cc_jointTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture(cc_jointTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n #else\n mat4 getJointMatrix (float i) {\n #if USE_INSTANCING\n highp float j = 12.0 * (a_jointAnimInfo.x * a_jointAnimInfo.y + i) + a_jointAnimInfo.z;\n #else\n highp float j = 12.0 * (cc_jointAnimInfo.x * cc_jointTextureInfo.y + i) + cc_jointTextureInfo.z;\n #endif\n highp float invSize = cc_jointTextureInfo.w;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n #endif\n#else\n mat4 getJointMatrix (float i) {\n int idx = int(i);\n vec4 v1 = cc_joints[idx * 3];\n vec4 v2 = cc_joints[idx * 3 + 1];\n vec4 v3 = cc_joints[idx * 3 + 2];\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y\n + getJointMatrix(a_joints.z) * a_weights.z\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\nlayout(std140) uniform CCShadow {\n highp mat4 cc_matLightPlaneProj;\n highp mat4 cc_matLightViewProj;\n lowp vec4 cc_shadowColor;\n lowp vec4 cc_shadowPCF;\n lowp vec4 cc_shadowSize;\n};\n#if USE_INSTANCING\n in vec4 a_matWorld0;\n in vec4 a_matWorld1;\n in vec4 a_matWorld2;\n #if USE_LIGHTMAP\n in vec4 a_lightingMapUVParam;\n #endif\n#elif USE_BATCHING\n in float a_dyn_batch_id;\n layout(std140) uniform CCLocalBatched {\n highp mat4 cc_matWorlds[10];\n };\n#else\nlayout(std140) uniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n highp vec4 cc_lightingMapUVParam;\n};\n#endif\nout vec4 vTexCoord;\nvec4 vert () {\n StandardVertInput In;\n In.position = vec4(a_position, 1.0);\n In.normal = a_normal;\n In.tangent = a_tangent;\n #if CC_USE_MORPH\n applyMorph(In);\n #endif\n #if CC_USE_SKINNING\n CCSkin(In);\n #endif\n mat4 matWorld, matWorldIT;\n #if USE_INSTANCING\n matWorld = mat4(\n vec4(a_matWorld0.xyz, 0.0),\n vec4(a_matWorld1.xyz, 0.0),\n vec4(a_matWorld2.xyz, 0.0),\n vec4(a_matWorld0.w, a_matWorld1.w, a_matWorld2.w, 1.0)\n );\n matWorldIT = matWorld;\n #elif USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id)];\n matWorldIT = matWorld;\n #else\n matWorld = cc_matWorld;\n matWorldIT = cc_matWorldIT;\n #endif\n vec4 worldPos = matWorld * In.position;\n vec4 clipPos = cc_matLightViewProj * worldPos;\n vTexCoord = vec4(a_texCoord, clipPos.z, clipPos.w);\n return clipPos;\n}\nvoid main() { gl_Position = vert(); }`, "frag": `\nprecision highp float;\nvec4 packDepthToRGBA (float depth) {\n vec4 ret = vec4(1.0, 255.0, 65025.0, 160581375.0) * depth;\n ret = fract(ret);\n ret -= ret.yzww * vec4(1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0, 0.0);\n return ret;\n}\nin vec4 vTexCoord;\n#if USE_ALBEDO_MAP\n uniform sampler2D albedoMap;\n#endif\nvec4 frag () {\n vec4 color = vec4(1.0);\n #if ALPHAMASK\n #if USE_ALBEDO_MAP\n float alpha = texture(albedoMap, vTexCoord.xy).a;\n if (alpha < 0.5)\n discard;\n #endif\n #endif\n return packDepthToRGBA(vTexCoord.z / vTexCoord.w * 0.5 + 0.5);\n}\nout vec4 cc_FragColor;\nvoid main() { cc_FragColor = frag(); }` }, "glsl1": { @@ -451,7 +451,7 @@ export default [ "frag": `\nprecision highp float;\nvec4 packDepthToRGBA (float depth) {\n vec4 ret = vec4(1.0, 255.0, 65025.0, 160581375.0) * depth;\n ret = fract(ret);\n ret -= ret.yzww * vec4(1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0, 0.0);\n return ret;\n}\nvarying vec4 vTexCoord;\n#if USE_ALBEDO_MAP\n uniform sampler2D albedoMap;\n#endif\nvec4 frag () {\n vec4 color = vec4(1.0);\n #if ALPHAMASK\n #if USE_ALBEDO_MAP\n float alpha = texture2D(albedoMap, vTexCoord.xy).a;\n if (alpha < 0.5)\n discard;\n #endif\n #endif\n return packDepthToRGBA(vTexCoord.z / vTexCoord.w * 0.5 + 0.5);\n}\nvoid main() { gl_FragColor = frag(); }` }, "glsl4": { - "vert": `\n#ifdef GL_EXT_shader_explicit_arithmetic_types_int16\n#extension GL_EXT_shader_explicit_arithmetic_types_int16: enable\n#endif\nprecision highp float;\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nlayout(location = 0) in vec3 a_position;\nlayout(location = 1) in vec3 a_normal;\nlayout(location = 2) in vec2 a_texCoord;\nlayout(location = 3) in vec4 a_tangent;\n#if CC_USE_MORPH\n int getVertexId() {\n return gl_VertexID;\n }\nlayout(set = 2, binding = 4) uniform CCMorph {\n vec4 cc_displacementWeights[15];\n vec4 cc_displacementTextureInfo;\n};\n vec4 fetchVec3ArrayFromTexture(sampler2D tex, int pixelIndex) {\n ivec2 texSize = textureSize(tex, 0);\n return texelFetch(tex, ivec2(pixelIndex % texSize.x, pixelIndex / texSize.x), 0);\n }\nfloat getDisplacementWeight(int index) {\n float m = mod(float(index), 4.0);\n if (m < 1.0) {\n return cc_displacementWeights[index / 4].x;\n } else if (m < 2.0) {\n return cc_displacementWeights[index / 4].y;\n } else if (m < 3.0) {\n return cc_displacementWeights[index / 4].z;\n } else {\n return cc_displacementWeights[index / 4].w;\n }\n}\nvec3 getVec3DisplacementFromTexture(sampler2D tex, int vertexIndex) {\n#if CC_MORPH_PRECOMPUTED\n return fetchVec3ArrayFromTexture(tex, vertexIndex).rgb;\n#else\n vec3 result = vec3(0, 0, 0);\n for (int iTarget = 0; iTarget < CC_MORPH_TARGET_COUNT; ++iTarget) {\n int dataPixelStart = int(fetchVec3ArrayFromTexture(tex, iTarget).r);\n result += (fetchVec3ArrayFromTexture(tex, dataPixelStart + vertexIndex).rgb * getDisplacementWeight(iTarget));\n }\n return result;\n#endif\n}\n#if CC_MORPH_TARGET_HAS_POSITION\n layout(set = 2, binding = 6) uniform sampler2D cc_PositionDisplacements;\n vec3 getPositionDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_PositionDisplacements, vertexId);\n }\n#endif\n#if CC_MORPH_TARGET_HAS_NORMAL\n layout(set = 2, binding = 7) uniform sampler2D cc_NormalDisplacements;\n vec3 getNormalDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_NormalDisplacements, vertexId);\n }\n#endif\n#if CC_MORPH_TARGET_HAS_TANGENT\n layout(set = 2, binding = 8) uniform sampler2D cc_TangentDisplacements;\n vec3 getTangentDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_TangentDisplacements, vertexId);\n }\n#endif\nvoid applyMorph (inout StandardVertInput attr) {\n int vertexId = getVertexId();\n#if CC_MORPH_TARGET_HAS_POSITION\n attr.position.xyz = attr.position.xyz + getPositionDisplacement(vertexId);\n#endif\n#if CC_MORPH_TARGET_HAS_NORMAL\n attr.normal.xyz = attr.normal.xyz + getNormalDisplacement(vertexId);\n#endif\n#if CC_MORPH_TARGET_HAS_TANGENT\n attr.tangent.xyz = attr.tangent.xyz + getTangentDisplacement(vertexId);\n#endif\n}\nvoid applyMorph (inout vec4 position) {\n#if CC_MORPH_TARGET_HAS_POSITION\n position.xyz = position.xyz + getPositionDisplacement(getVertexId());\n#endif\n}\n#endif\n#if CC_USE_SKINNING\nlayout(location = 4) in u16vec4 a_joints;\nlayout(location = 5) in vec4 a_weights;\n#if CC_USE_BAKED_ANIMATION\n #if USE_INSTANCING\n layout(location = 7) in highp vec4 a_jointAnimInfo;\n #endif\n layout(set = 2, binding = 3) uniform CCSkinningTexture {\n highp vec4 cc_jointTextureInfo;\n };\n layout(set = 2, binding = 2) uniform CCSkinningAnimation {\n highp vec4 cc_jointAnimInfo;\n };\n layout(set = 2, binding = 5) uniform highp sampler2D cc_jointTexture;\n #if !CC_SUPPORT_FLOAT_TEXTURE\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n #endif\n#else\n layout(set = 2, binding = 3) uniform CCSkinning {\n highp vec4 cc_joints[30 * 3];\n };\n#endif\n#if CC_USE_BAKED_ANIMATION\n #if CC_SUPPORT_FLOAT_TEXTURE\n mat4 getJointMatrix (float i) {\n #if USE_INSTANCING\n highp float j = 3.0 * (a_jointAnimInfo.x * a_jointAnimInfo.y + i) + a_jointAnimInfo.z;\n #else\n highp float j = 3.0 * (cc_jointAnimInfo.x * cc_jointTextureInfo.y + i) + cc_jointTextureInfo.z;\n #endif\n highp float invSize = cc_jointTextureInfo.w;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture(cc_jointTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture(cc_jointTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture(cc_jointTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n #else\n mat4 getJointMatrix (float i) {\n #if USE_INSTANCING\n highp float j = 12.0 * (a_jointAnimInfo.x * a_jointAnimInfo.y + i) + a_jointAnimInfo.z;\n #else\n highp float j = 12.0 * (cc_jointAnimInfo.x * cc_jointTextureInfo.y + i) + cc_jointTextureInfo.z;\n #endif\n highp float invSize = cc_jointTextureInfo.w;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n #endif\n#else\n mat4 getJointMatrix (float i) {\n int idx = int(i);\n vec4 v1 = cc_joints[idx * 3];\n vec4 v2 = cc_joints[idx * 3 + 1];\n vec4 v3 = cc_joints[idx * 3 + 2];\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y\n + getJointMatrix(a_joints.z) * a_weights.z\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\nlayout(set = 0, binding = 1) uniform CCShadow {\n highp mat4 cc_matLightPlaneProj;\n highp mat4 cc_matLightViewProj;\n lowp vec4 cc_shadowColor;\n};\n#if USE_INSTANCING\n layout(location = 8) in vec4 a_matWorld0;\n layout(location = 9) in vec4 a_matWorld1;\n layout(location = 10) in vec4 a_matWorld2;\n #if USE_LIGHTMAP\n layout(location = 11) in vec4 a_lightingMapUVParam;\n #endif\n#elif USE_BATCHING\n layout(location = 12) in float a_dyn_batch_id;\n layout(set = 2, binding = 0) uniform CCLocalBatched {\n highp mat4 cc_matWorlds[10];\n };\n#else\nlayout(set = 2, binding = 0) uniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n highp vec4 cc_lightingMapUVParam;\n};\n#endif\nlayout(location = 0) out vec4 vTexCoord;\nvec4 vert () {\n StandardVertInput In;\n In.position = vec4(a_position, 1.0);\n In.normal = a_normal;\n In.tangent = a_tangent;\n #if CC_USE_MORPH\n applyMorph(In);\n #endif\n #if CC_USE_SKINNING\n CCSkin(In);\n #endif\n mat4 matWorld, matWorldIT;\n #if USE_INSTANCING\n matWorld = mat4(\n vec4(a_matWorld0.xyz, 0.0),\n vec4(a_matWorld1.xyz, 0.0),\n vec4(a_matWorld2.xyz, 0.0),\n vec4(a_matWorld0.w, a_matWorld1.w, a_matWorld2.w, 1.0)\n );\n matWorldIT = matWorld;\n #elif USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id)];\n matWorldIT = matWorld;\n #else\n matWorld = cc_matWorld;\n matWorldIT = cc_matWorldIT;\n #endif\n vec4 worldPos = matWorld * In.position;\n vec4 clipPos = cc_matLightViewProj * worldPos;\n vTexCoord = vec4(a_texCoord, clipPos.z, clipPos.w);\n return clipPos;\n}\nvoid main() { gl_Position = vert(); }`, + "vert": `\n#ifdef GL_EXT_shader_explicit_arithmetic_types_int16\n#extension GL_EXT_shader_explicit_arithmetic_types_int16: enable\n#endif\nprecision highp float;\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nlayout(location = 0) in vec3 a_position;\nlayout(location = 1) in vec3 a_normal;\nlayout(location = 2) in vec2 a_texCoord;\nlayout(location = 3) in vec4 a_tangent;\n#if CC_USE_MORPH\n int getVertexId() {\n return gl_VertexID;\n }\nlayout(set = 2, binding = 4) uniform CCMorph {\n vec4 cc_displacementWeights[15];\n vec4 cc_displacementTextureInfo;\n};\n vec4 fetchVec3ArrayFromTexture(sampler2D tex, int pixelIndex) {\n ivec2 texSize = textureSize(tex, 0);\n return texelFetch(tex, ivec2(pixelIndex % texSize.x, pixelIndex / texSize.x), 0);\n }\nfloat getDisplacementWeight(int index) {\n float m = mod(float(index), 4.0);\n if (m < 1.0) {\n return cc_displacementWeights[index / 4].x;\n } else if (m < 2.0) {\n return cc_displacementWeights[index / 4].y;\n } else if (m < 3.0) {\n return cc_displacementWeights[index / 4].z;\n } else {\n return cc_displacementWeights[index / 4].w;\n }\n}\nvec3 getVec3DisplacementFromTexture(sampler2D tex, int vertexIndex) {\n#if CC_MORPH_PRECOMPUTED\n return fetchVec3ArrayFromTexture(tex, vertexIndex).rgb;\n#else\n vec3 result = vec3(0, 0, 0);\n for (int iTarget = 0; iTarget < CC_MORPH_TARGET_COUNT; ++iTarget) {\n int dataPixelStart = int(fetchVec3ArrayFromTexture(tex, iTarget).r);\n result += (fetchVec3ArrayFromTexture(tex, dataPixelStart + vertexIndex).rgb * getDisplacementWeight(iTarget));\n }\n return result;\n#endif\n}\n#if CC_MORPH_TARGET_HAS_POSITION\n layout(set = 2, binding = 6) uniform sampler2D cc_PositionDisplacements;\n vec3 getPositionDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_PositionDisplacements, vertexId);\n }\n#endif\n#if CC_MORPH_TARGET_HAS_NORMAL\n layout(set = 2, binding = 7) uniform sampler2D cc_NormalDisplacements;\n vec3 getNormalDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_NormalDisplacements, vertexId);\n }\n#endif\n#if CC_MORPH_TARGET_HAS_TANGENT\n layout(set = 2, binding = 8) uniform sampler2D cc_TangentDisplacements;\n vec3 getTangentDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_TangentDisplacements, vertexId);\n }\n#endif\nvoid applyMorph (inout StandardVertInput attr) {\n int vertexId = getVertexId();\n#if CC_MORPH_TARGET_HAS_POSITION\n attr.position.xyz = attr.position.xyz + getPositionDisplacement(vertexId);\n#endif\n#if CC_MORPH_TARGET_HAS_NORMAL\n attr.normal.xyz = attr.normal.xyz + getNormalDisplacement(vertexId);\n#endif\n#if CC_MORPH_TARGET_HAS_TANGENT\n attr.tangent.xyz = attr.tangent.xyz + getTangentDisplacement(vertexId);\n#endif\n}\nvoid applyMorph (inout vec4 position) {\n#if CC_MORPH_TARGET_HAS_POSITION\n position.xyz = position.xyz + getPositionDisplacement(getVertexId());\n#endif\n}\n#endif\n#if CC_USE_SKINNING\nlayout(location = 4) in u16vec4 a_joints;\nlayout(location = 5) in vec4 a_weights;\n#if CC_USE_BAKED_ANIMATION\n #if USE_INSTANCING\n layout(location = 7) in highp vec4 a_jointAnimInfo;\n #endif\n layout(set = 2, binding = 3) uniform CCSkinningTexture {\n highp vec4 cc_jointTextureInfo;\n };\n layout(set = 2, binding = 2) uniform CCSkinningAnimation {\n highp vec4 cc_jointAnimInfo;\n };\n layout(set = 2, binding = 5) uniform highp sampler2D cc_jointTexture;\n #if !CC_SUPPORT_FLOAT_TEXTURE\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n #endif\n#else\n layout(set = 2, binding = 3) uniform CCSkinning {\n highp vec4 cc_joints[30 * 3];\n };\n#endif\n#if CC_USE_BAKED_ANIMATION\n #if CC_SUPPORT_FLOAT_TEXTURE\n mat4 getJointMatrix (float i) {\n #if USE_INSTANCING\n highp float j = 3.0 * (a_jointAnimInfo.x * a_jointAnimInfo.y + i) + a_jointAnimInfo.z;\n #else\n highp float j = 3.0 * (cc_jointAnimInfo.x * cc_jointTextureInfo.y + i) + cc_jointTextureInfo.z;\n #endif\n highp float invSize = cc_jointTextureInfo.w;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture(cc_jointTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture(cc_jointTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture(cc_jointTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n #else\n mat4 getJointMatrix (float i) {\n #if USE_INSTANCING\n highp float j = 12.0 * (a_jointAnimInfo.x * a_jointAnimInfo.y + i) + a_jointAnimInfo.z;\n #else\n highp float j = 12.0 * (cc_jointAnimInfo.x * cc_jointTextureInfo.y + i) + cc_jointTextureInfo.z;\n #endif\n highp float invSize = cc_jointTextureInfo.w;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n #endif\n#else\n mat4 getJointMatrix (float i) {\n int idx = int(i);\n vec4 v1 = cc_joints[idx * 3];\n vec4 v2 = cc_joints[idx * 3 + 1];\n vec4 v3 = cc_joints[idx * 3 + 2];\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y\n + getJointMatrix(a_joints.z) * a_weights.z\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\nlayout(set = 0, binding = 1) uniform CCShadow {\n highp mat4 cc_matLightPlaneProj;\n highp mat4 cc_matLightViewProj;\n lowp vec4 cc_shadowColor;\n lowp vec4 cc_shadowPCF;\n lowp vec4 cc_shadowSize;\n};\n#if USE_INSTANCING\n layout(location = 8) in vec4 a_matWorld0;\n layout(location = 9) in vec4 a_matWorld1;\n layout(location = 10) in vec4 a_matWorld2;\n #if USE_LIGHTMAP\n layout(location = 11) in vec4 a_lightingMapUVParam;\n #endif\n#elif USE_BATCHING\n layout(location = 12) in float a_dyn_batch_id;\n layout(set = 2, binding = 0) uniform CCLocalBatched {\n highp mat4 cc_matWorlds[10];\n };\n#else\nlayout(set = 2, binding = 0) uniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n highp vec4 cc_lightingMapUVParam;\n};\n#endif\nlayout(location = 0) out vec4 vTexCoord;\nvec4 vert () {\n StandardVertInput In;\n In.position = vec4(a_position, 1.0);\n In.normal = a_normal;\n In.tangent = a_tangent;\n #if CC_USE_MORPH\n applyMorph(In);\n #endif\n #if CC_USE_SKINNING\n CCSkin(In);\n #endif\n mat4 matWorld, matWorldIT;\n #if USE_INSTANCING\n matWorld = mat4(\n vec4(a_matWorld0.xyz, 0.0),\n vec4(a_matWorld1.xyz, 0.0),\n vec4(a_matWorld2.xyz, 0.0),\n vec4(a_matWorld0.w, a_matWorld1.w, a_matWorld2.w, 1.0)\n );\n matWorldIT = matWorld;\n #elif USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id)];\n matWorldIT = matWorld;\n #else\n matWorld = cc_matWorld;\n matWorldIT = cc_matWorldIT;\n #endif\n vec4 worldPos = matWorld * In.position;\n vec4 clipPos = cc_matLightViewProj * worldPos;\n vTexCoord = vec4(a_texCoord, clipPos.z, clipPos.w);\n return clipPos;\n}\nvoid main() { gl_Position = vert(); }`, "frag": `\nprecision highp float;\nvec4 packDepthToRGBA (float depth) {\n vec4 ret = vec4(1.0, 255.0, 65025.0, 160581375.0) * depth;\n ret = fract(ret);\n ret -= ret.yzww * vec4(1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0, 0.0);\n return ret;\n}\nlayout(location = 0) in vec4 vTexCoord;\n#if USE_ALBEDO_MAP\n layout(set = 1, binding = 0) uniform sampler2D albedoMap;\n#endif\nvec4 frag () {\n vec4 color = vec4(1.0);\n #if ALPHAMASK\n #if USE_ALBEDO_MAP\n float alpha = texture(albedoMap, vTexCoord.xy).a;\n if (alpha < 0.5)\n discard;\n #endif\n #endif\n return packDepthToRGBA(vTexCoord.z / vTexCoord.w * 0.5 + 0.5);\n}\nlayout(location = 0) out vec4 cc_FragColor;\nvoid main() { cc_FragColor = frag(); }` }, "builtins": { @@ -641,16 +641,16 @@ export default [ "name": "pipeline/planar-shadow|planar-shadow-vs:vert|planar-shadow-fs:frag", "hash": 2261567163, "glsl3": { - "vert": `\nprecision highp float;\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nin vec3 a_position;\nin vec3 a_normal;\nin vec2 a_texCoord;\nin vec4 a_tangent;\n#if CC_USE_MORPH\n int getVertexId() {\n return gl_VertexID;\n }\nlayout(std140) uniform CCMorph {\n vec4 cc_displacementWeights[15];\n vec4 cc_displacementTextureInfo;\n};\n vec4 fetchVec3ArrayFromTexture(sampler2D tex, int pixelIndex) {\n ivec2 texSize = textureSize(tex, 0);\n return texelFetch(tex, ivec2(pixelIndex % texSize.x, pixelIndex / texSize.x), 0);\n }\nfloat getDisplacementWeight(int index) {\n float m = mod(float(index), 4.0);\n if (m < 1.0) {\n return cc_displacementWeights[index / 4].x;\n } else if (m < 2.0) {\n return cc_displacementWeights[index / 4].y;\n } else if (m < 3.0) {\n return cc_displacementWeights[index / 4].z;\n } else {\n return cc_displacementWeights[index / 4].w;\n }\n}\nvec3 getVec3DisplacementFromTexture(sampler2D tex, int vertexIndex) {\n#if CC_MORPH_PRECOMPUTED\n return fetchVec3ArrayFromTexture(tex, vertexIndex).rgb;\n#else\n vec3 result = vec3(0, 0, 0);\n for (int iTarget = 0; iTarget < CC_MORPH_TARGET_COUNT; ++iTarget) {\n int dataPixelStart = int(fetchVec3ArrayFromTexture(tex, iTarget).r);\n result += (fetchVec3ArrayFromTexture(tex, dataPixelStart + vertexIndex).rgb * getDisplacementWeight(iTarget));\n }\n return result;\n#endif\n}\n#if CC_MORPH_TARGET_HAS_POSITION\n uniform sampler2D cc_PositionDisplacements;\n vec3 getPositionDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_PositionDisplacements, vertexId);\n }\n#endif\n#if CC_MORPH_TARGET_HAS_NORMAL\n uniform sampler2D cc_NormalDisplacements;\n vec3 getNormalDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_NormalDisplacements, vertexId);\n }\n#endif\n#if CC_MORPH_TARGET_HAS_TANGENT\n uniform sampler2D cc_TangentDisplacements;\n vec3 getTangentDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_TangentDisplacements, vertexId);\n }\n#endif\nvoid applyMorph (inout StandardVertInput attr) {\n int vertexId = getVertexId();\n#if CC_MORPH_TARGET_HAS_POSITION\n attr.position.xyz = attr.position.xyz + getPositionDisplacement(vertexId);\n#endif\n#if CC_MORPH_TARGET_HAS_NORMAL\n attr.normal.xyz = attr.normal.xyz + getNormalDisplacement(vertexId);\n#endif\n#if CC_MORPH_TARGET_HAS_TANGENT\n attr.tangent.xyz = attr.tangent.xyz + getTangentDisplacement(vertexId);\n#endif\n}\nvoid applyMorph (inout vec4 position) {\n#if CC_MORPH_TARGET_HAS_POSITION\n position.xyz = position.xyz + getPositionDisplacement(getVertexId());\n#endif\n}\n#endif\n#if CC_USE_SKINNING\nin vec4 a_joints;\nin vec4 a_weights;\n#if CC_USE_BAKED_ANIMATION\n #if USE_INSTANCING\n in highp vec4 a_jointAnimInfo;\n #endif\n layout(std140) uniform CCSkinningTexture {\n highp vec4 cc_jointTextureInfo;\n };\n layout(std140) uniform CCSkinningAnimation {\n highp vec4 cc_jointAnimInfo;\n };\n uniform highp sampler2D cc_jointTexture;\n #if !CC_SUPPORT_FLOAT_TEXTURE\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n #endif\n#else\n layout(std140) uniform CCSkinning {\n highp vec4 cc_joints[30 * 3];\n };\n#endif\n#if CC_USE_BAKED_ANIMATION\n #if CC_SUPPORT_FLOAT_TEXTURE\n mat4 getJointMatrix (float i) {\n #if USE_INSTANCING\n highp float j = 3.0 * (a_jointAnimInfo.x * a_jointAnimInfo.y + i) + a_jointAnimInfo.z;\n #else\n highp float j = 3.0 * (cc_jointAnimInfo.x * cc_jointTextureInfo.y + i) + cc_jointTextureInfo.z;\n #endif\n highp float invSize = cc_jointTextureInfo.w;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture(cc_jointTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture(cc_jointTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture(cc_jointTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n #else\n mat4 getJointMatrix (float i) {\n #if USE_INSTANCING\n highp float j = 12.0 * (a_jointAnimInfo.x * a_jointAnimInfo.y + i) + a_jointAnimInfo.z;\n #else\n highp float j = 12.0 * (cc_jointAnimInfo.x * cc_jointTextureInfo.y + i) + cc_jointTextureInfo.z;\n #endif\n highp float invSize = cc_jointTextureInfo.w;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n #endif\n#else\n mat4 getJointMatrix (float i) {\n int idx = int(i);\n vec4 v1 = cc_joints[idx * 3];\n vec4 v2 = cc_joints[idx * 3 + 1];\n vec4 v3 = cc_joints[idx * 3 + 2];\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y\n + getJointMatrix(a_joints.z) * a_weights.z\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\nlayout(std140) uniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n mediump vec4 cc_fogColor;\n mediump vec4 cc_fogBase;\n mediump vec4 cc_fogAdd;\n};\n#if USE_INSTANCING\n in vec4 a_matWorld0;\n in vec4 a_matWorld1;\n in vec4 a_matWorld2;\n #if USE_LIGHTMAP\n in vec4 a_lightingMapUVParam;\n #endif\n#elif USE_BATCHING\n in float a_dyn_batch_id;\n layout(std140) uniform CCLocalBatched {\n highp mat4 cc_matWorlds[10];\n };\n#else\nlayout(std140) uniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n highp vec4 cc_lightingMapUVParam;\n};\n#endif\nlayout(std140) uniform CCShadow {\n highp mat4 cc_matLightPlaneProj;\n highp mat4 cc_matLightViewProj;\n lowp vec4 cc_shadowColor;\n};\nvec4 vert () {\n vec4 position;\n position = vec4(a_position, 1.0);\n #if CC_USE_MORPH\n applyMorph(position);\n #endif\n #if CC_USE_SKINNING\n CCSkin(position);\n #endif\n mat4 matWorld;\n #if USE_INSTANCING\n matWorld = mat4(\n vec4(a_matWorld0.xyz, 0.0),\n vec4(a_matWorld1.xyz, 0.0),\n vec4(a_matWorld2.xyz, 0.0),\n vec4(a_matWorld0.w, a_matWorld1.w, a_matWorld2.w, 1.0)\n );\n #elif USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id)];\n #else\n matWorld = cc_matWorld;\n #endif\n position = cc_matProj * (cc_matView * cc_matLightPlaneProj * matWorld) * position;\n position.z -= 0.0001;\n return position;\n}\nvoid main() { gl_Position = vert(); }`, - "frag": `\nprecision mediump float;\nlayout(std140) uniform CCShadow {\n highp mat4 cc_matLightPlaneProj;\n highp mat4 cc_matLightViewProj;\n lowp vec4 cc_shadowColor;\n};\nlayout(std140) uniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n mediump vec4 cc_fogColor;\n mediump vec4 cc_fogBase;\n mediump vec4 cc_fogAdd;\n};\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nvec4 CCFragOutput (vec4 color) {\n #if CC_USE_HDR\n color.rgb = mix(color.rgb, SRGBToLinear(color.rgb) * cc_exposure.w, vec3(cc_exposure.z));\n #endif\n return color;\n}\nvec4 frag () {\n return CCFragOutput(cc_shadowColor);\n}\nout vec4 cc_FragColor;\nvoid main() { cc_FragColor = frag(); }` + "vert": `\nprecision highp float;\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nin vec3 a_position;\nin vec3 a_normal;\nin vec2 a_texCoord;\nin vec4 a_tangent;\n#if CC_USE_MORPH\n int getVertexId() {\n return gl_VertexID;\n }\nlayout(std140) uniform CCMorph {\n vec4 cc_displacementWeights[15];\n vec4 cc_displacementTextureInfo;\n};\n vec4 fetchVec3ArrayFromTexture(sampler2D tex, int pixelIndex) {\n ivec2 texSize = textureSize(tex, 0);\n return texelFetch(tex, ivec2(pixelIndex % texSize.x, pixelIndex / texSize.x), 0);\n }\nfloat getDisplacementWeight(int index) {\n float m = mod(float(index), 4.0);\n if (m < 1.0) {\n return cc_displacementWeights[index / 4].x;\n } else if (m < 2.0) {\n return cc_displacementWeights[index / 4].y;\n } else if (m < 3.0) {\n return cc_displacementWeights[index / 4].z;\n } else {\n return cc_displacementWeights[index / 4].w;\n }\n}\nvec3 getVec3DisplacementFromTexture(sampler2D tex, int vertexIndex) {\n#if CC_MORPH_PRECOMPUTED\n return fetchVec3ArrayFromTexture(tex, vertexIndex).rgb;\n#else\n vec3 result = vec3(0, 0, 0);\n for (int iTarget = 0; iTarget < CC_MORPH_TARGET_COUNT; ++iTarget) {\n int dataPixelStart = int(fetchVec3ArrayFromTexture(tex, iTarget).r);\n result += (fetchVec3ArrayFromTexture(tex, dataPixelStart + vertexIndex).rgb * getDisplacementWeight(iTarget));\n }\n return result;\n#endif\n}\n#if CC_MORPH_TARGET_HAS_POSITION\n uniform sampler2D cc_PositionDisplacements;\n vec3 getPositionDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_PositionDisplacements, vertexId);\n }\n#endif\n#if CC_MORPH_TARGET_HAS_NORMAL\n uniform sampler2D cc_NormalDisplacements;\n vec3 getNormalDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_NormalDisplacements, vertexId);\n }\n#endif\n#if CC_MORPH_TARGET_HAS_TANGENT\n uniform sampler2D cc_TangentDisplacements;\n vec3 getTangentDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_TangentDisplacements, vertexId);\n }\n#endif\nvoid applyMorph (inout StandardVertInput attr) {\n int vertexId = getVertexId();\n#if CC_MORPH_TARGET_HAS_POSITION\n attr.position.xyz = attr.position.xyz + getPositionDisplacement(vertexId);\n#endif\n#if CC_MORPH_TARGET_HAS_NORMAL\n attr.normal.xyz = attr.normal.xyz + getNormalDisplacement(vertexId);\n#endif\n#if CC_MORPH_TARGET_HAS_TANGENT\n attr.tangent.xyz = attr.tangent.xyz + getTangentDisplacement(vertexId);\n#endif\n}\nvoid applyMorph (inout vec4 position) {\n#if CC_MORPH_TARGET_HAS_POSITION\n position.xyz = position.xyz + getPositionDisplacement(getVertexId());\n#endif\n}\n#endif\n#if CC_USE_SKINNING\nin vec4 a_joints;\nin vec4 a_weights;\n#if CC_USE_BAKED_ANIMATION\n #if USE_INSTANCING\n in highp vec4 a_jointAnimInfo;\n #endif\n layout(std140) uniform CCSkinningTexture {\n highp vec4 cc_jointTextureInfo;\n };\n layout(std140) uniform CCSkinningAnimation {\n highp vec4 cc_jointAnimInfo;\n };\n uniform highp sampler2D cc_jointTexture;\n #if !CC_SUPPORT_FLOAT_TEXTURE\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n #endif\n#else\n layout(std140) uniform CCSkinning {\n highp vec4 cc_joints[30 * 3];\n };\n#endif\n#if CC_USE_BAKED_ANIMATION\n #if CC_SUPPORT_FLOAT_TEXTURE\n mat4 getJointMatrix (float i) {\n #if USE_INSTANCING\n highp float j = 3.0 * (a_jointAnimInfo.x * a_jointAnimInfo.y + i) + a_jointAnimInfo.z;\n #else\n highp float j = 3.0 * (cc_jointAnimInfo.x * cc_jointTextureInfo.y + i) + cc_jointTextureInfo.z;\n #endif\n highp float invSize = cc_jointTextureInfo.w;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture(cc_jointTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture(cc_jointTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture(cc_jointTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n #else\n mat4 getJointMatrix (float i) {\n #if USE_INSTANCING\n highp float j = 12.0 * (a_jointAnimInfo.x * a_jointAnimInfo.y + i) + a_jointAnimInfo.z;\n #else\n highp float j = 12.0 * (cc_jointAnimInfo.x * cc_jointTextureInfo.y + i) + cc_jointTextureInfo.z;\n #endif\n highp float invSize = cc_jointTextureInfo.w;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n #endif\n#else\n mat4 getJointMatrix (float i) {\n int idx = int(i);\n vec4 v1 = cc_joints[idx * 3];\n vec4 v2 = cc_joints[idx * 3 + 1];\n vec4 v3 = cc_joints[idx * 3 + 2];\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y\n + getJointMatrix(a_joints.z) * a_weights.z\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\nlayout(std140) uniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n mediump vec4 cc_fogColor;\n mediump vec4 cc_fogBase;\n mediump vec4 cc_fogAdd;\n};\n#if USE_INSTANCING\n in vec4 a_matWorld0;\n in vec4 a_matWorld1;\n in vec4 a_matWorld2;\n #if USE_LIGHTMAP\n in vec4 a_lightingMapUVParam;\n #endif\n#elif USE_BATCHING\n in float a_dyn_batch_id;\n layout(std140) uniform CCLocalBatched {\n highp mat4 cc_matWorlds[10];\n };\n#else\nlayout(std140) uniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n highp vec4 cc_lightingMapUVParam;\n};\n#endif\nlayout(std140) uniform CCShadow {\n highp mat4 cc_matLightPlaneProj;\n highp mat4 cc_matLightViewProj;\n lowp vec4 cc_shadowColor;\n lowp vec4 cc_shadowPCF;\n lowp vec4 cc_shadowSize;\n};\nvec4 vert () {\n vec4 position;\n position = vec4(a_position, 1.0);\n #if CC_USE_MORPH\n applyMorph(position);\n #endif\n #if CC_USE_SKINNING\n CCSkin(position);\n #endif\n mat4 matWorld;\n #if USE_INSTANCING\n matWorld = mat4(\n vec4(a_matWorld0.xyz, 0.0),\n vec4(a_matWorld1.xyz, 0.0),\n vec4(a_matWorld2.xyz, 0.0),\n vec4(a_matWorld0.w, a_matWorld1.w, a_matWorld2.w, 1.0)\n );\n #elif USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id)];\n #else\n matWorld = cc_matWorld;\n #endif\n position = cc_matProj * (cc_matView * cc_matLightPlaneProj * matWorld) * position;\n position.z -= 0.0001;\n return position;\n}\nvoid main() { gl_Position = vert(); }`, + "frag": `\nprecision mediump float;\nlayout(std140) uniform CCShadow {\n highp mat4 cc_matLightPlaneProj;\n highp mat4 cc_matLightViewProj;\n lowp vec4 cc_shadowColor;\n lowp vec4 cc_shadowPCF;\n lowp vec4 cc_shadowSize;\n};\nlayout(std140) uniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n mediump vec4 cc_fogColor;\n mediump vec4 cc_fogBase;\n mediump vec4 cc_fogAdd;\n};\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nvec4 CCFragOutput (vec4 color) {\n #if CC_USE_HDR\n color.rgb = mix(color.rgb, SRGBToLinear(color.rgb) * cc_exposure.w, vec3(cc_exposure.z));\n #endif\n return color;\n}\nvec4 frag () {\n return CCFragOutput(cc_shadowColor);\n}\nout vec4 cc_FragColor;\nvoid main() { cc_FragColor = frag(); }` }, "glsl1": { "vert": `\nprecision highp float;\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nattribute vec3 a_position;\nattribute vec3 a_normal;\nattribute vec2 a_texCoord;\nattribute vec4 a_tangent;\n#if CC_USE_MORPH\n attribute float a_vertexId;\n int getVertexId() {\n return int(a_vertexId);\n }\nuniform vec4 cc_displacementWeights[15];\nuniform vec4 cc_displacementTextureInfo;\n vec2 getPixelLocation(vec2 textureResolution, int pixelIndex) {\n float pixelIndexF = float(pixelIndex);\n float x = mod(pixelIndexF, textureResolution.x);\n float y = floor(pixelIndexF / textureResolution.x);\n return vec2(x, y);\n }\n vec2 getPixelCoordFromLocation(vec2 location, vec2 textureResolution) {\n return (vec2(location.x, location.y) + .5) / textureResolution;\n }\n #if CC_SUPPORT_FLOAT_TEXTURE\n vec4 fetchVec3ArrayFromTexture(sampler2D tex, int elementIndex) {\n int pixelIndex = elementIndex;\n vec2 location = getPixelLocation(cc_displacementTextureInfo.xy, pixelIndex);\n vec2 uv = getPixelCoordFromLocation(location, cc_displacementTextureInfo.xy);\n return texture2D(tex, uv);\n }\n #else\n vec4 fetchVec3ArrayFromTexture(sampler2D tex, int elementIndex) {\n int pixelIndex = elementIndex * 4;\n vec2 location = getPixelLocation(cc_displacementTextureInfo.xy, pixelIndex);\n vec2 x = getPixelCoordFromLocation(location + vec2(0.0, 0.0), cc_displacementTextureInfo.xy);\n vec2 y = getPixelCoordFromLocation(location + vec2(1.0, 0.0), cc_displacementTextureInfo.xy);\n vec2 z = getPixelCoordFromLocation(location + vec2(2.0, 0.0), cc_displacementTextureInfo.xy);\n return vec4(\n decode32(texture2D(tex, x)),\n decode32(texture2D(tex, y)),\n decode32(texture2D(tex, z)),\n 1.0\n );\n }\n #endif\nfloat getDisplacementWeight(int index) {\n float m = mod(float(index), 4.0);\n if (m < 1.0) {\n return cc_displacementWeights[index / 4].x;\n } else if (m < 2.0) {\n return cc_displacementWeights[index / 4].y;\n } else if (m < 3.0) {\n return cc_displacementWeights[index / 4].z;\n } else {\n return cc_displacementWeights[index / 4].w;\n }\n}\nvec3 getVec3DisplacementFromTexture(sampler2D tex, int vertexIndex) {\n#if CC_MORPH_PRECOMPUTED\n return fetchVec3ArrayFromTexture(tex, vertexIndex).rgb;\n#else\n vec3 result = vec3(0, 0, 0);\n for (int iTarget = 0; iTarget < CC_MORPH_TARGET_COUNT; ++iTarget) {\n int dataPixelStart = int(fetchVec3ArrayFromTexture(tex, iTarget).r);\n result += (fetchVec3ArrayFromTexture(tex, dataPixelStart + vertexIndex).rgb * getDisplacementWeight(iTarget));\n }\n return result;\n#endif\n}\n#if CC_MORPH_TARGET_HAS_POSITION\n uniform sampler2D cc_PositionDisplacements;\n vec3 getPositionDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_PositionDisplacements, vertexId);\n }\n#endif\n#if CC_MORPH_TARGET_HAS_NORMAL\n uniform sampler2D cc_NormalDisplacements;\n vec3 getNormalDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_NormalDisplacements, vertexId);\n }\n#endif\n#if CC_MORPH_TARGET_HAS_TANGENT\n uniform sampler2D cc_TangentDisplacements;\n vec3 getTangentDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_TangentDisplacements, vertexId);\n }\n#endif\nvoid applyMorph (inout StandardVertInput attr) {\n int vertexId = getVertexId();\n#if CC_MORPH_TARGET_HAS_POSITION\n attr.position.xyz = attr.position.xyz + getPositionDisplacement(vertexId);\n#endif\n#if CC_MORPH_TARGET_HAS_NORMAL\n attr.normal.xyz = attr.normal.xyz + getNormalDisplacement(vertexId);\n#endif\n#if CC_MORPH_TARGET_HAS_TANGENT\n attr.tangent.xyz = attr.tangent.xyz + getTangentDisplacement(vertexId);\n#endif\n}\nvoid applyMorph (inout vec4 position) {\n#if CC_MORPH_TARGET_HAS_POSITION\n position.xyz = position.xyz + getPositionDisplacement(getVertexId());\n#endif\n}\n#endif\n#if CC_USE_SKINNING\nattribute vec4 a_joints;\nattribute vec4 a_weights;\n#if CC_USE_BAKED_ANIMATION\n #if USE_INSTANCING\n attribute highp vec4 a_jointAnimInfo;\n #endif\n uniform highp vec4 cc_jointTextureInfo;\n uniform highp vec4 cc_jointAnimInfo;\n uniform highp sampler2D cc_jointTexture;\n #if !CC_SUPPORT_FLOAT_TEXTURE\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n #endif\n#else\n uniform highp vec4 cc_joints[90];\n#endif\n#if CC_USE_BAKED_ANIMATION\n #if CC_SUPPORT_FLOAT_TEXTURE\n mat4 getJointMatrix (float i) {\n #if USE_INSTANCING\n highp float j = 3.0 * (a_jointAnimInfo.x * a_jointAnimInfo.y + i) + a_jointAnimInfo.z;\n #else\n highp float j = 3.0 * (cc_jointAnimInfo.x * cc_jointTextureInfo.y + i) + cc_jointTextureInfo.z;\n #endif\n highp float invSize = cc_jointTextureInfo.w;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture2D(cc_jointTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture2D(cc_jointTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture2D(cc_jointTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n #else\n mat4 getJointMatrix (float i) {\n #if USE_INSTANCING\n highp float j = 12.0 * (a_jointAnimInfo.x * a_jointAnimInfo.y + i) + a_jointAnimInfo.z;\n #else\n highp float j = 12.0 * (cc_jointAnimInfo.x * cc_jointTextureInfo.y + i) + cc_jointTextureInfo.z;\n #endif\n highp float invSize = cc_jointTextureInfo.w;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture2D(cc_jointTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture2D(cc_jointTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture2D(cc_jointTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture2D(cc_jointTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture2D(cc_jointTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture2D(cc_jointTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture2D(cc_jointTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture2D(cc_jointTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture2D(cc_jointTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture2D(cc_jointTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture2D(cc_jointTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture2D(cc_jointTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n #endif\n#else\n mat4 getJointMatrix (float i) {\n int idx = int(i);\n vec4 v1 = cc_joints[idx * 3];\n vec4 v2 = cc_joints[idx * 3 + 1];\n vec4 v3 = cc_joints[idx * 3 + 2];\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y\n + getJointMatrix(a_joints.z) * a_weights.z\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\nuniform highp mat4 cc_matView;\nuniform highp mat4 cc_matProj;\n#if USE_INSTANCING\n attribute vec4 a_matWorld0;\n attribute vec4 a_matWorld1;\n attribute vec4 a_matWorld2;\n #if USE_LIGHTMAP\n attribute vec4 a_lightingMapUVParam;\n #endif\n#elif USE_BATCHING\n attribute float a_dyn_batch_id;\n uniform highp mat4 cc_matWorlds[10];\n#else\nuniform highp mat4 cc_matWorld;\n#endif\nuniform highp mat4 cc_matLightPlaneProj;\nvec4 vert () {\n vec4 position;\n position = vec4(a_position, 1.0);\n #if CC_USE_MORPH\n applyMorph(position);\n #endif\n #if CC_USE_SKINNING\n CCSkin(position);\n #endif\n mat4 matWorld;\n #if USE_INSTANCING\n matWorld = mat4(\n vec4(a_matWorld0.xyz, 0.0),\n vec4(a_matWorld1.xyz, 0.0),\n vec4(a_matWorld2.xyz, 0.0),\n vec4(a_matWorld0.w, a_matWorld1.w, a_matWorld2.w, 1.0)\n );\n #elif USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id)];\n #else\n matWorld = cc_matWorld;\n #endif\n position = cc_matProj * (cc_matView * cc_matLightPlaneProj * matWorld) * position;\n position.z -= 0.0001;\n return position;\n}\nvoid main() { gl_Position = vert(); }`, "frag": `\nprecision mediump float;\nuniform lowp vec4 cc_shadowColor;\nuniform mediump vec4 cc_exposure;\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nvec4 CCFragOutput (vec4 color) {\n #if CC_USE_HDR\n color.rgb = mix(color.rgb, SRGBToLinear(color.rgb) * cc_exposure.w, vec3(cc_exposure.z));\n #endif\n return color;\n}\nvec4 frag () {\n return CCFragOutput(cc_shadowColor);\n}\nvoid main() { gl_FragColor = frag(); }` }, "glsl4": { - "vert": `\n#ifdef GL_EXT_shader_explicit_arithmetic_types_int16\n#extension GL_EXT_shader_explicit_arithmetic_types_int16: enable\n#endif\nprecision highp float;\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nlayout(location = 0) in vec3 a_position;\nlayout(location = 1) in vec3 a_normal;\nlayout(location = 2) in vec2 a_texCoord;\nlayout(location = 3) in vec4 a_tangent;\n#if CC_USE_MORPH\n int getVertexId() {\n return gl_VertexID;\n }\nlayout(set = 2, binding = 4) uniform CCMorph {\n vec4 cc_displacementWeights[15];\n vec4 cc_displacementTextureInfo;\n};\n vec4 fetchVec3ArrayFromTexture(sampler2D tex, int pixelIndex) {\n ivec2 texSize = textureSize(tex, 0);\n return texelFetch(tex, ivec2(pixelIndex % texSize.x, pixelIndex / texSize.x), 0);\n }\nfloat getDisplacementWeight(int index) {\n float m = mod(float(index), 4.0);\n if (m < 1.0) {\n return cc_displacementWeights[index / 4].x;\n } else if (m < 2.0) {\n return cc_displacementWeights[index / 4].y;\n } else if (m < 3.0) {\n return cc_displacementWeights[index / 4].z;\n } else {\n return cc_displacementWeights[index / 4].w;\n }\n}\nvec3 getVec3DisplacementFromTexture(sampler2D tex, int vertexIndex) {\n#if CC_MORPH_PRECOMPUTED\n return fetchVec3ArrayFromTexture(tex, vertexIndex).rgb;\n#else\n vec3 result = vec3(0, 0, 0);\n for (int iTarget = 0; iTarget < CC_MORPH_TARGET_COUNT; ++iTarget) {\n int dataPixelStart = int(fetchVec3ArrayFromTexture(tex, iTarget).r);\n result += (fetchVec3ArrayFromTexture(tex, dataPixelStart + vertexIndex).rgb * getDisplacementWeight(iTarget));\n }\n return result;\n#endif\n}\n#if CC_MORPH_TARGET_HAS_POSITION\n layout(set = 2, binding = 6) uniform sampler2D cc_PositionDisplacements;\n vec3 getPositionDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_PositionDisplacements, vertexId);\n }\n#endif\n#if CC_MORPH_TARGET_HAS_NORMAL\n layout(set = 2, binding = 7) uniform sampler2D cc_NormalDisplacements;\n vec3 getNormalDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_NormalDisplacements, vertexId);\n }\n#endif\n#if CC_MORPH_TARGET_HAS_TANGENT\n layout(set = 2, binding = 8) uniform sampler2D cc_TangentDisplacements;\n vec3 getTangentDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_TangentDisplacements, vertexId);\n }\n#endif\nvoid applyMorph (inout StandardVertInput attr) {\n int vertexId = getVertexId();\n#if CC_MORPH_TARGET_HAS_POSITION\n attr.position.xyz = attr.position.xyz + getPositionDisplacement(vertexId);\n#endif\n#if CC_MORPH_TARGET_HAS_NORMAL\n attr.normal.xyz = attr.normal.xyz + getNormalDisplacement(vertexId);\n#endif\n#if CC_MORPH_TARGET_HAS_TANGENT\n attr.tangent.xyz = attr.tangent.xyz + getTangentDisplacement(vertexId);\n#endif\n}\nvoid applyMorph (inout vec4 position) {\n#if CC_MORPH_TARGET_HAS_POSITION\n position.xyz = position.xyz + getPositionDisplacement(getVertexId());\n#endif\n}\n#endif\n#if CC_USE_SKINNING\nlayout(location = 4) in u16vec4 a_joints;\nlayout(location = 5) in vec4 a_weights;\n#if CC_USE_BAKED_ANIMATION\n #if USE_INSTANCING\n layout(location = 7) in highp vec4 a_jointAnimInfo;\n #endif\n layout(set = 2, binding = 3) uniform CCSkinningTexture {\n highp vec4 cc_jointTextureInfo;\n };\n layout(set = 2, binding = 2) uniform CCSkinningAnimation {\n highp vec4 cc_jointAnimInfo;\n };\n layout(set = 2, binding = 5) uniform highp sampler2D cc_jointTexture;\n #if !CC_SUPPORT_FLOAT_TEXTURE\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n #endif\n#else\n layout(set = 2, binding = 3) uniform CCSkinning {\n highp vec4 cc_joints[30 * 3];\n };\n#endif\n#if CC_USE_BAKED_ANIMATION\n #if CC_SUPPORT_FLOAT_TEXTURE\n mat4 getJointMatrix (float i) {\n #if USE_INSTANCING\n highp float j = 3.0 * (a_jointAnimInfo.x * a_jointAnimInfo.y + i) + a_jointAnimInfo.z;\n #else\n highp float j = 3.0 * (cc_jointAnimInfo.x * cc_jointTextureInfo.y + i) + cc_jointTextureInfo.z;\n #endif\n highp float invSize = cc_jointTextureInfo.w;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture(cc_jointTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture(cc_jointTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture(cc_jointTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n #else\n mat4 getJointMatrix (float i) {\n #if USE_INSTANCING\n highp float j = 12.0 * (a_jointAnimInfo.x * a_jointAnimInfo.y + i) + a_jointAnimInfo.z;\n #else\n highp float j = 12.0 * (cc_jointAnimInfo.x * cc_jointTextureInfo.y + i) + cc_jointTextureInfo.z;\n #endif\n highp float invSize = cc_jointTextureInfo.w;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n #endif\n#else\n mat4 getJointMatrix (float i) {\n int idx = int(i);\n vec4 v1 = cc_joints[idx * 3];\n vec4 v2 = cc_joints[idx * 3 + 1];\n vec4 v3 = cc_joints[idx * 3 + 2];\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y\n + getJointMatrix(a_joints.z) * a_weights.z\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\nlayout(set = 0, binding = 0) uniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n mediump vec4 cc_fogColor;\n mediump vec4 cc_fogBase;\n mediump vec4 cc_fogAdd;\n};\n#if USE_INSTANCING\n layout(location = 8) in vec4 a_matWorld0;\n layout(location = 9) in vec4 a_matWorld1;\n layout(location = 10) in vec4 a_matWorld2;\n #if USE_LIGHTMAP\n layout(location = 11) in vec4 a_lightingMapUVParam;\n #endif\n#elif USE_BATCHING\n layout(location = 12) in float a_dyn_batch_id;\n layout(set = 2, binding = 0) uniform CCLocalBatched {\n highp mat4 cc_matWorlds[10];\n };\n#else\nlayout(set = 2, binding = 0) uniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n highp vec4 cc_lightingMapUVParam;\n};\n#endif\nlayout(set = 0, binding = 1) uniform CCShadow {\n highp mat4 cc_matLightPlaneProj;\n highp mat4 cc_matLightViewProj;\n lowp vec4 cc_shadowColor;\n};\nvec4 vert () {\n vec4 position;\n position = vec4(a_position, 1.0);\n #if CC_USE_MORPH\n applyMorph(position);\n #endif\n #if CC_USE_SKINNING\n CCSkin(position);\n #endif\n mat4 matWorld;\n #if USE_INSTANCING\n matWorld = mat4(\n vec4(a_matWorld0.xyz, 0.0),\n vec4(a_matWorld1.xyz, 0.0),\n vec4(a_matWorld2.xyz, 0.0),\n vec4(a_matWorld0.w, a_matWorld1.w, a_matWorld2.w, 1.0)\n );\n #elif USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id)];\n #else\n matWorld = cc_matWorld;\n #endif\n position = cc_matProj * (cc_matView * cc_matLightPlaneProj * matWorld) * position;\n position.z -= 0.0001;\n return position;\n}\nvoid main() { gl_Position = vert(); }`, - "frag": `\nprecision mediump float;\nlayout(set = 0, binding = 1) uniform CCShadow {\n highp mat4 cc_matLightPlaneProj;\n highp mat4 cc_matLightViewProj;\n lowp vec4 cc_shadowColor;\n};\nlayout(set = 0, binding = 0) uniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n mediump vec4 cc_fogColor;\n mediump vec4 cc_fogBase;\n mediump vec4 cc_fogAdd;\n};\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nvec4 CCFragOutput (vec4 color) {\n #if CC_USE_HDR\n color.rgb = mix(color.rgb, SRGBToLinear(color.rgb) * cc_exposure.w, vec3(cc_exposure.z));\n #endif\n return color;\n}\nvec4 frag () {\n return CCFragOutput(cc_shadowColor);\n}\nlayout(location = 0) out vec4 cc_FragColor;\nvoid main() { cc_FragColor = frag(); }` + "vert": `\n#ifdef GL_EXT_shader_explicit_arithmetic_types_int16\n#extension GL_EXT_shader_explicit_arithmetic_types_int16: enable\n#endif\nprecision highp float;\nstruct StandardVertInput {\n highp vec4 position;\n vec3 normal;\n vec4 tangent;\n};\nlayout(location = 0) in vec3 a_position;\nlayout(location = 1) in vec3 a_normal;\nlayout(location = 2) in vec2 a_texCoord;\nlayout(location = 3) in vec4 a_tangent;\n#if CC_USE_MORPH\n int getVertexId() {\n return gl_VertexID;\n }\nlayout(set = 2, binding = 4) uniform CCMorph {\n vec4 cc_displacementWeights[15];\n vec4 cc_displacementTextureInfo;\n};\n vec4 fetchVec3ArrayFromTexture(sampler2D tex, int pixelIndex) {\n ivec2 texSize = textureSize(tex, 0);\n return texelFetch(tex, ivec2(pixelIndex % texSize.x, pixelIndex / texSize.x), 0);\n }\nfloat getDisplacementWeight(int index) {\n float m = mod(float(index), 4.0);\n if (m < 1.0) {\n return cc_displacementWeights[index / 4].x;\n } else if (m < 2.0) {\n return cc_displacementWeights[index / 4].y;\n } else if (m < 3.0) {\n return cc_displacementWeights[index / 4].z;\n } else {\n return cc_displacementWeights[index / 4].w;\n }\n}\nvec3 getVec3DisplacementFromTexture(sampler2D tex, int vertexIndex) {\n#if CC_MORPH_PRECOMPUTED\n return fetchVec3ArrayFromTexture(tex, vertexIndex).rgb;\n#else\n vec3 result = vec3(0, 0, 0);\n for (int iTarget = 0; iTarget < CC_MORPH_TARGET_COUNT; ++iTarget) {\n int dataPixelStart = int(fetchVec3ArrayFromTexture(tex, iTarget).r);\n result += (fetchVec3ArrayFromTexture(tex, dataPixelStart + vertexIndex).rgb * getDisplacementWeight(iTarget));\n }\n return result;\n#endif\n}\n#if CC_MORPH_TARGET_HAS_POSITION\n layout(set = 2, binding = 6) uniform sampler2D cc_PositionDisplacements;\n vec3 getPositionDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_PositionDisplacements, vertexId);\n }\n#endif\n#if CC_MORPH_TARGET_HAS_NORMAL\n layout(set = 2, binding = 7) uniform sampler2D cc_NormalDisplacements;\n vec3 getNormalDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_NormalDisplacements, vertexId);\n }\n#endif\n#if CC_MORPH_TARGET_HAS_TANGENT\n layout(set = 2, binding = 8) uniform sampler2D cc_TangentDisplacements;\n vec3 getTangentDisplacement(int vertexId) {\n return getVec3DisplacementFromTexture(cc_TangentDisplacements, vertexId);\n }\n#endif\nvoid applyMorph (inout StandardVertInput attr) {\n int vertexId = getVertexId();\n#if CC_MORPH_TARGET_HAS_POSITION\n attr.position.xyz = attr.position.xyz + getPositionDisplacement(vertexId);\n#endif\n#if CC_MORPH_TARGET_HAS_NORMAL\n attr.normal.xyz = attr.normal.xyz + getNormalDisplacement(vertexId);\n#endif\n#if CC_MORPH_TARGET_HAS_TANGENT\n attr.tangent.xyz = attr.tangent.xyz + getTangentDisplacement(vertexId);\n#endif\n}\nvoid applyMorph (inout vec4 position) {\n#if CC_MORPH_TARGET_HAS_POSITION\n position.xyz = position.xyz + getPositionDisplacement(getVertexId());\n#endif\n}\n#endif\n#if CC_USE_SKINNING\nlayout(location = 4) in u16vec4 a_joints;\nlayout(location = 5) in vec4 a_weights;\n#if CC_USE_BAKED_ANIMATION\n #if USE_INSTANCING\n layout(location = 7) in highp vec4 a_jointAnimInfo;\n #endif\n layout(set = 2, binding = 3) uniform CCSkinningTexture {\n highp vec4 cc_jointTextureInfo;\n };\n layout(set = 2, binding = 2) uniform CCSkinningAnimation {\n highp vec4 cc_jointAnimInfo;\n };\n layout(set = 2, binding = 5) uniform highp sampler2D cc_jointTexture;\n #if !CC_SUPPORT_FLOAT_TEXTURE\n highp float decode32 (highp vec4 rgba) {\n rgba = rgba * 255.0;\n highp float Sign = 1.0 - step(128.0, rgba[3]) * 2.0;\n highp float Exponent = 2.0 * mod(rgba[3], 128.0) + step(128.0, rgba[2]) - 127.0;\n highp float Mantissa = mod(rgba[2], 128.0) * 65536.0 + rgba[1] * 256.0 + rgba[0] + 8388608.0;\n return Sign * exp2(Exponent - 23.0) * Mantissa;\n }\n #endif\n#else\n layout(set = 2, binding = 3) uniform CCSkinning {\n highp vec4 cc_joints[30 * 3];\n };\n#endif\n#if CC_USE_BAKED_ANIMATION\n #if CC_SUPPORT_FLOAT_TEXTURE\n mat4 getJointMatrix (float i) {\n #if USE_INSTANCING\n highp float j = 3.0 * (a_jointAnimInfo.x * a_jointAnimInfo.y + i) + a_jointAnimInfo.z;\n #else\n highp float j = 3.0 * (cc_jointAnimInfo.x * cc_jointTextureInfo.y + i) + cc_jointTextureInfo.z;\n #endif\n highp float invSize = cc_jointTextureInfo.w;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = texture(cc_jointTexture, vec2((x + 0.5) * invSize, y));\n vec4 v2 = texture(cc_jointTexture, vec2((x + 1.5) * invSize, y));\n vec4 v3 = texture(cc_jointTexture, vec2((x + 2.5) * invSize, y));\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n #else\n mat4 getJointMatrix (float i) {\n #if USE_INSTANCING\n highp float j = 12.0 * (a_jointAnimInfo.x * a_jointAnimInfo.y + i) + a_jointAnimInfo.z;\n #else\n highp float j = 12.0 * (cc_jointAnimInfo.x * cc_jointTextureInfo.y + i) + cc_jointTextureInfo.z;\n #endif\n highp float invSize = cc_jointTextureInfo.w;\n highp float y = floor(j * invSize);\n highp float x = j - y * cc_jointTextureInfo.x;\n y = (y + 0.5) * invSize;\n vec4 v1 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 0.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 1.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 2.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 3.5) * invSize, y)))\n );\n vec4 v2 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 4.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 5.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 6.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 7.5) * invSize, y)))\n );\n vec4 v3 = vec4(\n decode32(texture(cc_jointTexture, vec2((x + 8.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 9.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 10.5) * invSize, y))),\n decode32(texture(cc_jointTexture, vec2((x + 11.5) * invSize, y)))\n );\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n #endif\n#else\n mat4 getJointMatrix (float i) {\n int idx = int(i);\n vec4 v1 = cc_joints[idx * 3];\n vec4 v2 = cc_joints[idx * 3 + 1];\n vec4 v3 = cc_joints[idx * 3 + 2];\n return mat4(vec4(v1.xyz, 0.0), vec4(v2.xyz, 0.0), vec4(v3.xyz, 0.0), vec4(v1.w, v2.w, v3.w, 1.0));\n }\n#endif\nmat4 skinMatrix () {\n return getJointMatrix(a_joints.x) * a_weights.x\n + getJointMatrix(a_joints.y) * a_weights.y\n + getJointMatrix(a_joints.z) * a_weights.z\n + getJointMatrix(a_joints.w) * a_weights.w;\n}\nvoid CCSkin (inout vec4 position) {\n mat4 m = skinMatrix();\n position = m * position;\n}\nvoid CCSkin (inout StandardVertInput attr) {\n mat4 m = skinMatrix();\n attr.position = m * attr.position;\n attr.normal = (m * vec4(attr.normal, 0.0)).xyz;\n attr.tangent.xyz = (m * vec4(attr.tangent.xyz, 0.0)).xyz;\n}\n#endif\nlayout(set = 0, binding = 0) uniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n mediump vec4 cc_fogColor;\n mediump vec4 cc_fogBase;\n mediump vec4 cc_fogAdd;\n};\n#if USE_INSTANCING\n layout(location = 8) in vec4 a_matWorld0;\n layout(location = 9) in vec4 a_matWorld1;\n layout(location = 10) in vec4 a_matWorld2;\n #if USE_LIGHTMAP\n layout(location = 11) in vec4 a_lightingMapUVParam;\n #endif\n#elif USE_BATCHING\n layout(location = 12) in float a_dyn_batch_id;\n layout(set = 2, binding = 0) uniform CCLocalBatched {\n highp mat4 cc_matWorlds[10];\n };\n#else\nlayout(set = 2, binding = 0) uniform CCLocal {\n highp mat4 cc_matWorld;\n highp mat4 cc_matWorldIT;\n highp vec4 cc_lightingMapUVParam;\n};\n#endif\nlayout(set = 0, binding = 1) uniform CCShadow {\n highp mat4 cc_matLightPlaneProj;\n highp mat4 cc_matLightViewProj;\n lowp vec4 cc_shadowColor;\n lowp vec4 cc_shadowPCF;\n lowp vec4 cc_shadowSize;\n};\nvec4 vert () {\n vec4 position;\n position = vec4(a_position, 1.0);\n #if CC_USE_MORPH\n applyMorph(position);\n #endif\n #if CC_USE_SKINNING\n CCSkin(position);\n #endif\n mat4 matWorld;\n #if USE_INSTANCING\n matWorld = mat4(\n vec4(a_matWorld0.xyz, 0.0),\n vec4(a_matWorld1.xyz, 0.0),\n vec4(a_matWorld2.xyz, 0.0),\n vec4(a_matWorld0.w, a_matWorld1.w, a_matWorld2.w, 1.0)\n );\n #elif USE_BATCHING\n matWorld = cc_matWorlds[int(a_dyn_batch_id)];\n #else\n matWorld = cc_matWorld;\n #endif\n position = cc_matProj * (cc_matView * cc_matLightPlaneProj * matWorld) * position;\n position.z -= 0.0001;\n return position;\n}\nvoid main() { gl_Position = vert(); }`, + "frag": `\nprecision mediump float;\nlayout(set = 0, binding = 1) uniform CCShadow {\n highp mat4 cc_matLightPlaneProj;\n highp mat4 cc_matLightViewProj;\n lowp vec4 cc_shadowColor;\n lowp vec4 cc_shadowPCF;\n lowp vec4 cc_shadowSize;\n};\nlayout(set = 0, binding = 0) uniform CCGlobal {\n highp vec4 cc_time;\n mediump vec4 cc_screenSize;\n mediump vec4 cc_screenScale;\n mediump vec4 cc_nativeSize;\n highp mat4 cc_matView;\n highp mat4 cc_matViewInv;\n highp mat4 cc_matProj;\n highp mat4 cc_matProjInv;\n highp mat4 cc_matViewProj;\n highp mat4 cc_matViewProjInv;\n highp vec4 cc_cameraPos;\n mediump vec4 cc_exposure;\n mediump vec4 cc_mainLitDir;\n mediump vec4 cc_mainLitColor;\n mediump vec4 cc_ambientSky;\n mediump vec4 cc_ambientGround;\n mediump vec4 cc_fogColor;\n mediump vec4 cc_fogBase;\n mediump vec4 cc_fogAdd;\n};\nvec3 SRGBToLinear (vec3 gamma) {\n return gamma * gamma;\n}\nvec4 CCFragOutput (vec4 color) {\n #if CC_USE_HDR\n color.rgb = mix(color.rgb, SRGBToLinear(color.rgb) * cc_exposure.w, vec3(cc_exposure.z));\n #endif\n return color;\n}\nvec4 frag () {\n return CCFragOutput(cc_shadowColor);\n}\nlayout(location = 0) out vec4 cc_FragColor;\nvoid main() { cc_FragColor = frag(); }` }, "builtins": { "globals": { "blocks": [{ "name": "CCGlobal", "defines": [] }, { "name": "CCShadow", "defines": [] }], "samplers": [] }, diff --git a/cocos/core/geometry/sphere.ts b/cocos/core/geometry/sphere.ts index 26283e31f19..fcc3d74a4a2 100644 --- a/cocos/core/geometry/sphere.ts +++ b/cocos/core/geometry/sphere.ts @@ -4,8 +4,12 @@ import { Mat4, Quat, Vec3 } from '../math'; import enums from './enums'; +import aabb from './aabb'; const _v3_tmp = new Vec3(); +const _offset = new Vec3(); +const _min = new Vec3(); +const _max = new Vec3(); function maxComponent (v: Vec3) { return Math.max(Math.max(v.x, v.y), v.z); } /** @@ -79,7 +83,7 @@ export default class sphere { /** * @en * Set the components of a sphere to the given values - * @zh + * @zh * 将球体的属性设置为给定的值。 * @param {sphere} out 接受操作的 sphere。 * @param cx 形状的相对于原点的 X 坐标。 @@ -98,6 +102,43 @@ export default class sphere { return out; } + /** + * @zh + * 球跟点合并 + */ + public static mergePoint (out: sphere, s: sphere, point: Vec3) { + if (s.radius < 0.0) { + out.center = point; + out.radius = 0.0; + return out; + } + + Vec3.subtract(_offset, point, s.center); + const dist = _offset.length(); + + if (dist > s.radius) { + const half = (dist - s.radius) * 0.5; + out.radius += half; + Vec3.multiplyScalar(_offset, _offset, half / dist); + Vec3.add(out.center, out.center, _offset); + } + + return out; + } + + /** + * @zh + * 球跟立方体合并 + */ + public static mergeAABB (out: sphere, s:sphere, a: aabb) { + a.getBoundary(_min, _max); + + sphere.mergePoint(out, s, _min); + sphere.mergePoint(out, s, _max); + + return out; + } + /** * @en * The center of this sphere. diff --git a/cocos/core/pipeline/define.ts b/cocos/core/pipeline/define.ts index 147d3580a20..1187613f089 100644 --- a/cocos/core/pipeline/define.ts +++ b/cocos/core/pipeline/define.ts @@ -198,7 +198,9 @@ export class UBOShadow { public static MAT_LIGHT_PLANE_PROJ_OFFSET: number = 0; public static MAT_LIGHT_VIEW_PROJ_OFFSET: number = UBOShadow.MAT_LIGHT_PLANE_PROJ_OFFSET + 16; public static SHADOW_COLOR_OFFSET: number = UBOShadow.MAT_LIGHT_VIEW_PROJ_OFFSET + 16; - public static COUNT: number = UBOShadow.SHADOW_COLOR_OFFSET + 4; + public static SHADOW_PCF_OFFSET: number = UBOShadow.SHADOW_COLOR_OFFSET + 4; + public static SHADOW_SIZE_OFFSET: number = UBOShadow.SHADOW_PCF_OFFSET + 4; + public static COUNT: number = UBOShadow.SHADOW_SIZE_OFFSET + 4; public static SIZE: number = UBOShadow.COUNT * 4; public static BLOCK: IBlockInfo = { @@ -207,6 +209,8 @@ export class UBOShadow { { name: 'cc_matLightPlaneProj', type: GFXType.MAT4, count: 1 }, { name: 'cc_matLightViewProj', type: GFXType.MAT4, count: 1 }, { name: 'cc_shadowColor', type: GFXType.FLOAT4, count: 1 }, + { name: 'cc_shadowPCF', type: GFXType.FLOAT4, count: 1 }, + { name: 'cc_shadowSize', type: GFXType.FLOAT4, count: 1 }, ], }; } diff --git a/cocos/core/pipeline/forward/forward-pipeline.ts b/cocos/core/pipeline/forward/forward-pipeline.ts index 4d95feaaf5e..c0331d75d55 100644 --- a/cocos/core/pipeline/forward/forward-pipeline.ts +++ b/cocos/core/pipeline/forward/forward-pipeline.ts @@ -27,6 +27,7 @@ import { sceneCulling } from './scene-culling'; const matShadowView = new Mat4(); const matShadowViewProj = new Mat4(); +const vec4 = new Vec4(); /** * @en The forward render pipeline @@ -178,11 +179,20 @@ export class ForwardPipeline extends RenderPipeline { if (mainLight && shadowInfo.type === ShadowType.ShadowMap) { // light view - Mat4.invert(matShadowView, mainLight!.node!.worldMatrix); + const shadowCameraView = shadowInfo.getWorldMatrix(mainLight!.node!.worldRotation, mainLight!.direction); + Mat4.invert(matShadowView, shadowCameraView); // light proj - const x = shadowInfo.orthoSize * shadowInfo.aspect; - const y = shadowInfo.orthoSize; + let x: number = 0; + let y: number = 0; + if (shadowInfo.orthoSize > shadowInfo.sphere.radius) { + x = shadowInfo.orthoSize * shadowInfo.aspect; + y = shadowInfo.orthoSize; + } else { + // if orthoSize is the smallest, auto calculate orthoSize. + x = shadowInfo.sphere.radius * shadowInfo.aspect; + y = shadowInfo.sphere.radius; + } const projectionSignY = device.screenSpaceSignY * device.UVSpaceSignY; Mat4.ortho(matShadowViewProj, -x, x, -y, y, shadowInfo.near, shadowInfo.far, device.clipSpaceMinZ, projectionSignY); @@ -191,6 +201,12 @@ export class ForwardPipeline extends RenderPipeline { Mat4.multiply(matShadowViewProj, matShadowViewProj, matShadowView); Mat4.toArray(this._shadowUBO, matShadowViewProj, UBOShadow.MAT_LIGHT_VIEW_PROJ_OFFSET); + + vec4.set(shadowInfo.pcf); + Vec4.toArray(this._shadowUBO, vec4, UBOShadow.SHADOW_PCF_OFFSET); + + vec4.set(shadowInfo.size.x, shadowInfo.size.y); + Vec4.toArray(this._shadowUBO, vec4, UBOShadow.SHADOW_SIZE_OFFSET); } // update ubos diff --git a/cocos/core/pipeline/forward/scene-culling.ts b/cocos/core/pipeline/forward/scene-culling.ts index 85c67597fa4..8583c96c9c4 100644 --- a/cocos/core/pipeline/forward/scene-culling.ts +++ b/cocos/core/pipeline/forward/scene-culling.ts @@ -1,4 +1,4 @@ -import { intersect } from '../../geometry'; +import { intersect, sphere } from '../../geometry'; import { Model, Camera } from '../../renderer'; import { Layers } from '../../scene-graph'; import { Vec3} from '../../math'; @@ -48,6 +48,9 @@ export function sceneCulling (pipeline: ForwardPipeline, view: RenderView) { const mainLight = scene.mainLight; const shadows = pipeline.shadows; + const shadowSphere = shadows.sphere; + shadowSphere.center.set(0.0, 0.0, 0.0); + shadowSphere.radius = 0.01; if (mainLight) { mainLight.update(); if (shadows.type === ShadowType.Planar) { @@ -78,6 +81,7 @@ export function sceneCulling (pipeline: ForwardPipeline, view: RenderView) { // shadow render Object if (model.castShadow) { + sphere.mergeAABB(shadowSphere, shadowSphere, model.worldBounds!); shadowObjects.push(getCastShadowRenderObject(model, camera)); } diff --git a/cocos/core/renderer/scene/shadows.ts b/cocos/core/renderer/scene/shadows.ts index 1dc8b202515..0b034ae21a4 100644 --- a/cocos/core/renderer/scene/shadows.ts +++ b/cocos/core/renderer/scene/shadows.ts @@ -1,8 +1,8 @@ import { Material } from '../../assets/material'; -import { aabb, frustum, intersect } from '../../geometry'; +import { aabb, frustum, intersect, sphere } from '../../geometry'; import { GFXPipelineState } from '../../gfx/pipeline-state'; -import { Color, Mat4, Quat, Vec3, Vec2 } from '../../math'; +import { Color, Mat4, Quat, Vec3, Vec2, Vec4 } from '../../math'; import { UBOShadow, SetIndex} from '../../pipeline/define'; import { DirectionalLight } from './directional-light'; import { Model } from './model'; @@ -21,6 +21,9 @@ const _v3 = new Vec3(); const _ab = new aabb(); const _qt = new Quat(); const _up = new Vec3(0, 1, 0); +const _dir_negate = new Vec3(); +const _vec3_p = new Vec3(); +const _mat4_trans = new Mat4(); /** * @zh 阴影类型。 @@ -46,6 +49,42 @@ export const ShadowType = Enum({ ShadowMap: 1, }) +/** + * @zh pcf阴影等级。 + * @en The pcf type + * @static + * @enum Shadows.ShadowType + */ +export const PCFType = Enum({ + /** + * @zh x1 次采样 + * @en x1 times + * @readonly + */ + HARD: 0, + + /** + * @zh x5 次采样 + * @en x5 times + * @readonly + */ + FILTER_X5: 1, + + /** + * @zh x9 次采样 + * @en x9 times + * @readonly + */ + FILTER_X9: 2, + + /** + * @zh x25 次采样 + * @en x25 times + * @readonly + */ + FILTER_X25: 3, +}) + interface IShadowRenderData { model: Model; shaders: GFXShader[]; @@ -134,6 +173,9 @@ export class Shadows { get data () { return this._data; } + get sphere () { + return this._sphere; + } protected _enabled: boolean = false; protected _type = ShadowType.Planar; protected _normal = new Vec3(0, 1, 0); @@ -151,6 +193,11 @@ export class Shadows { protected _device: GFXDevice|null = null; protected _globalDescriptorSet: GFXDescriptorSet | null = null; protected _dirty: boolean = true; + /** + * @zh + * 场景包围球 + */ + protected _sphere: sphere = new sphere(0.0, 0.0, 0.0, 0.01); /** * @en get or set shadow camera near * @zh 获取或者设置阴影相机近裁剪面 @@ -170,13 +217,19 @@ export class Shadows { * @en get or set shadow camera orthoSize * @zh 获取或者设置阴影相机正交大小 */ - public orthoSize: number = 5; + public orthoSize: number = 1; /** * @en get or set shadow camera orthoSize * @zh 获取或者设置阴影纹理大小 */ public size: Vec2 = new Vec2(512, 512); + /** + * @en get or set shadow pcf + * @zh 获取或者设置阴影pcf等级 + */ + public pcf = PCFType.HARD; + public activate () { const pipeline = legacyCC.director.root.pipeline; this._globalDescriptorSet = pipeline.descriptorSet; @@ -190,6 +243,17 @@ export class Shadows { } } + public getWorldMatrix (rotation: Quat, dir: Vec3) { + Vec3.negate(_dir_negate, dir); + const distance: number = Math.sqrt(2) * this._sphere.radius; + Vec3.multiplyScalar(_vec3_p, _dir_negate, distance); + Vec3.add(_vec3_p, _vec3_p, this._sphere.center); + + Mat4.fromRT(_mat4_trans, rotation, _vec3_p); + + return _mat4_trans; + } + protected _updatePlanarInfo () { this._dirty = true; if (!this._material) { diff --git a/cocos/core/scene-graph/scene-globals.ts b/cocos/core/scene-graph/scene-globals.ts index f7652de98e0..e78bdb53efd 100644 --- a/cocos/core/scene-graph/scene-globals.ts +++ b/cocos/core/scene-graph/scene-globals.ts @@ -28,7 +28,7 @@ import { ccclass, property, visible, type, displayOrder, slide, range, rangeStep import { CCBoolean, CCFloat } from '../data/utils/attribute'; import { Color, Quat, Vec3, Vec2 } from '../math'; import { Ambient } from '../renderer/scene/ambient'; -import { Shadows, ShadowType } from '../renderer/scene/shadows'; +import { Shadows, ShadowType, PCFType } from '../renderer/scene/shadows'; import { Skybox } from '../renderer/scene/skybox'; import { Fog, FogType } from '../renderer/scene/fog'; import { Node } from './node'; @@ -386,6 +386,8 @@ export class ShadowsInfo { @property protected _shadowColor = new Color(0, 0, 0, 76); @property + protected _pcf = PCFType.HARD; + @property protected _near: number = 1; @property protected _far: number = 30; @@ -461,6 +463,20 @@ export class ShadowsInfo { return this._distance; } + /** + * @en The normal of the plane which receives shadow + * @zh 阴影接收平面的法线 + */ + @type(PCFType) + @visible(function (this: ShadowsInfo) { return this._type === ShadowType.ShadowMap; }) + set pcf (val) { + this._pcf = val; + if (this._resource) { this._resource.pcf = val; } + } + get pcf () { + return this._pcf; + } + /** * @en get or set shadow camera near * @zh 获取或者设置阴影相机近裁剪面 diff --git a/editor/assets/chunks/cc-shadow-map-fs.chunk b/editor/assets/chunks/cc-shadow-map-fs.chunk index fdbcda5ba52..7d8148ca16c 100644 --- a/editor/assets/chunks/cc-shadow-map-fs.chunk +++ b/editor/assets/chunks/cc-shadow-map-fs.chunk @@ -7,9 +7,54 @@ in vec4 v_shadowPos; #pragma builtin(global) layout(set = 0, binding = 4) uniform sampler2D cc_shadowMap; -vec4 CCGetShadowFactor () { +vec4 CCGetShadowFactorX1 () { vec3 clipPos = v_shadowPos.xyz / v_shadowPos.w * 0.5 + 0.5; float depth = unpackRGBAToDepth(texture(cc_shadowMap, clipPos.xy)); if (depth < (clipPos.z - 0.001)) return cc_shadowColor; else return vec4(0); } + +vec4 CCGetShadowFactorX5 () { + vec3 clipPos = v_shadowPos.xyz / v_shadowPos.w * 0.5 + 0.5; + float offsetx = 1.0 / cc_shadowSize.x; + float offsety = 1.0 / cc_shadowSize.y; + float depth = 0.0; + depth += unpackRGBAToDepth(texture(cc_shadowMap, vec2(clipPos.x - offsetx, clipPos.y - offsety))); + depth += unpackRGBAToDepth(texture(cc_shadowMap, vec2(clipPos.x - offsetx, clipPos.y + offsety))); + depth += unpackRGBAToDepth(texture(cc_shadowMap, vec2(clipPos.x, clipPos.y))); + depth += unpackRGBAToDepth(texture(cc_shadowMap, vec2(clipPos.x + offsetx, clipPos.y - offsety))); + depth += unpackRGBAToDepth(texture(cc_shadowMap, vec2(clipPos.x + offsetx, clipPos.y + offsety))); + depth /= 5.0; + if (depth < (clipPos.z - 0.001)) return cc_shadowColor; + else return vec4(0); +} + +vec4 CCGetShadowFactorX9 () { + vec3 clipPos = v_shadowPos.xyz / v_shadowPos.w * 0.5 + 0.5; + float offsetx = 1.0 / cc_shadowSize.x; + float offsety = 1.0 / cc_shadowSize.y; + float depth = 0.0; + for (int i = -1; i <= 1; i++) { + for (int j = -1; j <= 1; j++) { + depth += unpackRGBAToDepth(texture(cc_shadowMap, clipPos.xy + vec2(i, j) * vec2(offsetx, offsety))); + } + } + depth /= 9.0; + if (depth < (clipPos.z - 0.001)) return cc_shadowColor; + else return vec4(0); +} + +vec4 CCGetShadowFactorX25 () { + vec3 clipPos = v_shadowPos.xyz / v_shadowPos.w * 0.5 + 0.5; + float offsetx = 1.0 / cc_shadowSize.x; + float offsety = 1.0 / cc_shadowSize.y; + float depth = 0.0; + for (int i = -2; i <= 2; i++) { + for (int j = -2; j <= 2; j++) { + depth += unpackRGBAToDepth(texture(cc_shadowMap, clipPos.xy + vec2(i, j) * vec2(offsetx, offsety))); + } + } + depth /= 25.0; + if (depth < (clipPos.z - 0.001)) return cc_shadowColor; + else return vec4(0); +} diff --git a/editor/assets/chunks/cc-shadow.chunk b/editor/assets/chunks/cc-shadow.chunk index 3fb23749b3a..6efa3b041f2 100644 --- a/editor/assets/chunks/cc-shadow.chunk +++ b/editor/assets/chunks/cc-shadow.chunk @@ -5,4 +5,6 @@ layout(set = 0, binding = 1) uniform CCShadow { highp mat4 cc_matLightPlaneProj; highp mat4 cc_matLightViewProj; lowp vec4 cc_shadowColor; + lowp vec4 cc_shadowPCF; + lowp vec4 cc_shadowSize; }; diff --git a/editor/assets/chunks/shading-standard.chunk b/editor/assets/chunks/shading-standard.chunk index dd212471801..574df0b5ff5 100644 --- a/editor/assets/chunks/shading-standard.chunk +++ b/editor/assets/chunks/shading-standard.chunk @@ -2,6 +2,7 @@ // reference: 'moving frostbite to pbr' & UE4 BRDF.usf #include +#include #if CC_USE_IBL #include @@ -154,7 +155,13 @@ struct StandardSurface { finalColor += s.emissive; #if CC_RECEIVE_SHADOW - vec4 shadow = CCGetShadowFactor(); + vec4 shadow = vec4(1.0); + float pcf = cc_shadowPCF.x + 0.001; + if (pcf > 3.0) {shadow = CCGetShadowFactorX25();} + else if (3.0 > pcf && pcf > 2.0) {shadow = CCGetShadowFactorX9();} + else if (2.0 > pcf && pcf > 1.0) {shadow = CCGetShadowFactorX5();} + else {shadow = CCGetShadowFactorX1();} + finalColor = shadow.rgb * shadow.a + finalColor * (1.0 - shadow.a); #endif