//! Function computes contribution of spotlight source //! into global variable DirectLighting (PBR shading). //! @param theId light source index //! @param theNormal surface normal //! @param theView view direction //! @param thePoint 3D position (world space) //! @param theIsFront front/back face flag void occSpotLight (in int theId, in vec3 theNormal, in vec3 theView, in vec3 thePoint, in bool theIsFront) { vec3 aLight = occLight_Position (theId) - thePoint; float aDist = length (aLight); float aRange = occLight_Range (theId); float anAtten = occPointLightAttenuation (aDist, aRange); if (anAtten <= 0.0) return; aLight /= aDist; vec3 aSpotDir = occLight_SpotDirection (theId); // light cone float aCosA = dot (aSpotDir, -aLight); float aRelativeAngle = 2.0 * acos(aCosA) / occLight_SpotCutOff(theId); if (aCosA >= 1.0 || aRelativeAngle > 1.0) { return; } float anExponent = occLight_SpotExponent (theId); if ((1.0 - aRelativeAngle) <= anExponent) { float anAngularAttenuationOffset = cos(0.5 * occLight_SpotCutOff(theId)); float anAngularAttenuationScale = 1.0 / max(0.001, cos(0.5 * occLight_SpotCutOff(theId) * (1.0 - anExponent)) - anAngularAttenuationOffset); anAngularAttenuationOffset *= -anAngularAttenuationScale; float anAngularAttenuantion = clamp(aCosA * anAngularAttenuationScale + anAngularAttenuationOffset, 0.0, 1.0); anAtten *= anAngularAttenuantion * anAngularAttenuantion; } theNormal = theIsFront ? theNormal : -theNormal; DirectLighting += occPBRIllumination (theView, aLight, theNormal, BaseColor, Metallic, Roughness, IOR, occLight_Specular(theId), occLight_Intensity(theId) * anAtten); }