aboutsummaryrefslogtreecommitdiff
path: root/apps/openmb/resources/shaders/textured_lit.frag
blob: 58c71f7812b1854f270fceb4a2da87032a59d9e0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#version 330 core

in vec2 vUV;
in vec3 vNormal;
in vec3 vFragPos;
in vec4 vFragPosLightSpace;
out vec4 FragColor;

uniform sampler2D albedo;
uniform sampler2D normalMap;
uniform int normalEnabled;
uniform float normalStrength;
uniform vec3 tint;
uniform int radialEnabled;
uniform float radialInner;
uniform float radialOuter;

struct DirectionalLight
{
    vec3 direction;
    vec3 color;
    float intensity;
};

uniform DirectionalLight dirLight;
uniform vec3 ambientColor = vec3(0.15, 0.15, 0.15);
uniform sampler2D shadowMap;
uniform float shadowBiasMin;
uniform float shadowBiasScale;
uniform int pcfRadius;
uniform sampler2D ssao;
uniform float aoStrength;
uniform float screenWidth;
uniform float screenHeight;

// Fog
uniform vec3 cameraPos;
uniform vec3 fogColor;
uniform float fogDensity; // e.g. 0.02
uniform float fogAmount;  // 0..1 blend factor
float ShadowCalculation(vec4 fragPosLightSpace, vec3 normal, vec3 lightDir)
{
    
    vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
    
    projCoords = projCoords * 0.5 + 0.5;
    
    if (projCoords.z > 1.0)
        return 0.0;

    
    float currentDepth = projCoords.z;
    
    float bias = max(shadowBiasScale * (1.0 - max(dot(normal, lightDir), 0.0)), shadowBiasMin);

    
    ivec2 texSize = textureSize(shadowMap, 0);
    vec2 texelSize = 1.0 / vec2(texSize);
    float vis = 0.0;
    int samples = 0;
    for (int x = -pcfRadius; x <= pcfRadius; ++x)
    {
        for (int y = -pcfRadius; y <= pcfRadius; ++y)
        {
            vec2 offset = vec2(x, y) * texelSize;
            float depthSample = texture(shadowMap, projCoords.xy + offset).r;
            // texture returns stored light-space depth. If our fragment's depth (minus bias)
            // is less than or equal to the sampled depth, it's visible to the light.
            vis += (currentDepth - bias <= depthSample) ? 1.0 : 0.0;
            samples++;
        }
    }
    float visibility = vis / float(samples);
    float shadow = 1.0 - visibility;
    return shadow;
}

void main()
{
    vec4 tex = texture(albedo, vUV);
    vec3 color = tex.rgb * tint;
    float alpha = tex.a;
    vec3 finalNormal = vec3(0.0, 0.0, 1.0);
    if (normalEnabled == 1)
    {
        vec3 n = texture(normalMap, vUV).rgb;
        n = n * 2.0 - 1.0;
        finalNormal = normalize(vec3(n.x * normalStrength, n.y * normalStrength, 1.0));
    }
    if (radialEnabled == 1)
    {
        float dist = distance(vUV, vec2(0.5, 0.5));
        float mask = 1.0 - smoothstep(radialInner, radialOuter, dist);
        alpha *= mask;
    }

    
    vec3 N = normalize(finalNormal);
    vec3 L = normalize(dirLight.direction);
    float diff = max(dot(N, L), 0.0);
    vec3 diffuse = dirLight.color * dirLight.intensity * diff;
    
    float shadow = ShadowCalculation(vFragPosLightSpace, N, L);
    float shadowFactor = 1.0 - shadow * 0.9; 
    float ao = 1.0;
    if (aoStrength > 0.0)
    {
        vec2 ssaoUV = gl_FragCoord.xy / vec2(screenWidth, screenHeight);
        ao = texture(ssao, ssaoUV).r;
    }
    float aoFactor = mix(1.0, ao, aoStrength);
    vec3 result = color * (ambientColor * aoFactor + diffuse * shadowFactor);

    // Compute fog based on distance from camera
    float dist = length(vFragPos - cameraPos);
    float fogFactor = 1.0 - exp(-fogDensity * dist);
    fogFactor = clamp(fogFactor * fogAmount, 0.0, 1.0);
    vec3 finalColor = mix(result, fogColor, fogFactor);

    FragColor = vec4(finalColor, alpha);
}