407 lines
13 KiB
GLSL
407 lines
13 KiB
GLSL
#include "model_fs.glsl"
|
|
#include "light.glsl"
|
|
#include "brdf.glsl"
|
|
#include "sh_lighting.glsl"
|
|
|
|
#ifdef LIGHTMAP_BAKING
|
|
void main() {
|
|
vec3 n = normalize(v_normal_ws);
|
|
vec4 diffuse;
|
|
|
|
if(u_textured) {
|
|
diffuse = texture(u_texture2d, v_texcoord);
|
|
} else {
|
|
diffuse = u_diffuse; // * v_color;
|
|
}
|
|
|
|
if (u_texlit) {
|
|
vec4 litsample = texture(u_lightmap, v_texcoord);
|
|
diffuse *= litsample;
|
|
}
|
|
|
|
fragcolor = vec4(diffuse.rgb*u_litboost, 1.0);
|
|
}
|
|
#endif
|
|
|
|
#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
|