summaryrefslogtreecommitdiff
path: root/src/assets/shaders/common/frag.glsl
blob: 26d63fa6d8b235b6860123399bace55ae2dc2338 (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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#version 300 es
precision highp float;

uniform vec3 camera_pos;
uniform float time;

uniform vec3 light_ambient_color;
uniform vec3 light_dir;
uniform vec3 light_dir_color;
uniform int light_count;
uniform vec3 light_pos[5];
uniform vec3 light_color[5];
uniform vec2 light_attenuation[5];
uniform highp sampler2DShadow light_shadowbuffer_dir;
uniform samplerCube light_shadowbuffer_point[5];

uniform int has_point_shadows;

in vec2 vertex_texcoord;
in vec3 vertex_normal;
in vec3 vertex_fragpos;
in vec4 vertex_fragpos_shadow_dir;
in vec3 vertex_view_vector;

out vec4 frag_color;

mat3 compute_tbn() {
    vec3 p = -vertex_view_vector;
    vec3 normal = normalize(vertex_normal);
    vec3 dpx = dFdx(p);
    vec3 dpy = dFdy(p);
    vec2 duvx = dFdx(vertex_texcoord);
    vec2 duvy = dFdy(vertex_texcoord);
    vec3 dpyperp = cross(dpy, normal);
    vec3 dpxperp = cross(normal, dpx);
    vec3 tangent = dpyperp * duvx.x + dpxperp * duvy.x;
    vec3 bitangent = dpyperp * duvx.y + dpxperp * duvy.y;
    float invmax = inversesqrt(max(dot(bitangent, bitangent), dot(bitangent, bitangent)));
    return mat3(-tangent * invmax, -bitangent * invmax, normal);
}

vec4 normal_as_color(vec3 n) {
    float r = (128.0 + 127.0 * n.r) / 255.0;
    float g = (128.0 + 127.0 * n.g) / 255.0;
    float b = (128.0 + 127.0 * n.b) / 255.0;
    return vec4(r, g, b, 1.0);
}

vec3 dir_light(vec3 normal) {
    return max(dot(normal, -normalize(light_dir)), 0.0) * light_dir_color;
}

float dir_shadow(vec3 normal) {
    vec3 proj = vertex_fragpos_shadow_dir.xyz / vertex_fragpos_shadow_dir.w;
    float bias = 0.002;
    // float current_depth = proj.z;
    // float bias = max(0.05 * (1.0 - dot(normal, -normalize(light_dir))), 0.005);
    proj.z -= bias;
    proj *= 0.5; proj += 0.5;
    if (proj.z > 1.0) return 0.0;
    return 1.0 - texture(light_shadowbuffer_dir, proj.xyz);
}

float point_shadow(vec3 normal, vec3 shadow_vector, float closest_depth) {
    closest_depth *= 25.0;
    float current_depth = length(shadow_vector);
    float bias = max(0.1 * (1.0 - dot(normal, normalize(shadow_vector))), 0.005);
    bias = min(bias + current_depth * 0.01, 0.2);
    float shadow = current_depth - bias > closest_depth ? 1.0 : 0.0; 
    return shadow;
}

vec3 point_light(vec3 normal, const int idx) {
    vec3 pos = light_pos[idx];
    vec3 color = light_color[idx];
    float linear = light_attenuation[idx].x;
    float quadratic = light_attenuation[idx].y;
    vec3 light_vector = pos - vertex_fragpos;
    float distance = length(light_vector);
    float attenuation = 1.0 / (1.0 + distance * linear + distance * distance * quadratic);

    float directional = max(dot(normal.xyz, normalize(light_vector)), 0.0);
    vec3 directional_light = color * directional;

    vec3 view_dir = normalize(camera_pos - vertex_fragpos);
    vec3 reflect_dir = reflect(-normalize(light_vector), normalize(normal.xyz));
    float specular = pow(max(dot(view_dir, reflect_dir), 0.0), 32.0);
    vec3 specular_light = 0.5 * specular * color;
    // return (directional_light + specular_light) * attenuation;
    return directional_light * attenuation;
}

vec3 point_light_billboard(const int idx) {
    vec3 pos = light_pos[idx];
    vec3 color = light_color[idx];
    float linear = light_attenuation[idx].x;
    float quadratic = light_attenuation[idx].y;
    vec3 light_vector = pos - vertex_fragpos;
    float distance = length(light_vector);
    float attenuation = 1.0 / (1.0 + distance * linear + distance * distance * quadratic);

    return color * attenuation;
}

vec3 compute_lighting(vec3 normal) {
    vec3 ambient_light = light_ambient_color;

    vec3 from_dir = dir_light(normal) * (1.0 - dir_shadow(normal));

    vec3 shadow_vector[5];
    for (int i = 0; i < light_count; ++i) {
        shadow_vector[i] = vertex_fragpos - light_pos[i];
        shadow_vector[i].x *= -1.0;
    }

    // cannot only index array of samplers with a constant, hence the weird setup
    #define SAMPLE_SHADOW(n) n < light_count ? texture(light_shadowbuffer_point[n], shadow_vector[n]).r : 1.0
    float shadow_depth[5];
    shadow_depth[0] = SAMPLE_SHADOW(0);
    shadow_depth[1] = SAMPLE_SHADOW(1);
    shadow_depth[2] = SAMPLE_SHADOW(2);
    shadow_depth[3] = SAMPLE_SHADOW(3);
    shadow_depth[4] = SAMPLE_SHADOW(4);

    vec3 from_points = vec3(0.0, 0.0, 0.0);
    for (int i = 0; i < light_count; ++i) {
        from_points += has_point_shadows != 0
            ? point_light(normal, i) * (1.0 - point_shadow(normal, shadow_vector[i], shadow_depth[i]))
            : point_light(normal, i);
    }

    return (ambient_light + from_dir + from_points);
}

vec3 compute_lighting_noshadow(vec3 normal) {
    vec3 ambient_light = light_ambient_color;

    vec3 from_dir = dir_light(normal);

    vec3 from_points = vec3(0.0, 0.0, 0.0);
    for (int i = 0; i < light_count; ++i) {
        from_points += point_light(normal, i);
    }

    return (ambient_light + from_dir + from_points);
}

vec3 compute_lighting_billboard(vec3 normal) {
    vec3 ambient_light = light_ambient_color;

    vec3 from_dir = light_dir_color / 2.0;

    vec3 from_points = vec3(0.0, 0.0, 0.0);
    for (int i = 0; i < light_count; ++i) {
        from_points += point_light_billboard(i);
    }

    return (ambient_light + from_dir + from_points);
}