pbr_shader.fsh
4.43 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
#version 300 es
precision highp float;
uniform sampler2D sAlbedoMetal;
uniform sampler2D sNormalRoughness;
uniform samplerCube sDiffuse;
uniform samplerCube sSpecular;
// Transformation matrix of the cubemap texture
// Number of mip map levels in the texture
uniform float uMaxLOD;
// Number of mip map levels in the texture
uniform float uRoughness;
// Number of mip map levels in the texture
uniform float uMetallic;
in vec2 vUV;
in vec3 vNormal;
in vec3 vTangent;
in vec3 vBitangent;
in vec3 vViewVec;
in mat4 uCubeMatrix;
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
vec4 normalRoughness = texture(sNormalRoughness, vUV.st);
vec3 normalMap = normalRoughness.rgb;
float roughness = normalRoughness.a * uRoughness;
vec4 albedoMetal = texture(sAlbedoMetal, vUV.st);
vec3 albedoColor = albedoMetal.rgb;
float metallic = albedoMetal.a * uMetallic;
//Normalize vectors
vec3 normal = normalize(vNormal);
vec3 tangent = normalize(vTangent);
vec3 bitangent = normalize(vBitangent);
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) * 2.0);
vec3 newNormal = vInvTBN * normalMap.rgb;
// Calculate normal dot view vector
float NoV = clamp(dot(newNormal, -viewVec), 0.0, 1.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)).xyz;
reflecCube = normalize(reflecCube);
//transform it now to environment coordinates
vec3 normalCube = (uCubeMatrix * vec4(newNormal,0)).xyz;
normalCube = normalize(normalCube);
// Get irradiance from diffuse cubemap
vec3 irradiance = texture(sDiffuse, normalCube).rgb;
// Way to access the mip map level - copied from UE
const float REFLECTION_CAPTURE_ROUGHEST_MIP = 1.;
const float REFLECTION_CAPTURE_ROUGHNESS_MIP_SCALE = 1.2;
float LevelFrom1x1 = REFLECTION_CAPTURE_ROUGHEST_MIP - REFLECTION_CAPTURE_ROUGHNESS_MIP_SCALE * log2(roughness);
// Note: must match GReflectionCaptureSize
// We need to subtract 2 levels from the uMaxLOD because we don't have the smallest mipmaps
// (and because these levels are very small 1x1, 2x2, etc.)
float finalLod = (uMaxLOD - 2.0) - 1.0 - LevelFrom1x1;
// calculate the convexity and increase the reflectance lobe
float convexity = length(fwidth(newNormal));
finalLod += convexity * (uMaxLOD - 2.0);
// Access reflection color using roughness value
vec3 reflectionColor = textureLod(sSpecular, reflecCube, finalLod).rgb;
// For increasing contrast a little bit - It should be Gamma correction (2.2) but it gets to dark
albedoColor = pow(albedoColor,vec3(1.2));
// We use DielectricColor of a plastic (almost everything)
// http://blog.selfshadow.com/publications/s2014-shading-course/hoffman/s2014_pbs_physics_math_slides.pdf
vec3 DielectricSpecular = vec3(0.04);
vec3 DiffuseColor = albedoColor - albedoColor * metallic; // 1 mad
vec3 SpecularColor = (DielectricSpecular - DielectricSpecular * metallic) + albedoColor * metallic; //2 mad
// Calculate specular color using Magic Function (takes original rougness and normal dot view
vec3 specColor = reflectionColor.rgb * EnvBRDFApprox(SpecularColor, roughness, NoV);// * irradiance;
// 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;
//FragColor = vec4(1.0, 1.0, 1.0, 1.0);
finalColor = finalColor / (finalColor + vec3(1));
FragColor = vec4(finalColor,1.0);
}