dli_pbr.fsh
5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#version 300 es
#ifdef HIGHP
precision highp float;
#else
precision mediump float;
#endif
#ifdef THREE_TEX
#ifdef GLTF_CHANNELS
// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#pbrmetallicroughnessmetallicroughnesstexture
#define METALLIC b
#define ROUGHNESS g
#else //GLTF_CHANNELS
#define METALLIC r
#define ROUGHNESS a
#endif //GLTF_CHANNELS
#endif //THREE_TEX
#ifdef THREE_TEX
uniform sampler2D sAlbedoAlpha;
uniform sampler2D sMetalRoughness;
uniform sampler2D sNormal;
#ifdef ALPHA_TEST
uniform float uAlphaThreshold;
#endif //ALPHA_TEST
#else
uniform sampler2D sAlbedoMetal;
uniform sampler2D sNormalRoughness;
#endif
uniform samplerCube sDiffuse;
uniform samplerCube sSpecular;
// Number of mip map levels in the texture
uniform float uMaxLOD;
// Transformation matrix of the cubemap texture
uniform mat4 uCubeMatrix;
uniform vec4 uColor;
uniform float uMetallicFactor;
uniform float uRoughnessFactor;
//IBL Light intensity
uniform float uIblIntensity;
in vec2 vUV;
in vec3 vNormal;
in vec3 vTangent;
in vec3 vViewVec;
in vec4 vColor;
out vec4 FragColor;
// Functions for BRDF calculation come from
// https://www.unrealengine.com/blog/physically-based-shading-on-mobile
// Based on the paper by Dimitar Lazarov
// http://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf
vec3 EnvBRDFApprox( vec3 SpecularColor, float Roughness, float NoV )
{
const vec4 c0 = vec4( -1.0, -0.0275, -0.572, 0.022 );
const vec4 c1 = vec4( 1.0, 0.0425, 1.04, -0.04 );
vec4 r = Roughness * c0 + c1;
float a004 = min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y;
vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;
return SpecularColor * AB.x + AB.y;
}
void main()
{
// We get information from the maps (albedo, normal map, roughness, metalness
// I access the maps in the order they will be used
#ifdef THREE_TEX
vec4 albedoAlpha = texture(sAlbedoAlpha, vUV.st);
float alpha = albedoAlpha.a;
#ifdef ALPHA_TEST
if (alpha <= uAlphaThreshold)
{
discard;
}
#endif //ALPHA_TEST
vec3 albedoColor = albedoAlpha.rgb * vColor.rgb * uColor.rgb;
vec4 metalRoughness = texture(sMetalRoughness, vUV.st);
float metallic = metalRoughness.METALLIC * uMetallicFactor;
float roughness = metalRoughness.ROUGHNESS * uRoughnessFactor;
vec3 normalMap = texture(sNormal, vUV.st).rgb;
#else //THREE_TEX
vec4 albedoMetal = texture(sAlbedoMetal, vUV.st);
vec3 albedoColor = albedoMetal.rgb * vColor.rgb * uColor.rgb;
float metallic = albedoMetal.a * uMetallicFactor;
vec4 normalRoughness = texture(sNormalRoughness, vUV.st);
vec3 normalMap = normalRoughness.rgb;
float roughness = normalRoughness.a * uRoughnessFactor;
#endif
//Normalize vectors
vec3 normal = normalize(vNormal);
vec3 tangent = normalize(vTangent);
// NOTE: normal and tangent have to be orthogonal for the result of the cross()
// product to be a unit vector. We might find that we need to normalize().
vec3 bitangent = cross(normal, tangent);
vec3 viewVec = normalize(vViewVec);
// Create Inverse Local to world matrix
mat3 vInvTBN = mat3(tangent, bitangent, normal);
// Get normal map info in world space
normalMap = normalize(normalMap - 0.5);
vec3 newNormal = vInvTBN * normalMap.rgb;
// Calculate normal dot view vector
float NoV = max(dot(newNormal, -viewVec), 0.0);
// Reflect vector
vec3 reflectionVec = reflect(viewVec, newNormal);
//transform it now to environment coordinates (used when the environment rotates)
vec3 reflecCube = (uCubeMatrix * vec4( reflectionVec, 0.0 ) ).xyz;
reflecCube = normalize( reflecCube );
//transform it now to environment coordinates
vec3 normalCube = ( uCubeMatrix * vec4( newNormal, 0.0 ) ).xyz;
normalCube = normalize( normalCube );
// Get irradiance from diffuse cubemap
vec3 irradiance = texture( sDiffuse, normalCube ).rgb;
// Access reflection color using roughness value
float finalLod = mix( 0.0, uMaxLOD - 2.0, roughness);
vec3 reflectionColor = textureLod(sSpecular, reflecCube, finalLod).rgb;
// We are supposed to be using DielectricColor (0.04) of a plastic (almost everything)
// http://blog.selfshadow.com/publications/s2014-shading-course/hoffman/s2014_pbs_physics_math_slides.pdf
// however that seems to prevent achieving very dark tones (i.e. get dark gray blacks).
vec3 DiffuseColor = albedoColor - albedoColor * metallic; // 1 mad
vec3 SpecularColor = mix( vec3(0.04), albedoColor, metallic); // 2 mad
// Calculate specular color using Magic Function (takes original roughness and normal dot view).
vec3 specColor = reflectionColor.rgb * EnvBRDFApprox(SpecularColor, roughness, NoV );
// Multiply the result by albedo texture and do energy conservation
vec3 diffuseColor = irradiance * DiffuseColor;
// Final color is the sum of the diffuse and specular term
vec3 finalColor = diffuseColor + specColor;
finalColor = sqrt( finalColor ) * uIblIntensity;
#ifdef THREE_TEX
FragColor = vec4( finalColor, alpha );
#else //THREE_TEX
FragColor = vec4( finalColor, 1.0 );
#endif //THREE_TEX
}