v4k-git-backup/engine/art/shaders/basic_specgloss.fs

154 lines
4.8 KiB
Forth
Raw Normal View History

#version 330 core
struct Light
{
vec3 direction;
vec3 color;
};
struct ColorMap
{
bool has_tex;
vec4 color;
};
uniform ColorMap map_albedo; uniform sampler2D map_albedo_tex;
uniform ColorMap map_diffuse; uniform sampler2D map_diffuse_tex;
uniform ColorMap map_specular; uniform sampler2D map_specular_tex;
uniform ColorMap map_normals; uniform sampler2D map_normals_tex;
uniform ColorMap map_roughness; uniform sampler2D map_roughness_tex;
uniform ColorMap map_metallic; uniform sampler2D map_metallic_tex;
uniform ColorMap map_ao; uniform sampler2D map_ao_tex;
uniform ColorMap map_ambient; uniform sampler2D map_ambient_tex;
uniform ColorMap map_emissive; uniform sampler2D map_emissive_tex;
#define sample_colormap(ColorMap_, uv_) \
(ColorMap_.has_tex ? texture( ColorMap_##_tex, uv_ ) : ColorMap_.color)
in vec3 out_normal;
in vec3 out_tangent;
in vec3 out_binormal;
in vec2 out_texcoord;
in vec3 out_worldpos;
in vec3 out_to_camera;
uniform float specular_shininess;
uniform float skysphere_rotation;
uniform float skysphere_mip_count;
uniform float exposure;
uniform vec3 camera_position;
uniform Light lights[3];
uniform vec4 global_ambient;
uniform bool has_tex_skysphere;
uniform bool has_tex_skyenv;
uniform sampler2D tex_skysphere;
uniform sampler2D tex_skyenv;
out vec4 frag_color;
const float PI = 3.1415926536;
vec2 sphere_to_polar( vec3 normal )
{
normal = normalize( normal );
return vec2( ( atan( normal.z, normal.x ) + skysphere_rotation ) / PI / 2.0 + 0.5, acos( normal.y ) / PI );
}
vec3 sample_irradiance_fast( vec3 normal )
{
// Sample the irradiance map if it exists, otherwise fall back to blurred reflection map.
if ( has_tex_skyenv )
{
vec2 polar = sphere_to_polar( normal );
// HACK: Sample a smaller mip here to avoid high frequency color variations on detailed normal
// mapped areas.
float miplevel = 5.5; // tweaked for a 360x180 irradiance texture
return textureLod( tex_skyenv, polar, miplevel ).rgb * exposure;
}
else
{
vec2 polar = sphere_to_polar( normal );
return textureLod( tex_skysphere, polar, 0.80 * skysphere_mip_count ).rgb * exposure;
}
}
float calculate_specular( vec3 normal, vec3 light_direction )
{
vec3 V = normalize( out_to_camera );
vec3 L = -normalize( light_direction );
vec3 H = normalize( V + L );
float rdotv = clamp( dot( normal, H ), 0.0, 1.0 );
float total_specular = pow( rdotv, specular_shininess );
return total_specular;
}
void main(void)
{
vec4 specular;
if( map_specular.has_tex ) {
specular = sample_colormap( map_specular, out_texcoord );
} else {
float roughness = 1.0;
float metallic = 0.0;
if( map_metallic.has_tex && map_roughness.has_tex ) {
metallic = sample_colormap( map_metallic, out_texcoord ).x;
roughness = sample_colormap( map_roughness, out_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, out_texcoord ).b + sample_colormap( map_roughness, out_texcoord ).r;
roughness = sample_colormap( map_roughness, out_texcoord ).g;
}
float gloss = metallic * (1.0 - roughness);
specular = vec4(gloss);
}
vec4 baseColor_alpha;
if ( map_albedo.has_tex )
baseColor_alpha = sample_colormap( map_albedo, out_texcoord );
else
baseColor_alpha = sample_colormap( map_diffuse, out_texcoord );
vec3 diffuse = baseColor_alpha.xyz;
float alpha = baseColor_alpha.w;
vec3 ambient = sample_colormap( map_ambient, out_texcoord ).xyz;
vec3 normals = normalize(texture( map_normals_tex, out_texcoord ).xyz * vec3(2.0) - vec3(1.0));
vec3 normal = out_normal;
if ( map_normals.has_tex )
{
// Mikkelsen's tangent space normal map decoding. See http://mikktspace.com/ for rationale.
vec3 bi = cross( out_normal, out_tangent );
vec3 nmap = normals.xyz;
normal = nmap.x * out_tangent + nmap.y * bi + nmap.z * out_normal;
}
normal = normalize( normal );
vec3 irradiance = sample_irradiance_fast( normal );
ambient *= irradiance;
vec3 color = ambient * global_ambient.rgb;
for ( int i = 0; i < lights.length(); i++ )
{
float ndotl = clamp( dot( normal, -normalize( lights[ i ].direction ) ), 0.0, 1.0 );
vec3 specular = specular.rgb * calculate_specular( normal, lights[ i ].direction ) * specular.a;
color += (diffuse + specular) * ndotl * lights[ i ].color;
}
color += sample_colormap( map_emissive, out_texcoord ).rgb;
frag_color = vec4( pow( color * exposure, vec3(1. / 2.2) ), alpha );
}