175 lines
5.2 KiB
GLSL
175 lines
5.2 KiB
GLSL
// XC_BUILTIN_FORWARD_LIT_OPENGL_PS
|
|
#version 430
|
|
layout(binding = 0) uniform sampler2D uBaseColorTexture;
|
|
layout(binding = 1) uniform sampler2D uShadowMapTexture;
|
|
|
|
layout(std140, binding = 0) uniform PerObjectConstants {
|
|
mat4 gProjectionMatrix;
|
|
mat4 gViewMatrix;
|
|
mat4 gModelMatrix;
|
|
mat4 gNormalMatrix;
|
|
};
|
|
|
|
const int XC_MAX_ADDITIONAL_LIGHTS = 8;
|
|
|
|
struct AdditionalLightData {
|
|
vec4 colorAndIntensity;
|
|
vec4 positionAndRange;
|
|
vec4 directionAndType;
|
|
vec4 spotAnglesAndFlags;
|
|
};
|
|
|
|
layout(std140, binding = 1) uniform LightingConstants {
|
|
vec4 gMainLightDirectionAndIntensity;
|
|
vec4 gMainLightColorAndFlags;
|
|
vec4 gLightingParams;
|
|
AdditionalLightData gAdditionalLights[XC_MAX_ADDITIONAL_LIGHTS];
|
|
};
|
|
|
|
layout(std140, binding = 2) uniform MaterialConstants {
|
|
vec4 gBaseColorFactor;
|
|
vec4 gAlphaCutoffParams;
|
|
};
|
|
|
|
layout(std140, binding = 3) uniform ShadowReceiverConstants {
|
|
mat4 gWorldToShadowMatrix;
|
|
vec4 gShadowBiasAndTexelSize;
|
|
vec4 gShadowOptions;
|
|
};
|
|
|
|
in vec3 vNormalWS;
|
|
in vec2 vTexCoord;
|
|
in vec3 vPositionWS;
|
|
|
|
layout(location = 0) out vec4 fragColor;
|
|
|
|
float ComputeShadowAttenuation(vec3 positionWS) {
|
|
#ifndef XC_MAIN_LIGHT_SHADOWS
|
|
return 1.0;
|
|
#else
|
|
if (gShadowOptions.x < 0.5) {
|
|
return 1.0;
|
|
}
|
|
|
|
vec4 shadowClip = gWorldToShadowMatrix * vec4(positionWS, 1.0);
|
|
if (shadowClip.w <= 0.0) {
|
|
return 1.0;
|
|
}
|
|
|
|
vec3 shadowNdc = shadowClip.xyz / shadowClip.w;
|
|
vec2 shadowUv = vec2(
|
|
shadowNdc.x * 0.5 + 0.5,
|
|
shadowNdc.y * 0.5 + 0.5);
|
|
if (shadowUv.x < 0.0 || shadowUv.x > 1.0 ||
|
|
shadowUv.y < 0.0 || shadowUv.y > 1.0 ||
|
|
shadowNdc.z < -1.0 || shadowNdc.z > 1.0) {
|
|
return 1.0;
|
|
}
|
|
|
|
float shadowDepth = texture(uShadowMapTexture, shadowUv).r;
|
|
float receiverDepth = shadowNdc.z * 0.5 + 0.5 - gShadowBiasAndTexelSize.x;
|
|
float shadowStrength = clamp(gShadowBiasAndTexelSize.w, 0.0, 1.0);
|
|
return receiverDepth <= shadowDepth ? 1.0 : (1.0 - shadowStrength);
|
|
#endif
|
|
}
|
|
|
|
float ComputeRangeAttenuation(float distanceSq, float range) {
|
|
if (range <= 0.0) {
|
|
return 0.0;
|
|
}
|
|
|
|
float clampedRange = max(range, 0.0001);
|
|
float rangeSq = clampedRange * clampedRange;
|
|
if (distanceSq >= rangeSq) {
|
|
return 0.0;
|
|
}
|
|
|
|
float distance = sqrt(max(distanceSq, 0.0));
|
|
float normalized = clamp(1.0 - distance / clampedRange, 0.0, 1.0);
|
|
return normalized * normalized;
|
|
}
|
|
|
|
float ComputeSpotAttenuation(AdditionalLightData light, vec3 directionToLightWS) {
|
|
float cosOuter = light.spotAnglesAndFlags.x;
|
|
float cosInner = light.spotAnglesAndFlags.y;
|
|
vec3 spotAxisToLightWS = normalize(light.directionAndType.xyz);
|
|
float cosTheta = dot(spotAxisToLightWS, directionToLightWS);
|
|
return clamp((cosTheta - cosOuter) / max(cosInner - cosOuter, 1e-4), 0.0, 1.0);
|
|
}
|
|
|
|
vec3 EvaluateAdditionalLight(AdditionalLightData light, vec3 normalWS, vec3 positionWS) {
|
|
float lightType = light.directionAndType.w;
|
|
vec3 lightColor = light.colorAndIntensity.rgb;
|
|
float lightIntensity = light.colorAndIntensity.w;
|
|
|
|
vec3 directionToLightWS = vec3(0.0);
|
|
float attenuation = 1.0;
|
|
|
|
if (lightType < 0.5) {
|
|
directionToLightWS = normalize(light.directionAndType.xyz);
|
|
} else {
|
|
vec3 lightVectorWS = light.positionAndRange.xyz - positionWS;
|
|
float distanceSq = dot(lightVectorWS, lightVectorWS);
|
|
if (distanceSq <= 1e-6) {
|
|
return vec3(0.0);
|
|
}
|
|
|
|
directionToLightWS = normalize(lightVectorWS);
|
|
attenuation = ComputeRangeAttenuation(distanceSq, light.positionAndRange.w);
|
|
if (attenuation <= 0.0) {
|
|
return vec3(0.0);
|
|
}
|
|
|
|
if (lightType > 1.5) {
|
|
attenuation *= ComputeSpotAttenuation(light, directionToLightWS);
|
|
if (attenuation <= 0.0) {
|
|
return vec3(0.0);
|
|
}
|
|
}
|
|
}
|
|
|
|
float diffuse = max(dot(normalWS, directionToLightWS), 0.0);
|
|
if (diffuse <= 0.0) {
|
|
return vec3(0.0);
|
|
}
|
|
|
|
return lightColor * (diffuse * lightIntensity * attenuation);
|
|
}
|
|
|
|
void main() {
|
|
vec4 baseColor = texture(uBaseColorTexture, vTexCoord) * gBaseColorFactor;
|
|
#ifdef XC_ALPHA_TEST
|
|
if (baseColor.a < gAlphaCutoffParams.x) {
|
|
discard;
|
|
}
|
|
#endif
|
|
int additionalLightCount = min(int(gLightingParams.x + 0.5), XC_MAX_ADDITIONAL_LIGHTS);
|
|
if (gMainLightColorAndFlags.w < 0.5 && additionalLightCount == 0) {
|
|
fragColor = baseColor;
|
|
return;
|
|
}
|
|
|
|
vec3 normalWS = normalize(vNormalWS);
|
|
vec3 lighting = gLightingParams.yyy;
|
|
|
|
if (gMainLightColorAndFlags.w >= 0.5) {
|
|
vec3 directionToLightWS = normalize(gMainLightDirectionAndIntensity.xyz);
|
|
float diffuse = max(dot(normalWS, directionToLightWS), 0.0);
|
|
float shadowAttenuation = diffuse > 0.0
|
|
? ComputeShadowAttenuation(vPositionWS)
|
|
: 1.0;
|
|
lighting +=
|
|
gMainLightColorAndFlags.rgb * (diffuse * gMainLightDirectionAndIntensity.w * shadowAttenuation);
|
|
}
|
|
|
|
for (int lightIndex = 0; lightIndex < XC_MAX_ADDITIONAL_LIGHTS; ++lightIndex) {
|
|
if (lightIndex >= additionalLightCount) {
|
|
break;
|
|
}
|
|
|
|
lighting += EvaluateAdditionalLight(gAdditionalLights[lightIndex], normalWS, vPositionWS);
|
|
}
|
|
|
|
fragColor = vec4(baseColor.rgb * lighting, baseColor.a);
|
|
}
|