Modify default shader according to the gltf pbr spec
[platform/core/uifw/dali-toolkit.git] / dali-scene-loader / internal / graphics / shaders / default-physically-based-shader.frag
1 // Original Code
2 // https://github.com/KhronosGroup/glTF-Sample-Viewer/blob/glTF-WebGL-PBR/shaders/pbr-frag.glsl
3 // Commit dc84b5e374fb3d23153d2248a338ef88173f9eb6
4 //
5 // This fragment shader defines a reference implementation for Physically Based Shading of
6 // a microfacet surface material defined by a glTF model.For the DamagedHelmet.gltf and its Assets
7 //
8 // References:
9 // [1] Real Shading in Unreal Engine 4
10 //     http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf
11 // [2] Physically Based Shading at Disney
12 //     http://blog.selfshadow.com/publications/s2012-shading-course/burley/s2012_pbs_disney_brdf_notes_v3.pdf
13 // [3] README.md - Environment Maps
14 //     https://github.com/KhronosGroup/glTF-Sample-Viewer/#environment-maps
15 // [4] \"An Inexpensive BRDF Model for Physically based Rendering\" by Christophe Schlick
16 //     https://www.cs.virginia.edu/~jdl/bib/appearance/analytic%20models/schlick94b.pdf
17
18 #version 300 es
19
20 #ifdef HIGHP
21 precision highp float;
22 #else
23 precision mediump float;
24 #endif
25
26 #ifdef THREE_TEX
27 #ifdef GLTF_CHANNELS
28 #define METALLIC b
29 #define ROUGHNESS g
30 #else //GLTF_CHANNELS
31 #define METALLIC r
32 #define ROUGHNESS a
33 #endif //GLTF_CHANNELS
34 #endif //THREE_TEX
35
36 uniform lowp vec4 uColorFactor;
37 uniform lowp float uMetallicFactor;
38 uniform lowp float uRoughnessFactor;
39
40 #ifdef THREE_TEX
41 #ifdef BASECOLOR_TEX
42 uniform sampler2D sAlbedoAlpha;
43 #endif // BASECOLOR_TEX
44 #ifdef METALLIC_ROUGHNESS_TEX
45 uniform sampler2D sMetalRoughness;
46 #endif // METALLIC_ROUGHNESS_TEX
47 #ifdef NORMAL_TEX
48 uniform sampler2D sNormal;
49 uniform float uNormalScale;
50 #endif // NORMAL_TEX
51 #else // THREE_TEX
52 uniform sampler2D sAlbedoMetal;
53 uniform sampler2D sNormalRoughness;
54 #endif
55
56 #ifdef OCCLUSION
57 uniform sampler2D sOcclusion;
58 uniform float uOcclusionStrength;
59 #endif
60
61 #ifdef EMISSIVE
62 uniform sampler2D sEmissive;
63 uniform vec3 uEmissiveFactor;
64 #endif
65
66 //// For IBL
67 uniform samplerCube sDiffuseEnvSampler;
68 uniform samplerCube sSpecularEnvSampler;
69 uniform sampler2D sbrdfLUT;
70 uniform float uIblIntensity;
71
72 // For Alpha Mode.
73 uniform lowp float uOpaque;
74 uniform lowp float uMask;
75 uniform lowp float uAlphaThreshold;
76
77 // TODO: Multiple texture coordinate will be supported.
78 in lowp vec2 vUV;
79 in lowp mat3 vTBN;
80 in lowp vec4 vColor;
81 in highp vec3 vPositionToCamera;
82
83 out vec4 FragColor;
84
85 struct PBRInfo
86 {
87   mediump float NdotL;        // cos angle between normal and light direction
88   mediump float NdotV;        // cos angle between normal and view direction
89   mediump float NdotH;        // cos angle between normal and half vector
90   mediump float VdotH;        // cos angle between view direction and half vector
91   mediump vec3 reflectance0;  // full reflectance color (normal incidence angle)
92   mediump vec3 reflectance90; // reflectance color at grazing angle
93   lowp float alphaRoughness;  // roughness mapped to a more linear change in the roughness (proposed by [2])
94 };
95
96 const float M_PI = 3.141592653589793;
97 const float c_MinRoughness = 0.04;
98
99 vec3 specularReflection(PBRInfo pbrInputs)
100 {
101   return pbrInputs.reflectance0 + (pbrInputs.reflectance90 - pbrInputs.reflectance0) * pow(clamp(1.0 - pbrInputs.VdotH, 0.0, 1.0), 5.0);
102 }
103
104 float geometricOcclusion(PBRInfo pbrInputs)
105 {
106   mediump float NdotL = pbrInputs.NdotL;
107   mediump float NdotV = pbrInputs.NdotV;
108   lowp float r = pbrInputs.alphaRoughness;
109
110   lowp float attenuationL = 2.0 * NdotL / (NdotL + sqrt(r * r + (1.0 - r * r) * (NdotL * NdotL)));
111   lowp float attenuationV = 2.0 * NdotV / (NdotV + sqrt(r * r + (1.0 - r * r) * (NdotV * NdotV)));
112   return attenuationL * attenuationV;
113 }
114
115 float microfacetDistribution(PBRInfo pbrInputs)
116 {
117   mediump float roughnessSq = pbrInputs.alphaRoughness * pbrInputs.alphaRoughness;
118   lowp float f = (pbrInputs.NdotH * roughnessSq - pbrInputs.NdotH) * pbrInputs.NdotH + 1.0;
119   return roughnessSq / (M_PI * f * f);
120 }
121
122 vec3 linear(vec3 color)
123 {
124   return pow(color, vec3(2.2));
125 }
126
127 void main()
128 {
129   // Metallic and Roughness material properties are packed together
130   // In glTF, these factors can be specified by fixed scalar values
131   // or from a metallic-roughness map
132   // Roughness is stored in the 'g' channel, metallic is stored in the 'b' channel.
133   // This layout intentionally reserves the 'r' channel for (optional) occlusion map data
134   lowp float metallic = uMetallicFactor;
135   lowp float perceptualRoughness = uRoughnessFactor;
136   // If there isn't normal texture, use surface normal
137   mediump vec3 n = normalize(vTBN[2].xyz);
138
139 #ifdef THREE_TEX
140   // The albedo may be defined from a base texture or a flat color
141 #ifdef BASECOLOR_TEX
142   lowp vec4 baseColor = texture(sAlbedoAlpha, vUV);
143   baseColor = vec4(linear(baseColor.rgb), baseColor.w) * uColorFactor;
144 #else // BASECOLOR_TEX
145   lowp vec4 baseColor = vColor * uColorFactor;
146 #endif // BASECOLOR_TEX
147
148 #ifdef METALLIC_ROUGHNESS_TEX
149   lowp vec4 metrou = texture(sMetalRoughness, vUV);
150   metallic = metrou.METALLIC * metallic;
151   perceptualRoughness = metrou.ROUGHNESS * perceptualRoughness;
152 #endif // METALLIC_ROUGHNESS_TEX
153
154 #ifdef NORMAL_TEX
155   n = texture(sNormal, vUV).rgb;
156   n = normalize(vTBN * ((2.0 * n - 1.0) * vec3(uNormalScale, uNormalScale, 1.0)));
157 #endif // NORMAL_TEX
158 #else // THREE_TEX
159   vec4 albedoMetal = texture(sAlbedoMetal, vUV);
160   lowp vec4 baseColor = vec4(linear(albedoMetal.rgb), 1.0) * vColor * uColorFactor;
161
162   metallic = albedoMetal.METALLIC * metallic;
163
164   vec4 normalRoughness = texture(sNormalRoughness, vUV);
165   perceptualRoughness = normalRoughness.ROUGHNESS * perceptualRoughness;
166
167   n = normalRoughness.rgb;
168   n = normalize(vTBN * ((2.0 * n - 1.0) * vec3(uNormalScale, uNormalScale, 1.0)));
169 #endif // THREE_TEX
170
171   // The value of uOpaque and uMask can be 0.0 or 1.0.
172   // If uOpaque is 1.0, alpha value of final color is 1.0;
173   // If uOpaque is 0.0 and uMask is 1.0, alpha value of final color is 0.0 when input alpha is lower than uAlphaThreshold or
174   // 1.0 when input alpha is larger than uAlphaThreshold.
175   // https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#_material_alphamode
176   baseColor.a = mix(baseColor.a, 1.0, uOpaque);
177   baseColor.a = min(mix(baseColor.a, floor(baseColor.a - uAlphaThreshold + 1.0), uMask), 1.0);
178
179   metallic = clamp(metallic, 0.0, 1.0);
180   // Roughness is authored as perceptual roughness; as is convention,
181   // convert to material roughness by squaring the perceptual roughness [2].
182   perceptualRoughness = clamp(perceptualRoughness, c_MinRoughness, 1.0);
183   lowp float alphaRoughness = perceptualRoughness * perceptualRoughness;
184
185   lowp vec3 f0 = vec3(0.04);
186   lowp vec3 diffuseColor = baseColor.rgb * (vec3(1.0) - f0);
187   diffuseColor *= (1.0 - metallic);
188   lowp vec3 specularColor = mix(f0, baseColor.rgb, metallic);
189
190   // Compute reflectance.
191   lowp float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b);
192
193   // For typical incident reflectance range (between 4% to 100%) set the grazing reflectance to 100% for typical fresnel effect.
194   // For very low reflectance range on highly diffuse objects (below 4%), incrementally reduce grazing reflecance to 0%.
195   lowp float reflectance90 = clamp(reflectance * 25.0, 0.0, 1.0);
196   lowp vec3 specularEnvironmentR0 = specularColor.rgb;
197   lowp vec3 specularEnvironmentR90 = vec3(1.0, 1.0, 1.0) * reflectance90;
198
199   mediump vec3 v = normalize(vPositionToCamera); // Vector from surface point to camera
200   mediump float NdotV = clamp(abs(dot(n, v)), 0.001, 1.0);
201   mediump vec3 reflection = -normalize(reflect(v, n));
202
203   lowp vec3 color = vec3(0.0);
204   lowp vec3 diffuseLight = linear(texture(sDiffuseEnvSampler, n).rgb);
205   lowp vec3 specularLight = linear(texture(sSpecularEnvSampler, reflection).rgb);
206   // retrieve a scale and bias to F0. See [1], Figure 3
207   lowp vec3 brdf = linear(texture(sbrdfLUT, vec2(NdotV, 1.0 - perceptualRoughness)).rgb);
208
209   lowp vec3 diffuse = diffuseLight * diffuseColor;
210   lowp vec3 specular = specularLight * (specularColor * brdf.x + brdf.y);
211   color += (diffuse + specular) * uIblIntensity;
212
213 #ifdef OCCLUSION
214   lowp float ao = texture(sOcclusion, vUV).r;
215   color = mix(color, color * ao, uOcclusionStrength);
216 #endif // OCCLUSION
217
218 #ifdef EMISSIVE
219   lowp vec3 emissive = linear(texture(sEmissive, vUV).rgb) * uEmissiveFactor;
220   color += emissive;
221 #endif // EMISSIVE
222
223   FragColor = vec4(pow(color, vec3(1.0 / 2.2)), baseColor.a);
224 }