playcanvas
Version:
PlayCanvas WebGL game engine
4 lines (2 loc) • 16.5 kB
JavaScript
var clusteredLightPS = "\nuniform highp sampler2D clusterWorldTexture;\nuniform highp sampler2D lightsTexture8;\nuniform highp sampler2D lightsTextureFloat;\n#if defined(CLUSTER_COOKIES)\n #define CLUSTER_COOKIES_OR_SHADOWS\n#endif\n#if defined(CLUSTER_SHADOWS)\n #define CLUSTER_COOKIES_OR_SHADOWS\n#endif\n#ifdef CLUSTER_SHADOWS\n uniform sampler2DShadow shadowAtlasTexture;\n#endif\n#ifdef CLUSTER_COOKIES\n uniform sampler2D cookieAtlasTexture;\n#endif\nuniform int clusterMaxCells;\nuniform float clusterSkip;\nuniform vec3 clusterCellsCountByBoundsSize;\nuniform vec3 clusterTextureSize;\nuniform vec3 clusterBoundsMin;\nuniform vec3 clusterBoundsDelta;\nuniform vec3 clusterCellsDot;\nuniform vec3 clusterCellsMax;\nuniform vec2 clusterCompressionLimit0;\nuniform vec2 shadowAtlasParams;\nstruct ClusterLightData {\n vec3 halfWidth;\n float lightType;\n vec3 halfHeight;\n int lightIndex;\n vec3 position;\n float shape;\n vec3 direction;\n float falloffMode;\n vec3 color;\n float shadowIntensity;\n vec3 omniAtlasViewport;\n float range;\n vec4 cookieChannelMask;\n float shadowBias;\n float shadowNormalBias;\n float innerConeAngleCos;\n float outerConeAngleCos;\n float cookie;\n float cookieRgb;\n float cookieIntensity;\n float mask;\n};\nmat4 lightProjectionMatrix;\n#define isClusteredLightCastShadow(light) ( light.shadowIntensity > 0.0 )\n#define isClusteredLightCookie(light) (light.cookie > 0.5 )\n#define isClusteredLightCookieRgb(light) (light.cookieRgb > 0.5 )\n#define isClusteredLightSpot(light) ( light.lightType > 0.5 )\n#define isClusteredLightFalloffLinear(light) ( light.falloffMode < 0.5 )\n#define isClusteredLightArea(light) ( light.shape > 0.1 )\n#define isClusteredLightRect(light) ( light.shape < 0.3 )\n#define isClusteredLightDisk(light) ( light.shape < 0.6 )\n#ifdef CLUSTER_MESH_DYNAMIC_LIGHTS\n #define acceptLightMask(light) ( light.mask < 0.75)\n#else\n #define acceptLightMask(light) ( light.mask > 0.25)\n#endif\nvec4 decodeClusterLowRange4Vec4(vec4 d0, vec4 d1, vec4 d2, vec4 d3) {\n return vec4(\n bytes2floatRange4(d0, -2.0, 2.0),\n bytes2floatRange4(d1, -2.0, 2.0),\n bytes2floatRange4(d2, -2.0, 2.0),\n bytes2floatRange4(d3, -2.0, 2.0)\n );\n}\nvec4 sampleLightsTexture8(const ClusterLightData clusterLightData, int index) {\n return texelFetch(lightsTexture8, ivec2(index, clusterLightData.lightIndex), 0);\n}\nvec4 sampleLightTextureF(const ClusterLightData clusterLightData, int index) {\n return texelFetch(lightsTextureFloat, ivec2(index, clusterLightData.lightIndex), 0);\n}\nvoid decodeClusterLightCore(inout ClusterLightData clusterLightData, float lightIndex) {\n clusterLightData.lightIndex = int(lightIndex);\n vec4 lightInfo = sampleLightsTexture8(clusterLightData, CLUSTER_TEXTURE_8_FLAGS);\n clusterLightData.lightType = lightInfo.x;\n clusterLightData.shape = lightInfo.y;\n clusterLightData.falloffMode = lightInfo.z;\n clusterLightData.shadowIntensity = lightInfo.w;\n vec4 colorA = sampleLightsTexture8(clusterLightData, CLUSTER_TEXTURE_8_COLOR_A);\n vec4 colorB = sampleLightsTexture8(clusterLightData, CLUSTER_TEXTURE_8_COLOR_B);\n clusterLightData.color = vec3(bytes2float2(colorA.xy), bytes2float2(colorA.zw), bytes2float2(colorB.xy)) * clusterCompressionLimit0.y;\n clusterLightData.cookie = colorB.z;\n clusterLightData.mask = colorB.w;\n vec4 lightPosRange = sampleLightTextureF(clusterLightData, CLUSTER_TEXTURE_F_POSITION_RANGE);\n clusterLightData.position = lightPosRange.xyz;\n clusterLightData.range = lightPosRange.w;\n vec4 lightDir_Unused = sampleLightTextureF(clusterLightData, CLUSTER_TEXTURE_F_SPOT_DIRECTION);\n clusterLightData.direction = lightDir_Unused.xyz;\n}\nvoid decodeClusterLightSpot(inout ClusterLightData clusterLightData) {\n vec4 coneAngle = sampleLightsTexture8(clusterLightData, CLUSTER_TEXTURE_8_SPOT_ANGLES);\n clusterLightData.innerConeAngleCos = bytes2float2(coneAngle.xy) * 2.0 - 1.0;\n clusterLightData.outerConeAngleCos = bytes2float2(coneAngle.zw) * 2.0 - 1.0;\n}\nvoid decodeClusterLightOmniAtlasViewport(inout ClusterLightData clusterLightData) {\n clusterLightData.omniAtlasViewport = sampleLightTextureF(clusterLightData, CLUSTER_TEXTURE_F_PROJ_MAT_0).xyz;\n}\nvoid decodeClusterLightAreaData(inout ClusterLightData clusterLightData) {\n clusterLightData.halfWidth = sampleLightTextureF(clusterLightData, CLUSTER_TEXTURE_F_AREA_DATA_WIDTH).xyz;\n clusterLightData.halfHeight = sampleLightTextureF(clusterLightData, CLUSTER_TEXTURE_F_AREA_DATA_HEIGHT).xyz;\n}\nvoid decodeClusterLightProjectionMatrixData(inout ClusterLightData clusterLightData) {\n \n vec4 m0 = sampleLightTextureF(clusterLightData, CLUSTER_TEXTURE_F_PROJ_MAT_0);\n vec4 m1 = sampleLightTextureF(clusterLightData, CLUSTER_TEXTURE_F_PROJ_MAT_1);\n vec4 m2 = sampleLightTextureF(clusterLightData, CLUSTER_TEXTURE_F_PROJ_MAT_2);\n vec4 m3 = sampleLightTextureF(clusterLightData, CLUSTER_TEXTURE_F_PROJ_MAT_3);\n lightProjectionMatrix = mat4(m0, m1, m2, m3);\n}\nvoid decodeClusterLightShadowData(inout ClusterLightData clusterLightData) {\n \n vec4 biases = sampleLightsTexture8(clusterLightData, CLUSTER_TEXTURE_8_SHADOW_BIAS);\n clusterLightData.shadowBias = bytes2floatRange2(biases.xy, -1.0, 20.0),\n clusterLightData.shadowNormalBias = bytes2float2(biases.zw);\n}\nvoid decodeClusterLightCookieData(inout ClusterLightData clusterLightData) {\n vec4 cookieA = sampleLightsTexture8(clusterLightData, CLUSTER_TEXTURE_8_COOKIE_A);\n clusterLightData.cookieIntensity = cookieA.x;\n clusterLightData.cookieRgb = cookieA.y;\n clusterLightData.cookieChannelMask = sampleLightsTexture8(clusterLightData, CLUSTER_TEXTURE_8_COOKIE_B);\n}\nvoid evaluateLight(\n ClusterLightData light, \n vec3 worldNormal, \n vec3 viewDir, \n vec3 reflectionDir,\n#if defined(LIT_CLEARCOAT)\n vec3 clearcoatReflectionDir,\n#endif\n float gloss, \n vec3 specularity, \n vec3 geometricNormal, \n mat3 tbn, \n#if defined(LIT_IRIDESCENCE)\n vec3 iridescenceFresnel,\n#endif\n vec3 clearcoat_worldNormal,\n float clearcoat_gloss,\n float sheen_gloss,\n float iridescence_intensity\n) {\n vec3 cookieAttenuation = vec3(1.0);\n float diffuseAttenuation = 1.0;\n float falloffAttenuation = 1.0;\n getLightDirPoint(light.position);\n #ifdef CLUSTER_AREALIGHTS\n if (isClusteredLightArea(light)) {\n decodeClusterLightAreaData(light);\n if (isClusteredLightRect(light)) {\n calcRectLightValues(light.position, light.halfWidth, light.halfHeight);\n } else if (isClusteredLightDisk(light)) {\n calcDiskLightValues(light.position, light.halfWidth, light.halfHeight);\n } else {\n calcSphereLightValues(light.position, light.halfWidth, light.halfHeight);\n }\n falloffAttenuation = getFalloffWindow(light.range, dLightDirW);\n } else\n #endif\n {\n if (isClusteredLightFalloffLinear(light))\n falloffAttenuation = getFalloffLinear(light.range, dLightDirW);\n else\n falloffAttenuation = getFalloffInvSquared(light.range, dLightDirW);\n }\n if (falloffAttenuation > 0.00001) {\n #ifdef CLUSTER_AREALIGHTS\n if (isClusteredLightArea(light)) {\n if (isClusteredLightRect(light)) {\n diffuseAttenuation = getRectLightDiffuse(worldNormal, viewDir, dLightDirW, dLightDirNormW) * 16.0;\n } else if (isClusteredLightDisk(light)) {\n diffuseAttenuation = getDiskLightDiffuse(worldNormal, viewDir, dLightDirW, dLightDirNormW) * 16.0;\n } else {\n diffuseAttenuation = getSphereLightDiffuse(worldNormal, viewDir, dLightDirW, dLightDirNormW) * 16.0;\n }\n } else\n #endif\n {\n falloffAttenuation *= getLightDiffuse(worldNormal, viewDir, dLightDirW, dLightDirNormW); \n }\n if (isClusteredLightSpot(light)) {\n decodeClusterLightSpot(light);\n falloffAttenuation *= getSpotEffect(light.direction, light.innerConeAngleCos, light.outerConeAngleCos, dLightDirNormW);\n }\n #if defined(CLUSTER_COOKIES_OR_SHADOWS)\n if (falloffAttenuation > 0.00001) {\n if (isClusteredLightCastShadow(light) || isClusteredLightCookie(light)) {\n if (isClusteredLightSpot(light)) {\n decodeClusterLightProjectionMatrixData(light);\n } else {\n decodeClusterLightOmniAtlasViewport(light);\n }\n float shadowTextureResolution = shadowAtlasParams.x;\n float shadowEdgePixels = shadowAtlasParams.y;\n #ifdef CLUSTER_COOKIES\n if (isClusteredLightCookie(light)) {\n decodeClusterLightCookieData(light);\n if (isClusteredLightSpot(light)) {\n cookieAttenuation = getCookie2DClustered(TEXTURE_PASS(cookieAtlasTexture), lightProjectionMatrix, vPositionW, light.cookieIntensity, isClusteredLightCookieRgb(light), light.cookieChannelMask);\n } else {\n cookieAttenuation = getCookieCubeClustered(TEXTURE_PASS(cookieAtlasTexture), dLightDirW, light.cookieIntensity, isClusteredLightCookieRgb(light), light.cookieChannelMask, shadowTextureResolution, shadowEdgePixels, light.omniAtlasViewport);\n }\n }\n #endif\n #ifdef CLUSTER_SHADOWS\n if (isClusteredLightCastShadow(light)) {\n decodeClusterLightShadowData(light);\n vec4 shadowParams = vec4(shadowTextureResolution, light.shadowNormalBias, light.shadowBias, 1.0 / light.range);\n if (isClusteredLightSpot(light)) {\n getShadowCoordPerspZbufferNormalOffset(lightProjectionMatrix, shadowParams, geometricNormal);\n \n #if defined(CLUSTER_SHADOW_TYPE_PCF1)\n float shadow = getShadowSpotClusteredPCF1(SHADOWMAP_PASS(shadowAtlasTexture), dShadowCoord, shadowParams);\n #elif defined(CLUSTER_SHADOW_TYPE_PCF3)\n float shadow = getShadowSpotClusteredPCF3(SHADOWMAP_PASS(shadowAtlasTexture), dShadowCoord, shadowParams);\n #elif defined(CLUSTER_SHADOW_TYPE_PCF5)\n float shadow = getShadowSpotClusteredPCF5(SHADOWMAP_PASS(shadowAtlasTexture), dShadowCoord, shadowParams);\n #elif defined(CLUSTER_SHADOW_TYPE_PCSS)\n float shadow = getShadowSpotClusteredPCSS(SHADOWMAP_PASS(shadowAtlasTexture), dShadowCoord, shadowParams);\n #endif\n falloffAttenuation *= mix(1.0, shadow, light.shadowIntensity);\n } else {\n vec3 dir = normalOffsetPointShadow(shadowParams, dLightPosW, dLightDirW, dLightDirNormW, geometricNormal);\n #if defined(CLUSTER_SHADOW_TYPE_PCF1)\n float shadow = getShadowOmniClusteredPCF1(SHADOWMAP_PASS(shadowAtlasTexture), shadowParams, light.omniAtlasViewport, shadowEdgePixels, dir);\n #elif defined(CLUSTER_SHADOW_TYPE_PCF3)\n float shadow = getShadowOmniClusteredPCF3(SHADOWMAP_PASS(shadowAtlasTexture), shadowParams, light.omniAtlasViewport, shadowEdgePixels, dir);\n #elif defined(CLUSTER_SHADOW_TYPE_PCF5)\n float shadow = getShadowOmniClusteredPCF5(SHADOWMAP_PASS(shadowAtlasTexture), shadowParams, light.omniAtlasViewport, shadowEdgePixels, dir);\n #endif\n falloffAttenuation *= mix(1.0, shadow, light.shadowIntensity);\n }\n }\n #endif\n }\n }\n #endif\n #ifdef CLUSTER_AREALIGHTS\n if (isClusteredLightArea(light)) {\n {\n vec3 areaDiffuse = (diffuseAttenuation * falloffAttenuation) * light.color * cookieAttenuation;\n #if defined(LIT_SPECULAR)\n areaDiffuse = mix(areaDiffuse, vec3(0), dLTCSpecFres);\n #endif\n dDiffuseLight += areaDiffuse;\n }\n #ifdef LIT_SPECULAR\n float areaLightSpecular;\n if (isClusteredLightRect(light)) {\n areaLightSpecular = getRectLightSpecular(worldNormal, viewDir);\n } else if (isClusteredLightDisk(light)) {\n areaLightSpecular = getDiskLightSpecular(worldNormal, viewDir);\n } else {\n areaLightSpecular = getSphereLightSpecular(worldNormal, viewDir);\n }\n dSpecularLight += dLTCSpecFres * areaLightSpecular * falloffAttenuation * light.color * cookieAttenuation;\n #ifdef LIT_CLEARCOAT\n float areaLightSpecularCC;\n if (isClusteredLightRect(light)) {\n areaLightSpecularCC = getRectLightSpecular(clearcoat_worldNormal, viewDir);\n } else if (isClusteredLightDisk(light)) {\n areaLightSpecularCC = getDiskLightSpecular(clearcoat_worldNormal, viewDir);\n } else {\n areaLightSpecularCC = getSphereLightSpecular(clearcoat_worldNormal, viewDir);\n }\n ccSpecularLight += ccLTCSpecFres * areaLightSpecularCC * falloffAttenuation * light.color * cookieAttenuation;\n #endif\n #endif\n } else\n #endif\n {\n {\n vec3 punctualDiffuse = falloffAttenuation * light.color * cookieAttenuation;\n #if defined(CLUSTER_AREALIGHTS)\n #if defined(LIT_SPECULAR)\n punctualDiffuse = mix(punctualDiffuse, vec3(0), specularity);\n #endif\n #endif\n dDiffuseLight += punctualDiffuse;\n }\n \n #ifdef LIT_SPECULAR\n vec3 halfDir = normalize(-dLightDirNormW + viewDir);\n \n #ifdef LIT_SPECULAR_FRESNEL\n dSpecularLight += \n getLightSpecular(halfDir, reflectionDir, worldNormal, viewDir, dLightDirNormW, gloss, tbn) * falloffAttenuation * light.color * cookieAttenuation * \n getFresnel(\n dot(viewDir, halfDir), \n gloss, \n specularity\n #if defined(LIT_IRIDESCENCE)\n , iridescenceFresnel,\n iridescence_intensity\n #endif\n );\n #else\n dSpecularLight += getLightSpecular(halfDir, reflectionDir, worldNormal, viewDir, dLightDirNormW, gloss, tbn) * falloffAttenuation * light.color * cookieAttenuation * specularity;\n #endif\n #ifdef LIT_CLEARCOAT\n #ifdef LIT_SPECULAR_FRESNEL\n ccSpecularLight += getLightSpecular(halfDir, clearcoatReflectionDir, clearcoat_worldNormal, viewDir, dLightDirNormW, clearcoat_gloss, tbn) * falloffAttenuation * light.color * cookieAttenuation * getFresnelCC(dot(viewDir, halfDir));\n #else\n ccSpecularLight += getLightSpecular(halfDir, clearcoatReflectionDir, clearcoat_worldNormal, viewDir, dLightDirNormW, clearcoat_gloss, tbn) * falloffAttenuation * light.color * cookieAttenuation; \n #endif\n #endif\n #ifdef LIT_SHEEN\n sSpecularLight += getLightSpecularSheen(halfDir, worldNormal, viewDir, dLightDirNormW, sheen_gloss) * falloffAttenuation * light.color * cookieAttenuation;\n #endif\n #endif\n }\n }\n dAtten = falloffAttenuation;\n dAttenD = diffuseAttenuation;\n dAtten3 = cookieAttenuation;\n}\nvoid evaluateClusterLight(\n float lightIndex, \n vec3 worldNormal, \n vec3 viewDir, \n vec3 reflectionDir, \n#if defined(LIT_CLEARCOAT)\n vec3 clearcoatReflectionDir,\n#endif\n float gloss, \n vec3 specularity, \n vec3 geometricNormal, \n mat3 tbn, \n#if defined(LIT_IRIDESCENCE)\n vec3 iridescenceFresnel,\n#endif\n vec3 clearcoat_worldNormal,\n float clearcoat_gloss,\n float sheen_gloss,\n float iridescence_intensity\n) {\n ClusterLightData clusterLightData;\n decodeClusterLightCore(clusterLightData, lightIndex);\n if (acceptLightMask(clusterLightData))\n evaluateLight(\n clusterLightData, \n worldNormal, \n viewDir, \n reflectionDir, \n#if defined(LIT_CLEARCOAT)\n clearcoatReflectionDir, \n#endif\n gloss, \n specularity, \n geometricNormal, \n tbn, \n#if defined(LIT_IRIDESCENCE)\n iridescenceFresnel,\n#endif\n clearcoat_worldNormal,\n clearcoat_gloss,\n sheen_gloss,\n iridescence_intensity\n );\n}\nvoid addClusteredLights(\n vec3 worldNormal, \n vec3 viewDir, \n vec3 reflectionDir, \n#if defined(LIT_CLEARCOAT)\n vec3 clearcoatReflectionDir,\n#endif\n float gloss, \n vec3 specularity, \n vec3 geometricNormal, \n mat3 tbn, \n#if defined(LIT_IRIDESCENCE)\n vec3 iridescenceFresnel,\n#endif\n vec3 clearcoat_worldNormal,\n float clearcoat_gloss,\n float sheen_gloss,\n float iridescence_intensity\n) {\n if (clusterSkip > 0.5)\n return;\n vec3 cellCoords = floor((vPositionW - clusterBoundsMin) * clusterCellsCountByBoundsSize);\n if (!(any(lessThan(cellCoords, vec3(0.0))) || any(greaterThanEqual(cellCoords, clusterCellsMax)))) {\n float cellIndex = dot(clusterCellsDot, cellCoords);\n float clusterV = floor(cellIndex * clusterTextureSize.y);\n float clusterU = cellIndex - (clusterV * clusterTextureSize.x);\n for (int lightCellIndex = 0; lightCellIndex < clusterMaxCells; lightCellIndex++) {\n float lightIndex = texelFetch(clusterWorldTexture, ivec2(int(clusterU) + lightCellIndex, clusterV), 0).x;\n if (lightIndex <= 0.0)\n return;\n evaluateClusterLight(\n lightIndex * 255.0, \n worldNormal, \n viewDir, \n reflectionDir,\n#if defined(LIT_CLEARCOAT)\n clearcoatReflectionDir,\n#endif\n gloss, \n specularity, \n geometricNormal, \n tbn, \n#if defined(LIT_IRIDESCENCE)\n iridescenceFresnel,\n#endif\n clearcoat_worldNormal,\n clearcoat_gloss,\n sheen_gloss,\n iridescence_intensity\n ); \n }\n }\n}\n";
export { clusteredLightPS as default };