#version 330 layout(std140, row_major) uniform StandardEnvironmentInformation{ mat4 view_matrix; mat4 inv_view_matrix; mat4 projection_matrix; mat4 inv_projection_matrix; uvec2 view_size; vec3 camera_position; float near_plane; float far_plane; float tt; float dt; float fdt; float gamma; } ;; struct PbrMaterial{ vec4 albedo_factor; vec3 emission_factor; float metalness_factor; float roughness_factor; float occlusion_factor; float alpha_cutoff; } ; layout(std140, row_major) uniform PbrMaterialBlock{ PbrMaterial materials[64]; } ;; struct StandardLight{ int type; vec3 position; vec3 direction; vec3 color; vec2 attenuation; vec2 spot_radius; int shadow_map; } ; layout(std140, row_major) uniform StandardLightBlock{ int light_count; StandardLight lights[128]; } ;; struct ShadowMapInfo{ int sample_count; float sample_spread; float far_plane; mat4 projection_matrix; } ; layout(std140, row_major) uniform ShadowMapBlock{ ShadowMapInfo shadow_info[18]; } ;; uniform mat4 model_matrix; uniform mat4 inv_model_matrix; in vec3 v_world_position; in vec3 v_view_position; in vec3 v_normal; in vec2 v_uv; uniform sampler2D splat_tex; uniform vec3 splat_color = vec3(1, 0, 0); float splat_factor; uniform sampler2D interior_tex; uniform float focus_distance = 8.0; uniform float floor_bias = 4.0; layout(location = 0) out vec4 f_color; layout(location = 1) out vec3 f_normal; vec3 world_position; vec3 view_position; vec3 normal; vec2 uv; vec4 color; struct StandardLightData{ vec3 direction; vec3 radiance; } ; uniform sampler2DArray shadow_map; vec2 shadow_texel_size; vec2 poisson_disk[16] = vec2[](vec2(-0.94201624, -0.39906216), vec2(0.9455861, -0.76890725), vec2(-0.0941841, -0.9293887), vec2(0.34495938, 0.2938776), vec2(-0.9158858, 0.45771432), vec2(-0.8154423, -0.87912464), vec2(-0.38277543, 0.27676845), vec2(0.974844, 0.7564838), vec2(0.44323325, -0.97511554), vec2(0.5374298, -0.4737342), vec2(-0.2649691, -0.41893023), vec2(0.79197514, 0.19090188), vec2(-0.2418884, 0.99706507), vec2(-0.81409955, 0.9143759), vec2(0.19984126, 0.78641367), vec2(0.14383161, -0.1410079)); const float PI = 3.1415927; PbrMaterial material; uniform int material_id; uniform sampler2D albedo_tex; uniform sampler2D metal_rough_occlusion_tex; uniform sampler2D normal_tex; uniform sampler2D emission_tex; uniform sampler2D brdf_lut; uniform samplerCube irradiance_map; uniform samplerCube environment_map; vec3 view_dir; vec3 F0; vec3 emission; vec4 albedo; float metalness; float roughness; float occlusion; const float _GLSLTK_PI_1 = 3.1415927; const float MAX_REFLECTION_LOD = 4.0; void standard_init(); vec4 standard_shade(in StandardLight light); vec4 standard_mix(in vec4 upper, in vec4 lower); void standard_finish(); float evaluate_light_attenuation(StandardLight light); StandardLightData evaluate_light_ambient(in StandardLight light); StandardLightData evaluate_light_point(in StandardLight light); StandardLightData evaluate_light_directional(in StandardLight light); StandardLightData evaluate_light_spot(in StandardLight light); StandardLightData evaluate_light(in StandardLight light); void main(); vec2 cubemap_uv(const vec3 v, out float face); int cubemap_texture_index(const vec3 v); float random(vec4 seed4); float shadow_factor(ShadowMapInfo info, vec3 uvw, float map, float bias); float shadow_bias(vec3 normal, vec3 light_direction); mat3 normal_map_cotangent_frame(in vec3 N, in vec3 p, in vec2 uv); vec3 normal_map(in sampler2D normal_tex, in vec3 position, in vec2 uv, in vec3 vertex_normal); float radical_inverse_vdc(uint bits); vec2 hammersley(uint i, uint N); vec3 importance_sample_ggx(vec2 Xi, vec3 N, float roughness); float distribution_ggx(vec3 N, vec3 H, float roughness); float NDF_ggx(vec3 N, vec3 H, float roughness); float G_sggx(float NdotV, float roughness); float G_smith(vec3 N, vec3 V, vec3 L, float roughness); vec3 F_s(float cos_theta, vec3 F0); vec3 F_s_r(float cosTheta, vec3 F0, float roughness); void _standard_init_before_1(){ world_position = v_world_position; view_position = v_view_position; normal = v_normal; uv = v_uv; } void _standard_init_primary_1(){ color = vec4(0); } void _standard_init_primary_2(){ _standard_init_primary_1(); material = materials[material_id]; normal = normal_map(normal_tex, (world_position - camera_position), uv, normal); emission = (texture(emission_tex, uv).xyz * material.emission_factor); view_dir = normalize((camera_position - world_position)); albedo = texture(albedo_tex, uv); albedo.xyz = pow(albedo.xyz, vec3(gamma)); albedo *= material.albedo_factor; vec3 mro = texture(metal_rough_occlusion_tex, uv).xyz; metalness = (mro.x * material.metalness_factor); roughness = (mro.y * material.roughness_factor); occlusion = (1.0 - (mro.z * material.occlusion_factor)); F0 = mix(vec3(0.04), albedo.xyz, metalness); } void _standard_init_after_1(){ splat_factor = texture(splat_tex, uv).r; albedo = mix(albedo, vec4(splat_color, 1), splat_factor); metalness = mix(metalness, 1.0, splat_factor); roughness = mix(roughness, 0.0, splat_factor); F0 = mix(vec3(0.04), albedo.xyz, metalness); } void _standard_init_after_2(){ float intersect_dist = (focus_distance - length(view_position)); float normal_dir = dot(normal, (camera_position - world_position)); if(((intersect_dist > 0.0) && ((abs(dot(normal, vec3(0, 1, 0))) < 0.5) || ((camera_position.y - floor_bias) < world_position.y)))){ discard; }else{ if((normal_dir < 0.0)){ albedo = texture(interior_tex, (gl_FragCoord.xy * 0.02)); albedo.xyz = pow(albedo.xyz, vec3(2.2)); normal = vec3(0, -1, 0); metalness = 0.0; roughness = 0.0; occlusion = 1.0; F0 = mix(vec3(0.04), albedo.xyz, metalness); }; }; } void _standard_init_after_3(){ shadow_texel_size = (0.5 / textureSize(shadow_map, 0).xy); } void standard_init(){ _standard_init_before_1(); _standard_init_primary_2(); _standard_init_after_1(); _standard_init_after_2(); _standard_init_after_3(); } vec4 _standard_shade_primary_1(in StandardLight light){ return vec4(0); } vec4 standard_shade(in StandardLight light){ if((light.type == 1)){ return vec4((occlusion * (albedo.xyz * light.color)), 1); }else{ if((light.type == 250)){ vec3 N = normal; vec3 V = view_dir; vec3 R = reflect(-V, N); R.y *= -1; vec3 F = F_s_r(max(dot(N, V), 0.0), F0, roughness); vec3 kS = F; vec3 kD = (1.0 - kS); kD *= (1.0 - metalness); vec3 irradiance = texture(irradiance_map, N).rgb; vec3 diffuse = (irradiance * albedo.xyz); vec2 envBRDF = texture(brdf_lut, vec2(max(dot(N, V), 0.0), roughness)).rg; vec3 prefiltered_color = textureLod(environment_map, R, (roughness * MAX_REFLECTION_LOD)).rgb; vec3 specular = (prefiltered_color * ((F * envBRDF.x) + envBRDF.y)); return vec4((((kD * diffuse) + specular) * (occlusion * light.color)), 1); }else{ StandardLightData light_data = evaluate_light(light); vec3 N = normal; vec3 V = view_dir; vec3 L = light_data.direction; vec3 H = normalize((V + L)); vec3 radiance = light_data.radiance; float NDF = NDF_ggx(N, H, roughness); float G = G_smith(N, V, L, roughness); vec3 F = F_s(max(dot(H, V), 0.0), F0); vec3 kS = F; vec3 kD = (vec3(1.0) - kS); kD *= (1.0 - metalness); vec3 numerator = (NDF * (G * F)); float denominator = (4.0 * (max(dot(N, V), 0.0) * max(dot(N, L), 0.0))); vec3 specular = (numerator / max(denominator, 0.001)); float NdotL = max(dot(N, L), 0.0); return vec4(((((kD * albedo.xyz) / _GLSLTK_PI_1) + specular) * (radiance * NdotL)), 1); }; }; } vec4 standard_mix(in vec4 upper, in vec4 lower){ return (upper + lower); } void _standard_finish_primary_1(){ } void standard_finish(){ color.rgb += (emission * 5.0); color.w = albedo.w; if((color.w < material.alpha_cutoff)){ discard; }; } float evaluate_light_attenuation(StandardLight light){ float distance = length((light.position - world_position)); return (1.0 / (1.0 + ((light.attenuation.x * distance) + (light.attenuation.y * (distance * distance))))); } StandardLightData evaluate_light_ambient(in StandardLight light){ return StandardLightData(normal, light.color); } StandardLightData _evaluate_light_point_primary_1(in StandardLight light){ return StandardLightData(normalize((light.position - world_position)), (light.color * evaluate_light_attenuation(light))); } StandardLightData evaluate_light_point(in StandardLight light){ StandardLightData data = _evaluate_light_point_primary_1(light); if((light.shadow_map < 65535)){ ShadowMapInfo info = shadow_info[light.shadow_map]; int shadow_map = (light.shadow_map + cubemap_texture_index(normalize((world_position - light.position)))); vec4 light_space_position = (shadow_info[shadow_map].projection_matrix * vec4(world_position, 1)); vec3 projected = (((light_space_position.xyz / light_space_position.w) + 1) * 0.5); float bias = shadow_bias(normal, data.direction); data.radiance *= (1.0 - shadow_factor(info, projected, shadow_map, bias)); }; return data; } StandardLightData _evaluate_light_directional_primary_1(in StandardLight light){ return StandardLightData(-light.direction, light.color); } StandardLightData evaluate_light_directional(in StandardLight light){ StandardLightData data = _evaluate_light_directional_primary_1(light); if((light.shadow_map < 65535)){ ShadowMapInfo info = shadow_info[light.shadow_map]; vec4 light_space_position = (info.projection_matrix * vec4(world_position, 1)); vec3 projected = (((light_space_position.xyz / light_space_position.w) + 1) * 0.5); float bias = shadow_bias(normal, data.direction); data.radiance *= (1.0 - shadow_factor(info, projected, light.shadow_map, bias)); }; return data; } StandardLightData _evaluate_light_spot_primary_1(in StandardLight light){ vec3 light_dir = normalize((light.position - world_position)); float theta = dot(light_dir, -light.direction); float intensity = 0.0; if((light.spot_radius.y < theta)){ float epsilon = (light.spot_radius.x - light.spot_radius.y); intensity = clamp(((theta - light.spot_radius.y) / epsilon), 0.0, 1.0); }; return StandardLightData(-light.direction, (light.color * (intensity * evaluate_light_attenuation(light)))); } StandardLightData evaluate_light_spot(in StandardLight light){ StandardLightData data = _evaluate_light_spot_primary_1(light); if((light.shadow_map < 65535)){ ShadowMapInfo info = shadow_info[light.shadow_map]; vec4 light_space_position = (info.projection_matrix * vec4(world_position, 1)); vec3 projected = (((light_space_position.xyz / light_space_position.w) + 1) * 0.5); float bias = shadow_bias(normal, data.direction); data.radiance *= (1.0 - shadow_factor(info, projected, light.shadow_map, bias)); }; return data; } StandardLightData evaluate_light(in StandardLight light){ switch(light.type){ case 0: return StandardLightData(-normal, vec3(0)); case 1: return evaluate_light_ambient(light); case 2: return evaluate_light_point(light); case 3: return evaluate_light_directional(light); case 4: return evaluate_light_spot(light); default: return StandardLightData(-normal, vec3(1, 0, 1)); }; } void _GLSLTK_main_2(){ standard_init(); for(int light_idx = 0; (light_idx < light_count); ++light_idx){ StandardLight light = lights[light_idx]; vec4 local_color; color = standard_mix(standard_shade(light), color); }; standard_finish(); f_color = color; f_normal = normal; } vec2 cubemap_uv(const vec3 v, out float face){ vec3 vabs = abs(v); float ma = 0.5; vec2 uv; if(((vabs.x <= vabs.z) && (vabs.y <= vabs.z))){ face = (v.z < 0)? 5 :4; uv = vec2((v.z < 0)? -v.x :v.x, -v.y); ma /= vabs.z; }else{ if((vabs.x <= vabs.y)){ face = (v.y < 0)? 3 :2; uv = vec2(v.x, (v.y < 0)? -v.z :v.z); ma /= vabs.y; }else{ face = (v.x < 0)? 1 :0; uv = vec2((v.x < 0)? v.z :-v.z, -v.y); ma /= vabs.x; }; }; return ((uv * ma) + 0.5); } int cubemap_texture_index(const vec3 v){ vec3 vabs = abs(v); if(((vabs.x <= vabs.z) && (vabs.y <= vabs.z))){ return (v.z < 0)? 5 :4; }else{ if((vabs.x <= vabs.y)){ return (v.y < 0)? 3 :2; }else{ return (v.x < 0)? 1 :0; }; }; } float random(vec4 seed4){ float dot_product = dot(seed4, vec4(12.9897995, 78.233, 45.164, 94.673)); return fract((sin(dot_product) * 43758.547)); } float shadow_factor(ShadowMapInfo info, vec3 uvw, float map, float bias){ float closest = texture(shadow_map, vec3(uvw.xy, map)).r; float current = uvw.z; float shadow = 0; for(int i = 0; (i < info.sample_count); ++i){ int index = (int((16 * random(vec4(gl_FragCoord.xyy, i)))) % 16); vec2 poisson = (poisson_disk[index] * info.sample_spread); for(int x = -1; (x <= 1); ++x){ for(int y = -1; (y <= 1); ++y){ vec2 pos = (uvw.xy + (poisson + (vec2(x, y) * shadow_texel_size))); float closest = texture(shadow_map, vec3(pos, map)).r; if(((current - bias) > closest)){ shadow += (1.0 / (info.sample_count * 8.0)); }; }; }; }; return clamp(shadow, 0.0, 1.0); } float shadow_bias(vec3 normal, vec3 light_direction){ return clamp((0.005 * tan(acos(dot(normal, light_direction)))), 0.0, 0.001); } mat3 normal_map_cotangent_frame(in vec3 N, in vec3 p, in vec2 uv){ vec3 dp1 = dFdx(p); vec3 dp2 = dFdy(p); vec2 duv1 = dFdx(uv); vec2 duv2 = dFdy(uv); vec3 dp2perp = cross(dp2, N); vec3 dp1perp = cross(N, dp1); vec3 T = ((dp2perp * duv1.x) + (dp1perp * duv2.x)); vec3 B = ((dp2perp * duv1.y) + (dp1perp * duv2.y)); float invmax = inversesqrt(max(dot(T, T), dot(B, B))); return mat3((T * invmax), (B * invmax), N); } vec3 normal_map(in sampler2D normal_tex, in vec3 position, in vec2 uv, in vec3 vertex_normal){ vec3 v_normal = normalize(vertex_normal); vec3 normal = ((texture(normal_tex, uv).rgb * 2.0) - 1.0); return normalize((normal_map_cotangent_frame(v_normal, position, uv) * normal)); } float radical_inverse_vdc(uint bits){ bits = ((bits << 16u) | (bits >> 16u)); bits = (((bits & 1431655765u) << 1u) | ((bits & 2863311530u) >> 1u)); bits = (((bits & 858993459u) << 2u) | ((bits & 3435973836u) >> 2u)); bits = (((bits & 252645135u) << 4u) | ((bits & 4042322160u) >> 4u)); bits = (((bits & 16711935u) << 8u) | ((bits & 4278255360u) >> 8u)); return (float(bits) * 0.00000000023283064); } vec2 hammersley(uint i, uint N){ return vec2((float(i) / float(N)), radical_inverse_vdc(i)); } vec3 importance_sample_ggx(vec2 Xi, vec3 N, float roughness){ float a = (roughness * roughness); float phi = (2.0 * (_GLSLTK_PI_1 * Xi.x)); float cos_theta = sqrt(((1.0 - Xi.y) / (1.0 + (((a * a) - 1.0) * Xi.y)))); float sin_theta = sqrt((1.0 - (cos_theta * cos_theta))); vec3 H; H.x = (cos(phi) * sin_theta); H.y = (sin(phi) * sin_theta); H.z = cos_theta; vec3 up = (abs(N.z) < 0.999)? vec3(0.0, 0.0, 1.0) :vec3(1.0, 0.0, 0.0); vec3 tangent = normalize(cross(up, N)); vec3 bitangent = cross(N, tangent); vec3 sample_vec = ((tangent * H.x) + ((bitangent * H.y) + (N * H.z))); return normalize(sample_vec); } float distribution_ggx(vec3 N, vec3 H, float roughness){ float a = (roughness * roughness); float a2 = (a * a); float n_h = max(dot(N, H), 0.0); float n_h2 = (n_h * n_h); float nom = a2; float denom = ((n_h2 * (a2 - 1.0)) + 1.0); denom = (_GLSLTK_PI_1 * (denom * denom)); return (nom / denom); } float NDF_ggx(vec3 N, vec3 H, float roughness){ float a = (roughness * roughness); float a2 = (a * a); float NdotH = max(dot(N, H), 0.0); float NdotH2 = (NdotH * NdotH); float denom = ((NdotH2 * (a2 - 1.0)) + 1.0); return (a2 / (_GLSLTK_PI_1 * (denom * denom))); } float G_sggx(float NdotV, float roughness){ float r = (roughness + 1.0); float k = ((r * r) / 8.0); return (NdotV / ((NdotV * (1.0 - k)) + k)); } float G_smith(vec3 N, vec3 V, vec3 L, float roughness){ float ggx1 = G_sggx(max(dot(N, V), 0.0), roughness); float ggx2 = G_sggx(max(dot(N, L), 0.0), roughness); return (ggx1 * ggx2); } vec3 F_s(float cos_theta, vec3 F0){ return (F0 + ((1.0 - F0) * pow((1.0 - cos_theta), 5.0))); } vec3 F_s_r(float cosTheta, vec3 F0, float roughness){ return (F0 + ((max(vec3((1.0 - roughness)), F0) - F0) * pow(clamp((1.0 - cosTheta), 0.0, 1.0), 5.0))); } void main(){ _GLSLTK_main_2(); }