[dali_2.3.21] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-scene3d / internal / graphics / shaders / default-physically-based-shader.frag
1
2 // Original Code
3 // https://github.com/KhronosGroup/glTF-Sample-Viewer/blob/glTF-WebGL-PBR/shaders/pbr-frag.glsl
4 // Commit dc84b5e374fb3d23153d2248a338ef88173f9eb6
5 //
6 // This fragment shader defines a reference implementation for Physically Based Shading of
7 // a microfacet surface material defined by a glTF model.For the DamagedHelmet.gltf and its Assets
8 //
9 // References:
10 // [1] Real Shading in Unreal Engine 4
11 //     http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf
12 // [2] Physically Based Shading at Disney
13 //     http://blog.selfshadow.com/publications/s2012-shading-course/burley/s2012_pbs_disney_brdf_notes_v3.pdf
14 // [3] README.md - Environment Maps
15 //     https://github.com/KhronosGroup/glTF-Sample-Viewer/#environment-maps
16 // [4] \"An Inexpensive BRDF Model for Physically based Rendering\" by Christophe Schlick
17 //     https://www.cs.virginia.edu/~jdl/bib/appearance/analytic%20models/schlick94b.pdf
18
19 #ifdef HIGHP
20 precision highp float;
21 #else
22 precision mediump float;
23 #endif
24
25 #ifdef GLTF_CHANNELS
26 #define METALLIC b
27 #define ROUGHNESS g
28 #else //GLTF_CHANNELS
29 #define METALLIC r
30 #define ROUGHNESS a
31 #endif //GLTF_CHANNELS
32
33 uniform lowp vec4 uColor; // Color from SceneGraph
34 uniform lowp vec4 uColorFactor; // Color from material
35 uniform lowp float uMetallicFactor;
36 uniform lowp float uRoughnessFactor;
37 uniform lowp float uDielectricSpecular;
38
39 #ifdef THREE_TEX
40 #ifdef BASECOLOR_TEX
41 uniform sampler2D sAlbedoAlpha;
42 uniform float uBaseColorTextureTransformAvailable;
43 uniform mat3 uBaseColorTextureTransform;
44 #endif // BASECOLOR_TEX
45 #ifdef METALLIC_ROUGHNESS_TEX
46 uniform sampler2D sMetalRoughness;
47 uniform float uMetalRoughnessTextureTransformAvailable;
48 uniform mat3 uMetalRoughnessTextureTransform;
49 #endif // METALLIC_ROUGHNESS_TEX
50 #ifdef NORMAL_TEX
51 uniform sampler2D sNormal;
52 uniform float uNormalTextureTransformAvailable;
53 uniform mat3 uNormalTextureTransform;
54 uniform float uNormalScale;
55 #endif // NORMAL_TEX
56 #else // THREE_TEX
57 uniform sampler2D sAlbedoMetal;
58 uniform float uBaseColorTextureTransformAvailable;
59 uniform mat3 uBaseColorTextureTransform;
60 uniform sampler2D sNormalRoughness;
61 uniform float uNormalRoughnessTextureTransformAvailable;
62 uniform mat3 uNormalRoughnessTextureTransform;
63 #endif
64
65
66
67 #ifdef OCCLUSION
68 uniform sampler2D sOcclusion;
69 uniform float uOcclusionTextureTransformAvailable;
70 uniform mat3 uOcclusionTextureTransform;
71 uniform float uOcclusionStrength;
72 #endif
73
74 #ifdef EMISSIVE_TEXTURE
75 uniform sampler2D sEmissive;
76 uniform float uEmissiveTextureTransformAvailable;
77 uniform mat3 uEmissiveTextureTransform;
78 #endif
79 uniform vec3 uEmissiveFactor;
80
81 uniform float uSpecularFactor;
82 uniform vec3  uSpecularColorFactor;
83 #ifdef MATERIAL_SPECULAR_TEXTURE
84 uniform sampler2D sSpecular;
85 #endif
86 #ifdef MATERIAL_SPECULAR_COLOR_TEXTURE
87 uniform sampler2D sSpecularColor;
88 #endif
89
90 // For Light (Currently Directional Only)
91 #define MAX_LIGHTS 5
92 uniform mediump int uLightCount;
93 uniform mediump vec3 uLightDirection[MAX_LIGHTS];
94 uniform mediump vec3 uLightColor[MAX_LIGHTS];
95
96 // For Shadow Map
97 uniform lowp int uIsShadowEnabled;
98 uniform sampler2D sShadowMap;
99 uniform lowp int uIsShadowReceiving;
100 #ifdef SL_VERSION_LOW
101 uniform int uShadowMapWidth;
102 uniform int uShadowMapHeight;
103 #endif
104 INPUT highp vec3 positionFromLightView;
105
106 //// For IBL
107 uniform sampler2D sbrdfLUT;
108 uniform samplerCube sDiffuseEnvSampler;
109 uniform samplerCube sSpecularEnvSampler;
110 uniform float uIblIntensity;
111 uniform mediump vec3 uYDirection;
112 uniform float uMaxLOD;
113
114 // For Alpha Mode.
115 uniform lowp float uOpaque;
116 uniform lowp float uMask;
117 uniform lowp float uAlphaThreshold;
118
119 // TODO: Multiple texture coordinate will be supported.
120 INPUT mediump vec2 vUV;
121 INPUT lowp mat3 vTBN;
122 INPUT lowp vec4 vColor;
123 INPUT highp vec3 vPositionToCamera;
124
125 const float c_MinRoughness = 0.04;
126 const float M_PI = 3.141592653589793;
127
128 // These properties can be used for circular sampling for PCF
129
130 // Percentage Closer Filtering to mitigate the banding artifacts.
131 const int kPcfSampleCount = 9;
132
133 const float kPi = 3.141592653589;
134 const float kInvSampleCount = 1.0 / float(kPcfSampleCount);
135 const float kPcfTheta = 2.0 * kPi * kInvSampleCount;
136 const float kSinPcfTheta = sin(kPcfTheta);
137 const float kCosPcfTheta = cos(kPcfTheta);
138
139 uniform lowp int uEnableShadowSoftFiltering;
140 uniform mediump float uShadowIntensity;
141 uniform highp float uShadowBias;
142
143 vec3 linear(vec3 color)
144 {
145   return pow(color, vec3(2.2));
146 }
147
148 vec2 computeTextureTransform(vec2 texCoord, mat3 textureTransform)
149 {
150     return vec2(textureTransform * vec3(texCoord, 1.0));
151 }
152
153 void main()
154 {
155   // Metallic and Roughness material properties are packed together
156   // In glTF, these factors can be specified by fixed scalar values
157   // or from a metallic-roughness map
158   // Roughness is stored in the 'g' channel, metallic is stored in the 'b' channel.
159   // This layout intentionally reserves the 'r' channel for (optional) occlusion map data
160   lowp float metallic = uMetallicFactor;
161   lowp float perceptualRoughness = uRoughnessFactor;
162   // If there isn't normal texture, use surface normal
163   highp vec3 n = normalize(vTBN[2].xyz);
164
165 #ifdef THREE_TEX
166   // The albedo may be defined from a base texture or a flat color
167 #ifdef BASECOLOR_TEX
168   mediump vec2 baseColorTexCoords = mix(vUV, computeTextureTransform(vUV, uBaseColorTextureTransform), uBaseColorTextureTransformAvailable);
169   lowp vec4 baseColor = TEXTURE(sAlbedoAlpha, baseColorTexCoords);
170   baseColor = vColor * vec4(linear(baseColor.rgb), baseColor.w) * uColorFactor;
171 #else // BASECOLOR_TEX
172   lowp vec4 baseColor = vColor * uColorFactor;
173 #endif // BASECOLOR_TEX
174
175 #ifdef METALLIC_ROUGHNESS_TEX
176   mediump vec2 metalRoughnessTexCoords = mix(vUV, computeTextureTransform(vUV, uMetalRoughnessTextureTransform), uMetalRoughnessTextureTransformAvailable);
177   lowp vec4 metrou = TEXTURE(sMetalRoughness, metalRoughnessTexCoords);
178   metallic = metrou.METALLIC * metallic;
179   perceptualRoughness = metrou.ROUGHNESS * perceptualRoughness;
180 #endif // METALLIC_ROUGHNESS_TEX
181
182 #ifdef NORMAL_TEX
183   mediump vec2 normalTexCoords = mix(vUV, computeTextureTransform(vUV, uNormalTextureTransform), uNormalTextureTransformAvailable);
184   n = TEXTURE(sNormal, normalTexCoords).rgb;
185   n = normalize(vTBN * ((2.0 * n - 1.0) * vec3(uNormalScale, uNormalScale, 1.0)));
186 #endif // NORMAL_TEX
187 #else // THREE_TEX
188   mediump vec2 baseColorTexCoords = mix(vUV, computeTextureTransform(vUV, uBaseColorTextureTransform), uBaseColorTextureTransformAvailable);
189   vec4 albedoMetal = TEXTURE(sAlbedoMetal, baseColorTexCoords);
190   lowp vec4 baseColor = vec4(linear(albedoMetal.rgb), 1.0) * vColor * uColorFactor;
191
192   metallic = albedoMetal.METALLIC * metallic;
193
194   mediump vec2 normalRoughnessTexCoords = mix(vUV, computeTextureTransform(vUV, uNormalRoughnessTextureTransform), uNormalRoughnessTextureTransformAvailable);
195   vec4 normalRoughness = TEXTURE(sNormalRoughness, normalRoughnessTexCoords);
196   perceptualRoughness = normalRoughness.ROUGHNESS * perceptualRoughness;
197
198   n = normalRoughness.rgb;
199   n = normalize(vTBN * ((2.0 * n - 1.0) * vec3(uNormalScale, uNormalScale, 1.0)));
200 #endif // THREE_TEX
201
202   // The value of uOpaque and uMask can be 0.0 or 1.0.
203   // If uMask is 1.0, a Pixel that has bigger alpha than uAlphaThreashold becomes fully opaque,
204   // and, a pixel that has smaller alpha than uAlphaThreashold becomes fully transparent.
205   // If uOpaque is 1.0, alpha value of final color is 1.0;
206   // https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#_material_alphamode
207   if(uMask > 0.5 && baseColor.a < uAlphaThreshold)
208   {
209     discard;
210   }
211   baseColor.a = mix(baseColor.a, 1.0, uOpaque);
212
213   metallic = clamp(metallic, 0.0, 1.0);
214   // Roughness is authored as perceptual roughness; as is convention,
215   // convert to material roughness by squaring the perceptual roughness [2].
216   perceptualRoughness = clamp(perceptualRoughness, c_MinRoughness, 1.0);
217
218   // Material ior
219   lowp vec3 f0 = vec3(uDielectricSpecular);
220
221   // Material Specular
222   float specularWeight = 1.0;
223   vec4 materialSpecularTexture = vec4(1.0);
224 #ifdef MATERIAL_SPECULAR_TEXTURE
225   materialSpecularTexture.a = TEXTURE(sSpecular, vUV).a;
226 #endif
227 #ifdef MATERIAL_SPECULAR_COLOR_TEXTURE
228   materialSpecularTexture.rgb = TEXTURE(sSpecularColor, vUV).rgb;
229 #endif
230   specularWeight = uSpecularFactor * materialSpecularTexture.a;
231   f0 = min(f0 * uSpecularColorFactor * materialSpecularTexture.rgb, vec3(1.0));
232   f0 = mix(f0, baseColor.rgb, metallic);
233
234   mediump vec3 v = normalize(vPositionToCamera); // Vector from surface point to camera
235   mediump float NdotV = clamp(abs(dot(n, v)), 0.001, 1.0);
236   mediump vec3 reflection = -normalize(reflect(v, n));
237   lowp vec3 brdf = TEXTURE(sbrdfLUT, vec2(NdotV, 1.0 - perceptualRoughness)).rgb;
238   vec3 Fr = max(vec3(1.0 - perceptualRoughness), f0) - f0;
239   vec3 k_S = f0 + Fr * pow(1.0 - NdotV, 5.0);
240   vec3 FssEss = specularWeight * (k_S * brdf.x + brdf.y);
241
242   // Specular Light
243   // uMaxLOD that means mipmap level of specular texture is used for bluring of reflection of specular following roughness.
244   float lod = perceptualRoughness * (uMaxLOD - 1.0);
245 #ifdef SL_VERSION_LOW
246   // glsl 1.0 doesn't support textureLod. Let we just use textureCube instead.
247   lowp vec3 specularLight = linear(textureCube(sSpecularEnvSampler, reflection * uYDirection).rgb);
248 #else
249   lowp vec3 specularLight = linear(textureLod(sSpecularEnvSampler, reflection * uYDirection, lod).rgb);
250 #endif
251   lowp vec3 specular = specularLight * FssEss;
252
253   // Diffuse Light
254   lowp vec3 diffuseColor = mix(baseColor.rgb, vec3(0), metallic);
255 #ifdef SL_VERSION_LOW
256   lowp vec3 irradiance = linear(textureCube(sDiffuseEnvSampler, n * uYDirection).rgb);
257 #else
258   lowp vec3 irradiance = linear(TEXTURE(sDiffuseEnvSampler, n * uYDirection).rgb);
259 #endif
260   float Ems = (1.0 - (brdf.x + brdf.y));
261   vec3 F_avg = specularWeight * (f0 + (1.0 - f0) / 21.0);
262   vec3 FmsEms = Ems * FssEss * F_avg / (1.0 - F_avg * Ems);
263   vec3 k_D = diffuseColor * (1.0 - FssEss + FmsEms);
264   lowp vec3 diffuse = (FmsEms + k_D) * irradiance;
265
266   lowp vec3 color = (diffuse + specular) * uIblIntensity;
267
268   // Punctual Light
269   if(uLightCount > 0)
270   {
271     // Compute reflectance.
272     highp float reflectance = max(max(f0.r, f0.g), f0.b);
273     highp float reflectance90 = clamp(reflectance * 25.0, 0.0, 1.0);
274     highp float r = perceptualRoughness * perceptualRoughness;
275     highp float attenuationV = 2.0 * NdotV / (NdotV + sqrt(r * r + (1.0 - r * r) * (NdotV * NdotV)));
276     highp float roughnessSq = r * r;
277     highp vec3 diffuseColorPunctual = baseColor.rgb * (vec3(1.0) - f0);
278     diffuseColorPunctual *= ( 1.0 - metallic );
279
280     for(int i = 0; i < uLightCount; ++i)
281     {
282       highp vec3 l = normalize(-uLightDirection[i]); // Vector from surface point to light
283       highp vec3 h = normalize(l+v);               // Half vector between both l and v
284       highp float VdotH = dot(v, h);
285       highp vec3 specularReflection = f0 + (reflectance90 - f0) * pow(clamp(1.0 - VdotH, 0.0, 1.0), 5.0);
286
287       highp float NdotL = clamp(dot(n, l), 0.001, 1.0);
288       highp float attenuationL = 2.0 * NdotL / (NdotL + sqrt(r * r + (1.0 - r * r) * (NdotL * NdotL)));
289       highp float geometricOcclusion = attenuationL * attenuationV;
290
291       highp float NdotH = dot(n, h);
292       highp float f = (NdotH * roughnessSq - NdotH) * NdotH + 1.0;
293       highp float microfacetDistribution = roughnessSq / (M_PI * f * f);;
294
295       // Calculation of analytical lighting contribution
296       highp vec3 diffuseContrib = ( 1.0 - specularReflection ) * ( diffuseColorPunctual / M_PI );
297       highp vec3 specContrib = specularReflection * geometricOcclusion * microfacetDistribution / ( 4.0 * NdotL * NdotV );
298
299       // Obtain final intensity as reflectance (BRDF) scaled by the energy of the light (cosine law)
300       color += NdotL * uLightColor[i] * (diffuseContrib + specContrib);
301     }
302   }
303
304   if(float(uIsShadowReceiving) * float(uIsShadowEnabled) * uShadowIntensity > 0.0)
305   {
306     mediump float exposureFactor = 0.0;
307     if(uEnableShadowSoftFiltering > 0)
308     {
309 #ifdef SL_VERSION_LOW
310       ivec2 texSize = ivec2(uShadowMapWidth, uShadowMapHeight);
311 #else
312       ivec2 texSize = textureSize(sShadowMap, 0);
313 #endif
314       mediump vec2 texelSize = vec2(1.0) / vec2(texSize.x, texSize.y);
315       mediump vec2 pcfSample = vec2(1.0, 0.0);
316       for (int i = 0; i < kPcfSampleCount; ++i)
317       {
318         pcfSample = vec2(kCosPcfTheta * pcfSample.x - kSinPcfTheta * pcfSample.y,
319                          kSinPcfTheta * pcfSample.x + kCosPcfTheta * pcfSample.y);
320         lowp float depthValue = TEXTURE(sShadowMap, positionFromLightView.xy + pcfSample * texelSize).r;
321         exposureFactor += (depthValue < positionFromLightView.z - uShadowBias) ? 0.0 : 1.0;
322       }
323       exposureFactor *= kInvSampleCount;
324     }
325     else
326     {
327       mediump float depthValue = TEXTURE(sShadowMap, positionFromLightView.xy).r;
328       exposureFactor           = (depthValue < positionFromLightView.z - uShadowBias) ? 0.0 : 1.0;
329     }
330     color *= (1.0 - (1.0 - exposureFactor) * uShadowIntensity);
331   }
332
333 #ifdef OCCLUSION
334   mediump vec2 occlusionTexCoords = mix(vUV, computeTextureTransform(vUV, uOcclusionTextureTransform), uOcclusionTextureTransformAvailable);
335   lowp float ao = TEXTURE(sOcclusion, occlusionTexCoords).r;
336   color = mix(color, color * ao, uOcclusionStrength);
337 #endif // OCCLUSION
338
339 #ifdef EMISSIVE_TEXTURE
340   mediump vec2 emissiveTexCoords = mix(vUV, computeTextureTransform(vUV, uEmissiveTextureTransform), uEmissiveTextureTransformAvailable);
341   lowp vec3 emissive = linear(TEXTURE(sEmissive, emissiveTexCoords).rgb) * uEmissiveFactor;
342 #else
343   lowp vec3 emissive = uEmissiveFactor;
344 #endif // EMISSIVE_TEXTURE
345   color += emissive;
346
347   OUT_COLOR = vec4(pow(color, vec3(1.0 / 2.2)), baseColor.a) * uColor;
348 }