diff options
author | 3gg <3gg@shellblade.net> | 2025-06-27 10:18:39 -0700 |
---|---|---|
committer | 3gg <3gg@shellblade.net> | 2025-06-27 10:18:39 -0700 |
commit | bd57f345ed9dbed1d81683e48199626de2ea9044 (patch) | |
tree | 4221f2f2a7ad2244d2e93052bd68187ec91b8ea9 /shaders | |
parent | 9a82ce0083437a4f9f58108b2c23b957d2249ad8 (diff) |
Diffstat (limited to 'shaders')
-rw-r--r-- | shaders/brdf_integration_map.frag | 93 | ||||
-rw-r--r-- | shaders/cook_torrance.frag | 255 | ||||
-rw-r--r-- | shaders/cook_torrance.vert | 75 | ||||
-rw-r--r-- | shaders/cubemap_filtering.vert | 39 | ||||
-rw-r--r-- | shaders/debug3d.frag | 21 | ||||
-rw-r--r-- | shaders/debug3d.vert | 15 | ||||
-rw-r--r-- | shaders/immediate_mode.frag | 10 | ||||
-rw-r--r-- | shaders/immediate_mode.vert | 11 | ||||
-rw-r--r-- | shaders/irradiance_map.frag | 65 | ||||
-rw-r--r-- | shaders/prefiltered_environment_map.frag | 78 | ||||
-rw-r--r-- | shaders/quad.vert | 9 | ||||
-rw-r--r-- | shaders/skyquad.frag | 13 | ||||
-rw-r--r-- | shaders/skyquad.vert | 27 | ||||
-rw-r--r-- | shaders/view_normal_mapped_normals.frag | 28 | ||||
-rw-r--r-- | shaders/view_normal_mapped_normals.vert | 22 | ||||
-rw-r--r-- | shaders/view_normals.frag | 11 | ||||
-rw-r--r-- | shaders/view_normals.vert | 15 | ||||
-rw-r--r-- | shaders/view_tangents.frag | 17 | ||||
-rw-r--r-- | shaders/view_tangents.vert | 14 | ||||
-rw-r--r-- | shaders/view_texture.frag | 15 | ||||
-rw-r--r-- | shaders/view_texture.vert | 13 |
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 @@ | |||
1 | precision highp float; | ||
2 | |||
3 | #define PI 3.1415926535897932384626433832795 | ||
4 | #define NUM_SAMPLES 1024 | ||
5 | |||
6 | in vec2 Texcoord; | ||
7 | |||
8 | layout (location = 0) out vec2 Color; | ||
9 | |||
10 | float 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 | |||
19 | vec2 hammersley(uint i, uint N) { | ||
20 | return vec2(float(i)/float(N), radical_inverse_VdC(i)); | ||
21 | } | ||
22 | |||
23 | vec3 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 | |||
53 | float geometry_schlick_GGX(float k, float NdotV) { | ||
54 | return NdotV / (NdotV * (1.0 - k) + k); | ||
55 | } | ||
56 | |||
57 | float 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 | |||
62 | vec2 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 | |||
90 | void 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 @@ | |||
1 | precision highp float; | ||
2 | |||
3 | uniform vec4 BaseColorFactor; | ||
4 | uniform float MetallicFactor; | ||
5 | uniform float RoughnessFactor; | ||
6 | uniform vec3 EmissiveFactor; | ||
7 | |||
8 | #ifdef HAS_ALBEDO_MAP | ||
9 | uniform sampler2D BaseColorTexture; | ||
10 | #endif | ||
11 | #ifdef HAS_METALLIC_ROUGHNESS_MAP | ||
12 | uniform sampler2D MetallicRoughnessTexture; | ||
13 | #endif | ||
14 | #ifdef HAS_EMISSIVE_MAP | ||
15 | uniform sampler2D EmissiveTexture; | ||
16 | #endif | ||
17 | #ifdef HAS_OCCLUSION_MAP | ||
18 | uniform sampler2D AmbientOcclusionTexture; | ||
19 | #endif | ||
20 | #ifdef HAS_NORMAL_MAP | ||
21 | uniform sampler2D NormalMap; | ||
22 | #endif | ||
23 | |||
24 | // TODO: Handle case in which there is no sky. Pass a boolean. | ||
25 | uniform samplerCube Sky; | ||
26 | uniform samplerCube IrradianceMap; | ||
27 | uniform samplerCube PrefilteredEnvironmentMap; | ||
28 | uniform sampler2D BRDFIntegrationMap; | ||
29 | uniform float MaxReflectionLOD; | ||
30 | |||
31 | uniform vec3 CameraPosition; // World space. | ||
32 | |||
33 | // World-space position, normal and tangent. | ||
34 | in vec3 Position; | ||
35 | #ifdef HAS_NORMALS | ||
36 | in vec3 Normal; | ||
37 | #endif | ||
38 | #ifdef HAS_TANGENTS | ||
39 | in vec4 Tangent; | ||
40 | #endif | ||
41 | #ifdef HAS_TEXCOORDS | ||
42 | in vec2 Texcoord; | ||
43 | #endif | ||
44 | |||
45 | layout (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)) | ||
57 | vec3 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 | |||
89 | float 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 | |||
96 | float geometry_schlick_GGX(float k, float NdotV) { | ||
97 | return NdotV / (NdotV * (1.0 - k) + k); | ||
98 | } | ||
99 | |||
100 | float 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 | |||
105 | vec3 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 | |||
109 | vec3 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. | ||
116 | vec3 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. | ||
131 | vec3 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 | |||
143 | void 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 @@ | |||
1 | precision highp float; | ||
2 | |||
3 | uniform mat4 ModelMatrix; | ||
4 | // uniform mat4 Modelview; | ||
5 | uniform mat4 View; | ||
6 | uniform 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]; | ||
20 | uniform mat4 JointMatrices[MAX_JOINTS]; // Use 4x4 for now to keep it simple. | ||
21 | #endif | ||
22 | |||
23 | layout (location = 0) in vec3 vPosition; | ||
24 | #ifdef HAS_NORMALS | ||
25 | layout (location = 1) in vec3 vNormal; | ||
26 | #endif | ||
27 | #ifdef HAS_TANGENTS | ||
28 | layout (location = 2) in vec4 vTangent; | ||
29 | #endif | ||
30 | #ifdef HAS_TEXCOORDS | ||
31 | layout (location = 3) in vec2 vTexcoord; | ||
32 | #endif | ||
33 | #ifdef HAS_JOINTS | ||
34 | layout (location = 4) in uvec4 vJoint; | ||
35 | layout (location = 5) in vec4 vWeight; | ||
36 | #endif | ||
37 | |||
38 | // World-space position, normal and tangent. | ||
39 | out vec3 Position; | ||
40 | #ifdef HAS_NORMALS | ||
41 | out vec3 Normal; | ||
42 | #endif | ||
43 | #ifdef HAS_TANGENTS | ||
44 | out vec4 Tangent; | ||
45 | #endif | ||
46 | #ifdef HAS_TEXCOORDS | ||
47 | out vec2 Texcoord; | ||
48 | #endif | ||
49 | |||
50 | void 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 @@ | |||
1 | precision highp float; | ||
2 | |||
3 | #define PI 3.1415926535897932384626433832795 | ||
4 | #define FOVY (90.0 * PI / 180.0) | ||
5 | |||
6 | uniform mat4 CameraRotation; // From camera space to world space. | ||
7 | uniform float Flip; | ||
8 | |||
9 | layout (location = 0) in vec2 vPosition; | ||
10 | |||
11 | out 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. | ||
22 | vec3 sky_ray(vec2 FilmPosition) | ||
23 | { | ||
24 | float d = 0.5 / tan(FOVY/2.0); | ||
25 | return vec3(FilmPosition, -d); | ||
26 | } | ||
27 | |||
28 | void 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 @@ | |||
1 | precision highp float; | ||
2 | |||
3 | const vec3 Colour = vec3(0.97, 0.948, 0.91); | ||
4 | |||
5 | const vec3 ToLight = vec3(1, 0.7, 1); | ||
6 | |||
7 | in vec3 Normal; | ||
8 | |||
9 | out vec4 FragColour; | ||
10 | |||
11 | void 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 @@ | |||
1 | precision highp float; | ||
2 | |||
3 | uniform mat4 Modelview; | ||
4 | uniform mat4 Projection; | ||
5 | |||
6 | layout (location = 0) in vec3 vPosition; | ||
7 | layout (location = 1) in vec3 vNormal; | ||
8 | |||
9 | out vec3 Normal; | ||
10 | |||
11 | void 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 @@ | |||
1 | precision highp float; | ||
2 | |||
3 | uniform vec4 Colour; | ||
4 | |||
5 | out vec4 FragColour; | ||
6 | |||
7 | void 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 @@ | |||
1 | precision highp float; | ||
2 | |||
3 | uniform mat4 Model; | ||
4 | uniform mat4 ViewProjection; | ||
5 | |||
6 | layout (location = 0) in vec3 vPosition; | ||
7 | |||
8 | void 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 @@ | |||
1 | precision 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 | |||
12 | uniform samplerCube Sky; | ||
13 | |||
14 | in vec3 Ray; | ||
15 | |||
16 | // DEBUG | ||
17 | // in vec2 Texcoord; | ||
18 | |||
19 | layout (location = 0) out vec4 Color; | ||
20 | |||
21 | void 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 @@ | |||
1 | precision highp float; | ||
2 | |||
3 | #define PI 3.1415926535897932384626433832795 | ||
4 | #define NUM_SAMPLES 4096 | ||
5 | |||
6 | uniform samplerCube Sky; | ||
7 | uniform float Roughness; | ||
8 | |||
9 | in vec3 Ray; | ||
10 | |||
11 | layout (location = 0) out vec4 Color; | ||
12 | |||
13 | float 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 | |||
22 | vec2 hammersley(uint i, uint N) { | ||
23 | return vec2(float(i)/float(N), radical_inverse_VdC(i)); | ||
24 | } | ||
25 | |||
26 | vec3 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 | |||
56 | void 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 @@ | |||
1 | layout (location = 0) in vec2 Position; // Assuming Position in [-1,1]. | ||
2 | |||
3 | out vec2 Texcoord; | ||
4 | |||
5 | void 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 @@ | |||
1 | uniform samplerCube Skyquad; | ||
2 | |||
3 | in vec3 Ray; | ||
4 | |||
5 | layout (location = 0) out vec4 Colour; | ||
6 | |||
7 | void 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 @@ | |||
1 | uniform mat4 CameraRotation; // From camera space to world space. | ||
2 | uniform float Fovy; | ||
3 | uniform float Aspect; | ||
4 | |||
5 | layout (location = 0) in vec2 Position; | ||
6 | |||
7 | out vec3 Ray; | ||
8 | |||
9 | // We would typically normalize the vector, but there is no need to do so when | ||
10 | // sampling a cube map. | ||
11 | vec3 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 | |||
21 | void 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 @@ | |||
1 | precision highp float; | ||
2 | |||
3 | uniform sampler2D NormalMap; | ||
4 | |||
5 | in vec3 Normal; | ||
6 | in vec4 Tangent; | ||
7 | in vec3 Bitangent; // TODO: Compute here or in PS? | ||
8 | in vec2 Texcoord; | ||
9 | |||
10 | out vec4 FragColour; | ||
11 | |||
12 | // TODO: Move to "normal.h" | ||
13 | vec3 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 | |||
24 | void 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 @@ | |||
1 | precision highp float; | ||
2 | |||
3 | uniform mat4 Modelview; | ||
4 | uniform mat4 Projection; | ||
5 | |||
6 | layout (location = 0) in vec3 vPosition; | ||
7 | layout (location = 1) in vec3 vNormal; | ||
8 | layout (location = 2) in vec4 vTangent; | ||
9 | layout (location = 3) in vec2 vTexcoord; | ||
10 | |||
11 | out vec3 Normal; | ||
12 | out vec4 Tangent; | ||
13 | out vec3 Bitangent; // TODO: Compute here or in PS? | ||
14 | out vec2 Texcoord; | ||
15 | |||
16 | void 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 @@ | |||
1 | precision highp float; | ||
2 | |||
3 | in vec3 Normal; | ||
4 | |||
5 | out vec4 FragColour; | ||
6 | |||
7 | void 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 @@ | |||
1 | precision highp float; | ||
2 | |||
3 | uniform mat4 Modelview; | ||
4 | uniform mat4 Projection; | ||
5 | |||
6 | layout (location = 0) in vec3 vPosition; | ||
7 | layout (location = 1) in vec3 vNormal; | ||
8 | |||
9 | out vec3 Normal; | ||
10 | |||
11 | void 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 @@ | |||
1 | precision highp float; | ||
2 | |||
3 | in vec4 Tangent; | ||
4 | |||
5 | out vec4 FragColour; | ||
6 | |||
7 | void 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 @@ | |||
1 | precision highp float; | ||
2 | |||
3 | uniform mat4 Modelview; | ||
4 | uniform mat4 Projection; | ||
5 | |||
6 | layout (location = 0) in vec3 vPosition; | ||
7 | layout (location = 2) in vec4 vTangent; | ||
8 | |||
9 | out vec4 Tangent; | ||
10 | |||
11 | void 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 @@ | |||
1 | uniform sampler2D Texture; | ||
2 | |||
3 | in vec2 Texcoord; | ||
4 | |||
5 | layout (location = 0) out vec4 Colour; | ||
6 | |||
7 | void 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 @@ | |||
1 | layout (location = 0) in vec2 Position; | ||
2 | |||
3 | out vec2 Texcoord; | ||
4 | |||
5 | void 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 | } | ||