Files
REM-Mod/FLARDATA/Shader/lighting.fp

732 lines
22 KiB
GLSL

//This shader file is part of FLAR - Advanced Renderer for Freelancer by Schmackbolzen
//If you use the supplied shader files you may not modify them unless you state in them what you changed
//and also mention the source or who the author is.
//PBR lighting shader for FLAR by Schmackbolzen
//Sources are either mentioned in the comments below,
//from https://learnopengl.com/PBR/Lighting or https://learnopengl.com/PBR/IBL/Specular-IBL
//or "Parallel-Split Shadow Maps on Programmable GPUs" GPU Gems 3 (2005)
#version 330
#include "ColorConversion.inc"
#define MAX_SHADOWS $MAX_SHADOWS
#define NUM_SPLITS $NUM_SPLITS
#define USE_PCF $USE_PCF
#define USE_HQ_DIFFUSE $USE_HQ_DIFFUSE
#define USE_PARALLAX_MAPS $USE_PARALLAX_MAPS
#define USE_CLUSTERED_SHADING $USE_CLUSTERED_SHADING
//#define SIMPLE_KD
#define IBL_MULTIPLE_SCATTERING
#if USE_CLUSTERED_SHADING == 1
#define NUM_POSSIBLE_LIGHTS $NUM_POSSIBLE_LIGHTS
#define LIGHT_GRID_TILE_DIM_X $LIGHT_GRID_TILE_DIM_X
#define LIGHT_GRID_TILE_DIM_Y $LIGHT_GRID_TILE_DIM_Y
#define LIGHT_GRID_MAX_DIM_X $LIGHT_GRID_MAX_DIM_X
#define LIGHT_GRID_MAX_DIM_Y $LIGHT_GRID_MAX_DIM_Y
#endif
const float PBR_FACTOR = 2;
const float PBR_FACTOR_ENV = 1.5;
in vec3 eyeVec;
in vec3 v,vWorld,worldNormal;
in vec3 N;
in mat3 tbnMatrix,tbnMatrixObj;
in vec4 shadowCoord[MAX_SHADOWS*NUM_SPLITS];
in vec4 texCoords;
in mat3 worldRotMat;
in float alphaValue;
in float fogEnd;
in float fogScale;
struct Light{
vec3 ambient;
vec3 diffuse;
vec4 position;
vec3 spotDirection;
float spotExponent;
float spotCosPhi;
float spotCosTheta;
float constantAttenuation;
float linearAttenuation;
float quadraticAttenuation;
};
struct glFogParameters
{
vec3 color;
float density;
float start;
float end;
};
#if USE_CLUSTERED_SHADING == 1
//Has to be 16 byte aligned (otherwise it will be padded)
struct ClusteredLight{
vec4 position;
vec4 diffuse;
};
layout (std140) uniform LightSourceClustered
{
ClusteredLight clusteredLights[NUM_POSSIBLE_LIGHTS];
};
uniform isamplerBuffer clusterLightIndexListsTex;
uniform usamplerBuffer clusterGridTex;
#endif
uniform glFogParameters glFog;
uniform Light glLightSource[8];
uniform sampler2D tex;
uniform sampler2D tex2;
uniform sampler2D heightMap;
uniform sampler2D normalMap;
uniform sampler2D roughnessMap;
uniform sampler2D metalnessMap;
uniform sampler2D reflectionMap;
uniform sampler2D brdfLUT;
uniform sampler2DArrayShadow shadowMap[MAX_SHADOWS];
uniform float splitPlanes[NUM_SPLITS];
uniform samplerCube envMap;
uniform samplerCube irradianceMap;
uniform vec2 texture1Size;
uniform vec2 textureShadowSize;
uniform int lightCount;
uniform int shadowCount;
uniform int tex2Mode;
uniform int fogMode;
uniform float metalnessConst;
uniform float roughnessConst;
uniform float roughnessTextureBias;
uniform mat4 invWorldView;
uniform vec3 camPos;
uniform vec3 ambientColor;
uniform vec3 matAmbientColor;
uniform vec3 matDiffuseColor;
uniform vec3 matEmissiveColor;
uniform int alphaTestCompareMethod;
uniform float alphaTestValue;
uniform bool enableNormalMaps;
uniform bool enableParallaxMaps;
uniform bool enableFirstTexture;
uniform bool enableSecondTexture;
uniform bool enableFog;
uniform bool enableEnvMap;
uniform bool enableTex2Modulate2X;
uniform bool enableRoughnessMap;
uniform bool enableMetalnessMap;
uniform bool enableAlphaTest;
#if USE_CLUSTERED_SHADING == 1
uniform bool enableClusteredShading;
uniform float recNear; /**< 1.0f / g_near */
uniform float recLogSD1; /**< 1.0f / logf(sD + 1.0f), used to compute cluster index. */
#endif
float HEIGHT_SCALE = 0.01;
const float PI = 3.141592654;
out vec4 diffuseColorOut;
float ShadowCalculation(const float bias, const int shadowMapIndex, const int lightIndex, const sampler2DArrayShadow shadowSampler)
{
vec4 fragPosLightSpace = shadowCoord[lightIndex*NUM_SPLITS+shadowMapIndex];
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
#if USE_PCF == 1
float currentDepth = clamp(projCoords.z,0,1);
// Check whether current frag pos is in shadow
//if(projCoords.z <= 1.0)
{
float shadow = 0.0;
vec2 texelSize = 1.0 / vec2(textureShadowSize);
for(int x = -1; x <= 1; ++x)
{
for(int y = -1; y <= 1; ++y)
{
float pcfDepth = clamp(texture(shadowSampler, vec4(projCoords.xy + vec2(x, y) * texelSize, shadowMapIndex, projCoords.z - bias)),0,1);
shadow += pcfDepth;
}
}
shadow *= 1.0/9.0;
return shadow;
}
//else
//return 1;
#else
return texture(shadowSampler, vec4(projCoords.xy, shadowMapIndex, projCoords.z - bias));
#endif
}
float ShadowCalculationForAllSplitPlanes(const int lightIndex, const vec3 lightDirViewSpace, const vec3 normal, float lightIntensity, const sampler2DArrayShadow shadowSampler)
{
float distance = v.z;
float bias = max(0.001 * (1.0 - dot(normal, lightDirViewSpace)), 0.0003);
bool applied = false;
for (int i = 0; i < NUM_SPLITS; i++)
if(!applied && (distance < splitPlanes[i]))
{
//bias = ((i+1)*0.1)*0.001;
lightIntensity *= ShadowCalculation(bias, i, lightIndex, shadowSampler);
applied=true;
//Graphics cards hate break (SLOW), hence boolean value above
//break;
}
return lightIntensity;
}
//Parallax mapping with offset limiting
//You can try different parallax mapping techniques, but they all have problems with steep angles so I decided this is something for later
vec2 ParallaxMapping(vec3 V, vec2 T)
{
// get depth for this fragment
float initialHeight = texture2D(heightMap, T).r-0.5;
// calculate amount of offset for Parallax Mapping With Offset Limiting
vec2 texCoordOffset = HEIGHT_SCALE * V.xy * initialHeight;
// return modified texture coordinates
return T + texCoordOffset;
}
float DistributionGGX(float NdotH, float roughnessSquared)
{
float a = roughnessSquared;
float a2 = a*a;
float NdotH2 = NdotH*NdotH;
float nom = a2;
float denom = NdotH2 * (a2 - 1.0) + 1.0;
denom = PI * denom * denom + 0.0001;
return nom / denom;
}
//"PBR Diffuse Lighting for GGX+Smith Microsurfaces", Earl Hammon, Jr.
float GeometrySmithG2HammonDenom(float NdotL, float NdotV, float roughnessSquared)
{
float denom = mix(2*NdotL*NdotV,NdotL+NdotV,roughnessSquared);
return denom;
}
vec3 fresnelSchlick(float cosTheta, vec3 F0)
{
return F0 + (1.0 - F0) * pow(max(1.0 - cosTheta,0), 5.0);
}
vec3 fresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness)
{
return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(max(1.0 - cosTheta, 0.0), 5.0);
}
struct LightValues
{
vec3 lightVec;
vec3 lightDir;
vec3 lightDirViewSpace;
float attenFactor;
float lightDist;
};
LightValues CalculateLightValues(const int index)
{
LightValues result;
if(glLightSource[index].spotCosTheta != -1.)
{
result.lightVec = glLightSource[index].position.xyz - v;
result.lightDirViewSpace=normalize(result.lightVec);
result.lightDist = length(result.lightVec);
result.lightDir = normalize(result.lightVec);
float angle = max(dot(normalize(glLightSource[index].spotDirection), -result.lightDir),0);
if (angle > glLightSource[index].spotCosPhi)
{
float spotAtten;
if (angle < glLightSource[index].spotCosTheta)
spotAtten = (angle-glLightSource[index].spotCosPhi)/(glLightSource[index].spotCosTheta-glLightSource[index].spotCosPhi);
else
spotAtten = 1;
if(glLightSource[index].spotExponent != 1.0)
spotAtten = pow(spotAtten, glLightSource[index].spotExponent);
result.attenFactor = spotAtten * min(1.0/ (glLightSource[index].constantAttenuation +
glLightSource[index].linearAttenuation * result.lightDist +
glLightSource[index].quadraticAttenuation * result.lightDist * result.lightDist),1);
}
else
result.attenFactor = 0.;
}
else if (glLightSource[index].position.w != 0.0)
{
result.lightVec = glLightSource[index].position.xyz - v;
result.lightDirViewSpace=normalize(result.lightVec);
result.lightDist = length(result.lightVec);
if (enableNormalMaps)
result.lightVec = tbnMatrix*result.lightVec;
result.lightDir = normalize(result.lightVec);
// positional light source
result.attenFactor = clamp(1.0/( glLightSource[index].constantAttenuation +
glLightSource[index].linearAttenuation * result.lightDist +
glLightSource[index].quadraticAttenuation * result.lightDist * result.lightDist ),0,1);
}
else
{
// directional light source
result.attenFactor = 1.0;
if (enableNormalMaps)
{
result.lightDirViewSpace=normalize(glLightSource[index].position.xyz);
result.lightVec = tbnMatrix*glLightSource[index].position.xyz;
result.lightDir = normalize(result.lightVec);
}
else
{
result.lightVec = glLightSource[index].position.xyz;
result.lightDir = normalize(result.lightVec);
result.lightDirViewSpace = result.lightDir;
}
result.lightDist = length(result.lightVec);
}
return result;
}
#if USE_CLUSTERED_SHADING == 1
LightValues CalculateLightValuesClustered(const int index)
{
LightValues result;
result.lightVec = clusteredLights[index].position.xyz - v;
result.lightDirViewSpace=normalize(result.lightVec);
result.lightDist = length(result.lightVec);
if (enableNormalMaps)
result.lightVec = tbnMatrix*result.lightVec;
result.lightDir = normalize(result.lightVec);
// positional light source
float inner = 0.0;
float att = max(1.0 - max(0.0, (result.lightDist - inner) / (clusteredLights[index].position.w - inner)), 0.0);
result.attenFactor = att;
return result;
}
#endif
vec3 ApplyAmbientLight(const int index,const vec3 firstTexture, const float intensity, vec3 lightSum)
{
vec3 IAmbient = (matAmbientColor)*(PBR_FACTOR*glLightSource[index].ambient)*firstTexture;
lightSum.rgb += IAmbient*intensity;
return lightSum;
}
vec3 ApplyPBRLight(vec3 lightDiffuseColor, const LightValues lightValues, const vec3 mapNormal, const vec3 eyeV, const vec3 F0, const float roughness, const vec3 IDiffuse, const vec3 firstTexture, vec3 lightSum, const float metalness)
{
float visible = 1.0;
float intensity = lightValues.attenFactor;
//vec3 IAmbient = (matAmbientColor.rgb)*(PBR_FACTOR*glLightSource[index].ambient)*firstTexture;
//lightSum.rgb += IAmbient*intensity;
vec3 L = lightValues.lightDir;
vec3 V = normalize(eyeV);
vec3 H = normalize(L + V);
vec3 reflected;
vec3 N = mapNormal;
float HdotV = max(dot(H, V), 0.0);
float NdotL = max(dot(N, L), 0.0);
float NdotV = max(dot(N, V), 0.0001);
float NdotH = max(dot(N, H), 0.0001);
vec3 F = fresnelSchlick(HdotV, F0);
// Cook-Torrance BRDF
float roughnessSquared = roughness*roughness;
float NDF = DistributionGGX(NdotH, roughnessSquared);
vec3 nominator = NDF * F;
float denominator = 2.0 * GeometrySmithG2HammonDenom(NdotV, NdotL, roughnessSquared) + 0.00001; // 0.00001 to prevent divide by zero.
vec3 specular = nominator/denominator;
#ifndef SIMPLE_KD
vec3 kD=mix(vec3(1.0)-F,vec3(0.0),metalness);
#else
float kD = 1.0 - metalness;
#endif
#if USE_HQ_DIFFUSE == 1
//GGX Diffuse Approximation from
//"PBR Diffuse Lighting for GGX+Smith Microsurfaces, Earl Hammon, Jr."
float LdotV = dot(L, V);
float facing = 0.5+0.5*LdotV;
float rough = facing*(0.9-0.4*facing)*(.5/(NdotH+0.05) + 1); //+0.05 to prevent too large values
float smooth_ = 1.05*(1-pow(1-NdotL,5))*(1-pow(1-NdotV,5));
float single = 1./PI*mix(smooth_, rough, roughnessSquared);
float multi = 0.1159*roughnessSquared;
vec3 diffuse = kD*IDiffuse.rgb*(single+IDiffuse.rgb*multi);
#else
vec3 diffuse = kD*IDiffuse.rgb/PI;
#endif
lightSum+= PBR_FACTOR*lightDiffuseColor*(diffuse + specular)*intensity*NdotL;
return lightSum;
}
vec3 ApplyLight(const int index, const LightValues lightValues, const vec3 mapNormal, const vec3 eyeV, const vec3 F0, const float roughness, const vec3 IDiffuse, const vec3 firstTexture, vec3 lightSum, const float metalness)
{
lightSum=ApplyAmbientLight(index, firstTexture, lightValues.attenFactor, lightSum);
lightSum=ApplyPBRLight(glLightSource[index].diffuse.rgb, lightValues, mapNormal, eyeV, F0, roughness, IDiffuse, firstTexture, lightSum, metalness);
return lightSum;
}
#if USE_CLUSTERED_SHADING == 1
//Clustered shading code partially from
//"Demo code implementing Clustered Forward Shading, accompanying the talk
//'Tiled and Clustered Forward Shading' presented at Siggraph 2012."
/**
* Computes the {i,j,k} integer index into the cluster grid. For details see our paper:
* 'Clustered Deferred and Forward Shading'
* http://www.cse.chalmers.se/~olaolss/main_frame.php?contents=publication&id=clustered_shading
*/
ivec3 calcClusterLoc(vec2 fragPos, float viewSpaceZ)
{
// i and j coordinates are just the same as tiled shading, and based on screen space position.
ivec2 l = ivec2(int(fragPos.x) / LIGHT_GRID_TILE_DIM_X, int(fragPos.y) / LIGHT_GRID_TILE_DIM_Y);
// k is based on the log of the view space Z coordinate.
float gridLocZ = log(viewSpaceZ * recNear) * recLogSD1;
return ivec3(l, int(gridLocZ));
}
/**
* Linearlizes the 3D cluster location into an offset, which can be used as an
* address into a linear buffer.
*/
int calcClusterOffset(ivec3 clusterLoc)
{
return (clusterLoc.z * LIGHT_GRID_MAX_DIM_Y + clusterLoc.y) * LIGHT_GRID_MAX_DIM_X + clusterLoc.x;
}
/**
* Convenience shorthand function, see above...
*/
int calcClusterOffset(vec2 fragPos, float viewSpaceZ)
{
return calcClusterOffset(calcClusterLoc(fragPos, viewSpaceZ));
}
vec3 ApplyClusteredLights(const vec3 mapNormal, const vec3 eyeV, const vec3 F0, const float roughness, const vec3 IDiffuse, const vec3 firstTexture, vec3 lightSum, const float metalness)
{
// fetch cluster data (i.e. offset to light indices, and numer of lights) from grid buffer.
uvec2 offsetCount = texelFetch(clusterGridTex, calcClusterOffset(gl_FragCoord.xy, v.z)).xy;
int lightOffset = int(offsetCount.x);
int lightCount = int(offsetCount.y);
for (int i = 0; i < lightCount; ++i)
{
// fetch light index from list of lights for the cluster.
int lightIndex = texelFetch(clusterLightIndexListsTex, lightOffset + i).x;
LightValues lightValues = CalculateLightValuesClustered(lightIndex);
// compute and accumulate shading.
lightSum = ApplyPBRLight(clusteredLights[lightIndex].diffuse.rgb*2, lightValues, mapNormal, eyeV, F0, roughness, IDiffuse, firstTexture, lightSum, metalness);
}
return lightSum;
}
#endif
void main(void)
{
float fogFactor = 0;
bool enableFog = false;
if (enableFog && fogMode > 0)
{
//Radial fog
float z = length(v);
if (fogMode == 3)
{
fogFactor = (fogEnd - z) * fogScale;
}
else if (fogMode == 1)
{
fogFactor = 1.0/exp(glFog.density * z);
}
else if (fogMode == 2)
{
fogFactor = 1.0 /exp( (z * glFog.density)* (z * glFog.density));
}
fogFactor = clamp(fogFactor, 0.0, 1.0);
}
vec3 eyeV=normalize(eyeVec);
vec3 normal=normalize(N);
vec2 texCoordsProcessed;
#if USE_PARALLAX_MAPS == 1
if (enableParallaxMaps)
texCoordsProcessed = ParallaxMapping(eyeV, texCoords.st);
else
#endif
texCoordsProcessed = texCoords.st;
vec4 firstTexture;
vec4 lightSum = vec4(0);
if (enableFirstTexture)
{
firstTexture = texture2D(tex, texCoordsProcessed);
if (enableSecondTexture)
{
if(tex2Mode == 0)
{
firstTexture *= texture2D(tex2, texCoords.pq);
if (enableTex2Modulate2X)
firstTexture.rgb*=4.6; //2^2.2 since rendering is gamma correct
}
else
{
lightSum.rgb += texture2D(tex2, texCoords.pq).rgb;
}
}
}
else{
firstTexture = vec4(1,1,1,1);
}
float alpha = alphaValue*firstTexture.a;
if (enableAlphaTest)
if(alphaTestCompareMethod==5)
{
if( alpha <= alphaTestValue)
discard;
}
else if(alphaTestCompareMethod==2)
{
if( alpha > alphaTestValue)
discard;
}
else
firstTexture =vec4(1,0,0,1);
vec3 mapNormal;
if (enableNormalMaps)
{
vec3 textureNormal = texture2D(normalMap, texCoordsProcessed).rgb;
textureNormal.g = 1.0 - textureNormal.g; // Invertiere den grünen Kanal für OpenGL
// Verstärkung der Normal Map Intensität
float intensity = 2.0; // Faktor zur Verstärkung, passe diesen Wert nach Bedarf an
textureNormal.xy = (textureNormal.rg * 2.0 - 1.0) * intensity;
// Rekalkuliere die Z-Komponente und normalisiere die Normal Map
textureNormal.z = sqrt(max(0.0, 1.0 - dot(textureNormal.xy, textureNormal.xy)));
mapNormal = normalize(textureNormal);
}
else
mapNormal = normal;
lightSum+=vec4(((matEmissiveColor.rgb))* firstTexture.rgb, alpha);
float metalness;
if (enableMetalnessMap)
{
metalness=texture2D(metalnessMap, texCoordsProcessed.st).r;
}
else
{
metalness=metalnessConst;
}
vec3 IDiffuse = (matDiffuseColor)*firstTexture.rgb;
float roughness;
if (enableRoughnessMap)
{
roughness=clamp(roughnessTextureBias+texture2D(roughnessMap, texCoordsProcessed.st).r,0.0,1.0);
}
else
{
roughness=roughnessConst;
}
#define DIELECTRIC_SPECULAR 0.04
vec3 F0 = mix(vec3(DIELECTRIC_SPECULAR), IDiffuse, metalness);
if (enableEnvMap)
{
vec3 n;
if (enableNormalMaps)
n=normalize( worldRotMat * (tbnMatrixObj * mapNormal ));
else
n=normalize(worldNormal);
vec3 v = normalize( camPos - vWorld);
vec3 reflectDir = reflect(-v, n);
const float MAX_REFLECTION_LOD = 7;
float lod = roughness * (2.0 - roughness) * MAX_REFLECTION_LOD;
vec3 irradiance;
vec3 radiance;
if (enableFog)
{
vec3 ambientTint=PBR_FACTOR_ENV*glFog.color.rgb;
irradiance = vec3(texture(irradianceMap, n).r)*ambientTint;
radiance = vec3(textureLod(envMap, reflectDir, lod).r)*ambientTint;
}
else
{
irradiance = texture(irradianceMap, n).rgb*PBR_FACTOR_ENV;
radiance = textureLod(envMap, reflectDir, lod).rgb*PBR_FACTOR_ENV;
}
float NdotV = max(dot(n,v),0.0);
vec2 brdf = texture(brdfLUT, vec2(NdotV, roughness)).rg;
#ifdef IBL_MULTIPLE_SCATTERING
vec3 diffuseColor = mix(IDiffuse.rgb, vec3(0), metalness);
// Multiple scattering, from:
//"A Multiple-Scattering Microfacet Model for Real-Time Image-based Lighting", Carmelo J. Fdez-Agüera
vec3 kS = F0;
vec3 FssEss = kS * brdf.x + brdf.y;
float Ess = brdf.x + brdf.y;
float Ems = 1.0-Ess;
vec3 Favg = F0 + (1.0-F0)/21.0;
vec3 Fms = FssEss*Favg/(1.0-Ems*Favg);
vec3 FmsEms = Fms * Ems;
// Dielectrics
vec3 Edss = 1.0 - (FssEss + FmsEms);
vec3 kD = diffuseColor * Edss;
// Composition
lightSum.rgb += FssEss * radiance + (FmsEms+kD) * irradiance;
#else
vec3 diffuse = irradiance * IDiffuse;
vec3 F = fresnelSchlickRoughness(NdotV, F0, roughness);
#ifndef SIMPLE_KD
vec3 kD=mix(vec3(1.0)-F,vec3(0.0),metalness);
#else
float kD = 1.0 - metalness;
#endif
vec3 specular = radiance * (F0 * brdf.x + brdf.y);
lightSum.rgb += kD*diffuse + specular;
#endif
}
else
{
if (enableNormalMaps)
{
vec3 dir = vec3(0,0,1);
float ambientIntensity = dot(dir,mapNormal);
lightSum.rgb+=matAmbientColor.rgb * ambientColor.rgb* ambientIntensity*IDiffuse.rgb;
}
else
lightSum.rgb+=matAmbientColor.rgb * ambientColor.rgb* IDiffuse.rgb;
}
//Unrolled loop and a separated shadow pass to help some glsl compilers. Also some glsl compilers need a constant value (not variable!) for sampler arrays.
if(lightCount > 0)
{
const int lightIndex = 0;
LightValues lightValues = CalculateLightValues(lightIndex);
#if MAX_SHADOWS > 0
if (shadowCount > 0)
lightValues.attenFactor = ShadowCalculationForAllSplitPlanes(lightIndex, lightValues.lightDirViewSpace, normal, lightValues.attenFactor, shadowMap[0]);
#endif
lightSum.rgb = ApplyLight(lightIndex, lightValues, mapNormal, eyeV, F0, roughness, IDiffuse.rgb, firstTexture.rgb, lightSum.rgb, metalness);
}
if(lightCount > 1)
{
const int lightIndex = 1;
LightValues lightValues = CalculateLightValues(lightIndex);
#if MAX_SHADOWS > 1
if (shadowCount > 1)
lightValues.attenFactor = ShadowCalculationForAllSplitPlanes(lightIndex, lightValues.lightDirViewSpace, normal, lightValues.attenFactor, shadowMap[1]);
#endif
lightSum.rgb = ApplyLight(lightIndex, lightValues, mapNormal, eyeV, F0, roughness, IDiffuse.rgb, firstTexture.rgb, lightSum.rgb, metalness);
}
if (lightCount > 2)
{
const int lightIndex = 2;
LightValues lightValues = CalculateLightValues(lightIndex);
lightSum.rgb = ApplyLight(lightIndex, lightValues, mapNormal, eyeV, F0, roughness, IDiffuse.rgb, firstTexture.rgb, lightSum.rgb, metalness);
}
if (lightCount > 3)
{
const int lightIndex = 3;
LightValues lightValues = CalculateLightValues(lightIndex);
lightSum.rgb = ApplyLight(lightIndex, lightValues, mapNormal, eyeV, F0, roughness, IDiffuse.rgb, firstTexture.rgb, lightSum.rgb, metalness);
}
if (lightCount > 4)
{
const int lightIndex = 4;
LightValues lightValues = CalculateLightValues(lightIndex);
lightSum.rgb = ApplyLight(lightIndex, lightValues, mapNormal, eyeV, F0, roughness, IDiffuse.rgb, firstTexture.rgb, lightSum.rgb, metalness);
}
if (lightCount > 5)
{
const int lightIndex = 5;
LightValues lightValues = CalculateLightValues(lightIndex);
lightSum.rgb = ApplyLight(lightIndex, lightValues, mapNormal, eyeV, F0, roughness, IDiffuse.rgb, firstTexture.rgb, lightSum.rgb, metalness);
}
if (lightCount > 6)
{
const int lightIndex = 6;
LightValues lightValues = CalculateLightValues(lightIndex);
lightSum.rgb = ApplyLight(lightIndex, lightValues, mapNormal, eyeV, F0, roughness, IDiffuse.rgb, firstTexture.rgb, lightSum.rgb, metalness);
}
if (lightCount > 7)
{
const int lightIndex = 7;
LightValues lightValues = CalculateLightValues(lightIndex);
lightSum.rgb = ApplyLight(lightIndex, lightValues, mapNormal, eyeV, F0, roughness, IDiffuse.rgb, firstTexture.rgb, lightSum.rgb, metalness);
}
#if USE_CLUSTERED_SHADING == 1
if(enableClusteredShading)
lightSum.rgb = ApplyClusteredLights(mapNormal, eyeV, F0, roughness, IDiffuse.rgb, firstTexture.rgb, lightSum.rgb, metalness);
#endif
vec4 finalColor = lightSum;
if (enableFog && fogMode > 0)
{
finalColor = mix(vec4(glFog.color,1.0),finalColor, fogFactor);
}
diffuseColorOut=vec4(ToGammaCorrected(finalColor.rgb),finalColor.a);
}