1
+ #pragma stage vertex
2
+ #version 450 core
3
+ layout (location = 0 ) in vec3 aPosition;
4
+ layout (location = 1 ) in vec3 aNormal;
5
+ layout (location = 2 ) in vec2 aUv;
6
+ layout (location = 3 ) in vec3 aTangent;
7
+ layout (location = 4 ) in vec3 aBiTangent;
8
+
9
+ layout (push_constant) uniform constants
10
+ {
11
+ mat4 cTransform;
12
+ } Transform;
13
+
14
+ layout (binding = 1 ) uniform CameraUB
15
+ {
16
+ mat4 u_ViewProjection;
17
+ vec4 u_CameraPosition;
18
+ };
19
+
20
+ struct VertexOutput
21
+ {
22
+ vec2 UV;
23
+ vec3 Normal;
24
+ vec3 WorldPos;
25
+ mat3 TBN;
26
+ vec4 CameraPosition;
27
+ };
28
+
29
+ layout (location = 0 ) out VertexOutput Output;
30
+
31
+ void main()
32
+ {
33
+ Output.UV = aUv;
34
+ Output.Normal = transpose (inverse(mat3 (Transform.cTransform))) * aNormal;
35
+ Output.WorldPos = vec3 (Transform.cTransform * vec4 (aPosition, 1.0 ));
36
+
37
+ vec3 T = normalize (vec3 (Transform.cTransform * vec4 (aTangent, 0.0 )));
38
+ vec3 B = normalize (vec3 (Transform.cTransform * vec4 (aBiTangent, 0.0 )));
39
+ vec3 N = normalize (vec3 (Transform.cTransform * vec4 (aNormal, 0.0 )));
40
+ mat3 TBN = mat3 (T, B, N);
41
+ Output.TBN = TBN;
42
+ Output.CameraPosition = u_CameraPosition;
43
+
44
+ gl_Position = u_ViewProjection * vec4 (Output.WorldPos, 1.0 );
45
+ }
46
+
47
+ #pragma stage end
48
+
49
+ #pragma stage fragment
50
+ #version 450 core
51
+ layout (location = 0 ) out vec4 aAlbedo;
52
+
53
+ struct VertexOutput
54
+ {
55
+ vec2 UV;
56
+ vec3 Normal;
57
+ vec3 WorldPos;
58
+ mat3 TBN;
59
+ vec4 CameraPosition;
60
+ };
61
+
62
+ layout (location = 0 ) in VertexOutput Output;
63
+
64
+ layout (binding = 3 ) uniform sampler2D u_Albedo;
65
+ layout (binding = 4 ) uniform sampler2D u_Normal;
66
+ layout (binding = 5 ) uniform sampler2D u_Metallic;
67
+ layout (binding = 6 ) uniform sampler2D u_Rougness;
68
+ layout (binding = 7 ) uniform sampler2D u_AO;
69
+ layout (binding = 8 ) uniform samplerCube u_IrradianceMap;
70
+ layout (binding = 9 ) uniform samplerCube u_PrefilterMap;
71
+ layout (binding = 10 ) uniform sampler2D u_BRDFLUT;
72
+
73
+ struct Light
74
+ {
75
+ vec4 color;
76
+ vec4 position;
77
+ vec4 rotation;
78
+ float intensity;
79
+ int type;
80
+ float radiusInner;
81
+ float radiusOuter;
82
+ };
83
+
84
+ const float PI = 3.14159265359 ;
85
+
86
+ vec3 getNormalFromMap()
87
+ {
88
+ vec3 tangentNormal = texture(u_Normal, Output.UV).xyz;
89
+ tangentNormal = tangentNormal * 2.0 - 1.0 ;
90
+ return normalize (Output.TBN * tangentNormal);
91
+ }
92
+
93
+ // ----------------------------------------------------------------------------
94
+ float DistributionGGX(vec3 N, vec3 H, float roughness)
95
+ {
96
+ float a = roughness* roughness;
97
+ float a2 = a* a;
98
+ float NdotH = max (dot (N, H), 0.0 );
99
+ float NdotH2 = NdotH* NdotH;
100
+
101
+ float nom = a2;
102
+ float denom = (NdotH2 * (a2 - 1.0 ) + 1.0 );
103
+ denom = PI * denom * denom;
104
+
105
+ return nom / denom;
106
+ }
107
+ // ----------------------------------------------------------------------------
108
+ float GeometrySchlickGGX(float NdotV, float roughness)
109
+ {
110
+ float r = (roughness + 1.0 );
111
+ float k = (r* r) / 8.0 ;
112
+
113
+ float nom = NdotV;
114
+ float denom = NdotV * (1.0 - k) + k;
115
+
116
+ return nom / denom;
117
+ }
118
+ // ----------------------------------------------------------------------------
119
+ float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)
120
+ {
121
+ float NdotV = max (dot (N, V), 0.0 );
122
+ float NdotL = max (dot (N, L), 0.0 );
123
+ float ggx2 = GeometrySchlickGGX(NdotV, roughness);
124
+ float ggx1 = GeometrySchlickGGX(NdotL, roughness);
125
+
126
+ return ggx1 * ggx2;
127
+ }
128
+ // ----------------------------------------------------------------------------
129
+ vec3 fresnelSchlick(float cosTheta, vec3 F0)
130
+ {
131
+ return F0 + (1.0 - F0) * pow (clamp (1.0 - cosTheta, 0.0 , 1.0 ), 5.0 );
132
+ }
133
+ // ----------------------------------------------------------------------------
134
+ vec3 fresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness)
135
+ {
136
+ return F0 + (max (vec3 (1.0 - roughness), F0) - F0) * pow (clamp (1.0 - cosTheta, 0.0 , 1.0 ), 5.0 );
137
+ }
138
+
139
+ void main()
140
+ {
141
+ vec3 albedo = pow (texture(u_Albedo, Output.UV).rgb, vec3 (2.2 ));
142
+ float metallic = 0 .0f;
143
+ float roughness = 1 .0f;
144
+ float ao = 1 .0f;
145
+
146
+ vec3 N = getNormalFromMap();
147
+
148
+ vec3 V = normalize (Output.CameraPosition.xyz - Output.WorldPos);
149
+ vec3 R = reflect (- V, N);
150
+
151
+ // calculate reflectance at normal incidence; if dia-electric (like plastic) use F0
152
+ // of 0.04 and if it's a metal, use the albedo color as F0 (metallic workflow)
153
+ vec3 F0 = vec3 (0.04 );
154
+ F0 = mix (F0, albedo, metallic);
155
+
156
+ // reflectance equation
157
+ vec3 Lo = vec3 (0.0 );
158
+
159
+ int u_LightsAmount = 1 ;
160
+ Light u_Light[1 ] = Light[](Light(vec4 (1 , 1 , 1 , 1 ), vec4 (0 , 0 , 0 , 0 ), vec4 (0 ), 300 , 0 , 10 , 1000 ));
161
+
162
+ for (int i = 0 ; i < u_LightsAmount; ++ i)
163
+ {
164
+ // calculate per-light radiance
165
+ vec3 L = normalize (vec3 (u_Light[i].position) - Output.WorldPos);
166
+ vec3 H = normalize (V + L);
167
+ float distance = length (vec3 (u_Light[i].position) - Output.WorldPos);
168
+ float attenuation = 1.0 / (distance * distance );
169
+
170
+ vec3 radiance = vec3 (u_Light[i].color) * u_Light[i].intensity * attenuation;
171
+
172
+ // Cook-Torrance BRDF
173
+ float NDF = DistributionGGX(N, H, roughness);
174
+ float G = GeometrySmith(N, V, L, roughness);
175
+ vec3 F = fresnelSchlick(max (dot (H, V), 0.0 ), F0);
176
+
177
+ vec3 numerator = NDF * G * F;
178
+ float denominator = 4.0 * max (dot (N, V), 0.0 ) * max (dot (N, L), 0.0 ) + 0.0001 ;// + 0.0001 to prevent divide by zero
179
+ vec3 specular = numerator / denominator;
180
+
181
+ // kS is equal to Fresnel
182
+ vec3 kS = F;
183
+ // for energy conservation, the diffuse and specular light can't
184
+ // be above 1.0 (unless the surface emits light); to preserve this
185
+ // relationship the diffuse component (kD) should equal 1.0 - kS.
186
+ vec3 kD = vec3 (1.0 ) - kS;
187
+ // multiply kD by the inverse metalness such that only non-metals
188
+ // have diffuse lighting, or a linear blend if partly metal (pure metals
189
+ // have no diffuse light).
190
+ kD *= 1.0 - metallic;
191
+
192
+ // scale light by NdotL
193
+ float NdotL = max (dot (N, L), 0.0 );
194
+
195
+ // add to outgoing radiance Lo
196
+ Lo += (kD * albedo / PI + specular) * radiance * NdotL;// note that we already multiplied the BRDF by the Fresnel (kS) so we won't multiply by kS again
197
+ }
198
+
199
+ vec3 F = fresnelSchlickRoughness(max (dot (N, V), 0.0 ), F0, roughness);
200
+ vec3 kS = F;
201
+ vec3 kD = 1.0 - kS;
202
+ kD *= 1.0 - metallic;
203
+
204
+ vec3 irradiance = texture(u_IrradianceMap, N).rgb;
205
+ vec3 diffuse = irradiance * albedo;
206
+
207
+ const float MAX_REFLECTION_LOD = 4.0 ;
208
+ vec3 prefilteredColor = textureLod(u_PrefilterMap, R, roughness * MAX_REFLECTION_LOD).rgb;
209
+ vec2 brdf = texture(u_BRDFLUT, vec2 (max (dot (N, V), 0.0 ), roughness)).rg;
210
+ vec3 specular = prefilteredColor * (F * brdf.x + brdf.y);
211
+
212
+ vec3 ambient = (kD * diffuse + specular) * ao;
213
+
214
+ vec3 color = ambient + Lo;
215
+
216
+ // HDR tonemapping
217
+ color = color / (color + vec3 (1.0 ));
218
+ // gamma correct
219
+ color = pow (color, vec3 (1.0 / 2.2 ));
220
+
221
+ aAlbedo = vec4 (color, 1.0 );
222
+ }
223
+
224
+ #pragma stage end
0 commit comments