framework2

Форк
0
1388 строк · 48.3 Кб
1
#include "ofMaterial.h"
2
#include "ofLight.h"
3
#include "ofShadow.h"
4
#include "ofCubeMap.h"
5
#include "ofImage.h"
6
#include "ofGLProgrammableRenderer.h"
7

8
#include <typeinfo>
9

10
using std::shared_ptr;
11
using std::string;
12

13
std::unordered_map<ofGLProgrammableRenderer*, std::unordered_map<std::string, std::weak_ptr<ofMaterial::Shaders>>> ofMaterial::shadersMap;
14

15
namespace{
16
string vertexSource(bool bPBR, string defaultHeader, int maxLights, bool hasTexture, bool hasColor, std::string addShaderSrc,const ofMaterialSettings& adata);
17
string fragmentSource(bool bPBR, string defaultHeader, string customUniforms, const ofMaterialSettings& adata, int maxLights, bool hasTexture, bool hasColor, std::string definesString="");
18
}
19

20
//----------------------------------------------------------
21
ofMaterial::ofMaterial() {
22
}
23

24
//----------------------------------------------------------
25
std::string ofMaterial::getUniformName( const ofMaterialTextureType& aMaterialTextureType ) {
26
	switch(aMaterialTextureType) {
27
		case OF_MATERIAL_TEXTURE_DIFFUSE:
28
			return "tex0";
29
		case OF_MATERIAL_TEXTURE_SPECULAR:
30
			return "tex_specular";
31
		case OF_MATERIAL_TEXTURE_AMBIENT:
32
			return "tex_ambient";
33
		case OF_MATERIAL_TEXTURE_EMISSIVE:
34
			return "tex_emissive";
35
		case OF_MATERIAL_TEXTURE_NORMAL:
36
			return "tex_normal";
37
		case OF_MATERIAL_TEXTURE_OCCLUSION:
38
			return "tex_occlusion";
39
		case OF_MATERIAL_TEXTURE_AO_ROUGHNESS_METALLIC:
40
			return "tex_ao_roughness_metallic";
41
		case OF_MATERIAL_TEXTURE_ROUGHNESS_METALLIC:
42
			return "tex_roughness_metallic";
43
		case OF_MATERIAL_TEXTURE_ROUGHNESS:
44
			return "tex_roughness";
45
		case OF_MATERIAL_TEXTURE_METALLIC:
46
			return "tex_metallic";
47
		case OF_MATERIAL_TEXTURE_DISPLACEMENT:
48
			return "tex_displacement";
49
		case OF_MATERIAL_TEXTURE_CLEARCOAT:
50
			return "tex_clearcoat_intensity";
51
		case OF_MATERIAL_TEXTURE_CLEARCOAT_ROUGHNESS:
52
			return "tex_clearcoat_roughness";
53
		case OF_MATERIAL_TEXTURE_CLEARCOAT_INTENSITY_ROUGHNESS:
54
			return "tex_clearcoat_intensity_roughness";
55
		case OF_MATERIAL_TEXTURE_CLEARCOAT_NORMAL:
56
			return "tex_clearcoat_normal";
57
		default:
58
			break;
59
	}
60
	return "";
61
}
62

63
//----------------------------------------------------------
64
bool ofMaterial::isPBRSupported() {
65
	#if defined(TARGET_OPENGLES) && !defined(TARGET_EMSCRIPTEN)
66
	return false;
67
	#endif
68
	
69
	if( !ofIsGLProgrammableRenderer() ) {
70
		return false;
71
	}
72
	return true;
73
}
74

75
//----------------------------------------------------------
76
void ofMaterial::setPBR(bool ab) {
77
	if( ab && !ofIsGLProgrammableRenderer() ) {
78
		if( !bPrintedPBRRenderWarning ) {
79
			bPrintedPBRRenderWarning=true;
80
			ofLogWarning("ofMaterial::setPBR") << " PBR material must be used with Programmable Renderer.";
81
		}
82
		data.isPbr = false;
83
		return;
84
	}
85
	
86
	#if defined(TARGET_OPENGLES) && !defined(TARGET_EMSCRIPTEN)
87
	if( ab ) {
88
		if( !bPrintedPBRRenderWarning ) {
89
			bPrintedPBRRenderWarning=true;
90
			ofLogWarning("ofMaterial::setPBR") << " PBR material is not supported on this OPENGL ES platform.";
91
		}
92
		data.isPbr = false;
93
		return;
94
	}
95
	#endif
96
	
97
	
98
	data.isPbr = ab;
99
}
100

101
//----------------------------------------------------------
102
void ofMaterial::setColors(ofFloatColor oDiffuse, ofFloatColor oAmbient, ofFloatColor oSpecular, ofFloatColor oEmissive) {
103
	setDiffuseColor(oDiffuse);
104
	setAmbientColor(oAmbient);
105
	setSpecularColor(oSpecular);
106
	setEmissiveColor(oEmissive);
107
}
108

109
//----------------------------------------------------------
110
void ofMaterial::setup(const ofMaterialSettings & settings){
111
	if(settings.customUniforms != data.customUniforms || settings.postFragment != data.postFragment || 
112
		settings.mainVertexKey != data.mainVertexKey || settings.mainFragmentKey != data.mainFragmentKey || 
113
		settings.isPbr != data.isPbr){
114
		shaders.clear();
115
		uniforms1f.clear();
116
		uniforms2f.clear();
117
		uniforms3f.clear();
118
		uniforms4f.clear();
119
		uniforms1i.clear();
120
		uniforms2i.clear();
121
		uniforms3i.clear();
122
		uniforms4i.clear();
123
		mCustomUniforms.clear();
124
		mDefines.clear();
125
		mBDefinesDirty = true;
126
	}
127
	data = settings;
128
	setClearCoatEnabled(data.clearCoatEnabled);
129
}
130

131
//----------------------------------------------------------
132
void ofMaterial::setShaderMain(std::string aShaderSrc, GLenum atype, std::string skey) {
133
	if(!isPBR()) {
134
		ofLogWarning("ofMaterial::setShaderMain") << "only available on PBR materials.";
135
		return;
136
	}
137
	
138
	if(atype == GL_VERTEX_SHADER) {
139
		// we would like to replace the current shader at key 
140
		// using a skey instead of shadersrc as key so we can easily overwrite
141
		if( data.mainVertexKey == skey) {
142
			// delete previous shader here, whether frag shader has same key or not
143
			std::string sid = getShaderStringId();
144
			mShaderIdsToRemove[sid]++;
145
		}
146
		data.mainVertex = aShaderSrc;
147
		data.mainVertexKey = skey;
148
	} else if( atype == GL_FRAGMENT_SHADER ) {
149
		if( data.mainFragmentKey == skey) {
150
			// delete previous shader here, whether frag shader has same key or not
151
			std::string sid = getShaderStringId();
152
			mShaderIdsToRemove[sid]++;
153
		}
154
		data.mainFragment = aShaderSrc;
155
		data.mainFragmentKey = skey;
156
	}
157
}
158

159
//----------------------------------------------------------
160
void ofMaterial::setDiffuseColor(ofFloatColor oDiffuse) {
161
	data.diffuse = oDiffuse;
162
	if( isBound() && currentRenderShader) {
163
		currentRenderShader->setUniform4fv("mat_diffuse", &data.diffuse.r );
164
	}
165
}
166

167
//----------------------------------------------------------
168
void ofMaterial::setAmbientColor(ofFloatColor oAmbient) {
169
	data.ambient = oAmbient;
170
	if( isBound() && !isPBR() && currentRenderShader) {
171
		currentRenderShader->setUniform4fv("mat_ambient", &data.ambient.r);
172
	}
173
}
174

175
//----------------------------------------------------------
176
void ofMaterial::setSpecularColor(ofFloatColor oSpecular) {
177
	data.specular = oSpecular;
178
	if( isBound() && !isPBR() && currentRenderShader) {
179
		currentRenderShader->setUniform4fv("mat_specular", &data.specular.r);
180
	}
181
}
182

183
//----------------------------------------------------------
184
void ofMaterial::setEmissiveColor(ofFloatColor oEmissive) {
185
	data.emissive = oEmissive;
186
	if( isBound() && currentRenderShader) {
187
		currentRenderShader->setUniform4fv("mat_emissive", &data.emissive.r);
188
	}
189
}
190

191
//----------------------------------------------------------
192
void ofMaterial::setShininess(float nShininess) {
193
	data.shininess = nShininess;
194
	if( isBound() && !isPBR() && currentRenderShader) {
195
		currentRenderShader->setUniform1f("mat_shininess",data.shininess);
196
	}
197
}
198

199
//----------------------------------------------------------
200
void ofMaterial::setTexCoordScale( float xscale, float yscale ) {
201
	data.texCoordScale.x = xscale;
202
	data.texCoordScale.y = yscale;
203
	if( isBound() && currentRenderShader) {
204
		currentRenderShader->setUniform2f("mat_texcoord_scale", data.texCoordScale );
205
	}
206
}
207

208
//----------------------------------------------------------
209
bool ofMaterial::loadTexture( const ofMaterialTextureType& aMaterialTextureType, std::string apath ) {
210
	return loadTexture(aMaterialTextureType, apath, ofGetUsingArbTex(), false);
211
}
212

213
//----------------------------------------------------------
214
bool ofMaterial::loadTexture( const ofMaterialTextureType& aMaterialTextureType, std::string apath, bool bTex2d, bool mirrorY ) {
215
	ofPixels tpix;
216
	bool bWasUsingArb = ofGetUsingArbTex();
217
	bTex2d ? ofEnableArbTex() : ofDisableArbTex();
218
	
219
	bool bLoadOk = false;
220
	
221
	if( ofLoadImage( tpix, apath )) {
222
		if( mirrorY ) {
223
			tpix.mirror(mirrorY, false);
224
		}
225
		bLoadOk = true;
226
		// if there was a previous instance, then erase it, then replace it 
227
		if( mLocalTextures.find(aMaterialTextureType) != mLocalTextures.end() ) {
228
			if( mLocalTextures[aMaterialTextureType] ) {
229
				mLocalTextures[aMaterialTextureType].reset();
230
			}
231
			mLocalTextures.erase(aMaterialTextureType);
232
		}
233
		
234
		auto tex = std::make_shared<ofTexture>();
235
		tex->loadData(tpix);
236
		mLocalTextures[aMaterialTextureType] = tex;
237
		setTexture( aMaterialTextureType, *tex );
238
	} else {
239
		ofLogError("ofMaterial") << "loadTexture(): FAILED for " << getUniformName(aMaterialTextureType) << " at path: " << apath;
240
	}
241
	
242
	bWasUsingArb ? ofEnableArbTex() : ofDisableArbTex();
243
	return bLoadOk;
244
}
245

246
//----------------------------------------------------------
247
bool ofMaterial::isPBRTexture(const ofMaterialTextureType& aMaterialTextureType) {
248
	return aMaterialTextureType >= (int)OF_MATERIAL_TEXTURE_AO_ROUGHNESS_METALLIC;
249
}
250

251
//----------------------------------------------------------
252
void ofMaterial::setTexture(const ofMaterialTextureType& aMaterialTextureType,const ofTexture & aTex) {
253
	if(isBound()) {
254
		ofLogWarning("ofMaterial::setTexture") << " must set texture when material is not bound.";
255
		return;
256
	}
257
	if( !isPBR() ) {
258
		if(isPBRTexture(aMaterialTextureType)) {
259
			ofLogVerbose("ofMaterial::setTexture") << " setting material to pbr.";
260
			setPBR(true);
261
		}
262
	}
263
	
264
	
265

266
	if(aMaterialTextureType == OF_MATERIAL_TEXTURE_CLEARCOAT ||
267
	   aMaterialTextureType == OF_MATERIAL_TEXTURE_CLEARCOAT_ROUGHNESS ||
268
	   aMaterialTextureType == OF_MATERIAL_TEXTURE_CLEARCOAT_INTENSITY_ROUGHNESS ) {
269
		if( aTex.isAllocated() ) {
270
			setClearCoatEnabled(true);
271
		}
272
	}
273
	setCustomUniformTexture(getUniformName(aMaterialTextureType), aTex);
274
	mergeCustomUniformTextures();
275
}
276

277
//----------------------------------------------------------
278
void ofMaterial::setDiffuseTexture(const ofTexture & aTex) {
279
	setTexture(OF_MATERIAL_TEXTURE_DIFFUSE, aTex);
280
}
281

282
//----------------------------------------------------------
283
void ofMaterial::setSpecularTexture(const ofTexture & aTex){
284
	setTexture(OF_MATERIAL_TEXTURE_SPECULAR, aTex);
285
}
286

287
//----------------------------------------------------------
288
void ofMaterial::setAmbientTexture(const ofTexture & aTex){
289
	setTexture(OF_MATERIAL_TEXTURE_AMBIENT, aTex);
290
}
291

292
//----------------------------------------------------------
293
void ofMaterial::setEmissiveTexture(const ofTexture & aTex){
294
	setTexture(OF_MATERIAL_TEXTURE_EMISSIVE, aTex);
295
}
296

297
//----------------------------------------------------------
298
void ofMaterial::setNormalTexture(const ofTexture & aTex){
299
	setTexture(OF_MATERIAL_TEXTURE_NORMAL, aTex);
300
}
301

302
//----------------------------------------------------------
303
void ofMaterial::setOcclusionTexture(const ofTexture & aTex){
304
	setTexture(OF_MATERIAL_TEXTURE_OCCLUSION, aTex);
305
}
306

307
//----------------------------------------------------
308
void ofMaterial::setAoRoughnessMetallicTexture(const ofTexture & aTex) {
309
	// r: occlusion, g: roughness, b: metallic
310
	setTexture(OF_MATERIAL_TEXTURE_AO_ROUGHNESS_METALLIC, aTex );
311
}
312

313
//----------------------------------------------------
314
void ofMaterial::setRoughnessMetallicTexture(const ofTexture & aTex) {
315
	// r: n/a, g: roughness, b: metallic
316
	setTexture(OF_MATERIAL_TEXTURE_ROUGHNESS_METALLIC, aTex);
317
}
318

319
//----------------------------------------------------
320
void ofMaterial::setRoughnessTexture(const ofTexture & aTex) {
321
	setTexture(OF_MATERIAL_TEXTURE_ROUGHNESS, aTex);
322
}
323

324
//----------------------------------------------------
325
void ofMaterial::setMetallicTexture(const ofTexture & aTex) {
326
	setTexture(OF_MATERIAL_TEXTURE_METALLIC, aTex);
327
}
328

329
//----------------------------------------------------
330
void ofMaterial::setDisplacementTexture(const ofTexture & aTex) {
331
	setTexture(OF_MATERIAL_TEXTURE_DISPLACEMENT, aTex);
332
}
333

334
//----------------------------------------------------
335
void ofMaterial::setClearCoatTexture( const ofTexture& aTex ) {
336
	setTexture(OF_MATERIAL_TEXTURE_CLEARCOAT, aTex );
337
}
338

339
//----------------------------------------------------
340
void ofMaterial::setMetallic( const float& ametallic ) {
341
	data.metallic = ametallic;
342
	
343
	if( isBound() && isPBR() && currentRenderShader) {
344
		currentRenderShader->setUniform1f("mat_metallic", data.metallic );
345
	}
346
	if( !isPBR() ) {
347
		setPBR(true);
348
	}
349
}
350

351
//----------------------------------------------------
352
void ofMaterial::setRoughness( const float& aroughness ) {
353
	data.roughness = aroughness;
354
	if( isBound() && isPBR() && currentRenderShader) {
355
		currentRenderShader->setUniform1f("mat_roughness", data.roughness );
356
	}
357
	if( !isPBR() ) {
358
		setPBR(true);
359
	}
360
}
361

362
//----------------------------------------------------
363
void ofMaterial::setReflectance( const float& areflectance ) {
364
	data.reflectance = areflectance;
365
	if( isBound() && isPBR() && currentRenderShader) {
366
		currentRenderShader->setUniform1f("mat_reflectance", data.reflectance );
367
	}
368
	if( !isPBR() ) {
369
		setPBR(true);
370
	}
371
}
372

373
//----------------------------------------------------
374
void ofMaterial::setClearCoatEnabled( bool ab ) {
375
	if(isBound()) {
376
		ofLogWarning("ofMaterial::setClearCoatEnabled") << " must be called when material is not bound.";
377
		return;
378
	}
379
	if( !isPBR() ) {
380
		setPBR(true);
381
	}
382
	data.clearCoatEnabled = ab;
383
	if(ab) {
384
		addShaderDefine( "HAS_CLEAR_COAT", "1" );
385
	} else {
386
		removeShaderDefine( "HAS_CLEAR_COAT" );
387
	}
388
}
389

390
//----------------------------------------------------
391
void ofMaterial::setClearCoatStrength( const float& astrength ) {
392
	data.clearCoatStrength = astrength;
393
	if( isClearCoatEnabled() && isBound() && isPBR() && currentRenderShader ) {
394
		currentRenderShader->setUniform2f("mat_clearcoat", data.clearCoatStrength, data.clearCoatRoughness );
395
	}
396
	if( !isPBR() ) {
397
		setPBR(true);
398
	}
399
}
400

401
//----------------------------------------------------
402
void ofMaterial::setClearCoatRoughness( const float& aroughness ) {
403
	data.clearCoatRoughness = aroughness;
404
	if( isClearCoatEnabled() && isBound() && isPBR() && currentRenderShader ) {
405
		currentRenderShader->setUniform2f("mat_clearcoat", data.clearCoatStrength, data.clearCoatRoughness );
406
	}
407
	if( !isPBR() ) {
408
		setPBR(true);
409
	}
410
}
411

412
//----------------------------------------------------------
413
void ofMaterial::setDisplacementStrength( const float& astrength ) {
414
	data.displacementStrength = astrength;
415
	if(isBound() && isPBR() && currentRenderShader ) {
416
		if( hasTexture(OF_MATERIAL_TEXTURE_DISPLACEMENT) ) {
417
			currentRenderShader->setUniform1f("mat_displacement_strength", data.displacementStrength );
418
		}
419
	}
420
	if( !isPBR() ) {
421
		setPBR(true);
422
	}
423
}
424

425
//----------------------------------------------------------
426
void ofMaterial::setDisplacementNormalsStrength( const float& astrength ) {
427
	data.displacementNormalsStrength = astrength;
428
	if(isBound() && isPBR() && currentRenderShader ) {
429
		if( hasTexture(OF_MATERIAL_TEXTURE_DISPLACEMENT) ) {
430
			currentRenderShader->setUniform1f("mat_displacement_normals_strength", data.displacementNormalsStrength );
431
		}
432
	}
433
}
434

435
//----------------------------------------------------------
436
void ofMaterial::setNormalGeomToNormalMapMix( const float& astrength ) {
437
	data.normalGeomToNormalMapMix = astrength;
438
	if(isBound() && isPBR() && currentRenderShader ) {
439
		if( hasTexture(OF_MATERIAL_TEXTURE_NORMAL) || hasTexture(OF_MATERIAL_TEXTURE_DISPLACEMENT) ) {
440
			currentRenderShader->setUniform1f("mat_normal_mix", data.normalGeomToNormalMapMix );
441
		}
442
	}
443
}
444

445
//----------------------------------------------------------
446
void ofMaterial::setData(const ofMaterial::Data &data){
447
	setup(data);
448
}
449

450
//----------------------------------------------------------
451
float ofMaterial::getShininess()const{
452
	return data.shininess;
453
}
454

455
//----------------------------------------------------
456
float ofMaterial::getMetallic() const {
457
	return data.metallic;
458
}
459

460
//----------------------------------------------------
461
float ofMaterial::getRoughness() const {
462
	return data.roughness;
463
}
464

465
//----------------------------------------------------
466
float ofMaterial::getReflectance() const {
467
	return data.reflectance;
468
}
469

470
//----------------------------------------------------
471
bool ofMaterial::isClearCoatEnabled() const {
472
	return data.clearCoatEnabled;
473
}
474

475
//----------------------------------------------------
476
float ofMaterial::getClearCoatStrength() const {
477
	return data.clearCoatStrength;
478
}
479

480
//----------------------------------------------------
481
float ofMaterial::getClearCoatRoughness() const {
482
	return data.clearCoatRoughness;
483
}
484

485
//----------------------------------------------------
486
float ofMaterial::getDisplacementStrength() const {
487
	return data.displacementStrength;
488
}
489

490
//----------------------------------------------------
491
float ofMaterial::getDisplacementNormalsStrength() const {
492
	return data.displacementNormalsStrength;
493
}
494

495
//----------------------------------------------------
496
float ofMaterial::getNormalGeomToNormalMapMix() const {
497
	return data.normalGeomToNormalMapMix;
498
}
499

500
//----------------------------------------------------------
501
ofFloatColor ofMaterial::getDiffuseColor()const {
502
	return data.diffuse;
503
}
504

505
//----------------------------------------------------------
506
ofFloatColor ofMaterial::getAmbientColor()const {
507
	return data.ambient;
508
}
509

510
//----------------------------------------------------------
511
ofFloatColor ofMaterial::getSpecularColor()const {
512
	return data.specular;
513
}
514

515
//----------------------------------------------------------
516
ofFloatColor ofMaterial::getEmissiveColor()const {
517
	return data.emissive;
518
}
519

520
//----------------------------------------------------------
521
ofMaterialSettings ofMaterial::getSettings() const{
522
    return data;
523
}
524

525
//-----------------------------------------------------------
526
void ofMaterial::begin() const{
527
	if(ofGetGLRenderer()){
528
		ofGetGLRenderer()->bind(*this);
529
	}
530
}
531

532
//----------------------------------------------------------
533
void ofMaterial::end() const{
534
	if(ofGetGLRenderer()){
535
		ofGetGLRenderer()->unbind(*this);
536
	}
537
}
538

539
//----------------------------------------------------------
540
void ofMaterial::uploadMatrices(const ofShader & shader,ofGLProgrammableRenderer & renderer) const {
541
	if(!isPBR()) {
542
		ofBaseMaterial::uploadMatrices(shader, renderer);
543
	}
544
}
545

546
//-----------------------------------------------------------
547
void ofMaterial::mergeCustomUniformTextures() {
548
	mergeCustomUniformTextures(OF_MATERIAL_TEXTURE_ROUGHNESS_METALLIC, {
549
		OF_MATERIAL_TEXTURE_ROUGHNESS,
550
		OF_MATERIAL_TEXTURE_METALLIC
551
	} );
552
	
553
	mergeCustomUniformTextures(OF_MATERIAL_TEXTURE_ROUGHNESS_METALLIC, {
554
		OF_MATERIAL_TEXTURE_OCCLUSION,
555
		OF_MATERIAL_TEXTURE_ROUGHNESS_METALLIC
556
	} );
557
	
558
	mergeCustomUniformTextures(OF_MATERIAL_TEXTURE_AO_ROUGHNESS_METALLIC, {
559
		OF_MATERIAL_TEXTURE_OCCLUSION,
560
		OF_MATERIAL_TEXTURE_ROUGHNESS,
561
		OF_MATERIAL_TEXTURE_METALLIC
562
	} );
563
}
564

565
//-----------------------------------------------------------
566
void ofMaterial::mergeCustomUniformTextures(ofMaterialTextureType mainType, std::vector<ofMaterialTextureType> mergeTypes) {
567
	size_t mtsSize = mergeTypes.size();
568
	if(!hasTexture(mainType) && mtsSize > 1){
569
		bool bHasAllMergeTypes = true;
570
		GLint texID;
571
		int texTarget;
572
		bool bMatchingTextures = true;
573
		int minTexLocation = 99999;
574
		
575
		for(size_t i = 0; i < mtsSize; i++ ) {
576
			if(!hasTexture(mergeTypes[i])){
577
				bHasAllMergeTypes = false;
578
				bMatchingTextures = false;
579
				break;
580
			} else {
581
				auto rtex = getCustomUniformTexture(mergeTypes[i]);
582
				if(i == 0 ) {
583
					texID = rtex.textureID;
584
					texTarget = rtex.textureTarget;
585
				}
586
				if( rtex.textureTarget != texTarget || rtex.textureID != texID ) {
587
					bMatchingTextures = false;
588
					break;
589
				} else {
590
					if( rtex.textureLocation < minTexLocation ) {
591
						minTexLocation = rtex.textureLocation;
592
					}
593
				}
594
			}
595
		}
596
		
597
		if(bHasAllMergeTypes && bMatchingTextures && minTexLocation < 1000){
598
			for(size_t i = 0; i < mtsSize; i++ ) {
599
				removeCustomUniformTexture(mergeTypes[i]);
600
			}
601
			setCustomUniformTexture( getUniformName(mainType), texTarget, texID, minTexLocation );
602
		}
603
	}
604
}
605

606
//-----------------------------------------------------------
607
ofMaterial::TextureUnifom ofMaterial::getCustomUniformTexture(const ofMaterialTextureType& aMaterialTextureType){
608
	return getCustomUniformTexture(getUniformName(aMaterialTextureType));
609
}
610

611
//-----------------------------------------------------------
612
ofMaterial::TextureUnifom ofMaterial::getCustomUniformTexture(const std::string & name){
613
	if(uniformstex.find(name) != uniformstex.end()){
614
		return uniformstex[name];
615
	}
616
	return TextureUnifom{};
617
}
618

619
// called from ofGLProgrammableRenderer
620
//-----------------------------------------------------------
621
void ofMaterial::unbind(ofGLProgrammableRenderer & renderer) const {
622
	mBound = false;
623
	currentRenderShader = nullptr;
624
}
625

626
//-----------------------------------------------------------
627
const std::string ofMaterial::getShaderStringId() const {
628
	std::string pbrStr = "pbr-yes";
629
	if(!isPBR()) {
630
		pbrStr = "pbr-no";
631
	}
632
	return pbrStr+data.uniqueIdString+data.postFragment+data.mainVertexKey+data.mainFragmentKey;
633
}
634

635
//-----------------------------------------------------------
636
void ofMaterial::initShaders(ofGLProgrammableRenderer & renderer) const{
637
	// remove any shaders that have their main source remove 
638
	{
639
		if( mShaderIdsToRemove.size() ) {
640
			for( auto& sids : mShaderIdsToRemove ) {
641
				if(shadersMap[&renderer].find(sids.first)!=shadersMap[&renderer].end()){
642
					auto newShaders = shadersMap[&renderer][sids.first].lock();
643
					if( newShaders ) {
644
						newShaders.reset();
645
					}
646
					shadersMap[&renderer].erase(sids.first);
647
				}
648
			}
649

650
			ofLogVerbose("ofMaterial :: initShaders") << shadersMap.size() << " | " << ofGetFrameNum();
651

652
			auto trendererShaders = shaders.find(&renderer);
653
			if( trendererShaders != shaders.end() ) {
654
				if(trendererShaders->second) {
655
					trendererShaders->second.reset();
656
				}
657
				shaders.erase(&renderer);
658
			}
659
			mShaderIdsToRemove.clear();
660
		}
661
	}
662

663
    auto rendererShaders = shaders.find(&renderer);
664
	
665
	size_t numLights = ofLightsData().size();
666
	// only support for a single cube map at a time
667
	size_t numCubeMaps = ofCubeMapsData().size() > 0 ? 1 : 0;
668
	const std::string shaderId = getShaderStringId();
669
	
670
	if(rendererShaders == shaders.end() ||
671
	   rendererShaders->second->numLights != numLights ||
672
	   rendererShaders->second->numCubeMaps != numCubeMaps ||
673
	   rendererShaders->second->shaderId != shaderId ){
674
		if(shadersMap[&renderer].find(shaderId)!=shadersMap[&renderer].end()){
675
			auto newShaders = shadersMap[&renderer][shaderId].lock();
676
			if(newShaders == nullptr || newShaders->numLights != numLights || newShaders->numCubeMaps != numCubeMaps ){
677
				shadersMap[&renderer].erase(shaderId);
678
				shaders[&renderer] = nullptr;
679
			}else{
680
				ofLogVerbose("ofMaterial") << "initShaders : swapping shaders | " << ofGetFrameNum();
681
				shaders[&renderer] = newShaders;
682
			}
683
		} else {
684
			shaders[&renderer] = nullptr;
685
		}
686
	}
687

688
    if(shaders[&renderer] == nullptr){
689
		ofLogVerbose("ofMaterial") << "initShaders : allocating shaders again | " << ofGetFrameNum();
690
        //add the custom uniforms to the shader header
691
        auto customUniforms = data.customUniforms;
692
        for( auto & custom : mCustomUniforms ){
693
        	customUniforms += custom.second + " " + custom.first + ";\n";
694
        }
695

696
		std::string definesString = getDefinesString();
697
		
698
		ofLogVerbose("ofMaterial") << " defines--------------- " << std::endl;
699
		ofLogVerbose("ofMaterial") << definesString;
700
		ofLogVerbose("ofMaterial") << "textures --------------- " << uniformstex.size();
701
		for (auto & uniform : uniformstex) {
702
			ofLogVerbose() << uniform.first << ", " << uniform.second.textureTarget <<", " << uniform.second.textureID << ", " << uniform.second.textureLocation << std::endl;
703
		}
704
		
705
		std::string extraVertString = definesString;
706
//		if( hasTexture(OF_MATERIAL_TEXTURE_DISPLACEMENT) ) {
707
//			extraVertString += "\nuniform SAMPLER "+getUniformName(OF_MATERIAL_TEXTURE_DISPLACEMENT)+";\n";
708
//		}
709
		extraVertString += customUniforms;
710
		ofLogVerbose( "ofMaterial" ) << " extraVertString------------------- ";
711
		ofLogVerbose() << extraVertString;
712
		ofLogVerbose( "ofMaterial" ) << "! extraVertString !------------------- " << std::endl;
713
     
714
        #ifndef TARGET_OPENGLES
715
            string vertexRectHeader = renderer.defaultVertexShaderHeader(GL_TEXTURE_RECTANGLE);
716
            string fragmentRectHeader = renderer.defaultFragmentShaderHeader(GL_TEXTURE_RECTANGLE);
717
        #endif
718
        string vertex2DHeader = renderer.defaultVertexShaderHeader(GL_TEXTURE_2D);
719
        string fragment2DHeader = renderer.defaultFragmentShaderHeader(GL_TEXTURE_2D);
720
		
721
		#if defined(TARGET_OPENGLES) && defined(TARGET_EMSCRIPTEN)
722
		// TODO: Should this be in programmable renderer?
723
		if(ofIsGLProgrammableRenderer()) {
724
//			if(isPBR()) {
725
//			header = "#version 300 es\n";// + header;
726
				vertex2DHeader = "#version "+ofGLSLVersionFromGL(renderer.getGLVersionMajor(), renderer.getGLVersionMinor())+"\n";
727
				vertex2DHeader += "precision highp float;\n";
728
				vertex2DHeader += "precision highp int;\n";
729
				vertex2DHeader += "#define TARGET_OPENGLES\n";
730
				vertex2DHeader += "#define IN in\n";
731
				vertex2DHeader += "#define OUT out\n";
732
				vertex2DHeader += "#define TEXTURE texture\n";
733
				vertex2DHeader += "#define SAMPLER sampler2D\n";
734

735
				fragment2DHeader = "#version "+ofGLSLVersionFromGL(renderer.getGLVersionMajor(), renderer.getGLVersionMinor())+"\n";
736
				fragment2DHeader += "precision highp float;\n";
737
				fragment2DHeader += "precision highp int;\n";
738
				fragment2DHeader += "#define TARGET_OPENGLES\n";
739
				fragment2DHeader += "#define IN in\n";
740
				fragment2DHeader += "#define OUT out\n";
741
				fragment2DHeader += "#define TEXTURE texture\n";
742
				fragment2DHeader += "#define FRAG_COLOR fragColor\n";
743
				fragment2DHeader += "out vec4 fragColor;\n";
744
				fragment2DHeader += "#define SAMPLER sampler2D\n";
745
				fragment2DHeader += "precision highp sampler2D;\n";
746
				fragment2DHeader += "precision highp samplerCube;\n";
747
				// we don't use any samplerCubeShadows
748
				//fragment2DHeader += "precision highp samplerCubeShadow;\n";
749
				fragment2DHeader += "precision mediump sampler2DShadow;\n";
750
				#if defined( GL_TEXTURE_2D_ARRAY ) && defined(glTexImage3D)
751
				fragment2DHeader += "precision mediump sampler2DArrayShadow;\n";
752
				#endif
753
//				fragment2DHeader += "precision highp samplerCubeShadow;\n";
754
//				fragment2DHeader += "precision highp sampler2DShadow;\n";
755
//				fragment2DHeader += "precision highp sampler2DArrayShadow;\n";
756
//			}
757
		}
758
		#endif
759
		
760
		ofLogVerbose( "ofMaterial" ) << " fragment2DHeader------------------- ";
761
		ofLogVerbose() << fragment2DHeader;
762
		ofLogVerbose( "ofMaterial" ) << " fragment2DHeader xxxxxxx ";
763

764
        shaders[&renderer].reset(new Shaders);
765
        shaders[&renderer]->numLights = numLights;
766
		shaders[&renderer]->numCubeMaps = numCubeMaps;
767
		shaders[&renderer]->shaderId = shaderId;
768
		
769
        shaders[&renderer]->noTexture.setupShaderFromSource(GL_VERTEX_SHADER,vertexSource(isPBR(),vertex2DHeader,numLights,false,false,extraVertString,data));
770
        shaders[&renderer]->noTexture.setupShaderFromSource(GL_FRAGMENT_SHADER,fragmentSource(isPBR(),fragment2DHeader, customUniforms, data,numLights,false,false, definesString));
771
        shaders[&renderer]->noTexture.bindDefaults();
772
        shaders[&renderer]->noTexture.linkProgram();
773

774
        shaders[&renderer]->texture2D.setupShaderFromSource(GL_VERTEX_SHADER,vertexSource(isPBR(),vertex2DHeader,numLights,true,false,extraVertString,data));
775
        shaders[&renderer]->texture2D.setupShaderFromSource(GL_FRAGMENT_SHADER,fragmentSource(isPBR(),fragment2DHeader, customUniforms, data,numLights,true,false,definesString));
776
        shaders[&renderer]->texture2D.bindDefaults();
777
        shaders[&renderer]->texture2D.linkProgram();
778

779
        #ifndef TARGET_OPENGLES
780
            shaders[&renderer]->textureRect.setupShaderFromSource(GL_VERTEX_SHADER,vertexSource(isPBR(),vertexRectHeader,numLights,true,false,extraVertString,data));
781
            shaders[&renderer]->textureRect.setupShaderFromSource(GL_FRAGMENT_SHADER,fragmentSource(isPBR(),fragmentRectHeader, customUniforms, data,numLights,true,false,definesString));
782
            shaders[&renderer]->textureRect.bindDefaults();
783
            shaders[&renderer]->textureRect.linkProgram();
784
        #endif
785

786
        shaders[&renderer]->color.setupShaderFromSource(GL_VERTEX_SHADER,vertexSource(isPBR(),vertex2DHeader,numLights,false,true,extraVertString,data));
787
        shaders[&renderer]->color.setupShaderFromSource(GL_FRAGMENT_SHADER,fragmentSource(isPBR(),fragment2DHeader, customUniforms, data,numLights,false,true, definesString));
788
        shaders[&renderer]->color.bindDefaults();
789
        shaders[&renderer]->color.linkProgram();
790

791

792
        shaders[&renderer]->texture2DColor.setupShaderFromSource(GL_VERTEX_SHADER,vertexSource(isPBR(),vertex2DHeader,numLights,true,true,extraVertString,data));
793
        shaders[&renderer]->texture2DColor.setupShaderFromSource(GL_FRAGMENT_SHADER,fragmentSource(isPBR(),fragment2DHeader, customUniforms, data,numLights,true,true,definesString));
794
        shaders[&renderer]->texture2DColor.bindDefaults();
795
        shaders[&renderer]->texture2DColor.linkProgram();
796

797
        #ifndef TARGET_OPENGLES
798
            shaders[&renderer]->textureRectColor.setupShaderFromSource(GL_VERTEX_SHADER,vertexSource(isPBR(),vertexRectHeader,numLights,true,true,extraVertString,data));
799
            shaders[&renderer]->textureRectColor.setupShaderFromSource(GL_FRAGMENT_SHADER,fragmentSource(isPBR(),fragmentRectHeader, customUniforms, data,numLights,true,true,definesString));
800
            shaders[&renderer]->textureRectColor.bindDefaults();
801
            shaders[&renderer]->textureRectColor.linkProgram();
802
        #endif
803

804
		shadersMap[&renderer][shaderId] = shaders[&renderer];
805
    }
806

807
}
808

809
const ofShader & ofMaterial::getShader(int textureTarget, bool geometryHasColor, ofGLProgrammableRenderer & renderer) const{
810
    initShaders(renderer);
811
	
812
	if(bHasCustomShader && customShader){
813
		return *customShader;
814
	}
815
	
816
	// override the textureTarget argument coming from the programmable renderer
817
	// the renderer is passing the textureTarget based on if there is a texture that is bound
818
	// if there is no texture bound, then go ahead and switch to the diffuse texture
819
	if(textureTarget == OF_NO_TEXTURE && hasTexture(OF_MATERIAL_TEXTURE_DIFFUSE) ) {
820
		const std::string loc = getUniformName(OF_MATERIAL_TEXTURE_DIFFUSE);
821
		const auto& dt = uniformstex.at(loc);
822
		textureTarget = dt.textureTarget;
823
	}
824
	
825
	switch(textureTarget){
826
	case OF_NO_TEXTURE:
827
        if(geometryHasColor){
828
            return shaders[&renderer]->color;
829
        }else{
830
            return shaders[&renderer]->noTexture;
831
        }
832
		break;
833
	case GL_TEXTURE_2D:
834
        if(geometryHasColor){
835
            return shaders[&renderer]->texture2DColor;
836
        }else{
837
            return shaders[&renderer]->texture2D;
838
        }
839
		break;
840
    default:
841
        if(geometryHasColor){
842
            return shaders[&renderer]->textureRectColor;
843
        }else{
844
            return shaders[&renderer]->textureRect;
845
        }
846
		break;
847
	}
848
}
849

850
void ofMaterial::updateMaterial(const ofShader & shader,ofGLProgrammableRenderer & renderer) const{
851
	currentRenderShader = &shader;
852
	
853
	shader.setUniform4fv("mat_emissive", &data.emissive.r);
854
	shader.setUniform2f("mat_texcoord_scale", data.texCoordScale );
855
	
856
	if( isPBR() ) {
857
		shader.setUniform3f("uCameraPos", renderer.getCurrentEyePosition());
858
		shader.setUniform4fv("mat_diffuse", &data.diffuse.r );
859
		shader.setUniform1f("mat_roughness", data.roughness );
860
		shader.setUniform1f("mat_metallic", data.metallic );
861
		shader.setUniform1f("mat_reflectance", data.reflectance );
862
		if( isClearCoatEnabled() ) {
863
			shader.setUniform2f("mat_clearcoat", data.clearCoatStrength, data.clearCoatRoughness );
864
		}
865
		
866
		if( hasTexture(OF_MATERIAL_TEXTURE_DISPLACEMENT) ) {
867
			shader.setUniform1f("mat_displacement_strength", data.displacementStrength );
868
			shader.setUniform1f("mat_displacement_normals_strength", data.displacementNormalsStrength );
869
		}
870
		if( hasTexture(OF_MATERIAL_TEXTURE_NORMAL) || hasTexture(OF_MATERIAL_TEXTURE_DISPLACEMENT) ) {
871
			shader.setUniform1f("mat_normal_mix", data.normalGeomToNormalMapMix );
872
		}
873
		
874
		std::shared_ptr<ofCubeMap::Data> cubeMapData = ofCubeMap::getActiveData();
875
		if( cubeMapData ) {
876
			shader.setUniform1f("mat_ibl_exposure", cubeMapData->exposure );
877
			shader.setUniform1f("uCubeMapEnabled", 1.0f );
878
			shader.setUniform1f("uEnvMapMaxMips", cubeMapData->maxMipLevels );
879
		} else {
880
			shader.setUniform1f("mat_ibl_exposure", 1.0f );
881
			shader.setUniform1f("uCubeMapEnabled", 0.0f );
882
			shader.setUniform1f("uEnvMapMaxMips", 1.0f );
883
		}
884
		
885
	} else {
886
		shader.setUniform4fv("mat_ambient", &data.ambient.r);
887
		shader.setUniform4fv("mat_diffuse", &data.diffuse.r);
888
		shader.setUniform4fv("mat_specular", &data.specular.r);
889
		shader.setUniform4fv("global_ambient", &ofGetGlobalAmbientColor().r);
890
		shader.setUniform1f("mat_shininess",data.shininess);
891
	}
892
	for(auto & uniform: uniforms1f){
893
		shader.setUniform1f(uniform.first, uniform.second);
894
	}
895
	for (auto & uniform : uniforms2f) {
896
		shader.setUniform2f(uniform.first, uniform.second);
897
	}
898
	for (auto & uniform : uniforms3f) {
899
		shader.setUniform3f(uniform.first, uniform.second);
900
	}
901
	for (auto & uniform : uniforms4f) {
902
		shader.setUniform4f(uniform.first, uniform.second);
903
	}
904
	for (auto & uniform : uniforms1i) {
905
		shader.setUniform1i(uniform.first, uniform.second);
906
	}
907
	for (auto & uniform : uniforms2i) {
908
		shader.setUniform2i(uniform.first, uniform.second.x, uniform.second.y);
909
	}
910
	for (auto & uniform : uniforms3i) {
911
		shader.setUniform3i(uniform.first, uniform.second.x, uniform.second.y, uniform.second.z);
912
	}
913
	for (auto & uniform : uniforms4i) {
914
		shader.setUniform4i(uniform.first, uniform.second.x, uniform.second.y, uniform.second.z, uniform.second.w);
915
	}
916
	for (auto & uniform : uniforms4m) {
917
		shader.setUniformMatrix4f(uniform.first, uniform.second);
918
	}
919
	for (auto & uniform : uniforms3m) {
920
		shader.setUniformMatrix3f(uniform.first, uniform.second);
921
	}
922
	for (auto & uniform : uniformstex) {
923
		shader.setUniformTexture(uniform.first,
924
								 uniform.second.textureTarget,
925
								 uniform.second.textureID,
926
								 uniform.second.textureLocation);
927
	}
928
}
929

930
void ofMaterial::updateLights(const ofShader & shader,ofGLProgrammableRenderer & renderer) const{
931
	for(size_t i=0;i<ofLightsData().size();i++){
932
		string idx = ofToString(i);
933
		shared_ptr<ofLight::Data> light = ofLightsData()[i].lock();
934
		if(!light || !light->isEnabled){
935
			shader.setUniform1f("lights["+idx+"].enabled",0);
936
			continue;
937
		}
938
		glm::vec4 lightEyePosition = light->position;
939
		// pbr uses global positions
940
		if( !isPBR() ) {
941
			if( light->lightType == OF_LIGHT_DIRECTIONAL ) {
942
				// support for reversed phong lighting setup
943
				lightEyePosition = renderer.getCurrentViewMatrix() * -light->position;
944
			} else {
945
				lightEyePosition = renderer.getCurrentViewMatrix() * light->position;
946
			}
947
		}
948

949
		if( isPBR() ) {
950
			if( light->lightType == OF_LIGHT_DIRECTIONAL ) {
951
				lightEyePosition = glm::vec4(-light->direction, lightEyePosition.w);
952
			}
953
			if( light->lightType != OF_LIGHT_POINT ) {
954
				shader.setUniform3f("lights["+idx+"].direction", light->direction );
955
			}
956
		}
957

958
		shader.setUniform1f("lights["+idx+"].enabled",1);
959
		shader.setUniform1f("lights["+idx+"].type", light->lightType);
960
		shader.setUniform4f("lights["+idx+"].position", lightEyePosition);
961
		if( !isPBR() ) {
962
			shader.setUniform4f("lights["+idx+"].ambient", light->ambientColor);
963
			shader.setUniform4f("lights["+idx+"].specular", light->specularColor);
964
		}
965
		shader.setUniform4f("lights["+idx+"].diffuse", light->diffuseColor);
966

967
		if(light->lightType!=OF_LIGHT_DIRECTIONAL){
968
			// TODO: add in light radius if pbr?
969
			shader.setUniform1f("lights["+idx+"].radius", 0.0f);
970
			shader.setUniform1f("lights["+idx+"].constantAttenuation", light->attenuation_constant);
971
			shader.setUniform1f("lights["+idx+"].linearAttenuation", light->attenuation_linear);
972
			shader.setUniform1f("lights["+idx+"].quadraticAttenuation", light->attenuation_quadratic);
973
		}
974

975
		if(light->lightType==OF_LIGHT_SPOT){
976
			// PBR light calcs are in world space
977
			glm::vec3 direction = light->direction;
978
			if( !isPBR() ) {
979
				direction = glm::vec3(light->position) + light->direction;
980
				glm::vec4 direction4 = renderer.getCurrentViewMatrix() * glm::vec4(direction,1.0);
981
				direction = glm::vec3(direction4) / direction4.w;
982
				direction = direction - glm::vec3(lightEyePosition);
983
				shader.setUniform3f("lights["+idx+"].spotDirection", glm::normalize(direction));
984
			}
985
			//shader.setUniform3f("lights["+idx+"].spotDirection", glm::normalize(direction));
986
			shader.setUniform1f("lights["+idx+"].spotExponent", light->exponent);
987
			shader.setUniform1f("lights["+idx+"].spotCutoff", light->spotCutOff);
988
			shader.setUniform1f("lights["+idx+"].spotCosCutoff", cos(ofDegToRad(light->spotCutOff)));
989
		}else if(light->lightType==OF_LIGHT_DIRECTIONAL){
990
			if( !isPBR() ) {
991
				glm::vec3 halfVector(glm::normalize(glm::vec4(0.f, 0.f, 1.f, 0.f) + lightEyePosition));
992
				shader.setUniform3f("lights["+idx+"].halfVector", halfVector);
993
			}
994
		}else if(light->lightType==OF_LIGHT_AREA){
995
			shader.setUniform1f("lights["+idx+"].width", light->width);
996
			shader.setUniform1f("lights["+idx+"].height", light->height);
997
			glm::vec3 direction = light->direction;
998
			if( !isPBR() ) {
999
				direction = glm::vec3(light->position) + light->direction;
1000
				glm::vec4 direction4 = renderer.getCurrentViewMatrix() * glm::vec4(direction, 1.0);
1001
				direction = glm::vec3(direction4) / direction4.w;
1002
				direction = direction - glm::vec3(lightEyePosition);
1003
				shader.setUniform3f("lights["+idx+"].spotDirection", glm::normalize(direction));
1004
			}
1005
			
1006
			auto right = light->right;
1007
			auto up = light->up;
1008
			if( !isPBR() ) {
1009
				right = glm::vec3(light->position) + light->right;
1010
				glm::vec4 right4 = renderer.getCurrentViewMatrix() * glm::vec4(right, 1.0);
1011
				right = glm::vec3(right4) / right4.w;
1012
				right = right - glm::vec3(lightEyePosition);
1013
				up = glm::cross(right, direction);
1014
			}
1015
			shader.setUniform3f("lights["+idx+"].right", glm::normalize(toGlm(right)));
1016
			shader.setUniform3f("lights["+idx+"].up", glm::normalize(up));
1017
		}
1018
	}
1019
}
1020

1021
void ofMaterial::updateShadows(const ofShader & shader,ofGLProgrammableRenderer & renderer) const {
1022
	// going to start above the highest tex location
1023
	shader.setShadowUniforms(getHighestUniformTextureLocation()+1);
1024
}
1025

1026
void ofMaterial::updateEnvironmentMaps(const ofShader & shader,ofGLProgrammableRenderer & renderer) const {
1027
	if( isPBR() ) {
1028
		// adding 4 to the offset to account for the shadows
1029
		shader.setPbrEnvironmentMapUniforms(getHighestUniformTextureLocation()+1+4);
1030
	}
1031
}
1032

1033
void ofMaterial::setCustomShader( std::shared_ptr<ofShader> aCustomShader) {
1034
	customShader = aCustomShader;
1035
	if( customShader ) {
1036
		bHasCustomShader = true;
1037
	}
1038
}
1039

1040
void ofMaterial::setCustomUniform1f(const std::string & name, float value){
1041
	uniforms1f[name] = value;
1042
	mCustomUniforms[name] = "uniform float";
1043
}
1044

1045
void ofMaterial::setCustomUniform2f(const std::string & name, glm::vec2 value){
1046
	uniforms2f[name] = value;
1047
	mCustomUniforms[name] = "uniform vec2";
1048
}
1049

1050
void ofMaterial::setCustomUniform3f(const std::string & name, glm::vec3 value) {
1051
	uniforms3f[name] = value;
1052
	mCustomUniforms[name] = "uniform vec3";
1053
}
1054

1055
void ofMaterial::setCustomUniform4f(const std::string & name, glm::vec4 value) {
1056
	uniforms4f[name] = value;
1057
	mCustomUniforms[name] = "uniform vec4";
1058
}
1059

1060
void ofMaterial::setCustomUniform1i(const std::string & name, int value) {
1061
	uniforms1i[name] = value;
1062
	mCustomUniforms[name] = "uniform int";
1063
}
1064

1065
void ofMaterial::setCustomUniform2i(const std::string & name, glm::vec<2,int> value) {
1066
	uniforms2i[name] = value;
1067
	mCustomUniforms[name] = "uniform ivec2";
1068
}
1069

1070
void ofMaterial::setCustomUniform3i(const std::string & name, glm::vec<3, int> value) {
1071
	uniforms3i[name] = value;
1072
	mCustomUniforms[name] = "uniform ivec3";
1073
}
1074

1075
void ofMaterial::setCustomUniform4i(const std::string & name, glm::vec<4, int> value) {
1076
	uniforms4i[name] = value;
1077
	mCustomUniforms[name] = "uniform ivec4";
1078
}
1079

1080
void ofMaterial::setCustomUniformMatrix4f(const std::string & name, glm::mat4 value){
1081
	uniforms4m[name] = value;
1082
	mCustomUniforms[name] = "uniform mat4";
1083
}
1084

1085
void ofMaterial::setCustomUniformMatrix3f(const std::string & name, glm::mat3 value){
1086
	uniforms3m[name] = value;
1087
	mCustomUniforms[name] = "uniform mat3";
1088
}
1089

1090
//--------------------------------------------------------
1091
void ofMaterial::setCustomUniformTexture(const std::string & name, const ofTexture & value ) {
1092
	setCustomUniformTexture(name, value.getTextureData().textureTarget, int(value.getTextureData().textureID) );
1093
}
1094

1095
//--------------------------------------------------------
1096
void ofMaterial::setCustomUniformTexture(const std::string & name, int textureTarget, GLint textureID){
1097
	
1098
	int textureLocation = -1;
1099
	// if the texture uniform name is not registered, then try to find a new location //
1100
	if( uniformstex.count(name) < 1 ) {
1101
		// not detected, lets get the next location
1102
		int newLoc = 1;
1103
		// set a max of 20 texture locations //
1104
		// going to start at 1 since OF will set the diffuse texture to 0
1105
		for( int i = 2; i < 20; i++ ) {
1106
			bool bAlreadyHas = false;
1107
			newLoc = i;
1108
			for( auto& iter : uniformstex ) {
1109
				if( iter.second.textureLocation == i ) {
1110
					bAlreadyHas = true;
1111
					break;
1112
				}
1113
			}
1114
			if( !bAlreadyHas ) {
1115
				textureLocation = newLoc;
1116
				break;
1117
			}
1118
		}
1119
		if( textureLocation < 0 ) {
1120
			ofLogWarning("ofMaterial") << "setCustomUniformTexture(): " << name << " auto textureLocation not detected";
1121
		} else {
1122
			ofLogVerbose("ofMaterial") << "setCustomUniformTexture(): add custom texture: " << name << " to textureLocation: " << textureLocation;
1123
		}
1124
	} else {
1125
		textureLocation = uniformstex[name].textureLocation;
1126
	}
1127
	
1128
	if( textureLocation > -1 ) {
1129
		setCustomUniformTexture(name, textureTarget, textureID, textureLocation);
1130
	}
1131
}
1132

1133
//--------------------------------------------------------
1134
void ofMaterial::setCustomUniformTexture(const std::string & name, const ofTexture & value, int textureLocation){
1135
	setCustomUniformTexture(name, value.getTextureData().textureTarget, int(value.getTextureData().textureID), textureLocation);
1136
}
1137

1138
//--------------------------------------------------------
1139
void ofMaterial::setCustomUniformTexture(const std::string & name, int textureTarget, GLint textureID, int textureLocation){
1140
	// only set the custom uniform and define if it is not the diffuse texture
1141
	// the texture shaders have HAS_TEXTURE and uniform SAMPLER tex0 already included
1142
	string shaderDefine = "";
1143
	if( name != getUniformName(OF_MATERIAL_TEXTURE_DIFFUSE) ) {
1144
		shaderDefine = "HAS_"+ofToUpper(name);
1145
		mCustomUniforms[name] = "uniform SAMPLER";
1146
		addShaderDefine(shaderDefine, "1" );
1147
	}
1148
	uniformstex[name] = {textureTarget, textureID, textureLocation, shaderDefine};
1149
}
1150

1151
//--------------------------------------------------------
1152
bool ofMaterial::removeCustomUniformTexture(const ofMaterialTextureType& aMaterialTextureType) {
1153
	return removeCustomUniformTexture(getUniformName(aMaterialTextureType));
1154
}
1155

1156
//--------------------------------------------------------
1157
bool ofMaterial::removeCustomUniformTexture(const std::string & name){
1158
	if( uniformstex.find(name) != uniformstex.end() ){
1159
		removeShaderDefine(uniformstex[name].shaderDefine);
1160
		uniformstex.erase(name);
1161
		return true;
1162
	}
1163
	return false;
1164
}
1165

1166
//--------------------------------------------------------
1167
int ofMaterial::getHighestUniformTextureLocation() const {
1168
	int max = 1;
1169
	for( auto& iter : uniformstex ) {
1170
		if( iter.second.textureLocation > max ) {
1171
			max = iter.second.textureLocation;
1172
		}
1173
	}
1174
	return max;
1175
}
1176

1177
//--------------------------------------------------------
1178
bool ofMaterial::hasTexture(const ofMaterialTextureType& aMaterialTextureType) const {
1179
	auto name = getUniformName(aMaterialTextureType);
1180
	if( uniformstex.find(name) != uniformstex.end() ){
1181
		return true;
1182
	}
1183
	return false;
1184
}
1185

1186
//--------------------------------------------------------
1187
void ofMaterial::addShaderDefine( const std::string & aDefineName ) {
1188
	addShaderDefine( aDefineName, "" );
1189
}
1190

1191
//--------------------------------------------------------
1192
void ofMaterial::addShaderDefine( const std::string & aDefineName, const std::string & aDefineValue ) {
1193
	if( aDefineName.empty() ) return;
1194
	
1195
	bool bUpdateDefines = false;
1196
	if( mDefines.count(aDefineName) < 1 ) {
1197
		bUpdateDefines = true;
1198
		mBDefinesDirty = true;
1199
	}
1200
	mDefines[aDefineName] = aDefineValue;
1201
	if( bUpdateDefines ) {
1202
		// update the unique id using uniqueIdString string //
1203
		data.uniqueIdString = "";
1204
		for( auto& def : mDefines ) {
1205
			data.uniqueIdString += def.first;
1206
		}
1207
	}
1208
}
1209

1210
//--------------------------------------------------------
1211
bool ofMaterial::removeShaderDefine( const std::string & aDefineName ) {
1212
	if( aDefineName.empty() ) return false;
1213
	
1214
	if(mDefines.count(aDefineName) > 0 ) {
1215
		mDefines.erase(aDefineName);
1216
		
1217
		// update the unique id using uniqueIdString string //
1218
		data.uniqueIdString = "";
1219
		for( auto& def : mDefines ) {
1220
			data.uniqueIdString += def.first;
1221
		}
1222
		
1223
		return true;
1224
	}
1225
	return false;
1226
}
1227

1228
//--------------------------------------------------------
1229
const std::string ofMaterial::getDefinesString() const {
1230
	std::string definesString = "";
1231
	for( auto& diter : mDefines ) {
1232
		definesString += "#define "+diter.first+" "+diter.second+"\n";
1233
	}
1234
	
1235
	if( isPBR() ) {
1236
		#ifdef TARGET_OPENGLES
1237
		definesString += "#define PBR_QUALITY_LEVEL_LOW 1 \n";
1238
		#else
1239
		definesString += "#define PBR_QUALITY_LEVEL_HIGH 1\n";
1240
		#endif
1241
	}
1242
	
1243
	if(isPBR() && ofCubeMapsData().size() > 0 && ofIsGLProgrammableRenderer() ) {
1244
//		const auto& cubeMapData = ofCubeMap::getActiveData();
1245
		
1246
		definesString += "#define HAS_CUBE_MAP 1\n";
1247
		
1248
		bool bHasIrradiance = false;
1249
		bool bPreFilteredMap = false;
1250
		bool bBrdfLutTex = false;
1251
		for( auto cmdWeak : ofCubeMapsData() ) {
1252
			auto cmd = cmdWeak.lock();
1253
			if( !cmd ) continue;
1254
			if( cmd->bIrradianceAllocated ) {
1255
				bHasIrradiance=true;
1256
			}
1257
			if( cmd->bPreFilteredMapAllocated ) {
1258
				bPreFilteredMap=true;
1259
			}
1260
			if( cmd->settings.useLutTex && ofCubeMap::getBrdfLutTexture().isAllocated() ) {
1261
				bBrdfLutTex=true;
1262
			}
1263
		}
1264
		
1265
		if(bHasIrradiance) {
1266
			definesString += "#define HAS_TEX_ENV_IRRADIANCE 1\n";
1267
		}
1268
		if(bPreFilteredMap) {
1269
			definesString += "#define HAS_TEX_ENV_PRE_FILTER 1\n";
1270
		}
1271
		if(bBrdfLutTex) {
1272
			definesString += "#define HAS_TEX_ENV_BRDF_LUT 1\n";
1273
		}
1274
		// need to add .0 to be read as a float in the shader for gl es
1275
		//definesString += "#define ENV_MAP_MAX_MIPS "+ofToString(ofCubeMap::getNumMipMaps(),0)+".0\n";
1276
		
1277
	}
1278
	
1279
	definesString += ofShadow::getShaderDefinesAsString();
1280
	return definesString;
1281
}
1282

1283

1284
#include "shaders/phong.vert"
1285
#include "shaders/phong.frag"
1286
#include "shaders/shadow.glsl"
1287

1288
#include "shaders/shaderUtils.glsl"
1289
#include "shaders/pbrMaterial.glsl"
1290
#include "shaders/pbrData.glsl"
1291
#include "shaders/pbrLightingFuncs.glsl"
1292
#include "shaders/pbrLighting.glsl"
1293
#include "shaders/pbrLightIBL.glsl"
1294

1295
#include "shaders/pbr.vert"
1296
#include "shaders/pbr.frag"
1297

1298

1299
namespace{
1300
    string shaderHeader(string header, int maxLights, bool hasTexture, bool hasColor){
1301
//        header += "#define MAX_LIGHTS " + ofToString(std::max(1,maxLights)) + "\n";
1302
		header += "#define MAX_LIGHTS " + ofToString(maxLights) + "\n";
1303
		
1304
        if(hasTexture){
1305
            header += "#define HAS_TEXTURE 1\n";
1306
		} else {
1307
			header += "#define HAS_TEXTURE 0\n";
1308
		}
1309
        if(hasColor){
1310
            header += "#define HAS_COLOR 1\n";
1311
		} else {
1312
			header += "#define HAS_COLOR 0\n";
1313
		}
1314
		
1315
        return header;
1316
    }
1317

1318
	//string vertexSource(bool bPBR, string defaultHeader, int maxLights, bool hasTexture, bool hasColor, std::string addShaderSrc){
1319
	string vertexSource(bool bPBR, string defaultHeader, int maxLights, bool hasTexture, bool hasColor, std::string addShaderSrc, const ofMaterialSettings& adata){
1320
		auto source = bPBR ? shader_pbr_vert : vertexShader;
1321
		if( bPBR ) {
1322
			ofStringReplace(source, "%additional_includes%", addShaderSrc);
1323
		} else {
1324
			ofStringReplace(source, "%additional_includes%", "");
1325
		}
1326

1327
		if( bPBR ) {
1328
			string mainVertex = adata.mainVertex;
1329
			if( mainVertex.empty() ) {
1330
				mainVertex = shader_pbr_main_vert;
1331
			}
1332
			ofStringReplace(source, "%mainVertex%", mainVertex);
1333
		}
1334

1335
        return shaderHeader(defaultHeader, maxLights, hasTexture, hasColor) + source;
1336
    }
1337
	// const ofMaterialSettings& adata
1338
	string fragmentSource(bool bPBR, string defaultHeader, string customUniforms, const ofMaterialSettings& adata, int maxLights, bool hasTexture, bool hasColor, string definesString){
1339
    // string fragmentSource(bool bPBR, string defaultHeader, string customUniforms, string postFragment, int maxLights, bool hasTexture, bool hasColor, string definesString){
1340
        auto source = bPBR ? shader_pbr_frag : fragmentShader;
1341
		
1342
		string postFragment = adata.postFragment;
1343
        if(postFragment.empty()){
1344
            postFragment = "vec4 postFragment(vec4 localColor){ return localColor; }";
1345
        }
1346
        ofStringReplace(source, "%postFragment%", postFragment);
1347
        ofStringReplace(source, "%custom_uniforms%", customUniforms);
1348

1349
		if( bPBR ) {
1350
			string mainFrag = adata.mainFragment;
1351
			if( mainFrag.empty() ) {
1352
				if(bPBR) {
1353
					mainFrag = shader_pbr_main_frag;
1354
				}
1355
			}
1356
			ofStringReplace(source, "%mainFragment%", mainFrag);
1357
		}
1358
		
1359
		if(bPBR) {
1360
			string addIncludes = shader_utils;
1361
			addIncludes += shader_pbr_material;
1362
			addIncludes += shader_pbr_lighting_funcs;
1363
			addIncludes += shader_pbr_data;
1364
			addIncludes += shader_pbr_lighting;
1365
			addIncludes += shader_pbr_lighting_ibl;
1366
			// set PBR includes here
1367
			ofStringReplace(source, "%additional_includes%", addIncludes);
1368
		}
1369
		
1370
		
1371
		if( ofIsGLProgrammableRenderer() ) {
1372
			#if defined(TARGET_OPENGLES)
1373
				#if defined(TARGET_EMSCRIPTEN)
1374
					ofStringReplace(source, "%shader_shadow_include%", shadow_shader_include );
1375
				#else
1376
					ofStringReplace(source, "%shader_shadow_include%", "" );
1377
				#endif
1378
			#else
1379
				ofStringReplace(source, "%shader_shadow_include%", shadow_shader_include );
1380
			#endif
1381
		} else {
1382
			ofStringReplace(source, "%shader_shadow_include%", "" );
1383
		}
1384
		
1385
        source = shaderHeader(defaultHeader, maxLights, hasTexture, hasColor) + definesString + source;
1386
        return source;
1387
    }
1388
}
1389

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

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

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

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