Last active
June 15, 2019 11:57
-
-
Save soma-arc/5d53816885e64628869ed54bfb95e31d to your computer and use it in GitHub Desktop.
glTF 2.0 PBR materials metaric-roughness shader for BRDF Explorer
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
analytic | |
# glTF 2.0 PBR Materials | |
# metallic-roughness | |
# Reference: | |
# glTF Specification, 2.0 | |
# https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#metallic-roughness-material | |
# glTF 2.0: PBR Materials by Saurabh Bhatia. May 2017 | |
# https://www.khronos.org/assets/uploads/developers/library/2017-gtc/glTF-2.0-and-PBR-GTC_May17.pdf | |
# glTF-WebGL-PBR | |
# https://github.com/KhronosGroup/glTF-WebGL-PBR | |
# variables go here... | |
# only floats supported right now. | |
# [type] [name] [min val] [max val] [default val] | |
::begin parameters | |
color u_baseColor 1. 1. 1. | |
float u_metallic 0. 1. 0. | |
float u_roughness 0. 1. 0. | |
::end parameters | |
::begin shader | |
const float PI = 3.14159265358979323846; | |
const float DIV_PI = 1.0 / PI; | |
const vec3 dielectricSpecular = vec3(0.04); | |
const vec3 BLACK = vec3(0); | |
// This G term is used in glTF-WebGL-PBR | |
// Microfacet Models for Refraction through Rough Surfaces | |
float G1_GGX(float alphaSq, float NoX) { | |
float tanSq = (1.0 - NoX * NoX) / max((NoX * NoX), 0.00001); | |
return 2. / (1. + sqrt(1. + alphaSq * tanSq)); | |
} | |
// 1 / (1 + delta(l)) * 1 / (1 + delta(v)) | |
float Smith_G(float alphaSq, float NoL, float NoV) { | |
return G1_GGX(alphaSq, NoL) * G1_GGX(alphaSq, NoV); | |
} | |
// Height-Correlated Masking and Shadowing | |
// Smith Joint Masking-Shadowing Function | |
float GGX_Delta(float alphaSq, float NoX) { | |
return (-1. + sqrt(1. + alphaSq * (1. / (NoX * NoX) - 1.))) / 2.; | |
} | |
float SmithJoint_G(float alphaSq, float NoL, float NoV) { | |
return 1. / (1. + GGX_Delta(alphaSq, NoL) + GGX_Delta(alphaSq, NoV)); | |
} | |
float GGX_D(float alphaSq, float NoH) { | |
float c = (NoH * NoH * (alphaSq - 1.) + 1.); | |
return alphaSq / (c * c) * DIV_PI; | |
} | |
vec3 BRDF( vec3 L, vec3 V, vec3 N, vec3 X, vec3 Y ) { | |
vec3 H = normalize(L+V); | |
float LoH = dot(L, H); | |
float NoH = dot(N, H); | |
float VoH = dot(V, H); | |
float NoL = dot(N, L); | |
float NoV = dot(N, V); | |
vec3 F0 = mix(dielectricSpecular, u_baseColor, u_metallic); | |
vec3 cDiff = mix(u_baseColor * (1. - dielectricSpecular.r), | |
BLACK, | |
u_metallic); | |
float alpha = u_roughness * u_roughness; | |
float alphaSq = alpha * alpha; | |
// Schlick's approximation | |
vec3 F = F0 + (vec3(1.) - F0) * pow((1. - VoH), 5.); | |
vec3 diffuse = (vec3(1.) - F) * cDiff * DIV_PI; | |
float G = SmithJoint_G(alphaSq, NoL, NoV); | |
// float G = Smith_G(alphaSq, NoL, NoV); | |
float D = GGX_D(alphaSq, NoH); | |
float specular = (F * G * D) / (4. * NoL * NoV); | |
return diffuse + vec3(specular); | |
} | |
::end shader |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I believe there's a typo in line 84, because F is a vec3 and the rest of values in the expression are all floats, so the result is a vec3 and not a float. In fact, in the next line you turn specular into a vec3. On my Mac I get a compilation error at line 84. If I change line 84 so that specular is a vec3, and I remove the vec3() conversion from line 85, it seems to work fine (although I don't have any ground truth for accurately testing the result).