Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Shader experiment
// bind gloss {label:"Gloss", default:0.5, max:1, step:0.01}
// bind cdiff {label:"Diffuse Colour", r:0.6, g:0.0, b:0.0}
// bind cspec {label:"Specular Colour", r:0.3, g:0.3, b:0.3}
// bind lightstrength {label:"Light Strength", default:3, max:100, step:0.1}
// bind envtop {label:"Environment Top", r:0.0, g:0.2, b:0.4}
// bind envmiddle {label:"Environment Middle", r:0.2, g:0.2, b:0.2}
// bind envbottom {label:"Environment Bottom", r:0.01, g:0.1, b:0.01}
// bind refractiveindex {label:"Refracive Index", default:1.5, max:3, step:0.1}
// bind normalmap {label:"Normal Map", default:false}
// bind diffuse {label:"Diffuse", default:true}
// bind specular {label:"Specular", default:true}
// bind exposure {label:"Exposure", default:0, min:-8, max:8, step:0.1}
varying vec2 texcoord;
varying vec3 wview;
varying vec3 wnormal;
varying vec3 wtangent;
uniform sampler2D normal_map;
uniform sampler2D gloss_map;
uniform float gloss;
uniform vec3 cdiff;
uniform vec3 cspec;
uniform vec3 envtop;
uniform vec3 envmiddle;
uniform vec3 envbottom;
uniform float lightstrength;
uniform float exposure;
uniform bool normalmap;
uniform bool diffuse;
uniform bool specular;
vec3 light = normalize(vec3(1, 1, 1));
const float gamma = 2.2;
const float pi = 3.1415927;
float saturate(float v)
{
return clamp(v, 0.0, 1.0);
}
vec3 pow(vec3 v, float p)
{
return vec3(pow(v.x, p), pow(v.y, p), pow(v.z, p));
}
vec3 lerp(vec3 a, vec3 b, float f)
{
float r = 1.0 - f;
return vec3(r * a.x + f * b.x, r * a.y + f * b.y, r * a.z + f * b.z);
}
vec3 ToLinear(vec3 v)
{
return pow(v, gamma);
}
vec3 ToSRGB(vec3 v)
{
return pow(v, 1.0/gamma);
}
vec3 Fresnel(vec3 reflectance, float x)
{
return reflectance + (1.0 - reflectance - 2.0 * reflectance * x) * pow(1.0 - x, 5.0);
}
vec3 SampleEnvironment(vec3 direction)
{
vec3 top = ToLinear(envtop);
vec3 middle = ToLinear(envmiddle);
vec3 bottom = ToLinear(envbottom);
if (direction.y > 0.0)
return lerp(middle, top, direction.y);
return lerp(middle, bottom, -direction.y);
}
float DiffuseConservation()
{
return 1.0 / pi;
}
float SpecularConservation(float power)
{
return 0.0397436 * power + 0.0856832;
}
void main()
{
// Unpack normal map
vec3 bump = texture2D(normal_map, texcoord.xy).xyz;
bump = bump*2.0 - 1.0;
// Transform normal to world-space
vec3 wbitangent = cross(wnormal, wtangent);
mat3 t2w = mat3(wtangent, wbitangent, wnormal);
vec3 n = normalize(t2w*bump);
if (!normalmap)
n = normalize(wnormal);
// Other vectors for lighting
vec3 l = normalize(light);
vec3 v = normalize(wview);
vec3 h = normalize(v + l);
vec3 r = reflect(-v, n);
// Cosines
float ndoth = saturate(dot(n, h));
float ndotv = saturate(dot(n, v));
float ndotl = saturate(dot(n, l));
float power = exp2(13.0 * gloss);
// Linearise material properties
vec3 cs = max(ToLinear(cspec), vec3(0.01));
vec3 cd = ToLinear(cdiff) * (1.0 - cs);
// Energy conserving diffuse and specular
vec3 diff = DiffuseConservation() * cd;
vec3 spec = SpecularConservation(power) * Fresnel(cs, ndoth) * pow(ndoth, power) / max(ndotv, ndotl);
// Combine diffuse and specular lighting
vec3 lightcontribution = vec3(0.0);
if (diffuse)
lightcontribution += cd*diff*ndotl*lightstrength;
if (specular)
lightcontribution += cs*spec*ndotl*lightstrength;
// Add simple environment lighting
vec3 envcontribution = vec3(0.0);
if (diffuse)
envcontribution += cd * SampleEnvironment(n);
if (specular)
envcontribution += Fresnel(cs, ndotv) * SampleEnvironment(r);
// Combine!
vec3 color = lightcontribution + envcontribution;
// Basic tone mapping
color *= pow(2.0, exposure);
color = color / (1.0 + color);
// Convert to sRGB for display
color = ToSRGB(color);
gl_FragColor = vec4(color, 1.0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.