koel/resources/assets/js/visualizers/asteroid/shaders/blob.frag.ts
2024-10-14 00:37:01 +07:00

300 lines
8.4 KiB
TypeScript

export const blobFrag
= `
varying float v_noise;
uniform float u_audio_high;
uniform float u_audio_mid;
uniform float u_audio_bass;
uniform float u_audio_level;
uniform float u_audio_history;
vec3 norm(in vec3 _v){
return length(_v) > .0 ? normalize(_v) : vec3(.0);
}
#if defined(IS_POINTS)
uniform sampler2D tex_sprite;
#endif
#if defined(IS_PBR) && defined(HAS_CUBEMAP)
uniform samplerCube cubemap;
uniform samplerCube cubemap_b;
uniform float cross_fader;
uniform sampler2D tex_normal;
uniform sampler2D tex_roughness;
uniform sampler2D tex_metallic;
uniform float u_normal;
uniform float u_roughness;
uniform float u_metallic;
uniform float u_exposure;
uniform float u_gamma;
varying vec3 v_world_normal;
varying vec3 v_object_pos;
varying vec3 v_eye_pos;
varying vec3 v_pos;
varying vec3 v_normal;
varying vec3 v_world_pos;
varying vec2 v_uv;
#define PI 3.1415926535897932384626433832795
// Filmic tonemapping from
// http://filmicgames.com/archives/75
const float A = 0.15;
const float B = 0.50;
const float C = 0.10;
const float D = 0.20;
const float E = 0.02;
const float F = 0.30;
vec3 Uncharted2Tonemap( vec3 x )
{
return ((x*(A*x+C*B)+D*E)/((x*(A*x+B)+D*F) + .00001))-E/F;
}
// https://www.unrealengine.com/blog/physically-based-shading-on-mobile
vec3 EnvBRDFApprox( vec3 SpecularColor, float Roughness, float NoV )
{
const vec4 c0 = vec4( -1, -0.0275, -0.572, 0.022 );
const vec4 c1 = vec4( 1, 0.0425, 1.04, -0.04 );
vec4 r = Roughness * c0 + c1;
float a004 = min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y;
vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;
return SpecularColor * AB.x + AB.y;
}
// http://the-witness.net/news/2012/02/seamless-cube-map-filtering/
vec3 fix_cube_lookup( vec3 v, float cube_size, float lod ) {
float M = max(max(abs(v.x), abs(v.y)), abs(v.z));
float scale = 1. - exp2(lod) / (cube_size + .00001);
if (abs(v.x) != M) v.x *= scale;
if (abs(v.y) != M) v.y *= scale;
if (abs(v.z) != M) v.z *= scale;
return v;
}
// Normal Blending
// Source adapted from http://blog.selfshadow.com/publications/blending-in-detail/
vec3 blendNormalsUnity( vec3 baseNormal, vec3 detailsNormal )
{
vec3 n1 = baseNormal;
vec3 n2 = detailsNormal;
mat3 nBasis = mat3(
vec3(n1.z, n1.y, -n1.x), // +90 degree rotation around y axis
vec3(n1.x, n1.z, -n1.y), // -90 degree rotation around x axis
vec3(n1.x, n1.y, n1.z));
return norm(n2.x*nBasis[0] + n2.y*nBasis[1] + n2.z*nBasis[2]);
}
vec3 blendNormals( vec3 n1, vec3 n2 )
{
return blendNormalsUnity( n1, n2 );
}
#endif
#if defined(HAS_SHADOW)
uniform sampler2D u_shadow_map;
uniform vec3 u_light_pos;
uniform bool u_debug_shadow;
varying vec4 v_shadow_coord;
float sample_shadow( vec4 sc )
{
float s = 1./1024.;
vec2 unproj2D = vec2 (sc.s / (sc.q + .00001),
sc.t / (sc.q + .00001));
float shadow = 0.0;
shadow += texture2D( u_shadow_map, unproj2D + vec2(-s,-s) ).r;
shadow += texture2D( u_shadow_map, unproj2D + vec2(-s, 0.) ).r;
shadow += texture2D( u_shadow_map, unproj2D + vec2(-s, s) ).r;
shadow += texture2D( u_shadow_map, unproj2D + vec2( 0.,-s) ).r;
shadow += texture2D( u_shadow_map, unproj2D + vec2( 0., 0.) ).r;
shadow += texture2D( u_shadow_map, unproj2D + vec2( 0., s) ).r;
shadow += texture2D( u_shadow_map, unproj2D + vec2( s,-s) ).r;
shadow += texture2D( u_shadow_map, unproj2D + vec2( s, 0.) ).r;
shadow += texture2D( u_shadow_map, unproj2D + vec2( s, s) ).r;
return shadow/9.0;;
}
#endif
void main(){
float m_noise = v_noise;
float m_noise_inv = 1.-v_noise;
vec3 m_diffuse = vec3(0.);
m_diffuse.r += m_noise_inv + m_noise;
m_diffuse.g += m_noise*1.5;
//m_diffuse.b += m_noise;
m_diffuse -= pow(abs(1.-m_noise), 4.)*.95; //<- darken peak
m_diffuse = clamp(m_diffuse, vec3(0.), vec3(2.));
m_diffuse *= pow(u_audio_level, 2.);
vec3 m_col = m_diffuse;
#if defined(IS_SHADOW)
gl_FragColor = vec4(m_col, 1.);
return;
#endif
#if defined(IS_PBR) && defined(HAS_CUBEMAP)
vec3 N = norm( v_world_normal );
// blend with PBR's
N = blendNormals( N, texture2D( tex_normal, v_uv ).xyz );
vec3 V = norm( v_eye_pos );
// fresnel
float m_fresnel = pow(1. + dot(norm(v_world_pos - v_eye_pos), v_world_normal), 8.);
#if defined(HAS_SHADOW)
// Light direction
vec3 L = norm( u_light_pos - v_world_pos.xyz );
// Surface reflection vector
vec3 R = norm( -reflect( L, N ) );
#endif
// sample the roughness and metallic textures
float roughnessMask = texture2D( tex_roughness, v_uv ).r;
float metallicMask = texture2D( tex_metallic, v_uv ).r;
// deduce the diffuse and specular color from the baseColor and how metallic the material is
vec3 m_specular_col = vec3(m_diffuse)*8.;
vec3 m_diffuse_col = vec3(m_diffuse)*8.;
vec3 diffuseColor = m_diffuse_col - m_diffuse_col * u_metallic * metallicMask;
vec3 specularColor = mix( vec3( 0.08 * m_specular_col ), m_diffuse_col, u_metallic * metallicMask );
// sample the pre-filtered cubemap at the corresponding mipmap level
int numMips = 6;
float mip = float(numMips) - 1. + log2( u_roughness * roughnessMask );
vec3 lookup = -reflect( V, N );
vec3 cube_a_rad = pow( abs(textureCube( cubemap, fix_cube_lookup( lookup, 2048., mip ) ).rgb), vec3( 2.2 ) );
vec3 cube_b_rad = pow( abs(textureCube( cubemap_b, fix_cube_lookup( lookup, 2048., mip ) ).rgb), vec3( 2.2 ) );
vec3 cube_a_irr = pow( abs(textureCube( cubemap, fix_cube_lookup( N, 2048., 0. ) ).rgb), vec3( 2.2 ) );
vec3 cube_b_irr = pow( abs(textureCube( cubemap_b, fix_cube_lookup( N, 2048., 0. ) ).rgb), vec3( 2.2 ) );
vec3 radiance = mix(cube_a_rad, cube_b_rad, cross_fader);
vec3 irradiance = mix(cube_a_irr, cube_b_irr, cross_fader);
// get the approximate reflectance
// float NoV = saturate( dot( N, V ) );
float NoV = clamp( dot( N, V ), 0., 1. );
vec3 reflectance = EnvBRDFApprox( specularColor, pow( abs(u_roughness * roughnessMask), 4.0 ), NoV );
// combine the specular IBL and the BRDF
vec3 diffuse = diffuseColor * radiance;
vec3 specular = radiance * reflectance;
m_col = (diffuse + specular)*u_audio_level*(1.-min(m_fresnel, .99));
#if defined(HAS_SHADOW)
// from light source
vec3 m_light_diffuse_color = vec3(m_diffuse)*3.;
vec3 m_light_specular_color = vec3(m_diffuse)*3.;
float m_light_diffuse_intensity = 30.;
float m_light_specular_intensity = 30.;
float m_light_diffuse_pow = 150.;
float m_light_specular_pow = 120.;
// Diffuse factor
float NdotL = max( dot( N, L ), 0.0 );
vec3 D = vec3( NdotL );
D = pow(abs(D), vec3(m_light_diffuse_pow));
D *= m_light_diffuse_color * m_light_diffuse_intensity;
// Specular factor
vec3 S = pow( max( dot( R, V ), 0.0 ), m_light_specular_pow ) * vec3(1.);
S *= m_light_specular_color * m_light_specular_intensity;
m_col += (D + S)*u_audio_level*(1.-min(m_fresnel, .99));
// cal shadow
float m_shadow = 1.;
vec4 m_shadow_coord = v_shadow_coord;
m_shadow_coord.z += .0003; // <- bias
m_shadow = sample_shadow(m_shadow_coord);
m_col *= (m_shadow + m_col*.2 + m_diffuse*.5);
#endif
// add noise diffuse
m_col += pow(abs(m_diffuse), vec3(10.))*8.;
// apply the tone-mapping
m_col = Uncharted2Tonemap( m_col * u_exposure );
// white balance
m_col = m_col * ( 1. / (Uncharted2Tonemap( vec3( 20. ) ) + .00001) );
// gamma correction
m_col = pow( abs(m_col), vec3( 1. / (u_gamma + .00001) ) );
#endif
#if defined(IS_WIRE) || defined(IS_POINTS)
m_col.b -= m_col.g;
// inner ziggle
m_col *= .4 * pow(abs(m_noise), 6.);
// outter ziggle
m_col.rg += .2 * pow(abs(m_noise_inv), 4.);
m_col.g *= .5;
// treble burn
m_col += pow(abs(u_audio_high), 3.) * 1.;
// on&off
m_col *= u_audio_level;
#if defined(IS_WIRE)
m_col *= .7;
#endif
#endif
gl_FragColor = vec4(m_col, 1.);
#if defined(HAS_SHADOW)
if(u_debug_shadow)
gl_FragColor = vec4(vec3(m_shadow), 1.);
#endif
#if defined(IS_POINTS)
gl_FragColor *= texture2D(tex_sprite, gl_PointCoord);
#endif
#if defined(IS_POP) || defined(IS_POP_OUT)
gl_FragColor.rgb = pow(abs(gl_FragColor.rgb), vec3(1.2));
#if defined(IS_POINTS) && defined(IS_POP)
gl_FragColor.rgb *= pow(u_audio_level, 2.);
gl_FragColor.rgb *= 50.;
#endif
#if defined(IS_WIRE)
gl_FragColor.rgb *= 2.;
#if defined(IS_POP_OUT)
gl_FragColor.rgb *= .2;
#endif
#endif
#endif
}
`