framework2

Форк
0
1354 строки · 40.4 Кб
1
//
2
//  ofCubeMap.cpp
3
//
4
//  Created by Nick Hardeman on 10/16/22.
5
//
6

7
#include "ofShader.h"
8
#include "ofCubeMap.h"
9
#include "ofImage.h"
10
#include "of3dUtils.h"
11
#include "ofGLBaseTypes.h"
12
#include "ofGLUtils.h"
13
#include "ofGLProgrammableRenderer.h"
14
#include "ofCubeMapShaders.h"
15
#include "ofFbo.h"
16
#include "ofConstants.h"
17

18
#define GLM_FORCE_CTOR_INIT
19
#include "glm/gtx/transform.hpp"
20
#include "glm/gtc/quaternion.hpp"
21
#include <map>
22

23
#ifdef TARGET_ANDROID
24
#include "ofAppAndroidWindow.h"
25
#endif
26

27
using std::weak_ptr;
28
using std::vector;
29
using std::shared_ptr;
30

31
ofVboMesh ofCubeMap::sCubeMesh;
32
ofShader ofCubeMap::shaderBrdfLUT;
33
ofTexture ofCubeMap::sBrdfLutTex;
34

35
void ofCubeMap::setExposure(float aExposure) {
36
	data->exposure=ofClamp(aExposure, 0.0f, 1.0f);
37
}
38

39
// texture management copied from ofTexture
40
static std::map<GLuint,int> & getTexturesIndex(){
41
	static std::map<GLuint,int> * textureReferences = new std::map<GLuint,int>;
42
	return *textureReferences;
43
}
44

45
static void retain(GLuint id){
46
	if(id!=0){
47
		if(getTexturesIndex().find(id)!=getTexturesIndex().end()){
48
			getTexturesIndex()[id]++;
49
		}else{
50
			getTexturesIndex()[id]=1;
51
		}
52
	}
53
}
54

55
static void release(GLuint id){
56
	// try to free up the texture memory so we don't reallocate
57
	// http://www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/deletetextures.html
58
	if (id != 0){
59
		if(getTexturesIndex().find(id)!=getTexturesIndex().end()){
60
			getTexturesIndex()[id]--;
61
			if(getTexturesIndex()[id]==0){
62
				
63
#ifdef TARGET_ANDROID
64
				if (!ofAppAndroidWindow::isSurfaceDestroyed())
65
#endif
66
					glDeleteTextures(1, (GLuint *)&id);
67
				
68
				getTexturesIndex().erase(id);
69
			}
70
		}else{
71
			ofLogError("ofCubeMap") << "release(): something's wrong here, releasing unknown texture id " << id;
72
			
73
#ifdef TARGET_ANDROID
74
			if (!ofAppAndroidWindow::isSurfaceDestroyed())
75
#endif
76
				glDeleteTextures(1, (GLuint *)&id);
77
		}
78
	}
79
}
80

81
//----------------------------------------
82
#ifdef TARGET_ANDROID
83
// TODO: Hook this up to an event
84
void ofCubeMap::regenerateAllTextures() {
85
	for(size_t i=0; i<ofCubeMapsData().size(); i++) {
86
		if(!ofCubeMapsData()[i].expired()) {
87
			std::shared_ptr<ofCubeMap::Data> cubeMap = ofCubeMapsData()[i].lock();
88
			ofCubeMap::clearTextureData(cubeMap);
89
		}
90
	}
91
	sBrdfLutTex.clear();
92
}
93
#endif
94

95

96

97
//----------------------------------------
98
vector<weak_ptr<ofCubeMap::Data> > & ofCubeMapsData(){
99
	static vector<weak_ptr<ofCubeMap::Data> > * cubeMapsActive = new vector<weak_ptr<ofCubeMap::Data> >;
100
	return *cubeMapsActive;
101
}
102

103
//--------------------------------------------------------------
104
bool ofCubeMap::hasActiveCubeMap() {
105
	for(size_t i=0;i< ofCubeMapsData().size();i++){
106
		std::shared_ptr<ofCubeMap::Data> cubeMap = ofCubeMapsData()[i].lock();
107
		if(cubeMap && cubeMap->isEnabled && cubeMap->index > -1 ){
108
			return true;
109
			break;
110
		}
111
	}
112
	return false;
113
}
114

115
//--------------------------------------------------------------
116
std::shared_ptr<ofCubeMap::Data> ofCubeMap::getActiveData() {
117
	for(size_t i=0;i< ofCubeMapsData().size();i++){
118
		std::shared_ptr<ofCubeMap::Data> cubeMap = ofCubeMapsData()[i].lock();
119
		if(cubeMap && cubeMap->isEnabled && cubeMap->index > -1 ){
120
			return cubeMap;
121
		}
122
	}
123
	return std::shared_ptr<ofCubeMap::Data>();
124
}
125

126
//--------------------------------------------------------------
127
void ofCubeMap::clearTextureData(std::shared_ptr<ofCubeMap::Data> adata) {
128
	if( adata ) {
129
		if( adata->bPreFilteredMapAllocated ) {
130
			adata->bPreFilteredMapAllocated=false;
131
			release(adata->preFilteredMapId);
132
		}
133
		
134
		if( adata->bIrradianceAllocated ) {
135
			adata->bIrradianceAllocated = false;
136
			release(adata->irradianceMapId);
137
		}
138
		if( adata->bCubeMapAllocated ) {
139
			adata->bCubeMapAllocated = false;
140
			release(adata->cubeMapId);
141
		}
142
	}
143
}
144

145
//--------------------------------------------------------------
146
void ofCubeMap::_checkSetup() {
147
	if( data->index < 0 ) {
148
		bool bFound = false;
149
		// search for the first free block
150
		for(size_t i=0; i<ofCubeMapsData().size(); i++) {
151
			if(ofCubeMapsData()[i].expired()) {
152
				data->index = i;
153
				ofCubeMapsData()[i] = data;
154
				bFound = true;
155
				break;
156
			}
157
		}
158
		if(!bFound && ofIsGLProgrammableRenderer()){
159
			ofCubeMapsData().push_back(data);
160
			data->index = ofCubeMapsData().size() - 1;
161
			bFound = true;
162
		}
163
	}
164
	// we should remove empty slots //
165
}
166

167
//----------------------------------------
168
const ofTexture& ofCubeMap::getBrdfLutTexture() {
169
	return sBrdfLutTex;
170
}
171

172
//----------------------------------------
173
ofCubeMap::ofCubeMap() {
174
	data = std::make_shared<ofCubeMap::Data>();
175
	_checkSetup();
176
	projectionMat = glm::perspective(glm::radians(90.0f), 1.0f, 0.1f, 10.0f );
177
}
178

179
//----------------------------------------
180
ofCubeMap::ofCubeMap(const ofCubeMap & mom) {
181
	clear();
182
	
183
	if(data) {
184
		data.reset();
185
	}
186
	if( mom.data ) {
187
		data = std::make_shared<ofCubeMap::Data>(*mom.data);
188
		if( data->bCubeMapAllocated ) {
189
			retain(data->cubeMapId);
190
		}
191
		if( data->bIrradianceAllocated ) {
192
			retain(data->irradianceMapId);
193
		}
194
		if( data->bPreFilteredMapAllocated ) {
195
			retain(data->preFilteredMapId);
196
		}
197
	}
198
	if( !data ) {
199
		data = std::make_shared<ofCubeMap::Data>();
200
	}
201
	data->index = -1;
202
	if( mom.data ) {
203
		data->settings = mom.data->settings;
204
	}
205
	_checkSetup(); // grab a new slot in ofCubeMapsData
206
	texFormat = mom.texFormat;
207
}
208

209
//----------------------------------------
210
ofCubeMap::ofCubeMap(ofCubeMap && mom) {
211
	clear();
212
	// taking ownership of the data shared_ptr
213
	data = mom.data;
214
	texFormat = mom.texFormat;
215
}
216

217
//----------------------------------------
218
ofCubeMap::~ofCubeMap() {
219
	clear();
220
}
221

222
//--------------------------------------------------------------
223
ofCubeMap & ofCubeMap::operator=(const ofCubeMap & mom){
224
	if(&mom==this) return *this;
225
	clear();
226
	
227
	if(data) {
228
		data.reset();
229
	}
230
	if( mom.data ) {
231
		data = std::make_shared<ofCubeMap::Data>(*mom.data);
232
		if( data->bCubeMapAllocated ) {
233
			retain(data->cubeMapId);
234
		}
235
		if( data->bIrradianceAllocated ) {
236
			retain(data->irradianceMapId);
237
		}
238
		if( data->bPreFilteredMapAllocated ) {
239
			retain(data->preFilteredMapId);
240
		}
241
	}
242
	if( !data ) {
243
		data = std::make_shared<ofCubeMap::Data>();
244
	}
245
	if( mom.data ) {
246
		data->settings = mom.data->settings;
247
	}
248
	data->index = -1;
249
	_checkSetup(); // grab a new slot in ofCubeMapsData
250
	texFormat = mom.texFormat;
251
	
252
	return *this;
253
}
254

255
//--------------------------------------------------------------
256
ofCubeMap& ofCubeMap::operator=(ofCubeMap && mom) {
257
	clear();
258
	data = mom.data;
259
	texFormat = mom.texFormat;
260
	return *this;
261
}
262

263
//----------------------------------------
264
GLenum ofCubeMap::getTextureTarget() {
265
	return GL_TEXTURE_CUBE_MAP;
266
}
267

268
//----------------------------------------
269
bool isPowerOfTwo(int x) {
270
	/* First x in the below expression is for the case when
271
	 * x is 0 */
272
	return x && (!(x & (x - 1)));
273
}
274

275
//----------------------------------------
276
bool ofCubeMap::load( const of::filesystem::path & apath, int aFaceResolution, bool aBFlipY ) {
277
	return load(apath, aFaceResolution, aBFlipY, 32, 128 );
278
}
279

280
//----------------------------------------
281
bool ofCubeMap::load( const of::filesystem::path & apath, int aFaceResolution, bool aBFlipY, int aIrradianceRes, int aPreFilterRes ) {
282
	
283
	ofCubeMapSettings settings;
284
	settings.flipVertically = aBFlipY;
285
	settings.filePath = apath;
286
	
287
	settings.resolution = aFaceResolution;
288
	settings.irradianceRes = aIrradianceRes;
289
	settings.preFilterRes = aPreFilterRes;
290
	
291
	return load(settings);
292
}
293

294
//----------------------------------------
295
bool ofCubeMap::load( ofCubeMapSettings aSettings ) {
296
	if( !ofIsGLProgrammableRenderer() ) {
297
		ofLogError("ofCubeMap::load") << " cube maps only supported with programmable renderer.";
298
		return false;
299
	}
300
//	if( aSettings.resolution > 512 ) {
301
//		ofLogWarning("ofCubeMap :: load : a face resolution larger than 512 can cause issues.");
302
//	}
303
	
304
	if( aSettings.filePath.empty() ) {
305
		ofLogError("ofCubeMap :: load : must set file path");
306
		return false;
307
	}
308
	
309
	clear();
310
	
311
	std::string ext = ofToLower(aSettings.filePath.extension().string());
312
	bool hdr = (ext == ".hdr" || ext == ".exr");
313
	
314
#if defined(TARGET_OPENGLES) && !defined(TARGET_EMSCRIPTEN)
315
	if( hdr ) {
316
		ofLogError("ofCubeMap :: load : hdr and exr not supported on OPENGL_ES");
317
		return false;
318
	}
319
#endif
320
	
321
	bool bLoadOk = false;
322
	data->settings = aSettings;
323
	
324
	ofTexture srcTex;
325
	
326
	bool bArbTexEnabled = ofGetUsingArbTex();
327
	ofDisableArbTex();
328
	if( hdr ) {
329
		ofFloatPixels fpix;
330
		if( ofLoadImage(fpix, data->settings.filePath) ) {
331
			ofLogNotice("ofCubeMap::load : loaded ") << ext << " image.";
332
			bLoadOk = true;
333
#if defined(TARGET_EMSCRIPTEN)
334
			// GL_RGB32F GL_RGB16F &&  is not supported in Emscripten opengl es, so we need to set to GL_RGBA16F or GL_RGBA32F
335
			// ofFloatPixels uses 32F and is supported via Emscripten, so we switch to that in the _load functions.
336
			texFormat = GL_RGBA16F;
337
			// just in case, we need to make sure that it's 4 channels
338
			if( fpix.getNumChannels() != 4 ) {
339
				fpix.setImageType( OF_IMAGE_COLOR_ALPHA );
340
			}
341
#elif !defined(TARGET_OPENGLES)
342
			if( fpix.getNumChannels() != 3 ) {
343
				fpix.setImageType( OF_IMAGE_COLOR );
344
			}
345
			texFormat = GL_RGB32F;
346
#endif
347
			srcTex.loadData(fpix);
348
		}
349
	} else {
350
		ofPixels ipix;
351
		if( ofLoadImage(ipix, data->settings.filePath) ) {
352
			bLoadOk = true;
353
			texFormat = GL_RGB;
354
			srcTex.loadData(ipix);
355
		}
356
	}
357
	if( !bLoadOk ) {
358
		ofLogWarning("ofCubeMap :: failed to load image from ") << data->settings.filePath;
359
	} else {
360
		srcTex.setTextureWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE);
361
		srcTex.setTextureMinMagFilter(GL_LINEAR, GL_LINEAR);
362
#if !defined(TARGET_OPENGLES) && defined(GL_TEXTURE_CUBE_MAP_SEAMLESS)
363
		glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
364
#endif
365
		
366
		if( !isPowerOfTwo(data->settings.resolution) ) {
367
			ofLogNotice("ofCubeMap :: load : changing resolution " ) << data->settings.resolution << " to next power of 2: " << ofNextPow2(data->settings.resolution);
368
			data->settings.resolution = ofNextPow2(data->settings.resolution);
369
		}
370
		if( !isPowerOfTwo(data->settings.irradianceRes) ) {
371
			ofLogNotice("ofCubeMap :: load : changing resolution " ) << data->settings.irradianceRes << " to next power of 2: " << ofNextPow2(data->settings.irradianceRes);
372
			data->settings.irradianceRes = ofNextPow2(data->settings.irradianceRes);
373
		}
374
		if( !isPowerOfTwo(data->settings.preFilterRes) ) {
375
			ofLogNotice("ofCubeMap :: load : changing resolution " ) << data->settings.preFilterRes << " to next power of 2: " << ofNextPow2(data->settings.preFilterRes);
376
			data->settings.preFilterRes = ofNextPow2(data->settings.preFilterRes);
377
		}
378
		
379
		_createCubeMap(srcTex);
380
		if( isHdr() ) {
381
			
382
			int srcCubeFSize = std::max(256, data->settings.preFilterRes);
383
			GLuint cubeFid = _createFloatCubeMap(srcTex, srcCubeFSize );
384
			
385
			// figure out the number of mip maps //
386
			data->maxMipLevels = log2(data->settings.preFilterRes) + 1;
387
			
388
			auto encFolder = data->settings.cacheDirectory;
389
			if( !encFolder.empty() ) {
390
				if( !ofDirectory::doesDirectoryExist( data->settings.cacheDirectory )) {
391
					#if !defined(TARGET_OPENGLES)
392
					if(!ofDirectory::createDirectory( data->settings.cacheDirectory )) {
393
						ofLogWarning("ofCubeMap :: load : unable to create directory: ") << data->settings.cacheDirectory;
394
					}
395
					#endif
396
				} else {
397
					
398
				}
399
				encFolder = data->settings.cacheDirectory;
400
			}
401
			of::filesystem::path baseName = data->settings.filePath.stem(); // equivalent to getBaseName
402
			of::filesystem::path cacheIrrName { baseName };
403
			cacheIrrName += ("_irr_"+ofToString(data->settings.irradianceRes,0)+".exr");
404
			of::filesystem::path cachePrefilterName { baseName };
405
			cachePrefilterName += ("_pre_"+ofToString(data->settings.preFilterRes,0)+".exr");
406
			
407
			bool bHasCachedIrr = false;
408
			bool bHasCachedPre = false;
409
			if( data->settings.useCache && !data->settings.overwriteCache ) {
410
				bHasCachedIrr = _loadIrradianceMap(encFolder / cacheIrrName);
411
				ofLogVerbose("ofCubeMap :: _loadIrradianceMap: ") << bHasCachedIrr;
412
				bHasCachedPre = _loadPrefilterMap(encFolder / cachePrefilterName);
413
				ofLogVerbose("ofCubeMap :: _loadPrefilterMap: ") << bHasCachedPre;
414
			}
415
			
416
			bool bMakeCache = data->settings.useCache;
417
			#if defined(TARGET_EMSCRIPTEN)
418
			// not supporting making caches on Emscripten.
419
			bMakeCache = false;
420
			#endif
421
			
422
			if( !bHasCachedIrr ) {
423
				ofLogVerbose("ofCubeMap :: going to create irradiance map");
424
				_createIrradianceMap(cubeFid,bMakeCache, encFolder / cacheIrrName);
425
			}
426
			
427
			if( !bHasCachedPre ) {
428
				ofLogVerbose("ofCubeMap :: going to create pre filtered cube map");
429
				_createPrefilteredCubeMap(cubeFid, srcCubeFSize,bMakeCache,encFolder / cachePrefilterName );
430
			}
431
			
432
			glDeleteTextures(1, &cubeFid );
433
		}
434
	}
435
	
436
	if( bArbTexEnabled ) {
437
		ofEnableArbTex();
438
	}
439
	
440
	return bLoadOk;
441
}
442

443

444
//----------------------------------------
445
void ofCubeMap::clear() {
446
	clearTextureData(data);
447
}
448

449
//--------------------------------------------------------------
450
void ofCubeMap::draw() {
451
	drawCubeMap();
452
}
453

454
//--------------------------------------------------------------
455
void ofCubeMap::drawCubeMap() {
456
	if( !data->bCubeMapAllocated ) {
457
		ofLogWarning("ofCubeMap::drawCubeMap() : textures not allocated, not drawing");
458
		return;
459
	}
460
	
461
	_drawCubeStart(data->cubeMapId);
462
	shaderRender.setUniform1f("uExposure", getExposure() );
463
	shaderRender.setUniform1f("uRoughness", 0.0f );
464
	shaderRender.setUniform1f("uMaxMips", 1.0f );
465
	shaderRender.setUniform1f("uIsHDR", 0.0f );
466
	_drawCubeEnd();
467
}
468

469
//--------------------------------------------------------------
470
void ofCubeMap::drawIrradiance() {
471
	if( !data->bIrradianceAllocated ) {
472
		ofLogWarning("ofCubeMap::drawIrradiance() : textures not allocated, not drawing");
473
		return;
474
	}
475
	
476
	_drawCubeStart(data->irradianceMapId);
477
	shaderRender.setUniform1f("uExposure", getExposure() );
478
	shaderRender.setUniform1f("uRoughness", 0.0f );
479
	shaderRender.setUniform1f("uMaxMips", 1.0f );
480
	shaderRender.setUniform1f("uIsHDR", 1.0f );
481
	_drawCubeEnd();
482
}
483

484
//--------------------------------------------------------------
485
void ofCubeMap::drawPrefilteredCube(float aRoughness) {
486
	if( !data->bPreFilteredMapAllocated ) {
487
		ofLogWarning("ofCubeMap::drawPrefilteredCube() : textures not allocated, not drawing");
488
		return;
489
	}
490
	
491
	_drawCubeStart(data->preFilteredMapId);
492
	shaderRender.setUniform1f("uIsHDR", 1.0f );
493
	shaderRender.setUniform1f("uExposure", getExposure() );
494
	shaderRender.setUniform1f("uRoughness", aRoughness );
495
	shaderRender.setUniform1f("uMaxMips", (float)data->maxMipLevels );
496
	_drawCubeEnd();
497
}
498

499
//--------------------------------------------------------------
500
void ofCubeMap::_drawCubeStart(GLuint aCubeMapId) {
501
	_allocateCubeMesh();
502
	
503
	if( !shaderRender.isLoaded() ) {
504
		_loadRenderShader();
505
	}
506
	if( shaderRender.isLoaded() ) {
507
		glDepthFunc(GL_LEQUAL);
508
		shaderRender.begin();
509
		shaderRender.setUniformTexture("uCubeMap", getTextureTarget(), aCubeMapId, 0 );	}
510
}
511

512
//--------------------------------------------------------------
513
void ofCubeMap::_drawCubeEnd() {
514
	sCubeMesh.draw();
515
	shaderRender.end();
516
	glDepthFunc(GL_LESS); // set depth function back to default
517
}
518

519
//--------------------------------------------------------------
520
bool ofCubeMap::hasCubeMap() {
521
	if( !data ) return false;
522
	return data->bCubeMapAllocated;
523
}
524

525
//--------------------------------------------------------------
526
bool ofCubeMap::hasPrefilteredMap() {
527
	if( !data ) return false;
528
	return data->bPreFilteredMapAllocated;
529
}
530

531
//--------------------------------------------------------------
532
bool ofCubeMap::hasIrradianceMap() {
533
	if( !data ) return false;
534
	return data->bIrradianceAllocated;
535
}
536

537
//--------------------------------------------------------------
538
GLuint ofCubeMap::getTextureId() {
539
	if( !data ) return 0;
540
	return data->cubeMapId;
541
}
542

543
//--------------------------------------------------------------
544
bool ofCubeMap::isHdr() {
545
#if defined(TARGET_OPENGLES) && !defined(TARGET_EMSCRIPTEN)
546
	return false;
547
#else
548
	#ifdef GL_RGBA32F_EXT
549
	if( texFormat == GL_RGBA32F_EXT ) {
550
		return true;
551
	}
552
	#endif
553
	#ifdef GL_RGB32F_EXT
554
	if( texFormat == GL_RGB32F_EXT ) {
555
		return true;
556
	}
557
	#endif
558
	#ifdef GL_RGBA16F
559
	if( texFormat == GL_RGBA16F ) {
560
		return true;
561
	}
562
	#endif
563
	return (texFormat == GL_RGBA32F || texFormat == GL_RGB32F);
564
#endif
565
}
566

567
//--------------------------------------------------------------
568
void ofCubeMap::setUseBrdfLutTexture( bool ab ) {
569
	#ifdef TARGET_OPENGLES
570
	data->settings.useLutTex = false;
571
	ofLogWarning("ofCubeMap::setUseBrdfLutTexture") << " brdf lut texture not supported on GLES.";
572
	return;
573
	#else
574
	data->settings.useLutTex = ab;
575
	if(ab && !sBrdfLutTex.isAllocated() ) {
576
		_createBrdfLUT();
577
	}
578
	#endif
579
}
580

581
//--------------------------------------------------------------
582
void ofCubeMap::_createCubeMap(ofTexture& aSrcTex) {
583
	
584
	if( !data->bCubeMapAllocated ) {
585
		data->bCubeMapAllocated = true;
586
		glGenTextures(1, &data->cubeMapId );
587
		retain(data->cubeMapId);
588
	}
589
		
590
	GLuint internalFormat = ofGetGLInternalFormatFromPixelFormat(OF_PIXELS_RGB);
591
	#ifdef TARGET_OPENGLES
592
	internalFormat = ofGetGLInternalFormatFromPixelFormat(OF_PIXELS_RGBA);
593
	#endif
594
	
595
	GLuint texStorageFormat = GL_UNSIGNED_BYTE;
596
	GLuint gFormat = GL_RGB;
597
	#ifdef TARGET_OPENGLES
598
	gFormat = GL_RGBA;
599
	#endif
600
	
601
	glBindTexture(GL_TEXTURE_CUBE_MAP, data->cubeMapId);
602
	
603
	for (GLint i = 0 ; i < 6 ; i++) {
604
		glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internalFormat, data->settings.resolution, data->settings.resolution, 0, gFormat, texStorageFormat, NULL);
605
	}
606
	
607
	glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
608
	
609
	_configureCubeTextures( data->cubeMapId, true );
610
	
611
	
612
	_equiRectToCubeMap( data->cubeMapId, aSrcTex, data->settings.resolution, true );
613
	
614
	
615
	glBindTexture(GL_TEXTURE_CUBE_MAP, data->cubeMapId);
616
	glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
617
	glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
618
	
619
}
620

621
//--------------------------------------------------------------
622
void ofCubeMap::_configureCubeTextures(GLuint aCubeMapId, bool abLinearMipLinear) {
623
	
624
	GLenum textureTarget = getTextureTarget();
625
	glBindTexture(textureTarget, aCubeMapId );
626
	
627
	if(abLinearMipLinear) {
628
		glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
629
	} else {
630
		glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
631
	}
632
	glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
633
	glTexParameteri(textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
634
	glTexParameteri(textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
635
#ifdef GL_TEXTURE_WRAP_R
636
	glTexParameteri(textureTarget, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
637
#endif
638
	glBindTexture(getTextureTarget(), 0);
639
}
640

641
//--------------------------------------------------------------
642
void ofCubeMap::_initEmptyTextures(GLuint aCubeMapId, int aSize) {
643
	
644
	GLenum textureTarget = getTextureTarget();
645
	glBindTexture(textureTarget, aCubeMapId );
646
	GLuint texStorageFormat = getTexStorageFormat();
647
	GLuint gFormat = getGlTypeFromInternalFormat();
648
	
649
	for (unsigned int i = 0; i < 6; i++) {
650
		glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, texFormat, aSize, aSize, 0, gFormat, texStorageFormat, nullptr );
651
	}
652
	
653
	glBindTexture(getTextureTarget(), 0);
654
}
655

656
//--------------------------------------------------------------
657
void ofCubeMap::_initEmptyTextures(GLuint aCubeMapId, GLuint aInternalFormat, int aSize, int aNumMipMaps ) {
658
	GLenum textureTarget = getTextureTarget();
659
	glBindTexture(textureTarget, aCubeMapId );
660
	GLuint texStorageFormat = getTexStorageFormat(aInternalFormat);
661
	GLuint gFormat = getGlTypeFromInternalFormat(aInternalFormat);
662
	
663
	for (int mip = 0; mip < data->maxMipLevels; mip++) {
664
		// reisze framebuffer according to mip-level size.
665
		unsigned int mipWidth  = static_cast<unsigned int>(data->settings.preFilterRes * std::pow(0.5, mip));
666
		if(mipWidth < 1 ) {
667
			mipWidth = 1;
668
		}
669
		for (unsigned int i = 0; i < 6; i++) {
670
			glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, mip, aInternalFormat, mipWidth, mipWidth, 0, gFormat, texStorageFormat, nullptr );
671
		}
672
	}
673
	
674
	glBindTexture(getTextureTarget(), 0);
675
}
676

677
//--------------------------------------------------------------
678
GLuint ofCubeMap::_createFloatCubeMap(ofTexture& aSrcTex, int aSrcRes) {
679
	GLuint cubeTexF;
680
	glGenTextures(1, &cubeTexF );
681
			
682
	GLuint texStorageFormat = getTexStorageFormat();
683
	GLuint gFormat = getGlTypeFromInternalFormat();
684
	
685
	glBindTexture(GL_TEXTURE_CUBE_MAP, cubeTexF );
686
	
687
	for (GLint i = 0 ; i < 6 ; i++) {
688
		glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, texFormat, aSrcRes, aSrcRes, 0, gFormat, texStorageFormat, NULL);
689
	}
690
	
691
	glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
692
	
693
	_configureCubeTextures( cubeTexF, true );
694
	_equiRectToCubeMap( cubeTexF, aSrcTex, aSrcRes, false );
695
	
696
	glBindTexture(GL_TEXTURE_CUBE_MAP, cubeTexF);
697
	glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
698
	glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
699
	
700
	return cubeTexF;
701
}
702

703
//--------------------------------------------------------------
704
void ofCubeMap::_equiRectToCubeMap( GLuint& aCubeTexId, ofTexture& aSrcTex, int aSrcRes, bool aBConvertToNonFloat ) {
705
	bool bShaderLoaded = _loadEquiRectToCubeMapShader();
706
	if( !bShaderLoaded ) {
707
		ofLogError("ofCubeMap::_equiRectToCubeMap : error loading shader");
708
		return;
709
	}
710
	
711
	_allocateCubeMesh();
712
	std::vector<glm::mat4> views = _getViewMatrices( glm::vec3(0,0,0) );
713
	
714
	unsigned int captureFBO;
715
	glGenFramebuffers(1, &captureFBO);
716
	glBindFramebuffer(GL_FRAMEBUFFER, captureFBO );
717
	
718
	ofSetColor( 255 );
719
		
720
	ofPushView();
721
	ofViewport(0, 0, aSrcRes, aSrcRes, false);
722
	
723
	shaderEquiRectToCubeMap.begin();
724
	shaderEquiRectToCubeMap.setUniformTexture("uEquirectangularTex", aSrcTex, 0 );
725
	shaderEquiRectToCubeMap.setUniformMatrix4f("uProjection", projectionMat );
726
	shaderEquiRectToCubeMap.setUniform1f("uFlipY", data->settings.flipVertically ? 1.0f : 0.0f );
727
	shaderEquiRectToCubeMap.setUniform1f("uConvertToNonFloat", aBConvertToNonFloat ? 1.0f : 0.0f );
728
	
729
	for (unsigned int i = 0; i < 6; i++) {
730
		shaderEquiRectToCubeMap.setUniformMatrix4f("uView", views[i]);
731
		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, aCubeTexId, 0);
732
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
733
		sCubeMesh.draw();
734
	}
735
	shaderEquiRectToCubeMap.end();
736
	ofPopView();
737
	
738
	glBindFramebuffer(GL_FRAMEBUFFER, 0);
739
	glDeleteFramebuffers(1, &captureFBO);
740
}
741

742
//--------------------------------------------------------------
743
void ofCubeMap::_createIrradianceMap(GLuint aSrcCubeFid, bool aBMakeCache, const of::filesystem::path & aCachePath) {
744
	if(data->bIrradianceAllocated) {
745
		return;
746
	}
747
	if( !data->bIrradianceAllocated ) {
748
		data->bIrradianceAllocated = true;
749
		glGenTextures(1, &data->irradianceMapId );
750
		retain(data->irradianceMapId);
751
	}
752
	
753
	_allocateCubeMesh();
754
	
755
	std::vector<glm::mat4> views = _getViewMatrices( glm::vec3(0,0,0) );
756
	
757
	if( !shaderIrradianceMap.isLoaded() ) {
758
		auto isource = ofCubeMapShaders::irriadianceCubeMap();
759
		shaderIrradianceMap.setupShaderFromSource(GL_VERTEX_SHADER, isource.vertShader );
760
		shaderIrradianceMap.setupShaderFromSource(GL_FRAGMENT_SHADER, isource.fragShader );
761
		shaderIrradianceMap.bindDefaults();
762
		shaderIrradianceMap.linkProgram();
763
	}
764
	
765
	if( aBMakeCache ) {
766
				
767
		ofLogNotice("ofCubeMap :: _createIrradianceMap : making cache");
768
		
769
		ofFbo tfbo;
770
		//	fbo.clear();
771
		ofFboSettings fboSettings;
772
		fboSettings.width = data->settings.irradianceRes;
773
		fboSettings.height = data->settings.irradianceRes;
774
		fboSettings.numSamples = 0;
775
		//	fboSettings.numColorbuffers = 6;
776
		fboSettings.useDepth = false;
777
//		fboSettings.textureTarget = GL_TEXTURE_2D;
778
		fboSettings.internalformat = texFormat;
779
		tfbo.allocate(fboSettings);
780
				
781
		ofSetColor( 255 );
782
		
783
		vector<ofFloatPixels> fpixels;
784
		fpixels.assign(6, ofFloatPixels());
785
		bool bAllPixelsCreated = true;
786
		
787
		for( unsigned int i = 0; i < 6; i++ ) {
788
			tfbo.begin();
789
			ofClear(0, 0, 0);
790
			shaderIrradianceMap.begin();
791
			shaderIrradianceMap.setUniformTexture("environmentMap", getTextureTarget(), aSrcCubeFid, 0 );
792
			shaderIrradianceMap.setUniformMatrix4f("uProjection", projectionMat );
793
			shaderIrradianceMap.setUniformMatrix4f("uView", views[i]);
794
			sCubeMesh.draw();
795
			shaderIrradianceMap.end();
796
			
797
			tfbo.end();
798
			tfbo.updateTexture(0);
799
			tfbo.readToPixels(fpixels[i]);
800
			if( fpixels[i].getWidth() < 1 || fpixels[i].getHeight() < 1 ) {
801
				bAllPixelsCreated = false;
802
			}
803
		}
804
		
805
		if(bAllPixelsCreated) {
806
			GLenum textureTarget = getTextureTarget();
807
			glBindTexture(textureTarget, data->irradianceMapId );
808
			GLuint texStorageFormat = getTexStorageFormat();
809
			GLuint gFormat = getGlTypeFromInternalFormat();
810
			// we need to create a single image //
811
			for (unsigned int i = 0; i < 6; i++) {
812
				glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, texFormat, fpixels[i].getWidth(), fpixels[i].getHeight(), 0, gFormat, texStorageFormat, fpixels[i].getData() );
813
			}
814
			glBindTexture(textureTarget, 0 );
815
			
816
			_configureCubeTextures(data->irradianceMapId, false);
817
			
818
			// ok, now lets make a single fbo
819
			int fullWidth = data->settings.irradianceRes * 3;
820
			fboSettings.width = fullWidth;
821
			fboSettings.height = data->settings.irradianceRes * 2;
822
			
823
			int texSize = data->settings.irradianceRes;
824
			
825
			tfbo.clear();
826
			tfbo.allocate( fboSettings );
827
			ofSetColor(255);
828
			tfbo.begin(); {
829
				ofClear(0);
830
				ofTexture ftex;
831
				for (unsigned int j = 0; j < 6; j++) {
832
					ftex.loadData( fpixels[j] );
833
					ftex.draw((j % 3) * texSize, floor(j / 3) * texSize, texSize, texSize);
834
				}
835
			} tfbo.end();
836
			
837
			ofFloatPixels fpix;
838
			tfbo.updateTexture(0);
839
			tfbo.readToPixels(fpix);
840
			if( fpix.getNumChannels() != 3 ) {
841
				fpix.setNumChannels(3);
842
			}
843
			if(!ofSaveImage(fpix, aCachePath)) {
844
				ofLogError("ofCubeMap :: _createIrradianceMap : ") << aCachePath;
845
			}
846
		}
847
		
848
		
849
	} else {
850
		
851
		_initEmptyTextures(data->irradianceMapId, data->settings.irradianceRes );
852
		_configureCubeTextures(data->irradianceMapId, false);
853
		
854
		unsigned int captureFBO;
855

856
		glGenFramebuffers(1, &captureFBO);
857
		glBindFramebuffer(GL_FRAMEBUFFER, captureFBO );
858

859
		ofPushView();
860
		ofViewport(0, 0, data->settings.irradianceRes, data->settings.irradianceRes, false);
861
		
862
		ofSetColor( 255 );
863
		shaderIrradianceMap.begin();
864
		shaderIrradianceMap.setUniformTexture("environmentMap", getTextureTarget(), aSrcCubeFid, 0 );
865
		shaderIrradianceMap.setUniformMatrix4f("uProjection", projectionMat );
866

867
		for( unsigned int i = 0; i < 6; i++ ) {
868
			shaderIrradianceMap.setUniformMatrix4f("uView", views[i]);
869
			glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, data->irradianceMapId, 0);
870
			ofClear(0, 0, 0, 255);
871
			sCubeMesh.draw();
872
		}
873

874
		shaderIrradianceMap.end();
875

876
		glBindFramebuffer(GL_FRAMEBUFFER, 0);
877
		glDeleteFramebuffers(1, &captureFBO);
878
		ofPopView();
879
	}
880
	
881
}
882

883
//--------------------------------------------------------------
884
bool ofCubeMap::_loadIrradianceMap(const of::filesystem::path & aCachePath) {
885
	
886
	if(data->bIrradianceAllocated) {
887
		return false;
888
	}
889
		
890
	ofLogVerbose("ofCubeMap :: _loadIrradianceMap : does file exist: ") << ofFile::doesFileExist(aCachePath);
891
	if( !ofFile::doesFileExist(aCachePath) ) {
892
		return false;
893
	}
894
	
895
	ofFloatPixels fullPix;
896
	if( !ofLoadImage( fullPix, aCachePath )) {
897
		ofLogError("ofCubeMap :: _loadIrradianceMap : unable to load from ") << aCachePath;
898
		return false;
899
	}
900
	
901
	if( !data->bIrradianceAllocated ) {
902
		data->bIrradianceAllocated = true;
903
		glGenTextures(1, &data->irradianceMapId );
904
		retain(data->irradianceMapId);
905
	}
906
	
907
//	_configureCubeTextures(data->irradianceMapId, false);
908
	
909
	int texSize = fullPix.getWidth() / 3;
910
	
911
	ofFloatPixels fpix;
912
	size_t numChannels = getNumPixelChannels();
913
	GLenum textureTarget = getTextureTarget();
914
	
915
	ofLogVerbose() << "ofCubeMap :: _loadIrradianceMap : num channels: " << numChannels;
916
	
917
	glBindTexture(textureTarget, data->irradianceMapId );
918
	
919
	GLuint loadTexFormat = texFormat;
920
#if defined(TARGET_EMSCRIPTEN)
921
	loadTexFormat = GL_RGBA32F;
922
#endif
923
	
924
	GLuint texStorageFormat = getTexStorageFormat(loadTexFormat);
925
	GLuint gFormat = getGlTypeFromInternalFormat(loadTexFormat);
926
	
927
	for(unsigned int j = 0; j < 6; j++ ) {
928
		//cropTo(ofPixels_<PixelType> &toPix, size_t x, size_t y, size_t _width, size_t _height)
929
		fullPix.cropTo( fpix, (j % 3) * texSize, floor(j / 3) * texSize, texSize, texSize );
930
		if( fpix.getNumChannels() != numChannels ) {
931
			fpix.setNumChannels(numChannels);
932
		}
933
		glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + j, 0, loadTexFormat, fpix.getWidth(), fpix.getHeight(), 0, gFormat, texStorageFormat, fpix.getData() );
934
	}
935
	glBindTexture(textureTarget, 0 );
936
	
937
	_configureCubeTextures(data->irradianceMapId, false);
938
	
939
	return true;
940
}
941

942
//--------------------------------------------------------------
943
void ofCubeMap::_createPrefilteredCubeMap(GLuint aSrcCubeFid, int aSrcRes, bool aBMakeCache, const of::filesystem::path & aCachePath) {
944
	if(data->bPreFilteredMapAllocated) {
945
		return;
946
	}
947
	
948
	_allocateCubeMesh();
949
	data->bPreFilteredMapAllocated = true;
950
	glGenTextures(1, &data->preFilteredMapId );
951
	retain(data->preFilteredMapId);
952
	
953
	glBindTexture(GL_TEXTURE_CUBE_MAP, data->preFilteredMapId);
954

955
	GLuint texStorageFormat = getTexStorageFormat();
956
	GLuint gFormat = getGlTypeFromInternalFormat();
957
	
958
	// generate all of the textures and mip maps at once ...
959
	//glTexStorage2D(GL_TEXTURE_CUBE_MAP, data->maxMipLevels, texFormat, data->settings.preFilterRes, data->settings.preFilterRes);
960
	// create all of the textures with mip maps //
961
	
962
	glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
963
	
964
	_initEmptyTextures( data->preFilteredMapId, texFormat, data->settings.preFilterRes, data->maxMipLevels );
965
	
966
	_configureCubeTextures(data->preFilteredMapId, true);
967
	
968
	if( !shaderPreFilterMap.isLoaded() ) {
969
		auto psource = ofCubeMapShaders::prefilter();
970
		shaderPreFilterMap.setupShaderFromSource(GL_VERTEX_SHADER, psource.vertShader );
971
		shaderPreFilterMap.setupShaderFromSource(GL_FRAGMENT_SHADER, psource.fragShader );
972
		shaderPreFilterMap.bindDefaults();
973
		shaderPreFilterMap.linkProgram();
974
	}
975
	
976
	std::vector<glm::mat4> views = _getViewMatrices( glm::vec3(0,0,0) );
977
	
978
	if( aBMakeCache ) {
979
		ofLogVerbose("ofCubeMap :: _createPrefilteredCubeMap : making cache");
980
		ofFboSettings fboSettings;
981
		ofFbo cacheFbo;
982
		fboSettings.width = data->settings.preFilterRes * 3;
983
		fboSettings.height = fboSettings.width;
984
		fboSettings.numSamples = 0;
985
		fboSettings.useDepth = false;
986
		fboSettings.internalformat = texFormat;
987
		
988
		cacheFbo.allocate(fboSettings);
989
		cacheFbo.begin(); {
990
			ofClear(255, 0, 0);
991
		} cacheFbo.end();
992
		
993
		ofFbo tfbo;
994
		
995
		vector<ofFloatPixels> fpixels;
996
		fpixels.assign(6, ofFloatPixels() );
997
		// bool bAllPixelsCreated = true;
998
		
999
		int shiftX = 0;
1000
		int shiftY = 0;
1001
		
1002
		for (int mip = 0; mip < data->maxMipLevels; mip++) {
1003
			// reisze framebuffer according to mip-level size.
1004
			unsigned int mipWidth  = static_cast<unsigned int>(data->settings.preFilterRes * std::pow(0.5, mip));
1005
			if(mipWidth < 1 ) {
1006
				mipWidth = 1;
1007
			}
1008
			fboSettings.width = mipWidth;
1009
			fboSettings.height = fboSettings.width;
1010
			tfbo.clear();
1011
			tfbo.allocate(fboSettings);
1012
			
1013
			float roughness = (float)mip / (float)(data->maxMipLevels - 1);
1014
			
1015
			if( mip > 0 ) {
1016
				shiftY = data->settings.preFilterRes * 2;
1017
			}
1018
			
1019
			for (unsigned int i = 0; i < 6; ++i) {
1020
				tfbo.begin();
1021
				ofClear(0);
1022
				shaderPreFilterMap.begin();
1023
				shaderPreFilterMap.setUniformTexture("environmentMap", getTextureTarget(), aSrcCubeFid, 0 );
1024
				shaderPreFilterMap.setUniformMatrix4f("uProjection", projectionMat );
1025
				shaderPreFilterMap.setUniform1f("resolution", (float)aSrcRes );
1026
				shaderPreFilterMap.setUniform1f("uroughness", roughness);
1027
				shaderPreFilterMap.setUniformMatrix4f( "uView", views[i] );
1028
				sCubeMesh.draw();
1029
				shaderPreFilterMap.end();
1030
				tfbo.end();
1031
				
1032
				tfbo.readToPixels(fpixels[i]);
1033
				if( fpixels[i].getWidth() < 1 || fpixels[i].getHeight() < 1 ) {
1034
					// bAllPixelsCreated = false;
1035
				} else {
1036
					cacheFbo.begin();
1037
					tfbo.getTexture().draw( (i%3) * mipWidth + shiftX, floor(i/3) * mipWidth + shiftY, mipWidth, mipWidth );
1038
					cacheFbo.end();
1039
				}
1040
			}
1041
			
1042
			if( mip > 0 ) {
1043
				shiftX += mipWidth * 3;
1044
			}
1045
			
1046
			glBindTexture(GL_TEXTURE_CUBE_MAP, data->preFilteredMapId);
1047
			for (unsigned int i = 0; i < 6; ++i) {
1048
				if( fpixels[i].getWidth() > 0 && fpixels[i].getHeight() > 0 ) {
1049
//					// must use glTexSubImage with glTexStorage2D
1050
					glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, mip, 0, 0, mipWidth, mipWidth, gFormat, texStorageFormat,fpixels[i].getData());
1051

1052
				}
1053
			}
1054
			glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
1055
		}
1056
		
1057
		ofFloatPixels cachePix;
1058
		cacheFbo.readToPixels(cachePix);
1059
		if( cachePix.getWidth() > 0 ) {
1060
			if( !ofSaveImage(cachePix, aCachePath) ) {
1061
				ofLogError("ofCubeMap :: _createPrefilteredCubeMap: ") << aCachePath;
1062
			}
1063
		}
1064
		
1065
	} else {
1066
		
1067
		unsigned int captureFBO;
1068
		glGenFramebuffers(1, &captureFBO);
1069
		glBindFramebuffer(GL_FRAMEBUFFER, captureFBO );
1070
		
1071
		for (int mip = 0; mip < data->maxMipLevels; mip++) {
1072
			// reisze framebuffer according to mip-level size.
1073
			unsigned int mipWidth  = static_cast<unsigned int>(data->settings.preFilterRes * std::pow(0.5, mip));
1074
			ofPushView();
1075
			ofViewport(0, 0, mipWidth, mipWidth, false);
1076
			shaderPreFilterMap.begin();
1077
			shaderPreFilterMap.setUniformTexture("environmentMap", getTextureTarget(), aSrcCubeFid, 0 );
1078
			shaderPreFilterMap.setUniformMatrix4f("uProjection", projectionMat );
1079
			shaderPreFilterMap.setUniform1f("resolution", (float)aSrcRes );
1080
			
1081
			float roughness = (float)mip / (float)(data->maxMipLevels - 1);
1082
			shaderPreFilterMap.setUniform1f("uroughness", roughness);
1083
			for (unsigned int i = 0; i < 6; ++i) {
1084
				shaderPreFilterMap.setUniformMatrix4f( "uView", views[i] );
1085
				glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, data->preFilteredMapId, mip);
1086
				ofClear(0, 0, 0);
1087
				sCubeMesh.draw();
1088
			}
1089
			shaderPreFilterMap.end();
1090
			ofPopView();
1091
		}
1092
		
1093
		glBindFramebuffer(GL_FRAMEBUFFER, 0);
1094
		glDeleteFramebuffers(1, &captureFBO);
1095
	}
1096
	
1097
	glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
1098
}
1099

1100
//--------------------------------------------------------------
1101
bool ofCubeMap::_loadPrefilterMap( const of::filesystem::path & aCachePath ) {
1102
	if(data->bPreFilteredMapAllocated) {
1103
		return false;
1104
	}
1105
	
1106
	ofLogVerbose("ofCubeMap :: _loadPrefilterMap : does file exist: ") << ofFile::doesFileExist(aCachePath);
1107
	if( !ofFile::doesFileExist(aCachePath) ) {
1108
		return false;
1109
	}
1110
	
1111
	ofFloatPixels fullPix;
1112
	if( !ofLoadImage( fullPix, aCachePath )) {
1113
		ofLogError("ofCubeMap :: _loadPrefilterMap : unable to load from ") << aCachePath;
1114
		return false;
1115
	}
1116
	
1117
	_allocateCubeMesh();
1118
	data->bPreFilteredMapAllocated = true;
1119
	glGenTextures(1, &data->preFilteredMapId );
1120
	retain(data->preFilteredMapId);
1121
	
1122
	
1123
	GLuint loadTexFormat = texFormat;
1124
#if defined(TARGET_EMSCRIPTEN)
1125
	loadTexFormat = GL_RGBA32F;
1126
#endif
1127
	
1128
	GLuint texStorageFormat = getTexStorageFormat(loadTexFormat);
1129
	GLuint gFormat = getGlTypeFromInternalFormat(loadTexFormat);
1130
	
1131
	_initEmptyTextures( data->preFilteredMapId, loadTexFormat, data->settings.preFilterRes, data->maxMipLevels );
1132
	
1133
	//glBindTexture(GL_TEXTURE_CUBE_MAP, data->preFilteredMapId);
1134
	//glTexStorage2D(GL_TEXTURE_CUBE_MAP, data->maxMipLevels, loadTexFormat, data->settings.preFilterRes, data->settings.preFilterRes);
1135
	//glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
1136
	
1137
	_configureCubeTextures(data->preFilteredMapId, true);
1138
		
1139
	ofFloatPixels fpix;
1140
	size_t numChannels = getNumPixelChannels();
1141
	
1142
	float shiftX = 0.0f;
1143
	float shiftY = 0.0f;
1144
	
1145
	glBindTexture(GL_TEXTURE_CUBE_MAP, data->preFilteredMapId );
1146
	for (int mip = 0; mip < data->maxMipLevels; mip++) {
1147
		// reisze framebuffer according to mip-level size.
1148
		unsigned int mipWidth  = static_cast<unsigned int>(data->settings.preFilterRes * std::pow(0.5, mip));
1149
		if(mipWidth < 1 ) {mipWidth = 1;}
1150
		
1151
		if( mip > 0 ) {
1152
			shiftY = data->settings.preFilterRes * 2;
1153
		}
1154
		
1155
		for (unsigned int i = 0; i < 6; ++i) {
1156
			fullPix.cropTo( fpix, (i % 3) * mipWidth + shiftX, floor(i / 3) * mipWidth + shiftY, mipWidth, mipWidth );
1157
			if( fpix.getNumChannels() != numChannels ) {
1158
				fpix.setNumChannels(numChannels);
1159
			}
1160
			glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, mip, 0, 0, mipWidth, mipWidth, gFormat, texStorageFormat,fpix.getData());
1161
		}
1162
		
1163
		if( mip > 0 ) {
1164
			shiftX += mipWidth * 3;
1165
		}
1166
	}
1167
	glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
1168
	return true;
1169
}
1170

1171
//--------------------------------------------------------------
1172
void ofCubeMap::_createBrdfLUT() {
1173
	#ifndef TARGET_OPENGLES
1174
	int lutWidth = 512;
1175
	int lutHeight = 512;
1176
	
1177
	ofFbo lutFbo;
1178
	
1179
	if( !shaderBrdfLUT.isLoaded() ) {
1180
		auto bsource = ofCubeMapShaders::brdfLUT();
1181
		shaderBrdfLUT.setupShaderFromSource(GL_VERTEX_SHADER, bsource.vertShader );
1182
		shaderBrdfLUT.setupShaderFromSource(GL_FRAGMENT_SHADER, bsource.fragShader );
1183
		shaderBrdfLUT.bindDefaults();
1184
		shaderBrdfLUT.linkProgram();
1185
	}
1186
	
1187
	ofMesh quadMesh;
1188
	quadMesh.setMode(OF_PRIMITIVE_TRIANGLES);
1189
	quadMesh.addVertices({
1190
		glm::vec3(0,0,0),
1191
		glm::vec3(lutWidth, 0.0, 0.0),
1192
		glm::vec3(lutWidth, lutHeight, 0.0),
1193
		glm::vec3(0, lutHeight, 0.0f)
1194
		
1195
	});
1196
	
1197
	quadMesh.addTexCoords( {
1198
		glm::vec2(0.0f, 1.0f),
1199
		glm::vec2(1.0f, 1.0f),
1200
		glm::vec2(1.0f, 0.0f),
1201
		glm::vec2(0.0f, 0.0f)
1202
	});
1203
	
1204
	quadMesh.addIndices({
1205
		0, 1, 3,
1206
		1, 2, 3
1207
	});
1208
	quadMesh.disableColors();
1209
	quadMesh.disableNormals();
1210
	lutFbo.allocate(lutWidth, lutHeight, GL_RG32F );
1211
	
1212
	ofSetColor(255);
1213
	ofPushView();
1214
	lutFbo.begin();
1215
	ofClear(0, 0, 0);
1216
	shaderBrdfLUT.begin();
1217
	quadMesh.draw();
1218
	ofSetColor(255);
1219
	shaderBrdfLUT.end();
1220
	lutFbo.end();
1221
	ofPopView();
1222
	
1223
	lutFbo.updateTexture(0);
1224
	sBrdfLutTex = lutFbo.getTexture(0);
1225
	lutFbo.clear();
1226
	
1227
	glBindTexture(GL_TEXTURE_2D, 0);
1228
	#else
1229
	ofLogWarning("ofCubeMap::_createBrdfLUT") << " brdf lut texture not supported on GLES";
1230
	#endif
1231
}
1232

1233
//--------------------------------------------------------------
1234
void ofCubeMap::_allocateCubeMesh() {
1235
	if( sCubeMesh.getNumVertices() > 0 ) {
1236
		return;
1237
	}
1238
	sCubeMesh = ofMesh::box( 1, 1, 1, 4, 4, 4);
1239
	sCubeMesh.disableColors();
1240
	sCubeMesh.disableTextures();
1241
	sCubeMesh.disableNormals();
1242
	sCubeMesh.getTexCoords().clear();
1243
}
1244

1245
//--------------------------------------------------------------
1246
std::vector<glm::mat4> ofCubeMap::_getViewMatrices(const glm::vec3& apos ) {
1247
	// eye, target and up vector
1248
	// +x, -x, +y, -y, +z and -z direction
1249
	vector<glm::mat4> views = {
1250
		glm::lookAt( apos, apos+glm::vec3(1,0,0), glm::vec3(0, -1, 0) ),
1251
		glm::lookAt( apos, apos+glm::vec3(-1,0,0), glm::vec3(0, -1, 0) ),
1252
		glm::lookAt( apos, apos+glm::vec3(0,1,0), glm::vec3(0, 0, 1) ),
1253
		glm::lookAt( apos, apos+glm::vec3(0,-1,0), glm::vec3(0, 0, -1) ),
1254
		glm::lookAt( apos, apos+glm::vec3(0,0,1), glm::vec3(0, -1, 0) ),
1255
		glm::lookAt( apos, apos+glm::vec3(0,0,-1), glm::vec3(0, -1, 0) )
1256
	};
1257
	return views;
1258
}
1259

1260
//--------------------------------------------------------------
1261
GLuint ofCubeMap::getTexStorageFormat() {
1262
	return getTexStorageFormat(texFormat);
1263
}
1264

1265
//--------------------------------------------------------------
1266
GLuint ofCubeMap::getTexStorageFormat(GLuint aInternalFormat) {
1267
	#if !defined(TARGET_OPENGLES) || defined(TARGET_EMSCRIPTEN)
1268
	if( aInternalFormat == GL_RGB32F ) {
1269
		return GL_FLOAT;
1270
	} else if( aInternalFormat == GL_RGBA32F ) {
1271
		return GL_FLOAT;
1272
	} else if( aInternalFormat == GL_RGBA16F ) {
1273
		return GL_HALF_FLOAT;
1274
	}
1275
	#ifdef GL_RGBA32F_EXT
1276
	if( aInternalFormat == GL_RGBA32F_EXT ) {
1277
		return GL_FLOAT;
1278
	}
1279
	#endif
1280
	#ifdef GL_RGB32F_EXT
1281
	if( aInternalFormat == GL_RGB32F_EXT ) {
1282
		return GL_FLOAT;
1283
	}
1284
	#endif
1285
	#endif
1286
	return GL_UNSIGNED_BYTE;
1287
}
1288

1289
//--------------------------------------------------------------
1290
GLuint ofCubeMap::getGlTypeFromInternalFormat() {
1291
	return getGlTypeFromInternalFormat(texFormat);
1292
}
1293

1294
//--------------------------------------------------------------
1295
GLuint ofCubeMap::getGlTypeFromInternalFormat(GLuint aInternalFormat) {
1296
	#if !defined(TARGET_OPENGLES) || defined(TARGET_EMSCRIPTEN)
1297
		if( aInternalFormat == GL_RGBA32F ) {
1298
			return GL_RGBA;
1299
		}
1300
		if( aInternalFormat == GL_RGBA16F ) {
1301
			return GL_RGBA;
1302
		}
1303
	
1304
		#ifdef GL_RGBA32F_EXT
1305
		if( aInternalFormat == GL_RGBA32F_EXT ) {
1306
			return GL_RGBA;
1307
		}
1308
		#endif
1309
		#ifdef GL_RGB32F_EXT
1310
		if( aInternalFormat == GL_RGB32F_EXT ) {
1311
			return GL_RGB;
1312
		}
1313
		#endif
1314
	#endif
1315
	return GL_RGB;
1316
}
1317

1318
//--------------------------------------------------------------
1319
int ofCubeMap::getNumPixelChannels() {
1320
	GLuint glType = getGlTypeFromInternalFormat();
1321
	if( glType == GL_RGBA ) {
1322
		return 4;
1323
	}
1324
	return 3;
1325
}
1326

1327
//--------------------------------------------------------------
1328
bool ofCubeMap::_loadRenderShader() {
1329
	shaderRender.unload();
1330
	
1331
	auto rsource = ofCubeMapShaders::renderShader();
1332
	shaderRender.setupShaderFromSource(GL_VERTEX_SHADER, rsource.vertShader );
1333
	shaderRender.setupShaderFromSource(GL_FRAGMENT_SHADER, rsource.fragShader );
1334
	shaderRender.bindDefaults();
1335
	return shaderRender.linkProgram();
1336
}
1337

1338
//--------------------------------------------------------------
1339
bool ofCubeMap::_loadEquiRectToCubeMapShader() {
1340
	if( !shaderEquiRectToCubeMap.isLoaded() ) {
1341
		auto esource = ofCubeMapShaders::equiRectToCubeMap();
1342
		shaderEquiRectToCubeMap.setupShaderFromSource(GL_VERTEX_SHADER, esource.vertShader );
1343
		shaderEquiRectToCubeMap.setupShaderFromSource(GL_FRAGMENT_SHADER, esource.fragShader );
1344
		shaderEquiRectToCubeMap.bindDefaults();
1345
		if(shaderEquiRectToCubeMap.linkProgram()) {
1346
			return true;
1347
		} else {
1348
			shaderEquiRectToCubeMap.unload();
1349
			ofLogNotice("ofCubeMap::_loadEquiRectToCubeMapShader : unable to create shaderEquiRectToCubeMap shader ");
1350
			return false;
1351
		}
1352
	}
1353
	return true;
1354
}
1355

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.