4 precision highp float;
\r
6 precision mediump float;
\r
10 #ifdef GLTF_CHANNELS
\r
11 // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#pbrmetallicroughnessmetallicroughnesstexture
\r
14 #else //GLTF_CHANNELS
\r
17 #endif //GLTF_CHANNELS
\r
21 uniform sampler2D sAlbedoAlpha;
\r
22 uniform sampler2D sMetalRoughness;
\r
23 uniform sampler2D sNormal;
\r
26 uniform float uAlphaThreshold;
\r
30 uniform sampler2D sAlbedoMetal;
\r
31 uniform sampler2D sNormalRoughness;
\r
35 uniform sampler2D sAmbientOcclusion;
\r
38 uniform samplerCube sDiffuse;
\r
39 uniform samplerCube sSpecular;
\r
41 // Number of mip map levels in the texture
\r
42 uniform float uMaxLOD;
\r
44 // Transformation matrix of the cubemap texture
\r
45 uniform mat4 uCubeMatrix;
\r
47 uniform vec4 uColor;
\r
48 uniform float uMetallicFactor;
\r
49 uniform float uRoughnessFactor;
\r
51 //IBL Light intensity
\r
52 uniform float uIblIntensity;
\r
61 // Functions for BRDF calculation come from
\r
62 // https://www.unrealengine.com/blog/physically-based-shading-on-mobile
\r
63 // Based on the paper by Dimitar Lazarov
\r
64 // http://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf
\r
65 vec3 EnvBRDFApprox( vec3 SpecularColor, float Roughness, float NoV )
\r
67 const vec4 c0 = vec4( -1.0, -0.0275, -0.572, 0.022 );
\r
68 const vec4 c1 = vec4( 1.0, 0.0425, 1.04, -0.04 );
\r
69 vec4 r = Roughness * c0 + c1;
\r
70 float a004 = min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y;
\r
71 vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;
\r
73 return SpecularColor * AB.x + AB.y;
\r
78 // We get information from the maps (albedo, normal map, roughness, metalness
\r
79 // I access the maps in the order they will be used
\r
81 vec4 albedoAlpha = texture(sAlbedoAlpha, vUV.st);
\r
82 float alpha = albedoAlpha.a;
\r
84 if (alpha <= uAlphaThreshold)
\r
89 vec3 albedoColor = albedoAlpha.rgb * uColor.rgb;
\r
91 vec4 metalRoughness = texture(sMetalRoughness, vUV.st);
\r
92 float metallic = metalRoughness.METALLIC * uMetallicFactor;
\r
93 float roughness = metalRoughness.ROUGHNESS * uRoughnessFactor;
\r
95 vec3 normalMap = texture(sNormal, vUV.st).rgb;
\r
97 vec4 albedoMetal = texture(sAlbedoMetal, vUV.st);
\r
98 vec3 albedoColor = albedoMetal.rgb * uColor.rgb;
\r
99 float metallic = albedoMetal.a * uMetallicFactor;
\r
101 vec4 normalRoughness = texture(sNormalRoughness, vUV.st);
\r
102 vec3 normalMap = normalRoughness.rgb;
\r
103 float roughness = normalRoughness.a * uRoughnessFactor;
\r
105 //Normalize vectors
\r
106 vec3 normal = normalize(vNormal);
\r
107 vec3 tangent = normalize(vTangent);
\r
109 // NOTE: normal and tangent have to be orthogonal for the result of the cross()
\r
110 // product to be a unit vector. We might find that we need to normalize().
\r
111 vec3 bitangent = cross(normal, tangent);
\r
113 vec3 viewVec = normalize(vViewVec);
\r
115 // Create Inverse Local to world matrix
\r
116 mat3 vInvTBN = mat3(tangent, bitangent, normal);
\r
118 // Get normal map info in world space
\r
119 normalMap = normalize(normalMap - 0.5);
\r
120 vec3 newNormal = vInvTBN * normalMap.rgb;
\r
122 // Calculate normal dot view vector
\r
123 float NoV = max(dot(newNormal, -viewVec), 0.0);
\r
126 vec3 reflectionVec = reflect(viewVec, newNormal);
\r
128 //transform it now to environment coordinates (used when the environment rotates)
\r
129 vec3 reflecCube = (uCubeMatrix * vec4( reflectionVec, 0.0 ) ).xyz;
\r
130 reflecCube = normalize( reflecCube );
\r
132 //transform it now to environment coordinates
\r
133 vec3 normalCube = ( uCubeMatrix * vec4( newNormal, 0.0 ) ).xyz;
\r
134 normalCube = normalize( normalCube );
\r
136 // Get irradiance from diffuse cubemap
\r
137 vec3 irradiance = texture( sDiffuse, normalCube ).rgb;
\r
139 // Access reflection color using roughness value
\r
140 float finalLod = mix( 0.0, uMaxLOD - 2.0, roughness);
\r
141 vec3 reflectionColor = textureLod(sSpecular, reflecCube, finalLod).rgb;
\r
143 // We are supposed to be using DielectricColor (0.04) of a plastic (almost everything)
\r
144 // http://blog.selfshadow.com/publications/s2014-shading-course/hoffman/s2014_pbs_physics_math_slides.pdf
\r
145 // however that seems to prevent achieving very dark tones (i.e. get dark gray blacks).
\r
146 vec3 DiffuseColor = albedoColor - albedoColor * metallic; // 1 mad
\r
147 vec3 SpecularColor = mix( vec3(0.04), albedoColor, metallic); // 2 mad
\r
149 // Calculate specular color using Magic Function (takes original roughness and normal dot view).
\r
150 vec3 specColor = reflectionColor.rgb * EnvBRDFApprox(SpecularColor, roughness, NoV );
\r
152 // Multiply the result by albedo texture and do energy conservation
\r
153 vec3 diffuseColor = irradiance * DiffuseColor;
\r
155 // Final color is the sum of the diffuse and specular term
\r
156 vec3 finalColor = diffuseColor + specColor;
\r
158 finalColor = sqrt( finalColor ) * uIblIntensity;
\r
161 finalColor *= texture(sAmbientOcclusion, vUV.st).r;
\r
165 FragColor = vec4( finalColor, alpha );
\r
167 FragColor = vec4( finalColor, 1.0 );
\r