reference

This documentation is automatically generated from the openFrameworks source code using doxygen and refers to the most recent release, version 0.12.0.

ofCubeMapShaders.h
Go to the documentation of this file.
1//
2// CubeMapShaders.h
3// CubeMap
4//
5// Created by Nick Hardeman on 10/21/22.
6//
7
8#pragma once
9
10#include "ofGLUtils.h"
11#include "ofConstants.h"
12
14public:
15
16 struct ShaderSource {
17 std::string vertShader;
18 std::string fragShader;
19 };
20
21 static std::string getGLSLHeader() {
22 std::string vstr = "#version 150\n";
23 if( ofGetGLRenderer() ) {
24 vstr = "#version "+ofGLSLVersionFromGL(ofGetGLRenderer()->getGLVersionMajor(), ofGetGLRenderer()->getGLVersionMinor())+"\n";
25 }
26 #ifdef TARGET_OPENGLES
27 vstr += "#define TARGET_OPENGLES\n";
28 //vstr += "#extension GL_OES_standard_derivatives : enable\n";
29 vstr += "precision highp float;\n";
30 vstr += "precision highp int;\n";
31 vstr += "precision highp sampler2D;\n";
32 vstr += "precision highp samplerCube;\n";
33 #endif
34 return vstr;
35 }
36
37 static std::string defaultVertShader() {
38 std::string vshader = getGLSLHeader();
39 vshader += R"(in vec4 position;
40 uniform mat4 uProjection;
41 uniform mat4 uView;
42
43 out vec3 oLocalPos;
44
45 void main() {
46 oLocalPos = position.xyz;
47 gl_Position = uProjection * uView * vec4(position.xyz, 1.0);
48 }
49 )";
50
51 return vshader;
52 }
53
55 ShaderSource rsource;
56 rsource.vertShader = defaultVertShader();
57
58 rsource.fragShader = getGLSLHeader();
59 rsource.fragShader += R"(
60 out vec4 FRAGCOLOR;
61 in vec3 oLocalPos;
62
63 uniform float uFlipY;
64 uniform float uConvertToNonFloat; // 0.0 // convert hdr to non float texture
65
66 uniform sampler2D uEquirectangularTex;
67
68 // https://learnopengl.com/PBR/IBL/Diffuse-irradiance
69 const vec2 invAtan = vec2(0.1591, 0.3183);
70 vec2 SampleSphericalMap(vec3 v) {
71 vec2 uv = vec2(atan(v.z, v.x), asin(v.y));
72 uv *= invAtan;
73 uv += 0.5;
74 if( uFlipY > 0.5 ) {
75 uv.y = 1.0-uv.y;
76 }
77 return uv;
78 }
79
80 void main() {
81 vec2 uv = SampleSphericalMap(normalize(oLocalPos)); // make sure to normalize localPos
82 vec3 color = texture(uEquirectangularTex, uv).rgb;
83
84 if(uConvertToNonFloat > 0.5) {
85 // hdr tone mapping
86 color = color / (color+vec3(1.0));
87 // gamma correction
88 //color = pow(color, vec3(1.0 / 2.2));
89 color = clamp( color, 0.0, 1.0);
90 }
91
92 FRAGCOLOR = vec4(color, 1.0);
93 }
94 )";
95 return rsource;
96 }
97
99 ShaderSource rsource;
100 rsource.vertShader = defaultVertShader();
101
102 rsource.fragShader = getGLSLHeader();
103 rsource.fragShader += R"(
104 out vec4 FRAGCOLOR;
105 in vec3 oLocalPos;
106
107 uniform samplerCube environmentMap;
108 const float PI = 3.14159265359;
109
110 // https://learnopengl.com/PBR/IBL/Diffuse-irradiance
111 void main() {
112 // the sample direction equals the hemisphere's orientation
113 // The world vector acts as the normal of a tangent surface
114 // from the origin, aligned to WorldPos. Given this normal, calculate all
115 // incoming radiance of the environment. The result of this radiance
116 // is the radiance of light coming from -Normal direction, which is what
117 // we use in the PBR shader to sample irradiance.
118 vec3 N = normalize(oLocalPos);
119
120 vec3 irradiance = vec3(0.0);
121
122 // tangent space calculation from origin point
123 vec3 up = vec3(0.0, 1.0, 0.0);
124 vec3 right = normalize(cross(up, N));
125 up = normalize(cross(N, right));
126
127 float sampleDelta = 0.025;
128 float nrSamples = 0.0;
129 for(float phi = 0.0; phi < 2.0 * PI; phi += sampleDelta) {
130 for(float theta = 0.0; theta < 0.5 * PI; theta += sampleDelta) {
131 // spherical to cartesian (in tangent space)
132 vec3 tangentSample = vec3(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta));
133 // tangent space to world
134 vec3 sampleVec = tangentSample.x * right + tangentSample.y * up + tangentSample.z * N;
135
136 irradiance += texture(environmentMap, sampleVec).rgb * cos(theta) * sin(theta);
137 //nrSamples++;
138 nrSamples += 1.0;
139 }
140 }
141 //irradiance = PI * irradiance * (1.0 / float(nrSamples));
142 irradiance = irradiance * PI * (1.0 / max(nrSamples, 1.0));
143 FRAGCOLOR = vec4(irradiance, 1.0);
144 }
145 )";
146 return rsource;
147 }
148
150 ShaderSource rsource;
151 rsource.vertShader = getGLSLHeader();
152 rsource.vertShader += R"(
153 in vec4 position;
154 // set from OF //
155 uniform mat4 modelViewProjectionMatrix;
156 uniform mat4 projectionMatrix;
157 uniform mat4 viewMatrix;
158
159 out vec3 oTexCoords;
160
161 void main() {
162 oTexCoords = position.xyz;
163 // removing the translation of the view matrix
164 vec4 pos = projectionMatrix * mat4(mat3(viewMatrix)) * position;
165 gl_Position = pos.xyww;
166 // gl_Position = modelViewProjectionMatrix * position;
167 }
168 )";
169 rsource.fragShader = getGLSLHeader();
170 rsource.fragShader += R"(
171 in vec3 oTexCoords;
172
173 uniform samplerCube uCubeMap;
174 uniform float uIsHDR;
175 uniform float uExposure;// = 1.0;
176 uniform float uRoughness;// = 0.0;
177 uniform float uMaxMips;// = 1;
178
179 out vec4 FRAGCOLOR;
180
181 vec3 getEnvColor( in vec3 aR, in float aroughness ) {
182 float lod = aroughness * (uMaxMips-1.0);
183 vec3 ai = textureLod(uCubeMap, aR, floor(lod) ).rgb;
184 vec3 ab = textureLod(uCubeMap, aR, clamp(ceil(lod), floor(lod), uMaxMips-1.0) ).rgb;
185 return mix(ai, ab, lod-floor(lod) );
186 }
187
188 void main() {
189 vec3 envColor = vec3(0.0);
190 if( uMaxMips > 1.0 && uRoughness > 0.0 ) {
191 envColor = getEnvColor(oTexCoords, uRoughness );
192 } else {
193 envColor = texture(uCubeMap, oTexCoords).rgb;
194 }
195
196 if( uIsHDR > 0.5 ) {
197 //envColor = envColor / (envColor + vec3(1.0));
198 // exposure tone mapping
199 vec3 mapped = vec3(1.0) - exp(-envColor * uExposure);
200
201 // gamma correction
202 envColor = pow(mapped, vec3(1.0 / 2.2));
203
204 //envColor = envColor / (envColor + vec3(1.0));
205 //envColor = pow(envColor, vec3(1.0/2.2));
206 } else {
207 // gamma correction
208 envColor = pow(envColor, vec3(1.0 / max(uExposure*2.2, 0.1) ) );
209 }
210
211 FRAGCOLOR = vec4(clamp(envColor, 0.0, 1.0), 1.0);
212 }
213
214 )";
215
216 return rsource;
217 }
218
219 static std::string hammersley() {
220 std::string ssrc = R"(
221 // ----------------------------------------------------------------------------
222 // http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
223 // efficient VanDerCorpus calculation.
224 #ifndef TARGET_OPENGLES
225 float RadicalInverse_VdC(uint bits) {
226 bits = (bits << 16u) | (bits >> 16u);
227 bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
228 bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
229 bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
230 bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
231 return float(bits) * 2.3283064365386963e-10; // / 0x100000000
232 }
233
234 // ----------------------------------------------------------------------------
235 vec2 HammersleyBits(uint i, uint N){
236 return vec2(float(i)/float(N), RadicalInverse_VdC(i));
237 }
238 #else
239
240 float VanDerCorput(uint n, uint base) {
241 float invBase = 1.0 / float(base);
242 float denom = 1.0;
243 float result = 0.0;
244
245 for(uint i = 0u; i < 32u; ++i){
246 if(n > 0u){
247 denom = mod(float(n), 2.0);
248 result += denom * invBase;
249 invBase = invBase / 2.0;
250 n = uint(float(n) / 2.0);
251 }
252 }
253 return result;
254 }
255 // ----------------------------------------------------------------------------
256 vec2 HammersleyNoBitOps(uint i, uint N){
257 return vec2(float(i)/float(N), VanDerCorput(i, 2u));
258 }
259 #endif
260
261
262 // ----------------------------------------------------------------------------
263 vec2 Hammersley(uint i, uint N){
264 #ifdef TARGET_OPENGLES
265 return HammersleyNoBitOps(i, N);
266 #else
267 return HammersleyBits(i, N);
268 #endif
270 )";
271 return ssrc;
272 }
273
274 // https://learnopengl.com/PBR/IBL/Specular-IBL
275 static ShaderSource prefilter() {
276 ShaderSource rsource;
277 rsource.vertShader = defaultVertShader();
278
279 rsource.fragShader = getGLSLHeader();
280 rsource.fragShader += R"(
281 out vec4 FragColor;
282 in vec3 oLocalPos;
283
284 uniform samplerCube environmentMap;
285 uniform float uroughness;
286 uniform float resolution; // resolution of source cubemap (per face)
287
288 const float PI = 3.14159265359;
289
290 )";
291
292 rsource.fragShader += hammersley();
293
294 rsource.fragShader += R"(
295 // ----------------------------------------------------------------------------
296 float DistributionGGX(vec3 N, vec3 H, float roughness) {
297 float a = roughness*roughness;
298 float a2 = a*a;
299 float NdotH = max(dot(N, H), 0.0);
300 float NdotH2 = NdotH*NdotH;
301
302 float nom = a2;
303 float denom = (NdotH2 * (a2 - 1.0) + 1.0);
304 denom = PI * denom * denom;
305
306 return nom / denom;
307 }
308
309 // ----------------------------------------------------------------------------
310 vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness){
311 float a = roughness*roughness;
312
313 float phi = 2.0 * PI * Xi.x;
314 float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y));
315 float sinTheta = sqrt(1.0 - cosTheta*cosTheta);
316
317 // from spherical coordinates to cartesian coordinates - halfway vector
318 vec3 H;
319 H.x = cos(phi) * sinTheta;
320 H.y = sin(phi) * sinTheta;
321 H.z = cosTheta;
322
323 // from tangent-space H vector to world-space sample vector
324 vec3 up = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
325 vec3 tangent = normalize(cross(up, N));
326 vec3 bitangent = cross(N, tangent);
327
328 vec3 sampleVec = tangent * H.x + bitangent * H.y + N * H.z;
329 return normalize(sampleVec);
330 }
331 // ----------------------------------------------------------------------------
332 void main(){
333 vec3 N = normalize(oLocalPos);
334
335 //float troughness = uroughness;
336
337 // make the simplyfying assumption that V equals R equals the normal
338 vec3 R = N;
339 vec3 V = R;
340 #ifdef TARGET_OPENGLES
341 const uint SAMPLE_COUNT = 1024u;
342 #else
343 const uint SAMPLE_COUNT = 2048u;
344 #endif
345 vec3 prefilteredColor = vec3(0.0);
346 float totalWeight = 0.0;
347
348 for(uint i = 0u; i < SAMPLE_COUNT; ++i){
349 // generates a sample vector that's biased towards the preferred alignment direction (importance sampling).
350 vec2 Xi = Hammersley(i, SAMPLE_COUNT);
351 vec3 H = ImportanceSampleGGX(Xi, N, uroughness);
352 vec3 L = normalize(2.0 * dot(V, H) * H - V);
353
354 float NdotL = max(dot(N, L), 0.0);
355 if(NdotL > 0.0){
356 // sample from the environment's mip level based on roughness/pdf
357 float D = DistributionGGX(N, H, uroughness);
358 float NdotH = max(dot(N, H), 0.0);
359 float HdotV = max(dot(H, V), 0.0);
360 float pdf = D * NdotH / (4.0 * HdotV) + 0.0001;
361
362// //float resolution = 512.0; // resolution of source cubemap (per face)
363 float saTexel = 4.0 * PI / (6.0 * resolution * resolution);
364 float saSample = 1.0 / (float(SAMPLE_COUNT) * pdf + 0.0001);
365
366 float mipLevel = uroughness == 0.0 ? 0.0 : max(0.5 * log2(saSample / saTexel), 0.0);
367 //mipLevel = clamp( mipLevel, 0.0, 4.0);
368
369 prefilteredColor += textureLod(environmentMap, L, mipLevel).rgb * NdotL;
370 totalWeight += NdotL;
371 }
372 }
373 if(totalWeight < 0.0001 ) {
374 totalWeight = 0.0001;
375 }
376
377 prefilteredColor = prefilteredColor / totalWeight;
378 FragColor = vec4(prefilteredColor, 1.0);
379 }
380
381 )";
382
383 return rsource;
384 }
385
386
387 static ShaderSource brdfLUT() {
388 ShaderSource rsource;
389 rsource.vertShader = getGLSLHeader();
390 rsource.vertShader += R"(
391 in vec4 position;
392 in vec2 texcoord;
393
394 uniform mat4 modelViewProjectionMatrix;
395
396 out vec2 TexCoords;
397
398 void main() {
399 TexCoords = texcoord;
400 gl_Position = modelViewProjectionMatrix * position;
401 }
402 )";
403 rsource.fragShader = getGLSLHeader();
404 rsource.fragShader += R"(
405 out vec4 FragColor;
406 in vec2 TexCoords;
407
408 const float PI = 3.14159265359;
409
410 )";
411
412 rsource.fragShader += hammersley();
413
414 rsource.fragShader += R"(
415 // ----------------------------------------------------------------------------
416 vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness){
417 float a = roughness*roughness;
418
419 float phi = 2.0 * PI * Xi.x;
420 float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y));
421 float sinTheta = sqrt(1.0 - cosTheta*cosTheta);
422
423 // from spherical coordinates to cartesian coordinates - halfway vector
424 vec3 H;
425 H.x = cos(phi) * sinTheta;
426 H.y = sin(phi) * sinTheta;
427 H.z = cosTheta;
428
429 // from tangent-space H vector to world-space sample vector
430 vec3 up = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
431 vec3 tangent = normalize(cross(up, N));
432 vec3 bitangent = cross(N, tangent);
433
434 vec3 sampleVec = tangent * H.x + bitangent * H.y + N * H.z;
435 return normalize(sampleVec);
436 }
437 // ----------------------------------------------------------------------------
438 float GeometrySchlickGGX(float NdotV, float roughness){
439 // note that we use a different k for IBL
440 float a = roughness;
441 float k = (a * a) / 2.0;
442
443 float nom = NdotV;
444 float denom = NdotV * (1.0 - k) + k;
445
446 return nom / denom;
447 }
448 // ----------------------------------------------------------------------------
449 float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness){
450 float NdotV = max(dot(N, V), 0.0);
451 float NdotL = max(dot(N, L), 0.0);
452 float ggx2 = GeometrySchlickGGX(NdotV, roughness);
453 float ggx1 = GeometrySchlickGGX(NdotL, roughness);
454
455 return ggx1 * ggx2;
456 }
457 // ----------------------------------------------------------------------------
458 vec2 IntegrateBRDF(float NdotV, float roughness){
459 vec3 V;
460 V.x = sqrt(1.0 - NdotV*NdotV);
461 V.y = 0.0;
462 V.z = NdotV;
463
464 float A = 0.0;
465 float B = 0.0;
466
467 vec3 N = vec3(0.0, 0.0, 1.0);
468
469 const uint SAMPLE_COUNT = 1024u;
470 for(uint i = 0u; i < SAMPLE_COUNT; ++i){
471 // generates a sample vector that's biased towards the
472 // preferred alignment direction (importance sampling).
473 vec2 Xi = Hammersley(i, SAMPLE_COUNT);
474 vec3 H = ImportanceSampleGGX(Xi, N, roughness);
475 vec3 L = normalize(2.0 * dot(V, H) * H - V);
476
477 float NdotL = max(L.z, 0.0);
478 float NdotH = max(H.z, 0.0);
479 float VdotH = max(dot(V, H), 0.0);
480
481 if(NdotL > 0.0)
482 {
483 float G = GeometrySmith(N, V, L, roughness);
484 float G_Vis = (G * VdotH) / (NdotH * NdotV);
485 float Fc = pow(1.0 - VdotH, 5.0);
486
487 A += (1.0 - Fc) * G_Vis;
488 B += Fc * G_Vis;
489 }
490 }
491 A /= float(SAMPLE_COUNT);
492 B /= float(SAMPLE_COUNT);
493 return vec2(A, B);
494 }
495 // ----------------------------------------------------------------------------
496 void main(){
497 vec2 integratedBRDF = IntegrateBRDF(TexCoords.x, TexCoords.y);
498 FragColor.rg = integratedBRDF;
499 FragColor.b = 0;
500// FragColor.r = 1.0;
501// FragColor.g = 0.0;
502 FragColor.a = 1.0;
503 }
504 )";
505 return rsource;
506 }
507
508};
Definition ofCubeMapShaders.h:13
static std::string hammersley()
Definition ofCubeMapShaders.h:219
static ShaderSource renderShader()
Definition ofCubeMapShaders.h:149
static ShaderSource prefilter()
Definition ofCubeMapShaders.h:269
static std::string getGLSLHeader()
Definition ofCubeMapShaders.h:21
static std::string defaultVertShader()
Definition ofCubeMapShaders.h:37
static ShaderSource brdfLUT()
Definition ofCubeMapShaders.h:378
static ShaderSource equiRectToCubeMap()
Definition ofCubeMapShaders.h:54
static ShaderSource irriadianceCubeMap()
Definition ofCubeMapShaders.h:98
string ofGLSLVersionFromGL()
Definition ofGLUtils.cpp:865
shared_ptr< ofBaseGLRenderer > ofGetGLRenderer()
Definition ofGLUtils.cpp:909
Definition ofCubeMapShaders.h:16
std::string fragShader
Definition ofCubeMapShaders.h:18
std::string vertShader
Definition ofCubeMapShaders.h:17