pex-renderer
Version:
Physically Based Renderer for Pex
108 lines (90 loc) • 3.91 kB
JavaScript
module.exports = /* glsl */ `
uniform vec4 uDiffuse;
uniform vec3 uSpecular;
uniform float uGlossiness;
uniform sampler2D uDiffuseMap;
uniform float uDiffuseMapEncoding;
uniform mat3 uDiffuseMapTexCoordTransform;
vec4 getDiffuse(in PBRData data) {
// assumes sRGB texture
vec2 texCoord = getTextureCoordinates(data, DIFFUSE_MAP_TEX_COORD_INDEX, uDiffuseMapTexCoordTransform);
vec2 texCoord = getTextureCoordinates(data, DIFFUSE_MAP_TEX_COORD_INDEX);
vec4 texelColor = texture2D(uDiffuseMap, texCoord);
return vec4(decode(uDiffuse, 3).rgb, uDiffuse.a) * vec4(decode(texelColor, 3).rgb, texelColor.a);
}
vec4 getDiffuse(in PBRData data) {
return vec4(decode(uDiffuse, 3).rgb, uDiffuse.a);
}
uniform sampler2D uSpecularGlossinessMap;
uniform mat3 uSpecularGlossinessMapTexCoordTransform;
vec4 getSpecularGlossiness(in PBRData data) {
// assumes specular is sRGB and glossiness is linear
vec2 texCoord = getTextureCoordinates(data, SPECULAR_GLOSSINESS_MAP_TEX_COORD_INDEX, uSpecularGlossinessMapTexCoordTransform);
vec2 texCoord = getTextureCoordinates(data, SPECULAR_GLOSSINESS_MAP_TEX_COORD_INDEX);
vec4 specGloss = texture2D(uSpecularGlossinessMap, texCoord);
//TODO: should i move uSpecular to linear?
return vec4(uSpecular, uGlossiness) * vec4(decode(vec4(specGloss.rgb, 1.0), 3).rgb, specGloss.a);
}
vec4 getSpecularGlossiness(in PBRData data) {
return vec4(uSpecular, uGlossiness);
}
// assumes linear color
float perceivedBrightness(vec3 c) {
return 0.299 * c.r + 0.587 * c.g + 0.114 * c.b;
}
float maxComponent(vec3 c) {
return max(c.r, max(c.b, c.g));
}
float solveMetallic(float diffuse, float specular, float oneMinusSpecularStrength) {
if (specular < 0.04) {
return 0.0;
}
float a = 0.04;
float b = diffuse * oneMinusSpecularStrength / (1.0 - a) + specular - 2.0 * a;
float c = a - specular;
float D = max(b * b - 4.0 * a * c, 0.0);
return clamp((-b + sqrt(D)) / (2.0 * a), 0.0, 1.0);
}
void getBaseColorAndMetallicRoughnessFromSpecularGlossiness(inout PBRData data) {
vec4 specularGlossiness = getSpecularGlossiness(data);
vec3 specular = specularGlossiness.rgb;
data.f0 = specular;
float glossiness = specularGlossiness.a;
data.roughness = 1.0 - glossiness;
vec4 diffuseRGBA = getDiffuse(data);
vec3 diffuse = diffuseRGBA.rgb;
data.opacity = diffuseRGBA.a;
float epsilon = 1e-6;
float a = 0.04;
// ported from https://github.com/KhronosGroup/glTF/blob/master/extensions/Khronos/KHR_materials_pbrSpecularGlossiness/examples/convert-between-workflows/js/three.pbrUtilities.js
float oneMinusSpecularStrength = 1.0 - maxComponent(specular);
data.metallic = solveMetallic(perceivedBrightness(diffuse), perceivedBrightness(specular), oneMinusSpecularStrength);
vec3 baseColorFromDiffuse = diffuse * oneMinusSpecularStrength / (1.0 - a) / max(1.0 - data.metallic, epsilon);
vec3 baseColorFromSpecular = (specular - a * (1.0 - data.metallic)) * (1.0 / max(data.metallic, epsilon));
data.baseColor = mix(baseColorFromDiffuse, baseColorFromSpecular, data.metallic * data.metallic);
vec3 tint = decode(vColor, SRGB).rgb;
data.baseColor *= tint;
data.f0 *= tint;
data.opacity *= vColor.a;
}
`