| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352 |
- include = [
- "core/shaders/common.shader"
- "core/shaders/shadow_map.shader"
- ]
- bgfx_shaders = {
- lighting = {
- includes = [ "shadow_mapping" "fog" ]
- code = """
- #if !defined(NO_LIGHT)
- # define LIGHT_SIZE 8 // In vec4 units.
- # define MAX_NUM_LIGHTS 32
- # define MAX_NUM_CASCADES 4
- uniform vec4 u_lights_num; // num_dir, num_omni, num_spot
- uniform vec4 u_lights_data[LIGHT_SIZE * MAX_NUM_LIGHTS]; // dir_0, .., dir_n-1, omni_0, .., omni_n-1, spot_0, .., spot_n-1
- uniform mat4 u_cascaded_lights[MAX_NUM_CASCADES]; // View-proj-crop matrices for cascaded shadow maps.
- uniform vec4 u_shadow_maps_texel_sizes;
- # define sun_sm_texel_size u_shadow_maps_texel_sizes.xy
- # define local_lights_sm_texel_size u_shadow_maps_texel_sizes.zw
- SAMPLER2DSHADOW(u_cascaded_shadow_map, 10);
- SAMPLER2DSHADOW(u_local_lights_shadow_map, 11);
- uniform vec4 u_local_lights_params;
- # define local_lights_distance_culling u_local_lights_params.x
- # define local_lights_distance_culling_fade u_local_lights_params.y
- # define local_lights_distance_culling_cutoff u_local_lights_params.z
- uniform vec4 u_lighting_params;
- # define ambient_color u_lighting_params.xyz
- CONST(float PI) = 3.14159265358979323846;
- float length_squared(vec3 a)
- {
- return dot(a, a);
- }
- vec3 fresnel(float dot, vec3 f0)
- {
- float a = clamp(1.0 - dot, 0.0, 1.0);
- return f0 + (1.0 - f0) * (a*a*a*a*a);
- }
- float dist_GGX(float ndoth, float roughness)
- {
- float r = roughness*roughness;
- float rr = r*r;
- float d = ((ndoth*ndoth) * (rr - 1.0) + 1.0);
- return rr / (PI * (d*d));
- }
- float geom_schlick_GGX(float ndotv, float roughness)
- {
- float r = roughness + 1.0;
- float k = r*r * (1.0/8.0);
- return ndotv / (ndotv * (1.0 - k) + k);
- }
- float geom_smith(float ndotv, float ndotl, float roughness)
- {
- float ggx2 = geom_schlick_GGX(ndotv, roughness);
- float ggx1 = geom_schlick_GGX(ndotl, roughness);
- return ggx1 * ggx2;
- }
- vec3 calc_radiance(vec3 n, vec3 l, vec3 v, vec3 h, vec3 albedo, vec3 radiance, float metallic, float roughness, vec3 f0)
- {
- float ndotl = max(0.0, dot(n, l));
- float ndotv = max(0.0, dot(n, v));
- float ndoth = max(0.0, dot(n, h));
- float hdotv = max(0.0, dot(h, v));
- vec3 f = fresnel(hdotv, f0);
- float ndf = dist_GGX(ndoth, roughness);
- float g = geom_smith(ndotv, ndotl, roughness);
- // Cook-Torrance BRDF.
- vec3 num = ndf * g * f;
- float den = 4.0 * ndotv * ndotl + 0.0001;
- vec3 specular = num / den;
- vec3 ks = f;
- vec3 kd = (vec3_splat(1.0) - ks) * (1.0 - metallic);
- return (kd * albedo / PI + specular) * radiance * ndotl;
- }
- vec3 calc_dir_light(vec3 n, vec3 v, vec3 color, float intensity, vec3 direction, vec3 albedo, float metallic, float roughness, vec3 f0)
- {
- vec3 l = normalize(-direction); // Direction to light.
- vec3 h = normalize(v + l); // Half-vector betwen v and l.
- vec3 radiance = color * intensity;
- return calc_radiance(n, l, v, h, albedo, radiance, metallic, roughness, f0);
- }
- vec3 calc_omni_light(vec3 n, vec3 v, vec3 frag_pos, vec3 color, float intensity, vec3 position, float range, vec3 albedo, float metallic, float roughness, vec3 f0)
- {
- vec3 dpos = position - frag_pos;
- vec3 l = normalize(dpos); // Direction to light.
- vec3 h = normalize(v + l); // Half-vector betwen v and l.
- float dd = length_squared(dpos);
- float attenuation_std = 1.0 / dd;
- float k = 0.15;
- float a = 1.0 - dd / (range*range);
- float t = clamp(a/k, 0.0, 1.0);
- float attenuation = max(mix(0.0, attenuation_std, t), 0.0);
- vec3 radiance = color * intensity * attenuation;
- return calc_radiance(n, l, v, h, albedo, radiance, metallic, roughness, f0);
- }
- vec3 calc_spot_light(vec3 n
- , vec3 v
- , vec3 frag_pos
- , vec3 color
- , float intensity
- , vec3 direction
- , float spot_angle
- , vec3 position
- , float range
- , vec3 albedo
- , float metallic
- , float roughness
- , vec3 f0
- )
- {
- vec3 dpos = position - frag_pos;
- vec3 l = normalize(dpos); // Direction to light.
- vec3 h = normalize(v + l); // Half-vector betwen v and l.
- float dd = length_squared(dpos);
- float ldotd = dot(l, -direction);
- float r = range / ldotd;
- float rr = r*r;
- float attenuation_std = 1.0 / dd;
- float k = 0.03;
- if (ldotd >= cos(spot_angle) && dd <= rr) {
- float a = ldotd - cos(spot_angle);
- float t = clamp(a/k, 0.0, 1.0);
- float attenuation = mix(0.0, attenuation_std, t);
- vec3 radiance = color * intensity * attenuation;
- return calc_radiance(n, l, v, h, albedo, radiance, metallic, roughness, f0);
- } else {
- return vec3_splat(0.0);
- }
- }
- float fade_smoothstep(float camera_dist, float fade_dist, float cutoff_dist)
- {
- if (cutoff_dist == fade_dist)
- return camera_dist <= fade_dist ? 1.0 : 0.0;
- return 1.0 - smoothstep(fade_dist, cutoff_dist, camera_dist);
- }
- vec3 apply_distance_fading(vec3 radiance, vec3 light_pos, vec3 camera_pos)
- {
- if (local_lights_distance_culling == 0.0)
- return radiance;
- float fade_dist = local_lights_distance_culling_fade;
- float cutoff_dist = local_lights_distance_culling_cutoff;
- float camera_dist = length(light_pos - camera_pos);
- return mix(vec3_splat(0.0), radiance, fade_smoothstep(camera_dist, fade_dist, cutoff_dist));
- }
- vec3 calc_lighting(mat3 tbn
- , vec3 n
- , vec3 v
- , vec3 frag_pos
- , vec3 camera_frag_pos
- , vec3 camera_pos
- , vec4 shadow_pos0
- , vec4 shadow_pos1
- , vec4 shadow_pos2
- , vec4 shadow_pos3
- , vec4 shadow_local
- , vec3 albedo
- , float metallic
- , float roughness
- , float ao
- , vec3 emission
- , vec3 f0
- )
- {
- vec3 radiance = ao * toLinearAccurate(ambient_color) * albedo;
- int loffset = 0;
- int num_dir = int(u_lights_num.x);
- int num_omni = int(u_lights_num.y);
- int num_spot = int(u_lights_num.z);
- vec3 sun_color = vec3(1, 1, 1);
- if (num_dir > 0) {
- // Brightest directional light (index == 0) generates cascaded shadow maps.
- vec3 light_color = u_lights_data[loffset + 0].rgb;
- float intensity = u_lights_data[loffset + 0].w;
- vec3 direction = u_lights_data[loffset + 2].xyz;
- float shadow_bias = u_lights_data[loffset + 3].r;
- float atlas_u = u_lights_data[loffset + 3].g;
- float atlas_v = u_lights_data[loffset + 3].b;
- float atlas_size = u_lights_data[loffset + 3].a;
- loffset += LIGHT_SIZE;
- sun_color = light_color;
- vec3 local_radiance = calc_dir_light(n
- , v
- , toLinearAccurate(light_color)
- , intensity
- , mul(direction, tbn)
- , albedo
- , metallic
- , roughness
- , f0
- );
- vec2 shadow0 = shadow_pos0.xy/shadow_pos0.w;
- vec2 shadow1 = shadow_pos1.xy/shadow_pos1.w;
- vec2 shadow2 = shadow_pos2.xy/shadow_pos2.w;
- vec2 shadow3 = shadow_pos3.xy/shadow_pos3.w;
- bool atlas0 = all(lessThan(shadow0, vec2_splat(1.0))) && all(greaterThan(shadow0, vec2_splat(0.0)));
- bool atlas1 = all(lessThan(shadow1, vec2_splat(1.0))) && all(greaterThan(shadow1, vec2_splat(0.0)));
- bool atlas2 = all(lessThan(shadow2, vec2_splat(1.0))) && all(greaterThan(shadow2, vec2_splat(0.0)));
- bool atlas3 = all(lessThan(shadow3, vec2_splat(1.0))) && all(greaterThan(shadow3, vec2_splat(0.0)));
- if (atlas0)
- local_radiance *= PCF(u_cascaded_shadow_map, shadow_pos0, shadow_bias, sun_sm_texel_size, vec3(atlas_u , atlas_v , atlas_size));
- else if (atlas1)
- local_radiance *= PCF(u_cascaded_shadow_map, shadow_pos1, shadow_bias, sun_sm_texel_size, vec3(atlas_u + atlas_size, atlas_v , atlas_size));
- else if (atlas2)
- local_radiance *= PCF(u_cascaded_shadow_map, shadow_pos2, shadow_bias, sun_sm_texel_size, vec3(atlas_u , atlas_v + atlas_size, atlas_size));
- else if (atlas3)
- local_radiance *= PCF(u_cascaded_shadow_map, shadow_pos3, shadow_bias, sun_sm_texel_size, vec3(atlas_u + atlas_size, atlas_v + atlas_size, atlas_size));
- radiance += local_radiance;
- }
- // Others directional lights just add to radiance.
- for (int di = 1; di < num_dir; ++di, loffset += LIGHT_SIZE) {
- vec3 light_color = u_lights_data[loffset + 0].rgb;
- float intensity = u_lights_data[loffset + 0].w;
- vec3 direction = u_lights_data[loffset + 2].xyz;
- float shadow_bias = u_lights_data[loffset + 3].r;
- radiance += calc_dir_light(n
- , v
- , toLinearAccurate(light_color)
- , intensity
- , mul(direction, tbn)
- , albedo
- , metallic
- , roughness
- , f0
- );
- }
- for (int oi = 0; oi < num_omni; ++oi, loffset += LIGHT_SIZE) {
- vec3 light_color = u_lights_data[loffset + 0].rgb;
- float intensity = u_lights_data[loffset + 0].w;
- vec3 position = u_lights_data[loffset + 1].xyz;
- float range = u_lights_data[loffset + 1].w;
- float shadow_bias = u_lights_data[loffset + 3].r;
- vec3 local_radiance = calc_omni_light(n
- , v
- , frag_pos
- , toLinearAccurate(light_color)
- , intensity
- , mul(position, tbn)
- , range
- , albedo
- , metallic
- , roughness
- , f0
- );
- radiance += apply_distance_fading(local_radiance, position, camera_pos);
- }
- for (int si = 0; si < num_spot; ++si, loffset += LIGHT_SIZE) {
- vec3 light_color = u_lights_data[loffset + 0].rgb;
- float intensity = u_lights_data[loffset + 0].w;
- vec3 position = u_lights_data[loffset + 1].xyz;
- float range = u_lights_data[loffset + 1].w;
- vec3 direction = u_lights_data[loffset + 2].xyz;
- float spot_angle = u_lights_data[loffset + 2].w;
- float shadow_bias = u_lights_data[loffset + 3].r;
- float atlas_u = u_lights_data[loffset + 3].g;
- float atlas_v = u_lights_data[loffset + 3].b;
- float atlas_size = u_lights_data[loffset + 3].a;
- vec4 axis_x = u_lights_data[loffset + 4];
- vec4 axis_y = u_lights_data[loffset + 5];
- vec4 axis_z = u_lights_data[loffset + 6];
- vec4 axis_t = u_lights_data[loffset + 7];
- vec3 local_radiance = calc_spot_light(n
- , v
- , frag_pos
- , toLinearAccurate(light_color)
- , intensity
- , mul(direction, tbn)
- , spot_angle
- , mul(position, tbn)
- , range
- , albedo
- , metallic
- , roughness
- , f0
- );
- mat4 mvp = mtxFromCols(axis_x, axis_y, axis_z, axis_t);
- vec4 shadow_pos0 = mul(mvp, shadow_local);
- local_radiance *= PCF(u_local_lights_shadow_map, shadow_pos0, shadow_bias, local_lights_sm_texel_size, vec3(atlas_u, atlas_v, atlas_size));
- radiance += apply_distance_fading(local_radiance, position, camera_pos);
- }
- return apply_fog(emission + radiance, length(camera_frag_pos), sun_color);
- }
- #endif
- """
- }
- fog = {
- code = """
- uniform vec4 u_fog_data[2];
- #define fog_color u_fog_data[0].rgb
- #define fog_density u_fog_data[0].w
- #define fog_range_min u_fog_data[1].x
- #define fog_range_max u_fog_data[1].y
- #define fog_sun_blend u_fog_data[1].z
- #define fog_enabled u_fog_data[1].w
- vec3 apply_fog(vec3 radiance, float d, vec3 sun_color)
- {
- if (fog_enabled == 0.0)
- return radiance;
- if (d < fog_range_min || d > fog_range_max)
- return radiance;
- float d2 = d - fog_range_min;
- float f = exp(-fog_density * d2);
- return mix(mix(fog_color, sun_color, fog_sun_blend), radiance, f);
- }
- """
- }
- }
|