| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438 |
- 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 22 // In vec4 units.
- # define MAX_NUM_LIGHTS 32
- # define MAX_NUM_CASCADES 4
- uniform vec4 u_lights_num; // num_dir, num_omni, num_spot
- SAMPLER2D(u_lights_data, 12); // 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));
- }
- vec4 lights_data(int offset)
- {
- float u = (float(offset) + 0.5) / float(LIGHT_SIZE * MAX_NUM_LIGHTS);
- return texture2D(u_lights_data, vec2(u, 0.0));
- }
- 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 = lights_data(loffset + 0).rgb;
- float intensity = lights_data(loffset + 0).w;
- vec3 direction = lights_data(loffset + 2).xyz;
- vec4 atlas_u = lights_data(loffset + 19).xyzw;
- vec4 atlas_v = lights_data(loffset + 20).xyzw;
- float atlas_size = lights_data(loffset + 21).x;
- float shadow_bias = lights_data(loffset + 21).y;
- 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.x , atlas_v.x , atlas_size));
- else if (atlas1)
- local_radiance *= PCF(u_cascaded_shadow_map, shadow_pos1, shadow_bias, sun_sm_texel_size, vec3(atlas_u.x + atlas_size, atlas_v.x , atlas_size));
- else if (atlas2)
- local_radiance *= PCF(u_cascaded_shadow_map, shadow_pos2, shadow_bias, sun_sm_texel_size, vec3(atlas_u.x , atlas_v.x + 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.x + atlas_size, atlas_v.x + 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 = lights_data(loffset + 0).rgb;
- float intensity = lights_data(loffset + 0).w;
- vec3 direction = lights_data(loffset + 2).xyz;
- float shadow_bias = lights_data(loffset + 21).y;
- 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 = lights_data(loffset + 0).rgb;
- float intensity = lights_data(loffset + 0).w;
- vec3 position = lights_data(loffset + 1).xyz;
- float range = lights_data(loffset + 1).w;
- float cast_shadow = lights_data(loffset + 21).z;
- vec3 local_radiance = calc_omni_light(n
- , v
- , frag_pos
- , toLinearAccurate(light_color)
- , intensity
- , mul(position, tbn)
- , range
- , albedo
- , metallic
- , roughness
- , f0
- );
- if (cast_shadow == 1.0) {
- // Tetrahedron normals.
- CONST(vec3 bn) = vec3( 0.0f, 0.81649661f, -0.57735026f);
- CONST(vec3 yn) = vec3( 0.0f, -0.81649661f, -0.57735026f);
- CONST(vec3 gn) = vec3(-0.81649661f, 0.0f, 0.57735026f);
- CONST(vec3 rn) = vec3( 0.81649661f, 0.0f, 0.57735026f);
- vec3 sl = shadow_local.xyz - position; // Transform to light-local space.
- // Select tetrahedon face.
- float b = dot(sl, bn);
- float y = dot(sl, yn);
- float g = dot(sl, gn);
- float r = dot(sl, rn);
- float maximum = max(max(b, y), max(g, r));
- vec4 atlas_u = lights_data(loffset + 19);
- vec4 atlas_v = lights_data(loffset + 20);
- float atlas_size = lights_data(loffset + 21).x;
- float shadow_bias = lights_data(loffset + 21).y;
- vec4 shadow_pos0;
- vec3 col;
- vec3 atlas_offset;
- if (maximum == b) {
- // Tetrahedron mvp matrices.
- mat4 bmtx = mtxFromCols(lights_data(loffset + 3)
- , lights_data(loffset + 4)
- , lights_data(loffset + 5)
- , lights_data(loffset + 6)
- );
- shadow_pos0 = mul(bmtx, shadow_local);
- col = vec3(0.1, 0.1, 1);
- atlas_offset = vec3(atlas_u.x, atlas_v.x, atlas_size);
- } else if (maximum == y) {
- mat4 ymtx = mtxFromCols(lights_data(loffset + 7)
- , lights_data(loffset + 8)
- , lights_data(loffset + 9)
- , lights_data(loffset + 10)
- );
- shadow_pos0 = mul(ymtx, shadow_local);
- col = vec3(1, 1, 0);
- atlas_offset = vec3(atlas_u.y, atlas_v.y, atlas_size);
- } else if (maximum == g) {
- mat4 gmtx = mtxFromCols(lights_data(loffset + 11)
- , lights_data(loffset + 12)
- , lights_data(loffset + 13)
- , lights_data(loffset + 14)
- );
- shadow_pos0 = mul(gmtx, shadow_local);
- col = vec3(0, 1, 0);
- atlas_offset = vec3(atlas_u.z, atlas_v.z, atlas_size);
- } else {
- mat4 rmtx = mtxFromCols(lights_data(loffset + 15)
- , lights_data(loffset + 16)
- , lights_data(loffset + 17)
- , lights_data(loffset + 18)
- );
- shadow_pos0 = mul(rmtx, shadow_local);
- col = vec3(1, 0, 0);
- atlas_offset = vec3(atlas_u.w, atlas_v.w, atlas_size);
- }
- local_radiance *= PCF(u_local_lights_shadow_map
- , shadow_pos0
- , shadow_bias
- , local_lights_sm_texel_size / 4.0
- , atlas_offset
- );
- }
- radiance += apply_distance_fading(local_radiance, position, camera_pos);
- }
- for (int si = 0; si < num_spot; ++si, loffset += LIGHT_SIZE) {
- vec3 light_color = lights_data(loffset + 0).rgb;
- float intensity = lights_data(loffset + 0).w;
- vec3 position = lights_data(loffset + 1).xyz;
- float range = lights_data(loffset + 1).w;
- vec3 direction = lights_data(loffset + 2).xyz;
- float spot_angle = lights_data(loffset + 2).w;
- float cast_shadow = lights_data(loffset + 21).z;
- 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
- );
- if (cast_shadow == 1.0) {
- mat4 mvp = mtxFromCols(lights_data(loffset + 3)
- , lights_data(loffset + 4)
- , lights_data(loffset + 5)
- , lights_data(loffset + 6)
- );
- vec4 atlas_u = lights_data(loffset + 19);
- vec4 atlas_v = lights_data(loffset + 20);
- float atlas_size = lights_data(loffset + 21).x;
- float shadow_bias = lights_data(loffset + 21).y;
- local_radiance *= PCF(u_local_lights_shadow_map
- , mul(mvp, shadow_local)
- , shadow_bias
- , local_lights_sm_texel_size
- , vec3(atlas_u.x, atlas_v.x, 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);
- }
- """
- }
- }
|