aboutsummaryrefslogtreecommitdiff
path: root/shaders
diff options
context:
space:
mode:
Diffstat (limited to 'shaders')
-rw-r--r--shaders/brdf_integration_map.frag93
-rw-r--r--shaders/cook_torrance.frag255
-rw-r--r--shaders/cook_torrance.vert75
-rw-r--r--shaders/cubemap_filtering.vert39
-rw-r--r--shaders/debug3d.frag21
-rw-r--r--shaders/debug3d.vert15
-rw-r--r--shaders/immediate_mode.frag10
-rw-r--r--shaders/immediate_mode.vert11
-rw-r--r--shaders/irradiance_map.frag65
-rw-r--r--shaders/prefiltered_environment_map.frag78
-rw-r--r--shaders/quad.vert9
-rw-r--r--shaders/skyquad.frag13
-rw-r--r--shaders/skyquad.vert27
-rw-r--r--shaders/view_normal_mapped_normals.frag28
-rw-r--r--shaders/view_normal_mapped_normals.vert22
-rw-r--r--shaders/view_normals.frag11
-rw-r--r--shaders/view_normals.vert15
-rw-r--r--shaders/view_tangents.frag17
-rw-r--r--shaders/view_tangents.vert14
-rw-r--r--shaders/view_texture.frag15
-rw-r--r--shaders/view_texture.vert13
21 files changed, 846 insertions, 0 deletions
diff --git a/shaders/brdf_integration_map.frag b/shaders/brdf_integration_map.frag
new file mode 100644
index 0000000..bb2cebd
--- /dev/null
+++ b/shaders/brdf_integration_map.frag
@@ -0,0 +1,93 @@
1precision highp float;
2
3#define PI 3.1415926535897932384626433832795
4#define NUM_SAMPLES 1024
5
6in vec2 Texcoord;
7
8layout (location = 0) out vec2 Color;
9
10float radical_inverse_VdC(uint bits) {
11 bits = (bits << 16u) | (bits >> 16u);
12 bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
13 bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
14 bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
15 bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
16 return float(bits) * 2.3283064365386963e-10; // / 0x100000000
17}
18
19vec2 hammersley(uint i, uint N) {
20 return vec2(float(i)/float(N), radical_inverse_VdC(i));
21}
22
23vec3 importance_sample_GGX(vec2 sample_box, vec3 N, float roughness) {
24 float r2 = roughness * roughness;
25
26 // Spherical coordinates.
27 float phi = 2.0 * PI * sample_box.x;
28 float cos_theta = sqrt((1.0 - sample_box.y) / (1.0 + (r2*r2 - 1.0) * sample_box.y));
29 float sin_theta = sqrt(1.0 - cos_theta * cos_theta);
30
31 // Map spherical coordinates to Cartesian coordinates in tangent space.
32 vec3 H = vec3(cos(phi) * sin_theta, sin(phi) * sin_theta, cos_theta);
33
34 // Map from tangent space to world space.
35 //
36 // Tangent space:
37 //
38 // N
39 // |
40 // |
41 // |
42 // |_ _ _ _ _ B
43 // /
44 // /
45 // T
46 vec3 up = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
47 vec3 T = normalize(cross(up,N));
48 vec3 B = cross(N,T);
49 vec3 H_ws = H.x*T + H.y*B + H.z*N;
50 return H_ws;
51}
52
53float geometry_schlick_GGX(float k, float NdotV) {
54 return NdotV / (NdotV * (1.0 - k) + k);
55}
56
57float geometry_smith(float roughness, float NdotL, float NdotV) {
58 float k = roughness * roughness / 2.0; // IBL
59 return geometry_schlick_GGX(k, NdotV) * geometry_schlick_GGX(k, NdotL);
60}
61
62vec2 integrate_brdf(float NdotV, float roughness)
63{
64 vec3 V = vec3(sqrt(1.0 - NdotV * NdotV), 0.0, NdotV);
65 vec3 N = vec3(0.0, 0.0, 1.0);
66
67 float scale = 0.0;
68 float bias = 0.0;
69 for (int i = 0; i < NUM_SAMPLES; ++i) {
70 vec2 sample_box = hammersley(i, NUM_SAMPLES);
71 vec3 H = importance_sample_GGX(sample_box, N, roughness);
72 vec3 L = reflect(-V,H);
73 float NdotL = max(0.0, L.z);
74
75 if (NdotL > 0.0) {
76 float NdotH = max(0.0, H.z);
77 float VdotH = max(0.0, dot(V,H));
78 float G = geometry_smith(roughness, NdotL, NdotV);
79 float G_vis = (G * VdotH) / (NdotH * NdotV);
80 float Fc = pow(1.0 - VdotH, 5.0);
81 scale += (1.0 - Fc) * G_vis;
82 bias += Fc * G_vis;
83 }
84 }
85 scale /= float(NUM_SAMPLES);
86 bias /= float(NUM_SAMPLES);
87 return vec2(scale, bias);
88}
89
90void main()
91{
92 Color = integrate_brdf(Texcoord.x, Texcoord.y);
93}
diff --git a/shaders/cook_torrance.frag b/shaders/cook_torrance.frag
new file mode 100644
index 0000000..1975491
--- /dev/null
+++ b/shaders/cook_torrance.frag
@@ -0,0 +1,255 @@
1precision highp float;
2
3uniform vec4 BaseColorFactor;
4uniform float MetallicFactor;
5uniform float RoughnessFactor;
6uniform vec3 EmissiveFactor;
7
8#ifdef HAS_ALBEDO_MAP
9uniform sampler2D BaseColorTexture;
10#endif
11#ifdef HAS_METALLIC_ROUGHNESS_MAP
12uniform sampler2D MetallicRoughnessTexture;
13#endif
14#ifdef HAS_EMISSIVE_MAP
15uniform sampler2D EmissiveTexture;
16#endif
17#ifdef HAS_OCCLUSION_MAP
18uniform sampler2D AmbientOcclusionTexture;
19#endif
20#ifdef HAS_NORMAL_MAP
21uniform sampler2D NormalMap;
22#endif
23
24// TODO: Handle case in which there is no sky. Pass a boolean.
25uniform samplerCube Sky;
26uniform samplerCube IrradianceMap;
27uniform samplerCube PrefilteredEnvironmentMap;
28uniform sampler2D BRDFIntegrationMap;
29uniform float MaxReflectionLOD;
30
31uniform vec3 CameraPosition; // World space.
32
33// World-space position, normal and tangent.
34in vec3 Position;
35#ifdef HAS_NORMALS
36in vec3 Normal;
37#endif
38#ifdef HAS_TANGENTS
39in vec4 Tangent;
40#endif
41#ifdef HAS_TEXCOORDS
42in vec2 Texcoord;
43#endif
44
45layout (location = 0) out vec4 Colour;
46
47#define PI 3.1415926535897932384626433832795
48#define INV_PI 0.3183098861837907
49
50/// Transform a normal map sample into world space.
51///
52/// |normalWs| is the surface normal in world space.
53/// |normalMapSample| is the normal map sample, not necessarily normalized.
54///
55/// TODO: Move to "normal.h"
56#if defined(HAS_NORMAL_MAP) && (defined(HAS_TANGENTS) || defined(HAS_TEXCOORDS))
57vec3 get_ws_normal(vec3 normalWs, vec3 normalMapSample) {
58 vec3 N = normalize(Normal);
59#ifdef HAS_TANGENTS
60 //vec3 T = normalize(tangent.xyz - dot(tangent.xyz, N) * N);
61 vec3 T = Tangent.xyz;
62 vec3 B = Tangent.w * cross(N, T);
63#elif HAS_TEXCOORDS // No tangents, but must have texcoords.
64 vec3 pos_dx = dFdx(Position);
65 vec3 pos_dy = dFdy(Position);
66 // vec3 uv_dx = vec3(dFdx(Texcoord), 0.0);
67 // vec3 uv_dy = vec3(dFdy(Texcoord), 0.0);
68 vec3 uv_dx = dFdx(vec3(Texcoord, 0.0));
69 vec3 uv_dy = dFdy(vec3(Texcoord, 0.0));
70 vec3 T = (uv_dy.t * pos_dx - uv_dx.t * pos_dy) /
71 (uv_dx.s * uv_dy.t - uv_dy.s * uv_dx.t);
72 // vec3 T = pos_dx * uv_dy.t - pos_dy * uv_dx.t;
73 T = normalize(T - dot(T, N) * N);
74 vec3 B = normalize(cross(N, T));
75#endif
76
77 if (gl_FrontFacing == false) {
78 T = -T;
79 B = -B;
80 N = -N;
81 }
82
83 vec3 s = normalMapSample;
84 //return normalize(s.x * T + s.y * B + s.z * N);
85 return normalize(mat3(T,B,N) * s);
86}
87#endif // HAS_TANGENTS || HAS_TEXCOORDS
88
89float trowbridge_reitz_GGX(float roughness, float NdotH) {
90 float a = roughness * roughness;
91 float a2 = a * a;
92 float d = NdotH * NdotH * (a2 - 1.0) + 1.0;
93 return a2 / (PI * d * d);
94}
95
96float geometry_schlick_GGX(float k, float NdotV) {
97 return NdotV / (NdotV * (1.0 - k) + k);
98}
99
100float geometry_smith(float roughness, float NdotL, float NdotV) {
101 float k = roughness * roughness / 2.0; // IBL
102 return geometry_schlick_GGX(k, NdotV) * geometry_schlick_GGX(k, NdotL);
103}
104
105vec3 fresnel_schlick(vec3 F0, float HdotV) {
106 return F0 + (1.0 - F0) * pow(clamp(1.0 - HdotV, 0.0, 1.0), 5.0);
107}
108
109vec3 fresnel_schlick_roughness(vec3 F0, float NdotV, float roughness) {
110 return F0
111 + (max(vec3(1.0 - roughness), F0) - F0)
112 * pow(clamp(1.0 - NdotV, 0.0, 1.0), 5.0);
113}
114
115// Cook-Torrance BRDF for a single light direction.
116vec3 cook_torrance(
117 vec3 albedo, float metallic, float roughness,
118 float NdotL, float NdotV, float NdotH, float HdotV) {
119 vec3 F0 = mix(vec3(0.04), albedo, metallic);
120 float D = trowbridge_reitz_GGX(roughness, NdotH);
121 vec3 F = fresnel_schlick(F0, HdotV);
122 float G = geometry_smith(roughness, NdotL, NdotV);
123 vec3 Kd = mix(vec3(1.0) - F, vec3(0.0), metallic);
124 vec3 diffuse = Kd*albedo*INV_PI;
125 // Take a max to prevent division by 0 when either dot product is 0.
126 vec3 specular = (D*F*G) / max(4.0 * NdotV * NdotL, 0.0001);
127 return diffuse + specular;
128}
129
130// Cook-Torrance BRDF for IBL.
131vec3 cook_torrance_IBL(
132 vec3 albedo, float metallic, float roughness, float occlusion,
133 float NdotV,
134 vec3 irradiance, vec3 prefiltered_env, vec2 BRDF_env) {
135 vec3 F0 = mix(vec3(0.04), albedo, metallic);
136 vec3 F = fresnel_schlick_roughness(F0, NdotV, roughness);
137 vec3 Kd = mix(vec3(1.0) - F, vec3(0.0), metallic);
138 vec3 diffuse = Kd * albedo * INV_PI * irradiance;
139 vec3 specular = prefiltered_env * (F * BRDF_env.x + BRDF_env.y);
140 return occlusion * (diffuse + specular);
141}
142
143void main()
144{
145 // TODO: Also use the specular F0 map from the model, and emissive. Make sure
146 // to use all maps.
147 // https://sketchfab.com/models/b81008d513954189a063ff901f7abfe4
148#ifdef HAS_NORMAL_MAP
149 vec3 normalMapSample = texture(NormalMap, Texcoord).xyz * 2.0 - 1.0;
150 vec3 N = get_ws_normal(Normal, normalMapSample);
151#elif HAS_NORMALS
152 vec3 N = normalize(Normal);
153#endif
154 vec3 V = normalize(CameraPosition - Position);
155 vec3 R = reflect(-V, N);
156 // Not needed for IBL.
157 //vec3 L = N;
158 //vec3 H = normalize(L + V);
159
160 float NdotV = max(0.0, dot(N, V));
161 // Not needed for IBL.
162 //float NdotL = max(0.0, dot(N,L));
163 //float NdotH = max(0.0, dot(N,H));
164 //float HdotV = clamp(dot(H,V), 0.0, 1.0); // Clamp to prevent black spots.
165
166 // TODO: BaseColorFactor and BaseColorTexture are vec4/rgba quantities
167 // respectively. Handle the alpha channel.
168 // TODO: Other factors.
169#ifdef HAS_ALBEDO_MAP
170 vec3 albedo = vec3(BaseColorFactor) * texture(BaseColorTexture, Texcoord).rgb;
171#else
172 vec3 albedo = vec3(BaseColorFactor);
173#endif
174#ifdef HAS_METALLIC_ROUGHNESS_MAP
175 // Spec: "Its green channel contains roughness values and its blue channel
176 // contains metalness values."
177 vec2 metal_roughness
178 = vec2(MetallicFactor, RoughnessFactor)
179 * texture(MetallicRoughnessTexture, Texcoord).bg;
180#else
181 vec2 metal_roughness = vec2(MetallicFactor, RoughnessFactor);
182#endif
183#ifdef HAS_EMISSIVE_MAP
184 vec3 emissive = EmissiveFactor * texture(EmissiveTexture, Texcoord).rgb;
185#else
186 vec3 emissive = EmissiveFactor;
187#endif
188#ifdef HAS_OCCLUSION_MAP
189 float occlusion = texture(AmbientOcclusionTexture, Texcoord).r;
190#else
191 float occlusion = 1.0;
192#endif
193 float metallic = metal_roughness.x;
194 float roughness = metal_roughness.y;
195
196 // For a single light direction:
197 // vec3 brdf = cook_torrance(albedo, metallic, roughness, NdotL, NdotV, NdotH, HdotV);
198 // vec3 Li = texture(Sky, N).rgb;
199 // vec3 colour = brdf * Li * NdotL;
200
201 // For IBL:
202 vec3 irradiance = texture(IrradianceMap, N).rgb;
203 vec3 prefiltered_env = textureLod(PrefilteredEnvironmentMap, R, roughness * MaxReflectionLOD).rgb;
204 vec2 BRDF_env = texture(BRDFIntegrationMap, vec2(NdotV, roughness)).rg;
205 vec3 colour = cook_torrance_IBL(
206 albedo, metallic, roughness, occlusion, NdotV, irradiance, prefiltered_env, BRDF_env);
207
208 colour += emissive;
209
210 // Reinhard tone mapping.
211 colour = colour / (colour + vec3(1.0));
212
213 // Gamma correction.
214 colour = pow(colour, vec3(1.0 / 2.2));
215
216 // Debugging.
217 //
218 // Normal texture.
219 //colour = normalMapSample * 0.5 + 0.5;
220 //
221 // Geometry normal.
222 //colour = normalize(Normal) * 0.5 + 0.5;
223 //
224 // Shading normal.
225 //colour = N * 0.5 + 0.5;
226 //
227 // Tangent and bitangent.
228 // {
229 // vec3 pos_dx = dFdx(Position);
230 // vec3 pos_dy = dFdy(Position);
231 // // vec3 uv_dx = vec3(dFdx(Texcoord), 0.0);
232 // // vec3 uv_dy = vec3(dFdy(Texcoord), 0.0);
233 // vec3 uv_dx = dFdx(vec3(Texcoord, 0.0));
234 // vec3 uv_dy = dFdy(vec3(Texcoord, 0.0));
235 // vec3 T = (uv_dy.t * pos_dx - uv_dx.t * pos_dy) /
236 // (uv_dx.s * uv_dy.t - uv_dy.s * uv_dx.t);
237 // // vec3 T = pos_dx * uv_dy.t - pos_dy * uv_dx.t;
238 // vec3 N = normalize(Normal);
239 // T = normalize(T - dot(T, N) * N);
240 // vec3 B = normalize(cross(N, T));
241
242 // if (gl_FrontFacing == false) {
243 // T = -T;
244 // B = -B;
245 // N = -N;
246 // }
247
248 // // Tangent.
249 // //colour = T * 0.5 + 0.5;
250 // // Bitangent.
251 // //colour = B * 0.5 + 0.5;
252 // }
253
254 Colour = vec4(colour, 1.0);
255}
diff --git a/shaders/cook_torrance.vert b/shaders/cook_torrance.vert
new file mode 100644
index 0000000..5f126c0
--- /dev/null
+++ b/shaders/cook_torrance.vert
@@ -0,0 +1,75 @@
1precision highp float;
2
3uniform mat4 ModelMatrix;
4// uniform mat4 Modelview;
5uniform mat4 View;
6uniform mat4 Projection;
7//uniform mat4 MVP;
8#ifdef HAS_JOINTS
9// The client should pass in an appropriate value for MAX_JOINTS.
10// #define MAX_JOINTS 96
11//
12// matnxm -- n columns and m rows, different convention from math.
13// We don't need the last row of [0, 0, 0, 1], so drop it to pack the matrices
14// as tightly as possible.
15// 256 joints * 4x4 matrix * 4 bytes/float = 16.0KB
16// 256 joints * 4x3 matrix * 4 bytes/float = 12.0KB
17// 96 joints * 4x4 matrix * 4 bytes/float = 6.0KB
18// 96 joints * 4x3 matrix * 4 bytes/float = 4.5KB
19//uniform mat4x3 Joints[MAX_JOINTS];
20uniform mat4 JointMatrices[MAX_JOINTS]; // Use 4x4 for now to keep it simple.
21#endif
22
23layout (location = 0) in vec3 vPosition;
24#ifdef HAS_NORMALS
25layout (location = 1) in vec3 vNormal;
26#endif
27#ifdef HAS_TANGENTS
28layout (location = 2) in vec4 vTangent;
29#endif
30#ifdef HAS_TEXCOORDS
31layout (location = 3) in vec2 vTexcoord;
32#endif
33#ifdef HAS_JOINTS
34layout (location = 4) in uvec4 vJoint;
35layout (location = 5) in vec4 vWeight;
36#endif
37
38// World-space position, normal and tangent.
39out vec3 Position;
40#ifdef HAS_NORMALS
41out vec3 Normal;
42#endif
43#ifdef HAS_TANGENTS
44out vec4 Tangent;
45#endif
46#ifdef HAS_TEXCOORDS
47out vec2 Texcoord;
48#endif
49
50void main()
51{
52#ifdef HAS_JOINTS
53 mat4 skinMatrix =
54 vWeight.x * JointMatrices[vJoint.x] +
55 vWeight.y * JointMatrices[vJoint.y] +
56 vWeight.z * JointMatrices[vJoint.z] +
57 vWeight.w * JointMatrices[vJoint.w];
58 Position = vec3(ModelMatrix * skinMatrix * vec4(vPosition, 1.0));
59#else
60 Position = vec3(ModelMatrix * vec4(vPosition, 1.0));
61#endif
62#ifdef HAS_NORMALS
63 Normal = mat3(ModelMatrix) * vNormal;
64 //Normal = normalize(ModelMatrix * vec4(vNormal, 0.0)).xyz;
65#endif
66#ifdef HAS_TANGENTS
67 Tangent = vec4(mat3(ModelMatrix) * vTangent.xyz, vTangent.w);
68#endif
69#ifdef HAS_TEXCOORDS
70 Texcoord = vTexcoord;
71#endif
72 gl_Position = Projection * View * vec4(Position, 1.0);
73 //gl_Position = Projection * vec4(Position, 1.0);
74 //gl_Position = MVP * vec4(vPosition, 1.0);
75}
diff --git a/shaders/cubemap_filtering.vert b/shaders/cubemap_filtering.vert
new file mode 100644
index 0000000..d0cf73f
--- /dev/null
+++ b/shaders/cubemap_filtering.vert
@@ -0,0 +1,39 @@
1precision highp float;
2
3#define PI 3.1415926535897932384626433832795
4#define FOVY (90.0 * PI / 180.0)
5
6uniform mat4 CameraRotation; // From camera space to world space.
7uniform float Flip;
8
9layout (location = 0) in vec2 vPosition;
10
11out vec3 Ray;
12
13// DEBUG
14// out vec2 Texcoord;
15
16// This is very similar to the skyquad vertex shader.
17//
18// The ray is not normalized because it isn't necessary for cubemap sampling.
19//
20// We also use a fixed fovy = 90 degrees because we want the frustum to pass
21// exactly through each face of the cube. The aspect ratio is also just 1.
22vec3 sky_ray(vec2 FilmPosition)
23{
24 float d = 0.5 / tan(FOVY/2.0);
25 return vec3(FilmPosition, -d);
26}
27
28void main()
29{
30 vec2 FilmPosition = vPosition * 0.5; // map [-1,1] -> [-1/2, +1/2]
31 FilmPosition *= Flip;
32 Ray = mat3(CameraRotation) * sky_ray(FilmPosition);
33 // TODO: Should disable depth test when rendering.
34 gl_Position = vec4(vPosition, 0.99999, 1.0); // z=1 -> send to background
35
36 // DEBUG
37 // Texcoord = FilmPosition + 0.5;
38 // Texcoord.y = 1.0 - Texcoord.y;
39}
diff --git a/shaders/debug3d.frag b/shaders/debug3d.frag
new file mode 100644
index 0000000..54568d4
--- /dev/null
+++ b/shaders/debug3d.frag
@@ -0,0 +1,21 @@
1precision highp float;
2
3const vec3 Colour = vec3(0.97, 0.948, 0.91);
4
5const vec3 ToLight = vec3(1, 0.7, 1);
6
7in vec3 Normal;
8
9out vec4 FragColour;
10
11void main()
12{
13 vec3 N = normalize(Normal);
14 vec3 L = normalize(ToLight);
15
16 vec3 a = vec3(0.7);
17 vec3 d = vec3(0.3 * (0.7*max(0.0, dot(L,N)) + 0.3*max(0.0, dot(-L,N))));
18 vec3 c = Colour * (a+d);
19
20 FragColour = vec4(pow(c, vec3(1.0 / 2.2)), 1.0);
21}
diff --git a/shaders/debug3d.vert b/shaders/debug3d.vert
new file mode 100644
index 0000000..d51684f
--- /dev/null
+++ b/shaders/debug3d.vert
@@ -0,0 +1,15 @@
1precision highp float;
2
3uniform mat4 Modelview;
4uniform mat4 Projection;
5
6layout (location = 0) in vec3 vPosition;
7layout (location = 1) in vec3 vNormal;
8
9out vec3 Normal;
10
11void main()
12{
13 Normal = mat3(Modelview) * vNormal;
14 gl_Position = Projection * Modelview * vec4(vPosition, 1.0);
15}
diff --git a/shaders/immediate_mode.frag b/shaders/immediate_mode.frag
new file mode 100644
index 0000000..ac23b5c
--- /dev/null
+++ b/shaders/immediate_mode.frag
@@ -0,0 +1,10 @@
1precision highp float;
2
3uniform vec4 Colour;
4
5out vec4 FragColour;
6
7void main()
8{
9 FragColour = vec4(pow(Colour.rgb, vec3(1.0/2.2)), Colour.a);
10}
diff --git a/shaders/immediate_mode.vert b/shaders/immediate_mode.vert
new file mode 100644
index 0000000..65070bb
--- /dev/null
+++ b/shaders/immediate_mode.vert
@@ -0,0 +1,11 @@
1precision highp float;
2
3uniform mat4 Model;
4uniform mat4 ViewProjection;
5
6layout (location = 0) in vec3 vPosition;
7
8void main()
9{
10 gl_Position = ViewProjection * Model * vec4(vPosition, 1.0);
11}
diff --git a/shaders/irradiance_map.frag b/shaders/irradiance_map.frag
new file mode 100644
index 0000000..8200e73
--- /dev/null
+++ b/shaders/irradiance_map.frag
@@ -0,0 +1,65 @@
1precision highp float;
2
3#define PI 3.1415926535897932384626433832795
4#define EPS 0.001
5#define NUM_SAMPLES_AZIMUTH 250
6#define NUM_SAMPLES_ZENITH 50
7#define MAX_AZIMUTH (2*PI)
8#define MAX_ZENITH (PI/2.0)
9#define AZIMUTH_DELTA (MAX_AZIMUTH / float(NUM_SAMPLES_AZIMUTH))
10#define ZENITH_DELTA (MAX_ZENITH / float(NUM_SAMPLES_ZENITH))
11
12uniform samplerCube Sky;
13
14in vec3 Ray;
15
16// DEBUG
17// in vec2 Texcoord;
18
19layout (location = 0) out vec4 Color;
20
21void main()
22{
23 // Tangent space:
24 //
25 // N
26 // |
27 // |
28 // |
29 // |_ _ _ _ _ B
30 // /
31 // /
32 // T
33 vec3 N = normalize(Ray);
34 vec3 B = (abs(N.x) - 1.0 <= EPS) ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
35 vec3 T = normalize(cross(B, N));
36 B = normalize(cross(N, T));
37
38 int num_samples = 0;
39 vec3 irradiance = vec3(0.0);
40 for (float theta = 0.0; theta < MAX_AZIMUTH; theta += AZIMUTH_DELTA) {
41 for (float phi = 0.0; phi < MAX_ZENITH; phi += ZENITH_DELTA) {
42 // Spherical to Cartesian.
43 vec3 sample_tangent_space = vec3(
44 sin(phi) * cos(theta),
45 sin(phi) * sin(theta),
46 cos(phi));
47 // Tangent space to world space.
48 vec3 sample_world_space =
49 sample_tangent_space.x * B +
50 sample_tangent_space.y * T +
51 sample_tangent_space.z * N;
52
53 irradiance += texture(Sky, sample_world_space).rgb * sin(phi) * cos(phi);
54 num_samples += 1;
55 }
56 }
57 irradiance = PI * irradiance / float(num_samples);
58
59 // For debugging in trace.
60 //irradiance = texture(Sky, Ray).rgb;
61 // irradiance = vec3(Texcoord, 0.0);
62 //irradiance = pow(irradiance, vec3(1.0/2.2));
63
64 Color = vec4(irradiance, 1.0);
65}
diff --git a/shaders/prefiltered_environment_map.frag b/shaders/prefiltered_environment_map.frag
new file mode 100644
index 0000000..8327950
--- /dev/null
+++ b/shaders/prefiltered_environment_map.frag
@@ -0,0 +1,78 @@
1precision highp float;
2
3#define PI 3.1415926535897932384626433832795
4#define NUM_SAMPLES 4096
5
6uniform samplerCube Sky;
7uniform float Roughness;
8
9in vec3 Ray;
10
11layout (location = 0) out vec4 Color;
12
13float radical_inverse_VdC(uint bits) {
14 bits = (bits << 16u) | (bits >> 16u);
15 bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
16 bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
17 bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
18 bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
19 return float(bits) * 2.3283064365386963e-10; // / 0x100000000
20}
21
22vec2 hammersley(uint i, uint N) {
23 return vec2(float(i)/float(N), radical_inverse_VdC(i));
24}
25
26vec3 importance_sample_GGX(vec2 sample_box, vec3 N, float roughness) {
27 float r2 = roughness * roughness;
28
29 // Spherical coordinates.
30 float phi = 2.0 * PI * sample_box.x;
31 float cos_theta = sqrt((1.0 - sample_box.y) / (1.0 + (r2*r2 - 1.0) * sample_box.y));
32 float sin_theta = sqrt(1.0 - cos_theta * cos_theta);
33
34 // Map spherical coordinates to Cartesian coordinates in tangent space.
35 vec3 H = vec3(cos(phi) * sin_theta, sin(phi) * sin_theta, cos_theta);
36
37 // Map from tangent space to world space.
38 //
39 // Tangent space:
40 //
41 // N
42 // |
43 // |
44 // |
45 // |_ _ _ _ _ B
46 // /
47 // /
48 // T
49 vec3 up = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
50 vec3 T = normalize(cross(up,N));
51 vec3 B = cross(N,T);
52 vec3 H_ws = H.x*T + H.y*B + H.z*N;
53 return H_ws;
54}
55
56void main()
57{
58 vec3 N = normalize(Ray);
59 vec3 R = N;
60 vec3 V = R;
61
62 vec3 irradiance = vec3(0.0);
63 float total_weight = 0.0;
64 for (uint i = 0; i < NUM_SAMPLES; ++i) {
65 vec2 sample_box = hammersley(i, NUM_SAMPLES);
66 vec3 H = importance_sample_GGX(sample_box, N, Roughness);
67 vec3 L = reflect(-V,H);
68
69 float NdotL = max(dot(N,L), 0.0);
70 if (NdotL > 0.0) {
71 irradiance += texture(Sky, H).rgb * NdotL;
72 total_weight += NdotL;
73 }
74 }
75 irradiance /= total_weight;
76
77 Color = vec4(irradiance, 1.0);
78}
diff --git a/shaders/quad.vert b/shaders/quad.vert
new file mode 100644
index 0000000..ef1834c
--- /dev/null
+++ b/shaders/quad.vert
@@ -0,0 +1,9 @@
1layout (location = 0) in vec2 Position; // Assuming Position in [-1,1].
2
3out vec2 Texcoord;
4
5void main()
6{
7 Texcoord = Position * 0.5 + 0.5;
8 gl_Position = vec4(Position, 0.0, 1.0);
9}
diff --git a/shaders/skyquad.frag b/shaders/skyquad.frag
new file mode 100644
index 0000000..9b44bfd
--- /dev/null
+++ b/shaders/skyquad.frag
@@ -0,0 +1,13 @@
1uniform samplerCube Skyquad;
2
3in vec3 Ray;
4
5layout (location = 0) out vec4 Colour;
6
7void main()
8{
9 vec3 R = normalize(Ray);
10 Colour = vec4(pow(texture(Skyquad, R).rgb, vec3(1.0/2.2)), 1.0);
11 // Debug.
12 //Colour = vec4(pow(R*0.5 + 0.5, vec3(1.0 / 2.2)), 1.0);
13}
diff --git a/shaders/skyquad.vert b/shaders/skyquad.vert
new file mode 100644
index 0000000..c0c46e6
--- /dev/null
+++ b/shaders/skyquad.vert
@@ -0,0 +1,27 @@
1uniform mat4 CameraRotation; // From camera space to world space.
2uniform float Fovy;
3uniform float Aspect;
4
5layout (location = 0) in vec2 Position;
6
7out vec3 Ray;
8
9// We would typically normalize the vector, but there is no need to do so when
10// sampling a cube map.
11vec3 sky_ray(vec2 FilmPosition)
12{
13 //float d = 0.5 / tan(Fovy/2.0);
14 // return vec3((FilmPosition.x - 0.5) * Aspect,
15 // FilmPosition.y - 0.5,
16 // -d);
17 float d = 0.5 / tan(Fovy/2.0);
18 return vec3(FilmPosition, -d);
19}
20
21void main()
22{
23 vec2 FilmPosition = Position * 0.5; // map [-1,1] -> [-1/2, +1/2]
24 Ray = mat3(CameraRotation) * sky_ray(FilmPosition);
25 // Set z to the background.
26 gl_Position = vec4(Position, 0.99999, 1.0); // z=1 -> send to background
27}
diff --git a/shaders/view_normal_mapped_normals.frag b/shaders/view_normal_mapped_normals.frag
new file mode 100644
index 0000000..a372c02
--- /dev/null
+++ b/shaders/view_normal_mapped_normals.frag
@@ -0,0 +1,28 @@
1precision highp float;
2
3uniform sampler2D NormalMap;
4
5in vec3 Normal;
6in vec4 Tangent;
7in vec3 Bitangent; // TODO: Compute here or in PS?
8in vec2 Texcoord;
9
10out vec4 FragColour;
11
12// TODO: Move to "normal.h"
13vec3 get_vs_normal(vec3 normal, vec4 tangent, vec3 normalMapSample) {
14 vec3 N = normal;
15 // vec3 T = normalize(interpTangent - dot(tangent, N)*N);
16 // vec3 B = normalize(interpBitangent - dot(interpTangent, N)*N - dot(interpTangent, T)*T);
17 vec3 T = tangent.xyz;
18 //vec3 B = tangent.w * cross(N,T);
19 vec3 B = Bitangent;
20 vec3 n = normalMapSample;
21 return normalize(n.x*T + n.y*B + n.z*N);
22}
23
24void main() {
25 vec3 normalMapSample = texture(NormalMap, Texcoord).xyz * 2.0 - 1.0;
26 vec3 N = get_vs_normal(Normal, Tangent, normalMapSample);
27 FragColour = vec4(pow(N, vec3(1.0 / 2.2)), 1.0);
28}
diff --git a/shaders/view_normal_mapped_normals.vert b/shaders/view_normal_mapped_normals.vert
new file mode 100644
index 0000000..004ed9a
--- /dev/null
+++ b/shaders/view_normal_mapped_normals.vert
@@ -0,0 +1,22 @@
1precision highp float;
2
3uniform mat4 Modelview;
4uniform mat4 Projection;
5
6layout (location = 0) in vec3 vPosition;
7layout (location = 1) in vec3 vNormal;
8layout (location = 2) in vec4 vTangent;
9layout (location = 3) in vec2 vTexcoord;
10
11out vec3 Normal;
12out vec4 Tangent;
13out vec3 Bitangent; // TODO: Compute here or in PS?
14out vec2 Texcoord;
15
16void main() {
17 Texcoord = vTexcoord;
18 Normal = mat3(Modelview) * vNormal;
19 Tangent = vec4(mat3(Modelview) * vTangent.xyz, vTangent.w);
20 Bitangent = cross(Normal, Tangent.xyz) * vTangent.w;
21 gl_Position = Projection * Modelview * vec4(vPosition, 1.0);
22}
diff --git a/shaders/view_normals.frag b/shaders/view_normals.frag
new file mode 100644
index 0000000..e90189c
--- /dev/null
+++ b/shaders/view_normals.frag
@@ -0,0 +1,11 @@
1precision highp float;
2
3in vec3 Normal;
4
5out vec4 FragColour;
6
7void main()
8{
9 vec3 N = normalize(Normal);
10 FragColour = vec4(pow(N, vec3(1.0 / 2.2)), 1.0);
11}
diff --git a/shaders/view_normals.vert b/shaders/view_normals.vert
new file mode 100644
index 0000000..d51684f
--- /dev/null
+++ b/shaders/view_normals.vert
@@ -0,0 +1,15 @@
1precision highp float;
2
3uniform mat4 Modelview;
4uniform mat4 Projection;
5
6layout (location = 0) in vec3 vPosition;
7layout (location = 1) in vec3 vNormal;
8
9out vec3 Normal;
10
11void main()
12{
13 Normal = mat3(Modelview) * vNormal;
14 gl_Position = Projection * Modelview * vec4(vPosition, 1.0);
15}
diff --git a/shaders/view_tangents.frag b/shaders/view_tangents.frag
new file mode 100644
index 0000000..11d1455
--- /dev/null
+++ b/shaders/view_tangents.frag
@@ -0,0 +1,17 @@
1precision highp float;
2
3in vec4 Tangent;
4
5out vec4 FragColour;
6
7void main() {
8 vec3 T = normalize(Tangent.xyz);
9 FragColour = vec4(pow(T, vec3(1.0 / 2.2)), 1.0);FragColour = vec4(pow(T, vec3(1.0 / 2.2)), 1.0);
10
11 // View sign.
12 // float sign = Tangent.w;
13 // float R = sign > 0.0 ? 1.0 : 0.0;
14 // float B = sign < 0.0 ? 1.0 : 0.0;
15 // vec3 signColour = vec3(R,0.0,B);
16 // FragColour = vec4(pow(signColour, vec3(1.0 / 2.2)), 1.0);
17}
diff --git a/shaders/view_tangents.vert b/shaders/view_tangents.vert
new file mode 100644
index 0000000..561ad22
--- /dev/null
+++ b/shaders/view_tangents.vert
@@ -0,0 +1,14 @@
1precision highp float;
2
3uniform mat4 Modelview;
4uniform mat4 Projection;
5
6layout (location = 0) in vec3 vPosition;
7layout (location = 2) in vec4 vTangent;
8
9out vec4 Tangent;
10
11void main() {
12 Tangent = vec4(Tangent.xyz = mat3(Modelview) * vTangent.xyz, vTangent.w);
13 gl_Position = Projection * Modelview * vec4(vPosition, 1.0);
14}
diff --git a/shaders/view_texture.frag b/shaders/view_texture.frag
new file mode 100644
index 0000000..12fa367
--- /dev/null
+++ b/shaders/view_texture.frag
@@ -0,0 +1,15 @@
1uniform sampler2D Texture;
2
3in vec2 Texcoord;
4
5layout (location = 0) out vec4 Colour;
6
7void main()
8{
9 // There is a question here whether we want to view the texture through the
10 // sampler or unfiltered. Prefer the latter for now.
11 //vec3 colour = texture(Texture, Texcoord).rgb;
12 ivec2 st = ivec2(Texcoord * vec2(textureSize(Texture, 0)));
13 vec3 colour = texelFetch(Texture, st, 0).rgb;
14 Colour = vec4(pow(colour, vec3(1.0 / 2.2)), 1.0);
15}
diff --git a/shaders/view_texture.vert b/shaders/view_texture.vert
new file mode 100644
index 0000000..4e3c7d7
--- /dev/null
+++ b/shaders/view_texture.vert
@@ -0,0 +1,13 @@
1layout (location = 0) in vec2 Position;
2
3out vec2 Texcoord;
4
5void main()
6{
7 Texcoord = Position * vec2(0.5) + vec2(0.5);// Map from [-1, +1] to [0, 1].
8 // The Gfx library is written to work with the glTF sample models, which
9 // seem to want the textures loaded "as is" without flipping. Flip the
10 // y-coordinate here so that the texture appears as expected.
11 Texcoord.y = 1.0 - Texcoord.y;
12 gl_Position = vec4(Position, 0.0, 1.0);
13}