Created
March 2, 2020 09:35
-
-
Save eXponenta/07da9be85e4d4c1e43247662c8979737 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const vertex100 = /* glsl */ ` | |
precision highp float; | |
precision highp int; | |
attribute vec3 position; | |
attribute vec2 uv; | |
attribute vec3 normal; | |
uniform mat3 normalMatrix; | |
uniform mat4 modelMatrix; | |
uniform mat4 modelViewMatrix; | |
uniform mat4 projectionMatrix; | |
varying vec2 vUv; | |
varying vec3 vNormal; | |
varying vec3 vMPos; | |
void main() { | |
vUv = uv; | |
vNormal = normalize(normalMatrix * normal); | |
vMPos = (modelMatrix * vec4(position, 1.0)).xyz; | |
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); | |
} | |
`; | |
const fragment100 = /* glsl */ ` | |
#extension GL_OES_standard_derivatives : enable | |
precision highp float; | |
precision highp int; | |
uniform vec3 cameraPosition; | |
uniform mat4 viewMatrix; | |
uniform sampler2D tBaseColor; | |
uniform vec3 uBaseColor; | |
uniform float uAlpha; | |
uniform sampler2D tRMO; | |
uniform float uMetallic; | |
uniform float uRoughness; | |
uniform float uOcclusion; | |
uniform sampler2D tNormal; | |
uniform float uNormalScale; | |
uniform float uNormalUVScale; | |
uniform sampler2D tEmissive; | |
uniform float uEmissive; | |
uniform sampler2D tOpacity; | |
uniform sampler2D tLUT; | |
uniform sampler2D tEnvDiffuse; | |
uniform sampler2D tEnvSpecular; | |
uniform float uEnvSpecular; | |
uniform vec3 uLightDirection; | |
uniform vec3 uLightColor; | |
varying vec2 vUv; | |
varying vec3 vNormal; | |
varying vec3 vMPos; | |
const float PI = 3.14159265359; | |
const float RECIPROCAL_PI = 0.31830988618; | |
const float RECIPROCAL_PI2 = 0.15915494; | |
const float LN2 = 0.6931472; | |
const float ENV_LODS = 6.0; | |
vec4 SRGBtoLinear(vec4 srgb) { | |
vec3 linOut = pow(srgb.xyz, vec3(2.2)); | |
return vec4(linOut, srgb.w);; | |
} | |
vec4 RGBMToLinear(in vec4 value) { | |
float maxRange = 6.0; | |
return vec4(value.xyz * value.w * maxRange, 1.0); | |
} | |
vec3 linearToSRGB(vec3 color) { | |
return pow(color, vec3(1.0 / 2.2)); | |
} | |
vec3 getNormal() { | |
vec3 pos_dx = dFdx(vMPos.xyz); | |
vec3 pos_dy = dFdy(vMPos.xyz); | |
vec2 tex_dx = dFdx(vUv); | |
vec2 tex_dy = dFdy(vUv); | |
vec3 t = normalize(pos_dx * tex_dy.t - pos_dy * tex_dx.t); | |
vec3 b = normalize(-pos_dx * tex_dy.s + pos_dy * tex_dx.s); | |
mat3 tbn = mat3(t, b, normalize(vNormal)); | |
vec3 n = texture2D(tNormal, vUv * uNormalUVScale).rgb * 2.0 - 1.0; | |
n.xy *= uNormalScale; | |
vec3 normal = normalize(tbn * n); | |
// Get world normal from view normal (normalMatrix * normal) | |
return normalize((vec4(normal, 0.0) * viewMatrix).xyz); | |
} | |
vec3 specularReflection(vec3 specularEnvR0, vec3 specularEnvR90, float VdH) { | |
return specularEnvR0 + (specularEnvR90 - specularEnvR0) * pow(clamp(1.0 - VdH, 0.0, 1.0), 5.0); | |
} | |
float geometricOcclusion(float NdL, float NdV, float roughness) { | |
float r = roughness; | |
float attenuationL = 2.0 * NdL / (NdL + sqrt(r * r + (1.0 - r * r) * (NdL * NdL))); | |
float attenuationV = 2.0 * NdV / (NdV + sqrt(r * r + (1.0 - r * r) * (NdV * NdV))); | |
return attenuationL * attenuationV; | |
} | |
float microfacetDistribution(float roughness, float NdH) { | |
float roughnessSq = roughness * roughness; | |
float f = (NdH * roughnessSq - NdH) * NdH + 1.0; | |
return roughnessSq / (PI * f * f); | |
} | |
vec2 cartesianToPolar(vec3 n) { | |
vec2 uv; | |
uv.x = atan(n.z, n.x) * RECIPROCAL_PI2 + 0.5; | |
uv.y = asin(n.y) * RECIPROCAL_PI + 0.5; | |
return uv; | |
} | |
void getIBLContribution(inout vec3 diffuse, inout vec3 specular, float NdV, float roughness, vec3 n, vec3 reflection, vec3 diffuseColor, vec3 specularColor) { | |
vec3 brdf = SRGBtoLinear(texture2D(tLUT, vec2(NdV, roughness))).rgb; | |
vec3 diffuseLight = RGBMToLinear(texture2D(tEnvDiffuse, cartesianToPolar(n))).rgb; | |
// Sample 2 levels and mix between to get smoother degradation | |
float blend = roughness * ENV_LODS; | |
float level0 = floor(blend); | |
float level1 = min(ENV_LODS, level0 + 1.0); | |
blend -= level0; | |
// Sample the specular env map atlas depending on the roughness value | |
vec2 uvSpec = cartesianToPolar(reflection); | |
uvSpec.y /= 2.0; | |
vec2 uv0 = uvSpec; | |
vec2 uv1 = uvSpec; | |
uv0 /= pow(2.0, level0); | |
uv0.y += 1.0 - exp(-LN2 * level0); | |
uv1 /= pow(2.0, level1); | |
uv1.y += 1.0 - exp(-LN2 * level1); | |
vec3 specular0 = RGBMToLinear(texture2D(tEnvSpecular, uv0)).rgb; | |
vec3 specular1 = RGBMToLinear(texture2D(tEnvSpecular, uv1)).rgb; | |
vec3 specularLight = mix(specular0, specular1, blend); | |
diffuse = diffuseLight * diffuseColor; | |
// Bit of extra reflection for smooth materials | |
float reflectivity = pow((1.0 - roughness), 2.0) * 0.05; | |
specular = specularLight * (specularColor * brdf.x + brdf.y + reflectivity); | |
specular *= uEnvSpecular; | |
} | |
void main() { | |
vec3 baseColor = SRGBtoLinear(texture2D(tBaseColor, vUv)).rgb * uBaseColor; | |
// RMO map packed as rgb = [roughness, metallic, occlusion] | |
vec4 rmaSample = texture2D(tRMO, vUv); | |
float roughness = clamp(rmaSample.r * uRoughness, 0.04, 1.0); | |
float metallic = clamp(rmaSample.g * uMetallic, 0.04, 1.0); | |
vec3 f0 = vec3(0.04); | |
vec3 diffuseColor = baseColor * (vec3(1.0) - f0) * (1.0 - metallic); | |
vec3 specularColor = mix(f0, baseColor, metallic); | |
vec3 specularEnvR0 = specularColor; | |
vec3 specularEnvR90 = vec3(clamp(max(max(specularColor.r, specularColor.g), specularColor.b) * 25.0, 0.0, 1.0)); | |
vec3 N = getNormal(); | |
vec3 V = normalize(cameraPosition - vMPos); | |
vec3 L = normalize(uLightDirection); | |
vec3 H = normalize(L + V); | |
vec3 reflection = normalize(reflect(-V, N)); | |
float NdL = clamp(dot(N, L), 0.001, 1.0); | |
float NdV = clamp(abs(dot(N, V)), 0.001, 1.0); | |
float NdH = clamp(dot(N, H), 0.0, 1.0); | |
float LdH = clamp(dot(L, H), 0.0, 1.0); | |
float VdH = clamp(dot(V, H), 0.0, 1.0); | |
vec3 F = specularReflection(specularEnvR0, specularEnvR90, VdH); | |
float G = geometricOcclusion(NdL, NdV, roughness); | |
float D = microfacetDistribution(roughness, NdH); | |
vec3 diffuseContrib = (1.0 - F) * (diffuseColor / PI); | |
vec3 specContrib = F * G * D / (4.0 * NdL * NdV); | |
// Shading based off lights | |
vec3 color = NdL * uLightColor * (diffuseContrib + specContrib); | |
// Get base alpha | |
float alpha = 1.0; | |
alpha *= texture2D(tOpacity, vUv).g; | |
// Add lights spec to alpha for reflections on transparent surfaces (glass) | |
alpha = max(alpha, max(max(specContrib.r, specContrib.g), specContrib.b)); | |
// Calculate IBL lighting | |
vec3 diffuseIBL; | |
vec3 specularIBL; | |
getIBLContribution(diffuseIBL, specularIBL, NdV, roughness, N, reflection, diffuseColor, specularColor); | |
// Add IBL on top of color | |
color += diffuseIBL + specularIBL; | |
// Add IBL spec to alpha for reflections on transparent surfaces (glass) | |
alpha = max(alpha, max(max(specularIBL.r, specularIBL.g), specularIBL.b)); | |
// Multiply occlusion | |
color = mix(color, color * rmaSample.b, uOcclusion); | |
// Add emissive on top | |
vec3 emissive = SRGBtoLinear(texture2D(tEmissive, vUv)).rgb * uEmissive; | |
color += emissive; | |
// Convert to sRGB to display | |
gl_FragColor.rgb = linearToSRGB(color); | |
// Apply uAlpha uniform at the end to overwrite any specular additions on transparent surfaces | |
gl_FragColor.a = alpha * uAlpha; | |
} | |
`; | |
const vertex300 = /* glsl */ `#version 300 es | |
precision highp float; | |
precision highp int; | |
in vec3 position; | |
in vec2 uv; | |
in vec3 normal; | |
uniform mat3 normalMatrix; | |
uniform mat4 modelMatrix; | |
uniform mat4 modelViewMatrix; | |
uniform mat4 projectionMatrix; | |
out vec2 vUv; | |
out vec3 vNormal; | |
out vec3 vMPos; | |
void main() { | |
vUv = uv; | |
vNormal = normalize(normalMatrix * normal); | |
vMPos = (modelMatrix * vec4(position, 1.0)).xyz; | |
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); | |
} | |
`; | |
const fragment300 = /* glsl */ `#version 300 es | |
precision highp float; | |
precision highp int; | |
uniform vec3 cameraPosition; | |
uniform mat4 viewMatrix; | |
uniform sampler2D tBaseColor; | |
uniform vec3 uBaseColor; | |
uniform float uAlpha; | |
uniform sampler2D tRMO; | |
uniform float uMetallic; | |
uniform float uRoughness; | |
uniform float uOcclusion; | |
uniform sampler2D tNormal; | |
uniform float uNormalScale; | |
uniform float uNormalUVScale; | |
uniform sampler2D tEmissive; | |
uniform float uEmissive; | |
uniform sampler2D tOpacity; | |
uniform sampler2D tLUT; | |
uniform sampler2D tEnvDiffuse; | |
uniform sampler2D tEnvSpecular; | |
uniform float uEnvSpecular; | |
uniform vec3 uLightDirection; | |
uniform vec3 uLightColor; | |
in vec2 vUv; | |
in vec3 vNormal; | |
in vec3 vMPos; | |
out vec4 FragColor; | |
const float PI = 3.14159265359; | |
const float RECIPROCAL_PI = 0.31830988618; | |
const float RECIPROCAL_PI2 = 0.15915494; | |
const float LN2 = 0.6931472; | |
const float ENV_LODS = 6.0; | |
vec4 SRGBtoLinear(vec4 srgb) { | |
vec3 linOut = pow(srgb.xyz, vec3(2.2)); | |
return vec4(linOut, srgb.w);; | |
} | |
vec4 RGBMToLinear(in vec4 value) { | |
float maxRange = 6.0; | |
return vec4(value.xyz * value.w * maxRange, 1.0); | |
} | |
vec3 linearToSRGB(vec3 color) { | |
return pow(color, vec3(1.0 / 2.2)); | |
} | |
vec3 getNormal() { | |
vec3 pos_dx = dFdx(vMPos.xyz); | |
vec3 pos_dy = dFdy(vMPos.xyz); | |
vec2 tex_dx = dFdx(vUv); | |
vec2 tex_dy = dFdy(vUv); | |
vec3 t = normalize(pos_dx * tex_dy.t - pos_dy * tex_dx.t); | |
vec3 b = normalize(-pos_dx * tex_dy.s + pos_dy * tex_dx.s); | |
mat3 tbn = mat3(t, b, normalize(vNormal)); | |
vec3 n = texture(tNormal, vUv * uNormalUVScale).rgb * 2.0 - 1.0; | |
n.xy *= uNormalScale; | |
vec3 normal = normalize(tbn * n); | |
// Get world normal from view normal (normalMatrix * normal) | |
return normalize((vec4(normal, 0.0) * viewMatrix).xyz); | |
} | |
vec3 specularReflection(vec3 specularEnvR0, vec3 specularEnvR90, float VdH) { | |
return specularEnvR0 + (specularEnvR90 - specularEnvR0) * pow(clamp(1.0 - VdH, 0.0, 1.0), 5.0); | |
} | |
float geometricOcclusion(float NdL, float NdV, float roughness) { | |
float r = roughness; | |
float attenuationL = 2.0 * NdL / (NdL + sqrt(r * r + (1.0 - r * r) * (NdL * NdL))); | |
float attenuationV = 2.0 * NdV / (NdV + sqrt(r * r + (1.0 - r * r) * (NdV * NdV))); | |
return attenuationL * attenuationV; | |
} | |
float microfacetDistribution(float roughness, float NdH) { | |
float roughnessSq = roughness * roughness; | |
float f = (NdH * roughnessSq - NdH) * NdH + 1.0; | |
return roughnessSq / (PI * f * f); | |
} | |
vec2 cartesianToPolar(vec3 n) { | |
vec2 uv; | |
uv.x = atan(n.z, n.x) * RECIPROCAL_PI2 + 0.5; | |
uv.y = asin(n.y) * RECIPROCAL_PI + 0.5; | |
return uv; | |
} | |
void getIBLContribution(inout vec3 diffuse, inout vec3 specular, float NdV, float roughness, vec3 n, vec3 reflection, vec3 diffuseColor, vec3 specularColor) { | |
vec3 brdf = SRGBtoLinear(texture(tLUT, vec2(NdV, roughness))).rgb; | |
vec3 diffuseLight = RGBMToLinear(texture(tEnvDiffuse, cartesianToPolar(n))).rgb; | |
// Sample 2 levels and mix between to get smoother degradation | |
float blend = roughness * ENV_LODS; | |
float level0 = floor(blend); | |
float level1 = min(ENV_LODS, level0 + 1.0); | |
blend -= level0; | |
// Sample the specular env map atlas depending on the roughness value | |
vec2 uvSpec = cartesianToPolar(reflection); | |
uvSpec.y /= 2.0; | |
vec2 uv0 = uvSpec; | |
vec2 uv1 = uvSpec; | |
uv0 /= pow(2.0, level0); | |
uv0.y += 1.0 - exp(-LN2 * level0); | |
uv1 /= pow(2.0, level1); | |
uv1.y += 1.0 - exp(-LN2 * level1); | |
vec3 specular0 = RGBMToLinear(texture(tEnvSpecular, uv0)).rgb; | |
vec3 specular1 = RGBMToLinear(texture(tEnvSpecular, uv1)).rgb; | |
vec3 specularLight = mix(specular0, specular1, blend); | |
diffuse = diffuseLight * diffuseColor; | |
// Bit of extra reflection for smooth materials | |
float reflectivity = pow((1.0 - roughness), 2.0) * 0.05; | |
specular = specularLight * (specularColor * brdf.x + brdf.y + reflectivity); | |
specular *= uEnvSpecular; | |
} | |
void main() { | |
vec3 baseColor = SRGBtoLinear(texture(tBaseColor, vUv)).rgb * uBaseColor; | |
// RMO map packed as rgb = [roughness, metallic, occlusion] | |
vec4 rmaSample = texture(tRMO, vUv); | |
float roughness = clamp(rmaSample.r * uRoughness, 0.04, 1.0); | |
float metallic = clamp(rmaSample.g * uMetallic, 0.04, 1.0); | |
vec3 f0 = vec3(0.04); | |
vec3 diffuseColor = baseColor * (vec3(1.0) - f0) * (1.0 - metallic); | |
vec3 specularColor = mix(f0, baseColor, metallic); | |
vec3 specularEnvR0 = specularColor; | |
vec3 specularEnvR90 = vec3(clamp(max(max(specularColor.r, specularColor.g), specularColor.b) * 25.0, 0.0, 1.0)); | |
vec3 N = getNormal(); | |
vec3 V = normalize(cameraPosition - vMPos); | |
vec3 L = normalize(uLightDirection); | |
vec3 H = normalize(L + V); | |
vec3 reflection = normalize(reflect(-V, N)); | |
float NdL = clamp(dot(N, L), 0.001, 1.0); | |
float NdV = clamp(abs(dot(N, V)), 0.001, 1.0); | |
float NdH = clamp(dot(N, H), 0.0, 1.0); | |
float LdH = clamp(dot(L, H), 0.0, 1.0); | |
float VdH = clamp(dot(V, H), 0.0, 1.0); | |
vec3 F = specularReflection(specularEnvR0, specularEnvR90, VdH); | |
float G = geometricOcclusion(NdL, NdV, roughness); | |
float D = microfacetDistribution(roughness, NdH); | |
vec3 diffuseContrib = (1.0 - F) * (diffuseColor / PI); | |
vec3 specContrib = F * G * D / (4.0 * NdL * NdV); | |
// Shading based off lights | |
vec3 color = NdL * uLightColor * (diffuseContrib + specContrib); | |
// Get base alpha | |
float alpha = 1.0; | |
alpha *= texture(tOpacity, vUv).g; | |
// Add lights spec to alpha for reflections on transparent surfaces (glass) | |
alpha = max(alpha, max(max(specContrib.r, specContrib.g), specContrib.b)); | |
// Calculate IBL lighting | |
vec3 diffuseIBL; | |
vec3 specularIBL; | |
getIBLContribution(diffuseIBL, specularIBL, NdV, roughness, N, reflection, diffuseColor, specularColor); | |
// Add IBL on top of color | |
color += diffuseIBL + specularIBL; | |
// Add IBL spec to alpha for reflections on transparent surfaces (glass) | |
alpha = max(alpha, max(max(specularIBL.r, specularIBL.g), specularIBL.b)); | |
// Multiply occlusion | |
color = mix(color, color * rmaSample.b, uOcclusion); | |
// Add emissive on top | |
vec3 emissive = SRGBtoLinear(texture(tEmissive, vUv)).rgb * uEmissive; | |
color += emissive; | |
// Convert to sRGB to display | |
FragColor.rgb = linearToSRGB(color); | |
// Apply uAlpha uniform at the end to overwrite any specular additions on transparent surfaces | |
FragColor.a = alpha * uAlpha; | |
} | |
`; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment