#include "model_fs.glsl" #include "light.glsl" #include "brdf.glsl" #include "sh_lighting.glsl" #include "lightmap.glsl" #ifdef SHADING_PHONG void main() { vec3 n = normalize(v_normal_ws); vec4 lit = vec4(1.0, 1.0, 1.0, 1.0); // SH lighting if (!u_texlit) { vec3 result = sh_lighting(n); if( (result.x*result.x+result.y*result.y+result.z*result.z) > 0.0 ) lit = vec4(result, 1.0); } // analytical lights lit += vec4(lighting(), 0.0); // base vec4 diffuse; if(u_matcaps) { vec2 muv = vec2(view * vec4(v_normal_ws, 0))*0.5+vec2(0.5,0.5); // normal (model space) to view space diffuse = texture(u_texture2d, vec2(muv.x, 1.0-muv.y)); } else if(u_textured) { diffuse = texture(u_texture2d, v_texcoord); } else { diffuse = u_diffuse; // * v_color; } diffuse *= v_color; if (u_texlit) { vec4 litsample = texture(u_lightmap, v_texcoord); if (u_texmod) { diffuse *= litsample; } else { diffuse += litsample; } diffuse.rgb += sh_lighting(n); } // lighting mix fragcolor = diffuse * lit * shadowing(); // rimlight #ifdef RIM { vec3 n = normalize(mat3(M) * v_normal); // convert normal to view space vec3 p = (M * vec4(v_position,1.0)).xyz; // convert position to view space vec3 v = vec3(0,-1,0); if (!u_rimambient) { v = normalize(u_rimpivot-p); } float rim = 1.0 - max(dot(v,n), 0.0); vec3 col = u_rimcolor*(pow(smoothstep(1.0-u_rimrange.x,u_rimrange.y,rim), u_rimrange.z)); fragcolor += vec4(col, 0.0); } #endif } #endif #ifdef SHADING_VERTEXLIT void main() { vec3 n = normalize(v_normal_ws); vec4 lit = vec4(1.0, 1.0, 1.0, 1.0); // SH lighting if (!u_texlit) { vec3 result = sh_lighting(n); if( (result.x*result.x+result.y*result.y+result.z*result.z) > 0.0 ) lit = vec4(result, 1.0); } lit += vec4(v_vertcolor, 0.0); // base vec4 diffuse; if(u_matcaps) { vec2 muv = vec2(view * vec4(v_normal_ws, 0))*0.5+vec2(0.5,0.5); // normal (model space) to view space diffuse = texture(u_texture2d, vec2(muv.x, 1.0-muv.y)); } else if(u_textured) { diffuse = texture(u_texture2d, v_texcoord); } else { diffuse = u_diffuse; // * v_color; } // vec4 vertcolor4 = vec4(v_vertcolor, 1.0); // if (length(diffuse*v_color) > length(vertcolor4)) { diffuse *= v_color; // } if (u_texlit) { vec4 litsample = texture(u_lightmap, v_texcoord); if (u_texmod) { diffuse *= litsample; } else { diffuse += litsample; } diffuse.rgb += sh_lighting(n); } // lighting mix fragcolor = diffuse * lit * shadowing(); // rimlight #ifdef RIM { vec3 n = normalize(mat3(M) * v_normal); // convert normal to view space vec3 p = (M * vec4(v_position,1.0)).xyz; // convert position to view space vec3 v = vec3(0,-1,0); if (!u_rimambient) { v = normalize(u_rimpivot-p); } float rim = 1.0 - max(dot(v,n), 0.0); vec3 col = u_rimcolor*(pow(smoothstep(1.0-u_rimrange.x,u_rimrange.y,rim), u_rimrange.z)); fragcolor += vec4(col, 0.0); } #endif } #endif #ifdef SHADING_PBR void main(void) { vec3 baseColor = vec3( 0.5, 0.5, 0.5 ); float roughness = 1.0; float metallic = 0.0; float ao = 1.0; float alpha = 1.0; vec4 baseColor_alpha; if ( map_albedo.has_tex ) baseColor_alpha = sample_colormap( map_albedo, v_texcoord ); else baseColor_alpha = sample_colormap( map_diffuse, v_texcoord ); baseColor = baseColor_alpha.xyz; alpha = baseColor_alpha.w; if( map_metallic.has_tex && map_roughness.has_tex ) { metallic = sample_colormap( map_metallic, v_texcoord ).x; roughness = sample_colormap( map_roughness, v_texcoord ).x; } else if( map_roughness.has_tex ) { //< @r-lyeh, metalness B, roughness G, (@todo: self-shadowing occlusion R; for now, any of R/B are metallic) metallic = sample_colormap( map_roughness, v_texcoord ).b;// + sample_colormap( map_roughness, v_texcoord ).r; roughness = sample_colormap( map_roughness, v_texcoord ).g; } if ( map_ao.has_tex ) ao = sample_colormap( map_ao, v_texcoord ).x; else if ( map_ambient.has_tex ) ao = sample_colormap( map_ambient, v_texcoord ).x; vec3 emissive = sample_colormap( map_emissive, v_texcoord ).rgb; vec3 normalmap = texture( map_normals_tex, v_texcoord ).xyz * vec3(2.0) - vec3(1.0); float normalmap_mip = textureQueryLod( map_normals_tex, v_texcoord ).x; float normalmap_length = length(normalmap); normalmap /= normalmap_length; vec3 normal = v_normal_ws; if ( map_normals.has_tex ) { // Mikkelsen's tangent space normal map decoding. See http://mikktspace.com/ for rationale. vec3 bi = cross( v_normal_ws, v_tangent ); vec3 nmap = normalmap.xyz; normal = nmap.x * v_tangent + nmap.y * bi + nmap.z * v_normal_ws; } normal = normalize( normal ); if( USE_MAP_DEBUGGING && !USE_AMBIENT_DEBUGGING ) { vec3 c = vec3(1., 0., 0.); float x = gl_FragCoord.x / resolution.x; float y = gl_FragCoord.y / resolution.y; if ( y < (7.0/7.0) ) c = vec3(.5) + .5*v_normal_ws; if ( y < (6.0/7.0) ) c = vec3(.5) + .5*normalmap; if ( y < (5.0/7.0) ) c = vec3(ao); if ( y < (4.0/7.0) ) c = vec3(emissive); if ( y < (3.0/7.0) ) c = vec3(metallic); if ( y < (2.0/7.0) ) c = vec3(roughness); if ( y < (1.0/7.0) ) c = baseColor; fragcolor = vec4(c, 1.); return; } if (USE_NORMAL_VARIATION_TO_ROUGHNESS) { // Try to reduce specular aliasing by increasing roughness when minified normal maps have high variation. float variation = 1. - pow( normalmap_length, 8. ); float minification = clamp( normalmap_mip - 2., 0., 1. ); roughness = mix( roughness, 1.0, variation * minification ); } fragcolor = baseColor_alpha; vec3 N = normal; vec3 V = normalize( v_to_camera ); vec3 Lo = vec3(0.); vec3 F0 = vec3(0.04); F0 = mix( F0, baseColor, metallic ); bool use_ibl = has_tex_skysphere; // use_ibl = false; // Add contributions from analytic lights. { for ( int i = 0; i < u_num_lights; i++ ) { light_t l = u_lights[i]; vec3 lightDir; float attenuation = 1.0; if (l.type == LIGHT_DIRECTIONAL) { lightDir = normalize(-l.dir); } else if (l.type == LIGHT_POINT || l.type == LIGHT_SPOT) { vec3 toLight = l.pos - v_position_ws; lightDir = normalize(toLight); float distance = length(toLight); attenuation = 1.0 / (l.constant + l.linear * distance + l.quadratic * (distance * distance)); if (l.type == LIGHT_SPOT) { float angle = dot(l.dir, -lightDir); if (angle > l.outerCone) { float intensity = (angle-l.outerCone)/(l.innerCone-l.outerCone); attenuation *= clamp(intensity, 0.0, 1.0); } else { attenuation = 0.0; } } } // fast-rejection for faraway vertices if (attenuation <= 0.01) { continue; } vec3 radiance = l.diffuse * BOOST_LIGHTING; vec3 L = normalize( lightDir ); vec3 H = normalize( V + L ); vec3 F = fresnel_schlick( H, V, F0 ); vec3 kS = F; vec3 kD = vec3(1.0) - kS; kD *= 1.0 - metallic; // Premultiplied alpha applied to the diffuse component only kD *= alpha; float D = distribution_ggx( N, H, roughness ); float G = geometry_smith( N, V, L, roughness ); vec3 num = D * F * G; float denom = 4. * max( 0., dot( N, V ) ) * max( 0., dot( N, L ) ); vec3 specular = kS * (num / max( 0.001, denom )); float NdotL = max( 0., dot( N, L ) ); Lo += ( kD * ( baseColor / PI ) + specular ) * radiance * NdotL * attenuation; } } vec3 ambient = sample_colormap( map_ambient, v_texcoord ).xyz; vec3 diffuse_ambient; vec3 specular_ambient; if ( use_ibl ) { // Image based lighting. // Based on https://learnopengl.com/PBR/IBL/Diffuse-irradiance vec3 irradiance = vec3(0.); if ( USE_BRUTEFORCE_IRRADIANCE ) { irradiance = sample_irradiance_slow( normal, v_tangent ); } else { irradiance = sample_irradiance_fast( normal, v_tangent ); } // Compute the Fresnel term for a perfect mirror reflection with L = R. // In this case the halfway vector H = N. // // We use a modified Fresnel function that dampens specular reflections of very // rough surfaces to avoid too bright pixels at grazing angles. vec3 F = fresnel_schlick_roughness( N, V, F0, roughness ); vec3 kS = F; // Subtract the amount of reflected light (specular) to get the energy left for // absorbed (diffuse) light. vec3 kD = vec3(1.) - kS; // Metallic surfaces have only a specular reflection. kD *= 1.0 - metallic; // Premultiplied alpha applied to the diffuse component only kD *= alpha; // Modulate the incoming lighting with the diffuse color: some wavelengths get absorbed. diffuse_ambient = irradiance * baseColor; // Ambient light also has a specular part. specular_ambient = specular_ibl( V, normal, roughness, F ); // Ambient occlusion tells us the fraction of sky light that reaches this point. if (USE_SPECULAR_AO_ATTENUATION) { ambient = ao * (kD * diffuse_ambient + specular_ambient); } else { // We don't attenuate specular_ambient ambient here with AO which might cause flickering in dark cavities. ambient = ao * (kD * diffuse_ambient) + specular_ambient; } } vec3 color = (ambient + Lo) + emissive; if ( USE_AMBIENT_DEBUGGING ) { float y = gl_FragCoord.y / resolution.y; if( USE_MAP_DEBUGGING && y > 0.5 ) { if ( (y-0.5) < (7.0/7.0/2.0) ) color = vec3(.5) + .5*v_normal_ws; if ( (y-0.5) < (6.0/7.0/2.0) ) color = vec3(.5) + .5*normalmap; if ( (y-0.5) < (5.0/7.0/2.0) ) color = vec3(ao); if ( (y-0.5) < (4.0/7.0/2.0) ) color = vec3(emissive); if ( (y-0.5) < (3.0/7.0/2.0) ) color = vec3(metallic); if ( (y-0.5) < (2.0/7.0/2.0) ) color = vec3(roughness); if ( (y-0.5) < (1.0/7.0/2.0) ) color = baseColor; } else { float x = gl_FragCoord.x / resolution.x; if ( x < 0.33 ) color = specular_ambient; else if( x > 0.66 ) color = diffuse_ambient; } } // dither with noise. // float dither = random( uvec3( floatBitsToUint( gl_FragCoord.xy ), frame_count ) ); // color += BOOST_NOISE * vec3( (-1.0/256.) + (2./256.) * dither ); #if 0 // original // basic tonemap and gamma correction color = color / ( vec3(1.) + color ); color = pow( color, vec3(1. / 2.2) ); #elif 0 // filmic tonemapper vec3 linearColor = color; vec3 x = max(vec3(0.0), linearColor - 0.004); color = (x * (6.2 * x + 0.5)) / (x * (6.2 * x + 1.7) + 0.06); // gamma correction // color = pow( color, vec3(1. / 2.2) ); #elif 0 // aces film (CC0, src: https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/) vec3 x = color; float a = 2.51f; float b = 0.03f; float c = 2.43f; float d = 0.59f; float e = 0.14f; color = clamp((x*(a*x+b))/(x*(c*x+d)+e), 0.0, 1.0); // gamma correction #endif // color = pow( color, vec3(1. / 2.2) ); // Technically this alpha may be too transparent, if there is a lot of reflected light we wouldn't // see the background, maybe we can approximate it well enough by adding a fresnel term fragcolor = vec4( color * shadowing().xyz, alpha ); } #endif