|
@@ -7,72 +7,139 @@ struct lightingInfo
|
|
|
#endif
|
|
|
};
|
|
|
|
|
|
+struct pointLightingInfo
|
|
|
+{
|
|
|
+ vec3 lightOffset;
|
|
|
+ float lightDistanceSquared;
|
|
|
+
|
|
|
+ float attenuation;
|
|
|
+};
|
|
|
+
|
|
|
+struct spotLightingInfo
|
|
|
+{
|
|
|
+ vec3 lightOffset;
|
|
|
+ float lightDistanceSquared;
|
|
|
+ vec3 directionToLightCenterW;
|
|
|
+
|
|
|
+ float attenuation;
|
|
|
+};
|
|
|
+
|
|
|
+float computeDistanceLightFalloff_Standard(vec3 lightOffset, float range)
|
|
|
+{
|
|
|
+ return max(0., 1.0 - length(lightOffset) / range);
|
|
|
+}
|
|
|
+
|
|
|
+float computeDistanceLightFalloff_Physical(float lightDistanceSquared)
|
|
|
+{
|
|
|
+ return 1.0 / ((lightDistanceSquared + 0.001));
|
|
|
+}
|
|
|
+
|
|
|
+float computeDistanceLightFalloff_GLTF(float lightDistanceSquared, float inverseSquaredRange)
|
|
|
+{
|
|
|
+ const float minDistanceSquared = 0.01*0.01;
|
|
|
+ float lightDistanceFalloff = 1.0 / (max(lightDistanceSquared, minDistanceSquared));
|
|
|
+
|
|
|
+ float factor = lightDistanceSquared * inverseSquaredRange;
|
|
|
+ float attenuation = clamp(1.0 - factor * factor, 0., 1.);
|
|
|
+ attenuation *= attenuation;
|
|
|
+
|
|
|
+ // Smooth attenuation of the falloff defined by the range.
|
|
|
+ lightDistanceFalloff *= attenuation;
|
|
|
+
|
|
|
+ return lightDistanceFalloff;
|
|
|
+}
|
|
|
+
|
|
|
float computeDistanceLightFalloff(vec3 lightOffset, float lightDistanceSquared, float range, float inverseSquaredRange)
|
|
|
{
|
|
|
#ifdef USEPHYSICALLIGHTFALLOFF
|
|
|
- float lightDistanceFalloff = 1.0 / ((lightDistanceSquared + 0.001));
|
|
|
+ return computeDistanceLightFalloff_Physical(lightDistanceSquared);
|
|
|
#elif defined(USEGLTFLIGHTFALLOFF)
|
|
|
- // Prevents infinity issues at 0.
|
|
|
- const float minDistanceSquared = 0.01*0.01;
|
|
|
- float lightDistanceFalloff = 1.0 / (max(lightDistanceSquared, minDistanceSquared));
|
|
|
-
|
|
|
- float factor = lightDistanceSquared * inverseSquaredRange;
|
|
|
- float attenuation = clamp(1.0 - factor * factor, 0., 1.);
|
|
|
- attenuation *= attenuation;
|
|
|
-
|
|
|
- // Smooth attenuation of the falloff defined by the range.
|
|
|
- lightDistanceFalloff *= attenuation;
|
|
|
+ return computeDistanceLightFalloff_GLTF(lightDistanceSquared, inverseSquaredRange);
|
|
|
#else
|
|
|
- float lightDistanceFalloff = max(0., 1.0 - length(lightOffset) / range);
|
|
|
+ return computeDistanceLightFalloff_Standard(lightOffset, range);
|
|
|
#endif
|
|
|
-
|
|
|
- return lightDistanceFalloff;
|
|
|
}
|
|
|
|
|
|
-float computeDirectionalLightFalloff(vec3 lightDirection, vec3 directionToLightCenterW, float cosHalfAngle, float exponent, float lightAngleScale, float lightAngleOffset)
|
|
|
+float computeDirectionalLightFalloff_Standard(vec3 lightDirection, vec3 directionToLightCenterW, float cosHalfAngle, float exponent)
|
|
|
{
|
|
|
float falloff = 0.0;
|
|
|
+
|
|
|
+ float cosAngle = max(0.000000000000001, dot(-lightDirection, directionToLightCenterW));
|
|
|
+ if (cosAngle >= cosHalfAngle)
|
|
|
+ {
|
|
|
+ falloff = max(0., pow(cosAngle, exponent));
|
|
|
+ }
|
|
|
|
|
|
+ return falloff;
|
|
|
+}
|
|
|
+
|
|
|
+float computeDirectionalLightFalloff_Physical(vec3 lightDirection, vec3 directionToLightCenterW, float cosHalfAngle)
|
|
|
+{
|
|
|
+ const float kMinusLog2ConeAngleIntensityRatio = 6.64385618977; // -log2(0.01)
|
|
|
+
|
|
|
+ // Calculate a Spherical Gaussian (von Mises-Fisher distribution, not angle-based Gaussian) such that the peak is in the light direction,
|
|
|
+ // and the value at the nominal cone angle is 1% of the peak. Because we want the distribution to decay from unity (100%)
|
|
|
+ // at the peak direction (dot product = 1) down to 1% at the nominal cone cutoff (dot product = cosAngle)
|
|
|
+ // the falloff rate expressed in terms of the base-two dot product is therefore -log2(ConeAngleIntensityRatio) / (1.0 - cosAngle).
|
|
|
+ // Note that the distribution is unnormalised in that peak density is unity, rather than the total energy is unity.
|
|
|
+ float concentrationKappa = kMinusLog2ConeAngleIntensityRatio / (1.0 - cosHalfAngle);
|
|
|
+
|
|
|
+ // Evaluate spherical gaussian for light directional falloff for spot light type (note: spot directional falloff;
|
|
|
+ // not directional light type)
|
|
|
+ vec4 lightDirectionSpreadSG = vec4(-lightDirection * concentrationKappa, -concentrationKappa);
|
|
|
+ float falloff = exp2(dot(vec4(directionToLightCenterW, 1.0), lightDirectionSpreadSG));
|
|
|
+ return falloff;
|
|
|
+}
|
|
|
+
|
|
|
+float computeDirectionalLightFalloff_GLTF(vec3 lightDirection, vec3 directionToLightCenterW, float lightAngleScale, float lightAngleOffset)
|
|
|
+{
|
|
|
+ // On the CPU
|
|
|
+ // float lightAngleScale = 1.0 f / max (0.001f, ( cosInner - cosOuter ));
|
|
|
+ // float lightAngleOffset = -cosOuter * angleScale;
|
|
|
+
|
|
|
+ float cd = dot(-lightDirection, directionToLightCenterW);
|
|
|
+ float falloff = clamp(cd * lightAngleScale + lightAngleOffset, 0., 1.);
|
|
|
+ // smooth the transition
|
|
|
+ falloff *= falloff;
|
|
|
+ return falloff;
|
|
|
+}
|
|
|
+
|
|
|
+float computeDirectionalLightFalloff(vec3 lightDirection, vec3 directionToLightCenterW, float cosHalfAngle, float exponent, float lightAngleScale, float lightAngleOffset)
|
|
|
+{
|
|
|
#ifdef USEPHYSICALLIGHTFALLOFF
|
|
|
- const float kMinusLog2ConeAngleIntensityRatio = 6.64385618977; // -log2(0.01)
|
|
|
-
|
|
|
- // Calculate a Spherical Gaussian (von Mises-Fisher distribution, not angle-based Gaussian) such that the peak is in the light direction,
|
|
|
- // and the value at the nominal cone angle is 1% of the peak. Because we want the distribution to decay from unity (100%)
|
|
|
- // at the peak direction (dot product = 1) down to 1% at the nominal cone cutoff (dot product = cosAngle)
|
|
|
- // the falloff rate expressed in terms of the base-two dot product is therefore -log2(ConeAngleIntensityRatio) / (1.0 - cosAngle).
|
|
|
- // Note that the distribution is unnormalised in that peak density is unity, rather than the total energy is unity.
|
|
|
- float concentrationKappa = kMinusLog2ConeAngleIntensityRatio / (1.0 - cosHalfAngle);
|
|
|
-
|
|
|
- // Evaluate spherical gaussian for light directional falloff for spot light type (note: spot directional falloff;
|
|
|
- // not directional light type)
|
|
|
- vec4 lightDirectionSpreadSG = vec4(-lightDirection * concentrationKappa, -concentrationKappa);
|
|
|
- falloff = exp2(dot(vec4(directionToLightCenterW, 1.0), lightDirectionSpreadSG));
|
|
|
+ return computeDirectionalLightFalloff_Physical(lightDirection, directionToLightCenterW, cosHalfAngle);
|
|
|
#elif defined(USEGLTFLIGHTFALLOFF)
|
|
|
- // On the CPU
|
|
|
- // float lightAngleScale = 1.0 f / max (0.001f, ( cosInner - cosOuter ));
|
|
|
- // float lightAngleOffset = -cosOuter * angleScale;
|
|
|
-
|
|
|
- float cd = dot(-lightDirection, directionToLightCenterW);
|
|
|
- falloff = clamp(cd * lightAngleScale + lightAngleOffset, 0., 1.);
|
|
|
- // smooth the transition
|
|
|
- falloff *= falloff;
|
|
|
+ return computeDirectionalLightFalloff_GLTF(lightDirection, directionToLightCenterW, lightAngleScale, lightAngleOffset);
|
|
|
#else
|
|
|
- float cosAngle = max(0.000000000000001, dot(-lightDirection, directionToLightCenterW));
|
|
|
- if (cosAngle >= cosHalfAngle)
|
|
|
- {
|
|
|
- falloff = max(0., pow(cosAngle, exponent));
|
|
|
- }
|
|
|
+ return computeDirectionalLightFalloff_Standard(lightDirection, directionToLightCenterW, cosHalfAngle, exponent);
|
|
|
#endif
|
|
|
-
|
|
|
- return falloff;
|
|
|
}
|
|
|
|
|
|
-lightingInfo computeDirectionalLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, float lightRadius, float roughness, float NdotV, vec3 reflectance0, vec3 reflectance90, float geometricRoughnessFactor, out float NdotL) {
|
|
|
- lightingInfo result;
|
|
|
+pointLightingInfo computePointLightingInfo(vec4 lightData) {
|
|
|
+ pointLightingInfo result;
|
|
|
|
|
|
- float lightDistance = length(-lightData.xyz);
|
|
|
- vec3 lightDirection = normalize(-lightData.xyz);
|
|
|
+ result.lightOffset = lightData.xyz - vPositionW;
|
|
|
+ result.lightDistanceSquared = dot(result.lightOffset, result.lightOffset);
|
|
|
+
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
+spotLightingInfo computeSpotLightingInfo(vec4 lightData) {
|
|
|
+ spotLightingInfo result;
|
|
|
|
|
|
+ result.lightOffset = lightData.xyz - vPositionW;
|
|
|
+ result.directionToLightCenterW = normalize(result.lightOffset);
|
|
|
+ result.lightDistanceSquared = dot(result.lightOffset, result.lightOffset);
|
|
|
+
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
+lightingInfo computePointLighting(pointLightingInfo info, vec3 viewDirectionW, vec3 vNormal, vec3 diffuseColor, float lightRadius, float roughness, float NdotV, vec3 reflectance0, vec3 reflectance90, float geometricRoughnessFactor, out float NdotL) {
|
|
|
+ lightingInfo result;
|
|
|
+
|
|
|
+ float lightDistance = sqrt(info.lightDistanceSquared);
|
|
|
+ vec3 lightDirection = normalize(info.lightOffset);
|
|
|
+
|
|
|
// Roughness
|
|
|
roughness = adjustRoughnessFromLightProperties(roughness, lightRadius, lightDistance);
|
|
|
|
|
@@ -82,83 +149,68 @@ lightingInfo computeDirectionalLighting(vec3 viewDirectionW, vec3 vNormal, vec4
|
|
|
float VdotH = clamp(dot(viewDirectionW, H), 0.0, 1.0);
|
|
|
|
|
|
float diffuseTerm = computeDiffuseTerm(NdotL, NdotV, VdotH, roughness);
|
|
|
- result.diffuse = diffuseTerm * diffuseColor;
|
|
|
+ result.diffuse = diffuseTerm * diffuseColor * info.attenuation;
|
|
|
|
|
|
#ifdef SPECULARTERM
|
|
|
// Specular
|
|
|
float NdotH = clamp(dot(vNormal, H), 0.000000000001, 1.0);
|
|
|
|
|
|
vec3 specTerm = computeSpecularTerm(NdotH, NdotL, NdotV, VdotH, roughness, reflectance0, reflectance90, geometricRoughnessFactor);
|
|
|
- result.specular = specTerm * diffuseColor;
|
|
|
+ result.specular = specTerm * diffuseColor * info.attenuation;
|
|
|
#endif
|
|
|
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
-lightingInfo computePointLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, float lightRadius, float roughness, float NdotV, vec3 reflectance0, vec3 reflectance90, float geometricRoughnessFactor, vec4 lightFalloff, out float NdotL) {
|
|
|
+lightingInfo computeSpotLighting(spotLightingInfo info, vec3 viewDirectionW, vec3 vNormal, vec4 lightDirection, vec3 diffuseColor, float lightRadius, float roughness, float NdotV, vec3 reflectance0, vec3 reflectance90, float geometricRoughnessFactor, out float NdotL) {
|
|
|
lightingInfo result;
|
|
|
|
|
|
- vec3 lightOffset = lightData.xyz - vPositionW;
|
|
|
- float lightDistanceSquared = dot(lightOffset, lightOffset);
|
|
|
- float attenuation = computeDistanceLightFalloff(lightOffset, lightDistanceSquared, lightFalloff.x, lightFalloff.y);
|
|
|
-
|
|
|
- float lightDistance = sqrt(lightDistanceSquared);
|
|
|
- vec3 lightDirection = normalize(lightOffset);
|
|
|
-
|
|
|
- // Roughness
|
|
|
+ // Roughness.
|
|
|
+ float lightDistance = sqrt(info.lightDistanceSquared);
|
|
|
roughness = adjustRoughnessFromLightProperties(roughness, lightRadius, lightDistance);
|
|
|
|
|
|
- // diffuse
|
|
|
- vec3 H = normalize(viewDirectionW + lightDirection);
|
|
|
- NdotL = clamp(dot(vNormal, lightDirection), 0.00000000001, 1.0);
|
|
|
+ // Diffuse
|
|
|
+ vec3 H = normalize(viewDirectionW + info.directionToLightCenterW);
|
|
|
+ NdotL = clamp(dot(vNormal, info.directionToLightCenterW), 0.000000000001, 1.0);
|
|
|
float VdotH = clamp(dot(viewDirectionW, H), 0.0, 1.0);
|
|
|
|
|
|
float diffuseTerm = computeDiffuseTerm(NdotL, NdotV, VdotH, roughness);
|
|
|
- result.diffuse = diffuseTerm * diffuseColor * attenuation;
|
|
|
+ result.diffuse = diffuseTerm * diffuseColor * info.attenuation;
|
|
|
|
|
|
#ifdef SPECULARTERM
|
|
|
// Specular
|
|
|
float NdotH = clamp(dot(vNormal, H), 0.000000000001, 1.0);
|
|
|
|
|
|
vec3 specTerm = computeSpecularTerm(NdotH, NdotL, NdotV, VdotH, roughness, reflectance0, reflectance90, geometricRoughnessFactor);
|
|
|
- result.specular = specTerm * diffuseColor * attenuation;
|
|
|
+ result.specular = specTerm * diffuseColor * info.attenuation;
|
|
|
#endif
|
|
|
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
-lightingInfo computeSpotLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec4 lightDirection, vec3 diffuseColor, vec3 specularColor, float lightRadius, float roughness, float NdotV, vec3 reflectance0, vec3 reflectance90, float geometricRoughnessFactor, vec4 lightFalloff, out float NdotL) {
|
|
|
+lightingInfo computeDirectionalLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, float lightRadius, float roughness, float NdotV, vec3 reflectance0, vec3 reflectance90, float geometricRoughnessFactor, out float NdotL) {
|
|
|
lightingInfo result;
|
|
|
|
|
|
- vec3 lightOffset = lightData.xyz - vPositionW;
|
|
|
- vec3 directionToLightCenterW = normalize(lightOffset);
|
|
|
+ float lightDistance = length(-lightData.xyz);
|
|
|
+ vec3 lightDirection = normalize(-lightData.xyz);
|
|
|
|
|
|
- // Distance falloff.
|
|
|
- float lightDistanceSquared = dot(lightOffset, lightOffset);
|
|
|
- float attenuation = computeDistanceLightFalloff(lightOffset, lightDistanceSquared, lightFalloff.x, lightFalloff.y);
|
|
|
-
|
|
|
- // Directional falloff.
|
|
|
- float directionalAttenuation = computeDirectionalLightFalloff(lightDirection.xyz, directionToLightCenterW, lightDirection.w, lightData.w, lightFalloff.z, lightFalloff.w);
|
|
|
- attenuation *= directionalAttenuation;
|
|
|
-
|
|
|
- // Roughness.
|
|
|
- float lightDistance = sqrt(lightDistanceSquared);
|
|
|
+ // Roughness
|
|
|
roughness = adjustRoughnessFromLightProperties(roughness, lightRadius, lightDistance);
|
|
|
|
|
|
- // Diffuse
|
|
|
- vec3 H = normalize(viewDirectionW + directionToLightCenterW);
|
|
|
- NdotL = clamp(dot(vNormal, directionToLightCenterW), 0.000000000001, 1.0);
|
|
|
+ // diffuse
|
|
|
+ vec3 H = normalize(viewDirectionW + lightDirection);
|
|
|
+ NdotL = clamp(dot(vNormal, lightDirection), 0.00000000001, 1.0);
|
|
|
float VdotH = clamp(dot(viewDirectionW, H), 0.0, 1.0);
|
|
|
|
|
|
float diffuseTerm = computeDiffuseTerm(NdotL, NdotV, VdotH, roughness);
|
|
|
- result.diffuse = diffuseTerm * diffuseColor * attenuation;
|
|
|
+ result.diffuse = diffuseTerm * diffuseColor;
|
|
|
|
|
|
#ifdef SPECULARTERM
|
|
|
// Specular
|
|
|
float NdotH = clamp(dot(vNormal, H), 0.000000000001, 1.0);
|
|
|
|
|
|
vec3 specTerm = computeSpecularTerm(NdotH, NdotL, NdotV, VdotH, roughness, reflectance0, reflectance90, geometricRoughnessFactor);
|
|
|
- result.specular = specTerm * diffuseColor * attenuation;
|
|
|
+ result.specular = specTerm * diffuseColor;
|
|
|
#endif
|
|
|
|
|
|
return result;
|