framework2
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
10using std::shared_ptr;
11using std::string;
12
13std::unordered_map<ofGLProgrammableRenderer*, std::unordered_map<std::string, std::weak_ptr<ofMaterial::Shaders>>> ofMaterial::shadersMap;
14
15namespace{
16string vertexSource(bool bPBR, string defaultHeader, int maxLights, bool hasTexture, bool hasColor, std::string addShaderSrc,const ofMaterialSettings& adata);
17string fragmentSource(bool bPBR, string defaultHeader, string customUniforms, const ofMaterialSettings& adata, int maxLights, bool hasTexture, bool hasColor, std::string definesString="");
18}
19
20//----------------------------------------------------------
21ofMaterial::ofMaterial() {
22}
23
24//----------------------------------------------------------
25std::string ofMaterial::getUniformName( const ofMaterialTextureType& aMaterialTextureType ) {
26switch(aMaterialTextureType) {
27case OF_MATERIAL_TEXTURE_DIFFUSE:
28return "tex0";
29case OF_MATERIAL_TEXTURE_SPECULAR:
30return "tex_specular";
31case OF_MATERIAL_TEXTURE_AMBIENT:
32return "tex_ambient";
33case OF_MATERIAL_TEXTURE_EMISSIVE:
34return "tex_emissive";
35case OF_MATERIAL_TEXTURE_NORMAL:
36return "tex_normal";
37case OF_MATERIAL_TEXTURE_OCCLUSION:
38return "tex_occlusion";
39case OF_MATERIAL_TEXTURE_AO_ROUGHNESS_METALLIC:
40return "tex_ao_roughness_metallic";
41case OF_MATERIAL_TEXTURE_ROUGHNESS_METALLIC:
42return "tex_roughness_metallic";
43case OF_MATERIAL_TEXTURE_ROUGHNESS:
44return "tex_roughness";
45case OF_MATERIAL_TEXTURE_METALLIC:
46return "tex_metallic";
47case OF_MATERIAL_TEXTURE_DISPLACEMENT:
48return "tex_displacement";
49case OF_MATERIAL_TEXTURE_CLEARCOAT:
50return "tex_clearcoat_intensity";
51case OF_MATERIAL_TEXTURE_CLEARCOAT_ROUGHNESS:
52return "tex_clearcoat_roughness";
53case OF_MATERIAL_TEXTURE_CLEARCOAT_INTENSITY_ROUGHNESS:
54return "tex_clearcoat_intensity_roughness";
55case OF_MATERIAL_TEXTURE_CLEARCOAT_NORMAL:
56return "tex_clearcoat_normal";
57default:
58break;
59}
60return "";
61}
62
63//----------------------------------------------------------
64bool ofMaterial::isPBRSupported() {
65#if defined(TARGET_OPENGLES) && !defined(TARGET_EMSCRIPTEN)
66return false;
67#endif
68
69if( !ofIsGLProgrammableRenderer() ) {
70return false;
71}
72return true;
73}
74
75//----------------------------------------------------------
76void ofMaterial::setPBR(bool ab) {
77if( ab && !ofIsGLProgrammableRenderer() ) {
78if( !bPrintedPBRRenderWarning ) {
79bPrintedPBRRenderWarning=true;
80ofLogWarning("ofMaterial::setPBR") << " PBR material must be used with Programmable Renderer.";
81}
82data.isPbr = false;
83return;
84}
85
86#if defined(TARGET_OPENGLES) && !defined(TARGET_EMSCRIPTEN)
87if( ab ) {
88if( !bPrintedPBRRenderWarning ) {
89bPrintedPBRRenderWarning=true;
90ofLogWarning("ofMaterial::setPBR") << " PBR material is not supported on this OPENGL ES platform.";
91}
92data.isPbr = false;
93return;
94}
95#endif
96
97
98data.isPbr = ab;
99}
100
101//----------------------------------------------------------
102void ofMaterial::setColors(ofFloatColor oDiffuse, ofFloatColor oAmbient, ofFloatColor oSpecular, ofFloatColor oEmissive) {
103setDiffuseColor(oDiffuse);
104setAmbientColor(oAmbient);
105setSpecularColor(oSpecular);
106setEmissiveColor(oEmissive);
107}
108
109//----------------------------------------------------------
110void ofMaterial::setup(const ofMaterialSettings & settings){
111if(settings.customUniforms != data.customUniforms || settings.postFragment != data.postFragment ||
112settings.mainVertexKey != data.mainVertexKey || settings.mainFragmentKey != data.mainFragmentKey ||
113settings.isPbr != data.isPbr){
114shaders.clear();
115uniforms1f.clear();
116uniforms2f.clear();
117uniforms3f.clear();
118uniforms4f.clear();
119uniforms1i.clear();
120uniforms2i.clear();
121uniforms3i.clear();
122uniforms4i.clear();
123mCustomUniforms.clear();
124mDefines.clear();
125mBDefinesDirty = true;
126}
127data = settings;
128setClearCoatEnabled(data.clearCoatEnabled);
129}
130
131//----------------------------------------------------------
132void ofMaterial::setShaderMain(std::string aShaderSrc, GLenum atype, std::string skey) {
133if(!isPBR()) {
134ofLogWarning("ofMaterial::setShaderMain") << "only available on PBR materials.";
135return;
136}
137
138if(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
141if( data.mainVertexKey == skey) {
142// delete previous shader here, whether frag shader has same key or not
143std::string sid = getShaderStringId();
144mShaderIdsToRemove[sid]++;
145}
146data.mainVertex = aShaderSrc;
147data.mainVertexKey = skey;
148} else if( atype == GL_FRAGMENT_SHADER ) {
149if( data.mainFragmentKey == skey) {
150// delete previous shader here, whether frag shader has same key or not
151std::string sid = getShaderStringId();
152mShaderIdsToRemove[sid]++;
153}
154data.mainFragment = aShaderSrc;
155data.mainFragmentKey = skey;
156}
157}
158
159//----------------------------------------------------------
160void ofMaterial::setDiffuseColor(ofFloatColor oDiffuse) {
161data.diffuse = oDiffuse;
162if( isBound() && currentRenderShader) {
163currentRenderShader->setUniform4fv("mat_diffuse", &data.diffuse.r );
164}
165}
166
167//----------------------------------------------------------
168void ofMaterial::setAmbientColor(ofFloatColor oAmbient) {
169data.ambient = oAmbient;
170if( isBound() && !isPBR() && currentRenderShader) {
171currentRenderShader->setUniform4fv("mat_ambient", &data.ambient.r);
172}
173}
174
175//----------------------------------------------------------
176void ofMaterial::setSpecularColor(ofFloatColor oSpecular) {
177data.specular = oSpecular;
178if( isBound() && !isPBR() && currentRenderShader) {
179currentRenderShader->setUniform4fv("mat_specular", &data.specular.r);
180}
181}
182
183//----------------------------------------------------------
184void ofMaterial::setEmissiveColor(ofFloatColor oEmissive) {
185data.emissive = oEmissive;
186if( isBound() && currentRenderShader) {
187currentRenderShader->setUniform4fv("mat_emissive", &data.emissive.r);
188}
189}
190
191//----------------------------------------------------------
192void ofMaterial::setShininess(float nShininess) {
193data.shininess = nShininess;
194if( isBound() && !isPBR() && currentRenderShader) {
195currentRenderShader->setUniform1f("mat_shininess",data.shininess);
196}
197}
198
199//----------------------------------------------------------
200void ofMaterial::setTexCoordScale( float xscale, float yscale ) {
201data.texCoordScale.x = xscale;
202data.texCoordScale.y = yscale;
203if( isBound() && currentRenderShader) {
204currentRenderShader->setUniform2f("mat_texcoord_scale", data.texCoordScale );
205}
206}
207
208//----------------------------------------------------------
209bool ofMaterial::loadTexture( const ofMaterialTextureType& aMaterialTextureType, std::string apath ) {
210return loadTexture(aMaterialTextureType, apath, ofGetUsingArbTex(), false);
211}
212
213//----------------------------------------------------------
214bool ofMaterial::loadTexture( const ofMaterialTextureType& aMaterialTextureType, std::string apath, bool bTex2d, bool mirrorY ) {
215ofPixels tpix;
216bool bWasUsingArb = ofGetUsingArbTex();
217bTex2d ? ofEnableArbTex() : ofDisableArbTex();
218
219bool bLoadOk = false;
220
221if( ofLoadImage( tpix, apath )) {
222if( mirrorY ) {
223tpix.mirror(mirrorY, false);
224}
225bLoadOk = true;
226// if there was a previous instance, then erase it, then replace it
227if( mLocalTextures.find(aMaterialTextureType) != mLocalTextures.end() ) {
228if( mLocalTextures[aMaterialTextureType] ) {
229mLocalTextures[aMaterialTextureType].reset();
230}
231mLocalTextures.erase(aMaterialTextureType);
232}
233
234auto tex = std::make_shared<ofTexture>();
235tex->loadData(tpix);
236mLocalTextures[aMaterialTextureType] = tex;
237setTexture( aMaterialTextureType, *tex );
238} else {
239ofLogError("ofMaterial") << "loadTexture(): FAILED for " << getUniformName(aMaterialTextureType) << " at path: " << apath;
240}
241
242bWasUsingArb ? ofEnableArbTex() : ofDisableArbTex();
243return bLoadOk;
244}
245
246//----------------------------------------------------------
247bool ofMaterial::isPBRTexture(const ofMaterialTextureType& aMaterialTextureType) {
248return aMaterialTextureType >= (int)OF_MATERIAL_TEXTURE_AO_ROUGHNESS_METALLIC;
249}
250
251//----------------------------------------------------------
252void ofMaterial::setTexture(const ofMaterialTextureType& aMaterialTextureType,const ofTexture & aTex) {
253if(isBound()) {
254ofLogWarning("ofMaterial::setTexture") << " must set texture when material is not bound.";
255return;
256}
257if( !isPBR() ) {
258if(isPBRTexture(aMaterialTextureType)) {
259ofLogVerbose("ofMaterial::setTexture") << " setting material to pbr.";
260setPBR(true);
261}
262}
263
264
265
266if(aMaterialTextureType == OF_MATERIAL_TEXTURE_CLEARCOAT ||
267aMaterialTextureType == OF_MATERIAL_TEXTURE_CLEARCOAT_ROUGHNESS ||
268aMaterialTextureType == OF_MATERIAL_TEXTURE_CLEARCOAT_INTENSITY_ROUGHNESS ) {
269if( aTex.isAllocated() ) {
270setClearCoatEnabled(true);
271}
272}
273setCustomUniformTexture(getUniformName(aMaterialTextureType), aTex);
274mergeCustomUniformTextures();
275}
276
277//----------------------------------------------------------
278void ofMaterial::setDiffuseTexture(const ofTexture & aTex) {
279setTexture(OF_MATERIAL_TEXTURE_DIFFUSE, aTex);
280}
281
282//----------------------------------------------------------
283void ofMaterial::setSpecularTexture(const ofTexture & aTex){
284setTexture(OF_MATERIAL_TEXTURE_SPECULAR, aTex);
285}
286
287//----------------------------------------------------------
288void ofMaterial::setAmbientTexture(const ofTexture & aTex){
289setTexture(OF_MATERIAL_TEXTURE_AMBIENT, aTex);
290}
291
292//----------------------------------------------------------
293void ofMaterial::setEmissiveTexture(const ofTexture & aTex){
294setTexture(OF_MATERIAL_TEXTURE_EMISSIVE, aTex);
295}
296
297//----------------------------------------------------------
298void ofMaterial::setNormalTexture(const ofTexture & aTex){
299setTexture(OF_MATERIAL_TEXTURE_NORMAL, aTex);
300}
301
302//----------------------------------------------------------
303void ofMaterial::setOcclusionTexture(const ofTexture & aTex){
304setTexture(OF_MATERIAL_TEXTURE_OCCLUSION, aTex);
305}
306
307//----------------------------------------------------
308void ofMaterial::setAoRoughnessMetallicTexture(const ofTexture & aTex) {
309// r: occlusion, g: roughness, b: metallic
310setTexture(OF_MATERIAL_TEXTURE_AO_ROUGHNESS_METALLIC, aTex );
311}
312
313//----------------------------------------------------
314void ofMaterial::setRoughnessMetallicTexture(const ofTexture & aTex) {
315// r: n/a, g: roughness, b: metallic
316setTexture(OF_MATERIAL_TEXTURE_ROUGHNESS_METALLIC, aTex);
317}
318
319//----------------------------------------------------
320void ofMaterial::setRoughnessTexture(const ofTexture & aTex) {
321setTexture(OF_MATERIAL_TEXTURE_ROUGHNESS, aTex);
322}
323
324//----------------------------------------------------
325void ofMaterial::setMetallicTexture(const ofTexture & aTex) {
326setTexture(OF_MATERIAL_TEXTURE_METALLIC, aTex);
327}
328
329//----------------------------------------------------
330void ofMaterial::setDisplacementTexture(const ofTexture & aTex) {
331setTexture(OF_MATERIAL_TEXTURE_DISPLACEMENT, aTex);
332}
333
334//----------------------------------------------------
335void ofMaterial::setClearCoatTexture( const ofTexture& aTex ) {
336setTexture(OF_MATERIAL_TEXTURE_CLEARCOAT, aTex );
337}
338
339//----------------------------------------------------
340void ofMaterial::setMetallic( const float& ametallic ) {
341data.metallic = ametallic;
342
343if( isBound() && isPBR() && currentRenderShader) {
344currentRenderShader->setUniform1f("mat_metallic", data.metallic );
345}
346if( !isPBR() ) {
347setPBR(true);
348}
349}
350
351//----------------------------------------------------
352void ofMaterial::setRoughness( const float& aroughness ) {
353data.roughness = aroughness;
354if( isBound() && isPBR() && currentRenderShader) {
355currentRenderShader->setUniform1f("mat_roughness", data.roughness );
356}
357if( !isPBR() ) {
358setPBR(true);
359}
360}
361
362//----------------------------------------------------
363void ofMaterial::setReflectance( const float& areflectance ) {
364data.reflectance = areflectance;
365if( isBound() && isPBR() && currentRenderShader) {
366currentRenderShader->setUniform1f("mat_reflectance", data.reflectance );
367}
368if( !isPBR() ) {
369setPBR(true);
370}
371}
372
373//----------------------------------------------------
374void ofMaterial::setClearCoatEnabled( bool ab ) {
375if(isBound()) {
376ofLogWarning("ofMaterial::setClearCoatEnabled") << " must be called when material is not bound.";
377return;
378}
379if( !isPBR() ) {
380setPBR(true);
381}
382data.clearCoatEnabled = ab;
383if(ab) {
384addShaderDefine( "HAS_CLEAR_COAT", "1" );
385} else {
386removeShaderDefine( "HAS_CLEAR_COAT" );
387}
388}
389
390//----------------------------------------------------
391void ofMaterial::setClearCoatStrength( const float& astrength ) {
392data.clearCoatStrength = astrength;
393if( isClearCoatEnabled() && isBound() && isPBR() && currentRenderShader ) {
394currentRenderShader->setUniform2f("mat_clearcoat", data.clearCoatStrength, data.clearCoatRoughness );
395}
396if( !isPBR() ) {
397setPBR(true);
398}
399}
400
401//----------------------------------------------------
402void ofMaterial::setClearCoatRoughness( const float& aroughness ) {
403data.clearCoatRoughness = aroughness;
404if( isClearCoatEnabled() && isBound() && isPBR() && currentRenderShader ) {
405currentRenderShader->setUniform2f("mat_clearcoat", data.clearCoatStrength, data.clearCoatRoughness );
406}
407if( !isPBR() ) {
408setPBR(true);
409}
410}
411
412//----------------------------------------------------------
413void ofMaterial::setDisplacementStrength( const float& astrength ) {
414data.displacementStrength = astrength;
415if(isBound() && isPBR() && currentRenderShader ) {
416if( hasTexture(OF_MATERIAL_TEXTURE_DISPLACEMENT) ) {
417currentRenderShader->setUniform1f("mat_displacement_strength", data.displacementStrength );
418}
419}
420if( !isPBR() ) {
421setPBR(true);
422}
423}
424
425//----------------------------------------------------------
426void ofMaterial::setDisplacementNormalsStrength( const float& astrength ) {
427data.displacementNormalsStrength = astrength;
428if(isBound() && isPBR() && currentRenderShader ) {
429if( hasTexture(OF_MATERIAL_TEXTURE_DISPLACEMENT) ) {
430currentRenderShader->setUniform1f("mat_displacement_normals_strength", data.displacementNormalsStrength );
431}
432}
433}
434
435//----------------------------------------------------------
436void ofMaterial::setNormalGeomToNormalMapMix( const float& astrength ) {
437data.normalGeomToNormalMapMix = astrength;
438if(isBound() && isPBR() && currentRenderShader ) {
439if( hasTexture(OF_MATERIAL_TEXTURE_NORMAL) || hasTexture(OF_MATERIAL_TEXTURE_DISPLACEMENT) ) {
440currentRenderShader->setUniform1f("mat_normal_mix", data.normalGeomToNormalMapMix );
441}
442}
443}
444
445//----------------------------------------------------------
446void ofMaterial::setData(const ofMaterial::Data &data){
447setup(data);
448}
449
450//----------------------------------------------------------
451float ofMaterial::getShininess()const{
452return data.shininess;
453}
454
455//----------------------------------------------------
456float ofMaterial::getMetallic() const {
457return data.metallic;
458}
459
460//----------------------------------------------------
461float ofMaterial::getRoughness() const {
462return data.roughness;
463}
464
465//----------------------------------------------------
466float ofMaterial::getReflectance() const {
467return data.reflectance;
468}
469
470//----------------------------------------------------
471bool ofMaterial::isClearCoatEnabled() const {
472return data.clearCoatEnabled;
473}
474
475//----------------------------------------------------
476float ofMaterial::getClearCoatStrength() const {
477return data.clearCoatStrength;
478}
479
480//----------------------------------------------------
481float ofMaterial::getClearCoatRoughness() const {
482return data.clearCoatRoughness;
483}
484
485//----------------------------------------------------
486float ofMaterial::getDisplacementStrength() const {
487return data.displacementStrength;
488}
489
490//----------------------------------------------------
491float ofMaterial::getDisplacementNormalsStrength() const {
492return data.displacementNormalsStrength;
493}
494
495//----------------------------------------------------
496float ofMaterial::getNormalGeomToNormalMapMix() const {
497return data.normalGeomToNormalMapMix;
498}
499
500//----------------------------------------------------------
501ofFloatColor ofMaterial::getDiffuseColor()const {
502return data.diffuse;
503}
504
505//----------------------------------------------------------
506ofFloatColor ofMaterial::getAmbientColor()const {
507return data.ambient;
508}
509
510//----------------------------------------------------------
511ofFloatColor ofMaterial::getSpecularColor()const {
512return data.specular;
513}
514
515//----------------------------------------------------------
516ofFloatColor ofMaterial::getEmissiveColor()const {
517return data.emissive;
518}
519
520//----------------------------------------------------------
521ofMaterialSettings ofMaterial::getSettings() const{
522return data;
523}
524
525//-----------------------------------------------------------
526void ofMaterial::begin() const{
527if(ofGetGLRenderer()){
528ofGetGLRenderer()->bind(*this);
529}
530}
531
532//----------------------------------------------------------
533void ofMaterial::end() const{
534if(ofGetGLRenderer()){
535ofGetGLRenderer()->unbind(*this);
536}
537}
538
539//----------------------------------------------------------
540void ofMaterial::uploadMatrices(const ofShader & shader,ofGLProgrammableRenderer & renderer) const {
541if(!isPBR()) {
542ofBaseMaterial::uploadMatrices(shader, renderer);
543}
544}
545
546//-----------------------------------------------------------
547void ofMaterial::mergeCustomUniformTextures() {
548mergeCustomUniformTextures(OF_MATERIAL_TEXTURE_ROUGHNESS_METALLIC, {
549OF_MATERIAL_TEXTURE_ROUGHNESS,
550OF_MATERIAL_TEXTURE_METALLIC
551} );
552
553mergeCustomUniformTextures(OF_MATERIAL_TEXTURE_ROUGHNESS_METALLIC, {
554OF_MATERIAL_TEXTURE_OCCLUSION,
555OF_MATERIAL_TEXTURE_ROUGHNESS_METALLIC
556} );
557
558mergeCustomUniformTextures(OF_MATERIAL_TEXTURE_AO_ROUGHNESS_METALLIC, {
559OF_MATERIAL_TEXTURE_OCCLUSION,
560OF_MATERIAL_TEXTURE_ROUGHNESS,
561OF_MATERIAL_TEXTURE_METALLIC
562} );
563}
564
565//-----------------------------------------------------------
566void ofMaterial::mergeCustomUniformTextures(ofMaterialTextureType mainType, std::vector<ofMaterialTextureType> mergeTypes) {
567size_t mtsSize = mergeTypes.size();
568if(!hasTexture(mainType) && mtsSize > 1){
569bool bHasAllMergeTypes = true;
570GLint texID;
571int texTarget;
572bool bMatchingTextures = true;
573int minTexLocation = 99999;
574
575for(size_t i = 0; i < mtsSize; i++ ) {
576if(!hasTexture(mergeTypes[i])){
577bHasAllMergeTypes = false;
578bMatchingTextures = false;
579break;
580} else {
581auto rtex = getCustomUniformTexture(mergeTypes[i]);
582if(i == 0 ) {
583texID = rtex.textureID;
584texTarget = rtex.textureTarget;
585}
586if( rtex.textureTarget != texTarget || rtex.textureID != texID ) {
587bMatchingTextures = false;
588break;
589} else {
590if( rtex.textureLocation < minTexLocation ) {
591minTexLocation = rtex.textureLocation;
592}
593}
594}
595}
596
597if(bHasAllMergeTypes && bMatchingTextures && minTexLocation < 1000){
598for(size_t i = 0; i < mtsSize; i++ ) {
599removeCustomUniformTexture(mergeTypes[i]);
600}
601setCustomUniformTexture( getUniformName(mainType), texTarget, texID, minTexLocation );
602}
603}
604}
605
606//-----------------------------------------------------------
607ofMaterial::TextureUnifom ofMaterial::getCustomUniformTexture(const ofMaterialTextureType& aMaterialTextureType){
608return getCustomUniformTexture(getUniformName(aMaterialTextureType));
609}
610
611//-----------------------------------------------------------
612ofMaterial::TextureUnifom ofMaterial::getCustomUniformTexture(const std::string & name){
613if(uniformstex.find(name) != uniformstex.end()){
614return uniformstex[name];
615}
616return TextureUnifom{};
617}
618
619// called from ofGLProgrammableRenderer
620//-----------------------------------------------------------
621void ofMaterial::unbind(ofGLProgrammableRenderer & renderer) const {
622mBound = false;
623currentRenderShader = nullptr;
624}
625
626//-----------------------------------------------------------
627const std::string ofMaterial::getShaderStringId() const {
628std::string pbrStr = "pbr-yes";
629if(!isPBR()) {
630pbrStr = "pbr-no";
631}
632return pbrStr+data.uniqueIdString+data.postFragment+data.mainVertexKey+data.mainFragmentKey;
633}
634
635//-----------------------------------------------------------
636void ofMaterial::initShaders(ofGLProgrammableRenderer & renderer) const{
637// remove any shaders that have their main source remove
638{
639if( mShaderIdsToRemove.size() ) {
640for( auto& sids : mShaderIdsToRemove ) {
641if(shadersMap[&renderer].find(sids.first)!=shadersMap[&renderer].end()){
642auto newShaders = shadersMap[&renderer][sids.first].lock();
643if( newShaders ) {
644newShaders.reset();
645}
646shadersMap[&renderer].erase(sids.first);
647}
648}
649
650ofLogVerbose("ofMaterial :: initShaders") << shadersMap.size() << " | " << ofGetFrameNum();
651
652auto trendererShaders = shaders.find(&renderer);
653if( trendererShaders != shaders.end() ) {
654if(trendererShaders->second) {
655trendererShaders->second.reset();
656}
657shaders.erase(&renderer);
658}
659mShaderIdsToRemove.clear();
660}
661}
662
663auto rendererShaders = shaders.find(&renderer);
664
665size_t numLights = ofLightsData().size();
666// only support for a single cube map at a time
667size_t numCubeMaps = ofCubeMapsData().size() > 0 ? 1 : 0;
668const std::string shaderId = getShaderStringId();
669
670if(rendererShaders == shaders.end() ||
671rendererShaders->second->numLights != numLights ||
672rendererShaders->second->numCubeMaps != numCubeMaps ||
673rendererShaders->second->shaderId != shaderId ){
674if(shadersMap[&renderer].find(shaderId)!=shadersMap[&renderer].end()){
675auto newShaders = shadersMap[&renderer][shaderId].lock();
676if(newShaders == nullptr || newShaders->numLights != numLights || newShaders->numCubeMaps != numCubeMaps ){
677shadersMap[&renderer].erase(shaderId);
678shaders[&renderer] = nullptr;
679}else{
680ofLogVerbose("ofMaterial") << "initShaders : swapping shaders | " << ofGetFrameNum();
681shaders[&renderer] = newShaders;
682}
683} else {
684shaders[&renderer] = nullptr;
685}
686}
687
688if(shaders[&renderer] == nullptr){
689ofLogVerbose("ofMaterial") << "initShaders : allocating shaders again | " << ofGetFrameNum();
690//add the custom uniforms to the shader header
691auto customUniforms = data.customUniforms;
692for( auto & custom : mCustomUniforms ){
693customUniforms += custom.second + " " + custom.first + ";\n";
694}
695
696std::string definesString = getDefinesString();
697
698ofLogVerbose("ofMaterial") << " defines--------------- " << std::endl;
699ofLogVerbose("ofMaterial") << definesString;
700ofLogVerbose("ofMaterial") << "textures --------------- " << uniformstex.size();
701for (auto & uniform : uniformstex) {
702ofLogVerbose() << uniform.first << ", " << uniform.second.textureTarget <<", " << uniform.second.textureID << ", " << uniform.second.textureLocation << std::endl;
703}
704
705std::string extraVertString = definesString;
706// if( hasTexture(OF_MATERIAL_TEXTURE_DISPLACEMENT) ) {
707// extraVertString += "\nuniform SAMPLER "+getUniformName(OF_MATERIAL_TEXTURE_DISPLACEMENT)+";\n";
708// }
709extraVertString += customUniforms;
710ofLogVerbose( "ofMaterial" ) << " extraVertString------------------- ";
711ofLogVerbose() << extraVertString;
712ofLogVerbose( "ofMaterial" ) << "! extraVertString !------------------- " << std::endl;
713
714#ifndef TARGET_OPENGLES
715string vertexRectHeader = renderer.defaultVertexShaderHeader(GL_TEXTURE_RECTANGLE);
716string fragmentRectHeader = renderer.defaultFragmentShaderHeader(GL_TEXTURE_RECTANGLE);
717#endif
718string vertex2DHeader = renderer.defaultVertexShaderHeader(GL_TEXTURE_2D);
719string fragment2DHeader = renderer.defaultFragmentShaderHeader(GL_TEXTURE_2D);
720
721#if defined(TARGET_OPENGLES) && defined(TARGET_EMSCRIPTEN)
722// TODO: Should this be in programmable renderer?
723if(ofIsGLProgrammableRenderer()) {
724// if(isPBR()) {
725// header = "#version 300 es\n";// + header;
726vertex2DHeader = "#version "+ofGLSLVersionFromGL(renderer.getGLVersionMajor(), renderer.getGLVersionMinor())+"\n";
727vertex2DHeader += "precision highp float;\n";
728vertex2DHeader += "precision highp int;\n";
729vertex2DHeader += "#define TARGET_OPENGLES\n";
730vertex2DHeader += "#define IN in\n";
731vertex2DHeader += "#define OUT out\n";
732vertex2DHeader += "#define TEXTURE texture\n";
733vertex2DHeader += "#define SAMPLER sampler2D\n";
734
735fragment2DHeader = "#version "+ofGLSLVersionFromGL(renderer.getGLVersionMajor(), renderer.getGLVersionMinor())+"\n";
736fragment2DHeader += "precision highp float;\n";
737fragment2DHeader += "precision highp int;\n";
738fragment2DHeader += "#define TARGET_OPENGLES\n";
739fragment2DHeader += "#define IN in\n";
740fragment2DHeader += "#define OUT out\n";
741fragment2DHeader += "#define TEXTURE texture\n";
742fragment2DHeader += "#define FRAG_COLOR fragColor\n";
743fragment2DHeader += "out vec4 fragColor;\n";
744fragment2DHeader += "#define SAMPLER sampler2D\n";
745fragment2DHeader += "precision highp sampler2D;\n";
746fragment2DHeader += "precision highp samplerCube;\n";
747// we don't use any samplerCubeShadows
748//fragment2DHeader += "precision highp samplerCubeShadow;\n";
749fragment2DHeader += "precision mediump sampler2DShadow;\n";
750#if defined( GL_TEXTURE_2D_ARRAY ) && defined(glTexImage3D)
751fragment2DHeader += "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
760ofLogVerbose( "ofMaterial" ) << " fragment2DHeader------------------- ";
761ofLogVerbose() << fragment2DHeader;
762ofLogVerbose( "ofMaterial" ) << " fragment2DHeader xxxxxxx ";
763
764shaders[&renderer].reset(new Shaders);
765shaders[&renderer]->numLights = numLights;
766shaders[&renderer]->numCubeMaps = numCubeMaps;
767shaders[&renderer]->shaderId = shaderId;
768
769shaders[&renderer]->noTexture.setupShaderFromSource(GL_VERTEX_SHADER,vertexSource(isPBR(),vertex2DHeader,numLights,false,false,extraVertString,data));
770shaders[&renderer]->noTexture.setupShaderFromSource(GL_FRAGMENT_SHADER,fragmentSource(isPBR(),fragment2DHeader, customUniforms, data,numLights,false,false, definesString));
771shaders[&renderer]->noTexture.bindDefaults();
772shaders[&renderer]->noTexture.linkProgram();
773
774shaders[&renderer]->texture2D.setupShaderFromSource(GL_VERTEX_SHADER,vertexSource(isPBR(),vertex2DHeader,numLights,true,false,extraVertString,data));
775shaders[&renderer]->texture2D.setupShaderFromSource(GL_FRAGMENT_SHADER,fragmentSource(isPBR(),fragment2DHeader, customUniforms, data,numLights,true,false,definesString));
776shaders[&renderer]->texture2D.bindDefaults();
777shaders[&renderer]->texture2D.linkProgram();
778
779#ifndef TARGET_OPENGLES
780shaders[&renderer]->textureRect.setupShaderFromSource(GL_VERTEX_SHADER,vertexSource(isPBR(),vertexRectHeader,numLights,true,false,extraVertString,data));
781shaders[&renderer]->textureRect.setupShaderFromSource(GL_FRAGMENT_SHADER,fragmentSource(isPBR(),fragmentRectHeader, customUniforms, data,numLights,true,false,definesString));
782shaders[&renderer]->textureRect.bindDefaults();
783shaders[&renderer]->textureRect.linkProgram();
784#endif
785
786shaders[&renderer]->color.setupShaderFromSource(GL_VERTEX_SHADER,vertexSource(isPBR(),vertex2DHeader,numLights,false,true,extraVertString,data));
787shaders[&renderer]->color.setupShaderFromSource(GL_FRAGMENT_SHADER,fragmentSource(isPBR(),fragment2DHeader, customUniforms, data,numLights,false,true, definesString));
788shaders[&renderer]->color.bindDefaults();
789shaders[&renderer]->color.linkProgram();
790
791
792shaders[&renderer]->texture2DColor.setupShaderFromSource(GL_VERTEX_SHADER,vertexSource(isPBR(),vertex2DHeader,numLights,true,true,extraVertString,data));
793shaders[&renderer]->texture2DColor.setupShaderFromSource(GL_FRAGMENT_SHADER,fragmentSource(isPBR(),fragment2DHeader, customUniforms, data,numLights,true,true,definesString));
794shaders[&renderer]->texture2DColor.bindDefaults();
795shaders[&renderer]->texture2DColor.linkProgram();
796
797#ifndef TARGET_OPENGLES
798shaders[&renderer]->textureRectColor.setupShaderFromSource(GL_VERTEX_SHADER,vertexSource(isPBR(),vertexRectHeader,numLights,true,true,extraVertString,data));
799shaders[&renderer]->textureRectColor.setupShaderFromSource(GL_FRAGMENT_SHADER,fragmentSource(isPBR(),fragmentRectHeader, customUniforms, data,numLights,true,true,definesString));
800shaders[&renderer]->textureRectColor.bindDefaults();
801shaders[&renderer]->textureRectColor.linkProgram();
802#endif
803
804shadersMap[&renderer][shaderId] = shaders[&renderer];
805}
806
807}
808
809const ofShader & ofMaterial::getShader(int textureTarget, bool geometryHasColor, ofGLProgrammableRenderer & renderer) const{
810initShaders(renderer);
811
812if(bHasCustomShader && customShader){
813return *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
819if(textureTarget == OF_NO_TEXTURE && hasTexture(OF_MATERIAL_TEXTURE_DIFFUSE) ) {
820const std::string loc = getUniformName(OF_MATERIAL_TEXTURE_DIFFUSE);
821const auto& dt = uniformstex.at(loc);
822textureTarget = dt.textureTarget;
823}
824
825switch(textureTarget){
826case OF_NO_TEXTURE:
827if(geometryHasColor){
828return shaders[&renderer]->color;
829}else{
830return shaders[&renderer]->noTexture;
831}
832break;
833case GL_TEXTURE_2D:
834if(geometryHasColor){
835return shaders[&renderer]->texture2DColor;
836}else{
837return shaders[&renderer]->texture2D;
838}
839break;
840default:
841if(geometryHasColor){
842return shaders[&renderer]->textureRectColor;
843}else{
844return shaders[&renderer]->textureRect;
845}
846break;
847}
848}
849
850void ofMaterial::updateMaterial(const ofShader & shader,ofGLProgrammableRenderer & renderer) const{
851currentRenderShader = &shader;
852
853shader.setUniform4fv("mat_emissive", &data.emissive.r);
854shader.setUniform2f("mat_texcoord_scale", data.texCoordScale );
855
856if( isPBR() ) {
857shader.setUniform3f("uCameraPos", renderer.getCurrentEyePosition());
858shader.setUniform4fv("mat_diffuse", &data.diffuse.r );
859shader.setUniform1f("mat_roughness", data.roughness );
860shader.setUniform1f("mat_metallic", data.metallic );
861shader.setUniform1f("mat_reflectance", data.reflectance );
862if( isClearCoatEnabled() ) {
863shader.setUniform2f("mat_clearcoat", data.clearCoatStrength, data.clearCoatRoughness );
864}
865
866if( hasTexture(OF_MATERIAL_TEXTURE_DISPLACEMENT) ) {
867shader.setUniform1f("mat_displacement_strength", data.displacementStrength );
868shader.setUniform1f("mat_displacement_normals_strength", data.displacementNormalsStrength );
869}
870if( hasTexture(OF_MATERIAL_TEXTURE_NORMAL) || hasTexture(OF_MATERIAL_TEXTURE_DISPLACEMENT) ) {
871shader.setUniform1f("mat_normal_mix", data.normalGeomToNormalMapMix );
872}
873
874std::shared_ptr<ofCubeMap::Data> cubeMapData = ofCubeMap::getActiveData();
875if( cubeMapData ) {
876shader.setUniform1f("mat_ibl_exposure", cubeMapData->exposure );
877shader.setUniform1f("uCubeMapEnabled", 1.0f );
878shader.setUniform1f("uEnvMapMaxMips", cubeMapData->maxMipLevels );
879} else {
880shader.setUniform1f("mat_ibl_exposure", 1.0f );
881shader.setUniform1f("uCubeMapEnabled", 0.0f );
882shader.setUniform1f("uEnvMapMaxMips", 1.0f );
883}
884
885} else {
886shader.setUniform4fv("mat_ambient", &data.ambient.r);
887shader.setUniform4fv("mat_diffuse", &data.diffuse.r);
888shader.setUniform4fv("mat_specular", &data.specular.r);
889shader.setUniform4fv("global_ambient", &ofGetGlobalAmbientColor().r);
890shader.setUniform1f("mat_shininess",data.shininess);
891}
892for(auto & uniform: uniforms1f){
893shader.setUniform1f(uniform.first, uniform.second);
894}
895for (auto & uniform : uniforms2f) {
896shader.setUniform2f(uniform.first, uniform.second);
897}
898for (auto & uniform : uniforms3f) {
899shader.setUniform3f(uniform.first, uniform.second);
900}
901for (auto & uniform : uniforms4f) {
902shader.setUniform4f(uniform.first, uniform.second);
903}
904for (auto & uniform : uniforms1i) {
905shader.setUniform1i(uniform.first, uniform.second);
906}
907for (auto & uniform : uniforms2i) {
908shader.setUniform2i(uniform.first, uniform.second.x, uniform.second.y);
909}
910for (auto & uniform : uniforms3i) {
911shader.setUniform3i(uniform.first, uniform.second.x, uniform.second.y, uniform.second.z);
912}
913for (auto & uniform : uniforms4i) {
914shader.setUniform4i(uniform.first, uniform.second.x, uniform.second.y, uniform.second.z, uniform.second.w);
915}
916for (auto & uniform : uniforms4m) {
917shader.setUniformMatrix4f(uniform.first, uniform.second);
918}
919for (auto & uniform : uniforms3m) {
920shader.setUniformMatrix3f(uniform.first, uniform.second);
921}
922for (auto & uniform : uniformstex) {
923shader.setUniformTexture(uniform.first,
924uniform.second.textureTarget,
925uniform.second.textureID,
926uniform.second.textureLocation);
927}
928}
929
930void ofMaterial::updateLights(const ofShader & shader,ofGLProgrammableRenderer & renderer) const{
931for(size_t i=0;i<ofLightsData().size();i++){
932string idx = ofToString(i);
933shared_ptr<ofLight::Data> light = ofLightsData()[i].lock();
934if(!light || !light->isEnabled){
935shader.setUniform1f("lights["+idx+"].enabled",0);
936continue;
937}
938glm::vec4 lightEyePosition = light->position;
939// pbr uses global positions
940if( !isPBR() ) {
941if( light->lightType == OF_LIGHT_DIRECTIONAL ) {
942// support for reversed phong lighting setup
943lightEyePosition = renderer.getCurrentViewMatrix() * -light->position;
944} else {
945lightEyePosition = renderer.getCurrentViewMatrix() * light->position;
946}
947}
948
949if( isPBR() ) {
950if( light->lightType == OF_LIGHT_DIRECTIONAL ) {
951lightEyePosition = glm::vec4(-light->direction, lightEyePosition.w);
952}
953if( light->lightType != OF_LIGHT_POINT ) {
954shader.setUniform3f("lights["+idx+"].direction", light->direction );
955}
956}
957
958shader.setUniform1f("lights["+idx+"].enabled",1);
959shader.setUniform1f("lights["+idx+"].type", light->lightType);
960shader.setUniform4f("lights["+idx+"].position", lightEyePosition);
961if( !isPBR() ) {
962shader.setUniform4f("lights["+idx+"].ambient", light->ambientColor);
963shader.setUniform4f("lights["+idx+"].specular", light->specularColor);
964}
965shader.setUniform4f("lights["+idx+"].diffuse", light->diffuseColor);
966
967if(light->lightType!=OF_LIGHT_DIRECTIONAL){
968// TODO: add in light radius if pbr?
969shader.setUniform1f("lights["+idx+"].radius", 0.0f);
970shader.setUniform1f("lights["+idx+"].constantAttenuation", light->attenuation_constant);
971shader.setUniform1f("lights["+idx+"].linearAttenuation", light->attenuation_linear);
972shader.setUniform1f("lights["+idx+"].quadraticAttenuation", light->attenuation_quadratic);
973}
974
975if(light->lightType==OF_LIGHT_SPOT){
976// PBR light calcs are in world space
977glm::vec3 direction = light->direction;
978if( !isPBR() ) {
979direction = glm::vec3(light->position) + light->direction;
980glm::vec4 direction4 = renderer.getCurrentViewMatrix() * glm::vec4(direction,1.0);
981direction = glm::vec3(direction4) / direction4.w;
982direction = direction - glm::vec3(lightEyePosition);
983shader.setUniform3f("lights["+idx+"].spotDirection", glm::normalize(direction));
984}
985//shader.setUniform3f("lights["+idx+"].spotDirection", glm::normalize(direction));
986shader.setUniform1f("lights["+idx+"].spotExponent", light->exponent);
987shader.setUniform1f("lights["+idx+"].spotCutoff", light->spotCutOff);
988shader.setUniform1f("lights["+idx+"].spotCosCutoff", cos(ofDegToRad(light->spotCutOff)));
989}else if(light->lightType==OF_LIGHT_DIRECTIONAL){
990if( !isPBR() ) {
991glm::vec3 halfVector(glm::normalize(glm::vec4(0.f, 0.f, 1.f, 0.f) + lightEyePosition));
992shader.setUniform3f("lights["+idx+"].halfVector", halfVector);
993}
994}else if(light->lightType==OF_LIGHT_AREA){
995shader.setUniform1f("lights["+idx+"].width", light->width);
996shader.setUniform1f("lights["+idx+"].height", light->height);
997glm::vec3 direction = light->direction;
998if( !isPBR() ) {
999direction = glm::vec3(light->position) + light->direction;
1000glm::vec4 direction4 = renderer.getCurrentViewMatrix() * glm::vec4(direction, 1.0);
1001direction = glm::vec3(direction4) / direction4.w;
1002direction = direction - glm::vec3(lightEyePosition);
1003shader.setUniform3f("lights["+idx+"].spotDirection", glm::normalize(direction));
1004}
1005
1006auto right = light->right;
1007auto up = light->up;
1008if( !isPBR() ) {
1009right = glm::vec3(light->position) + light->right;
1010glm::vec4 right4 = renderer.getCurrentViewMatrix() * glm::vec4(right, 1.0);
1011right = glm::vec3(right4) / right4.w;
1012right = right - glm::vec3(lightEyePosition);
1013up = glm::cross(right, direction);
1014}
1015shader.setUniform3f("lights["+idx+"].right", glm::normalize(toGlm(right)));
1016shader.setUniform3f("lights["+idx+"].up", glm::normalize(up));
1017}
1018}
1019}
1020
1021void ofMaterial::updateShadows(const ofShader & shader,ofGLProgrammableRenderer & renderer) const {
1022// going to start above the highest tex location
1023shader.setShadowUniforms(getHighestUniformTextureLocation()+1);
1024}
1025
1026void ofMaterial::updateEnvironmentMaps(const ofShader & shader,ofGLProgrammableRenderer & renderer) const {
1027if( isPBR() ) {
1028// adding 4 to the offset to account for the shadows
1029shader.setPbrEnvironmentMapUniforms(getHighestUniformTextureLocation()+1+4);
1030}
1031}
1032
1033void ofMaterial::setCustomShader( std::shared_ptr<ofShader> aCustomShader) {
1034customShader = aCustomShader;
1035if( customShader ) {
1036bHasCustomShader = true;
1037}
1038}
1039
1040void ofMaterial::setCustomUniform1f(const std::string & name, float value){
1041uniforms1f[name] = value;
1042mCustomUniforms[name] = "uniform float";
1043}
1044
1045void ofMaterial::setCustomUniform2f(const std::string & name, glm::vec2 value){
1046uniforms2f[name] = value;
1047mCustomUniforms[name] = "uniform vec2";
1048}
1049
1050void ofMaterial::setCustomUniform3f(const std::string & name, glm::vec3 value) {
1051uniforms3f[name] = value;
1052mCustomUniforms[name] = "uniform vec3";
1053}
1054
1055void ofMaterial::setCustomUniform4f(const std::string & name, glm::vec4 value) {
1056uniforms4f[name] = value;
1057mCustomUniforms[name] = "uniform vec4";
1058}
1059
1060void ofMaterial::setCustomUniform1i(const std::string & name, int value) {
1061uniforms1i[name] = value;
1062mCustomUniforms[name] = "uniform int";
1063}
1064
1065void ofMaterial::setCustomUniform2i(const std::string & name, glm::vec<2,int> value) {
1066uniforms2i[name] = value;
1067mCustomUniforms[name] = "uniform ivec2";
1068}
1069
1070void ofMaterial::setCustomUniform3i(const std::string & name, glm::vec<3, int> value) {
1071uniforms3i[name] = value;
1072mCustomUniforms[name] = "uniform ivec3";
1073}
1074
1075void ofMaterial::setCustomUniform4i(const std::string & name, glm::vec<4, int> value) {
1076uniforms4i[name] = value;
1077mCustomUniforms[name] = "uniform ivec4";
1078}
1079
1080void ofMaterial::setCustomUniformMatrix4f(const std::string & name, glm::mat4 value){
1081uniforms4m[name] = value;
1082mCustomUniforms[name] = "uniform mat4";
1083}
1084
1085void ofMaterial::setCustomUniformMatrix3f(const std::string & name, glm::mat3 value){
1086uniforms3m[name] = value;
1087mCustomUniforms[name] = "uniform mat3";
1088}
1089
1090//--------------------------------------------------------
1091void ofMaterial::setCustomUniformTexture(const std::string & name, const ofTexture & value ) {
1092setCustomUniformTexture(name, value.getTextureData().textureTarget, int(value.getTextureData().textureID) );
1093}
1094
1095//--------------------------------------------------------
1096void ofMaterial::setCustomUniformTexture(const std::string & name, int textureTarget, GLint textureID){
1097
1098int textureLocation = -1;
1099// if the texture uniform name is not registered, then try to find a new location //
1100if( uniformstex.count(name) < 1 ) {
1101// not detected, lets get the next location
1102int 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
1105for( int i = 2; i < 20; i++ ) {
1106bool bAlreadyHas = false;
1107newLoc = i;
1108for( auto& iter : uniformstex ) {
1109if( iter.second.textureLocation == i ) {
1110bAlreadyHas = true;
1111break;
1112}
1113}
1114if( !bAlreadyHas ) {
1115textureLocation = newLoc;
1116break;
1117}
1118}
1119if( textureLocation < 0 ) {
1120ofLogWarning("ofMaterial") << "setCustomUniformTexture(): " << name << " auto textureLocation not detected";
1121} else {
1122ofLogVerbose("ofMaterial") << "setCustomUniformTexture(): add custom texture: " << name << " to textureLocation: " << textureLocation;
1123}
1124} else {
1125textureLocation = uniformstex[name].textureLocation;
1126}
1127
1128if( textureLocation > -1 ) {
1129setCustomUniformTexture(name, textureTarget, textureID, textureLocation);
1130}
1131}
1132
1133//--------------------------------------------------------
1134void ofMaterial::setCustomUniformTexture(const std::string & name, const ofTexture & value, int textureLocation){
1135setCustomUniformTexture(name, value.getTextureData().textureTarget, int(value.getTextureData().textureID), textureLocation);
1136}
1137
1138//--------------------------------------------------------
1139void 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
1142string shaderDefine = "";
1143if( name != getUniformName(OF_MATERIAL_TEXTURE_DIFFUSE) ) {
1144shaderDefine = "HAS_"+ofToUpper(name);
1145mCustomUniforms[name] = "uniform SAMPLER";
1146addShaderDefine(shaderDefine, "1" );
1147}
1148uniformstex[name] = {textureTarget, textureID, textureLocation, shaderDefine};
1149}
1150
1151//--------------------------------------------------------
1152bool ofMaterial::removeCustomUniformTexture(const ofMaterialTextureType& aMaterialTextureType) {
1153return removeCustomUniformTexture(getUniformName(aMaterialTextureType));
1154}
1155
1156//--------------------------------------------------------
1157bool ofMaterial::removeCustomUniformTexture(const std::string & name){
1158if( uniformstex.find(name) != uniformstex.end() ){
1159removeShaderDefine(uniformstex[name].shaderDefine);
1160uniformstex.erase(name);
1161return true;
1162}
1163return false;
1164}
1165
1166//--------------------------------------------------------
1167int ofMaterial::getHighestUniformTextureLocation() const {
1168int max = 1;
1169for( auto& iter : uniformstex ) {
1170if( iter.second.textureLocation > max ) {
1171max = iter.second.textureLocation;
1172}
1173}
1174return max;
1175}
1176
1177//--------------------------------------------------------
1178bool ofMaterial::hasTexture(const ofMaterialTextureType& aMaterialTextureType) const {
1179auto name = getUniformName(aMaterialTextureType);
1180if( uniformstex.find(name) != uniformstex.end() ){
1181return true;
1182}
1183return false;
1184}
1185
1186//--------------------------------------------------------
1187void ofMaterial::addShaderDefine( const std::string & aDefineName ) {
1188addShaderDefine( aDefineName, "" );
1189}
1190
1191//--------------------------------------------------------
1192void ofMaterial::addShaderDefine( const std::string & aDefineName, const std::string & aDefineValue ) {
1193if( aDefineName.empty() ) return;
1194
1195bool bUpdateDefines = false;
1196if( mDefines.count(aDefineName) < 1 ) {
1197bUpdateDefines = true;
1198mBDefinesDirty = true;
1199}
1200mDefines[aDefineName] = aDefineValue;
1201if( bUpdateDefines ) {
1202// update the unique id using uniqueIdString string //
1203data.uniqueIdString = "";
1204for( auto& def : mDefines ) {
1205data.uniqueIdString += def.first;
1206}
1207}
1208}
1209
1210//--------------------------------------------------------
1211bool ofMaterial::removeShaderDefine( const std::string & aDefineName ) {
1212if( aDefineName.empty() ) return false;
1213
1214if(mDefines.count(aDefineName) > 0 ) {
1215mDefines.erase(aDefineName);
1216
1217// update the unique id using uniqueIdString string //
1218data.uniqueIdString = "";
1219for( auto& def : mDefines ) {
1220data.uniqueIdString += def.first;
1221}
1222
1223return true;
1224}
1225return false;
1226}
1227
1228//--------------------------------------------------------
1229const std::string ofMaterial::getDefinesString() const {
1230std::string definesString = "";
1231for( auto& diter : mDefines ) {
1232definesString += "#define "+diter.first+" "+diter.second+"\n";
1233}
1234
1235if( isPBR() ) {
1236#ifdef TARGET_OPENGLES
1237definesString += "#define PBR_QUALITY_LEVEL_LOW 1 \n";
1238#else
1239definesString += "#define PBR_QUALITY_LEVEL_HIGH 1\n";
1240#endif
1241}
1242
1243if(isPBR() && ofCubeMapsData().size() > 0 && ofIsGLProgrammableRenderer() ) {
1244// const auto& cubeMapData = ofCubeMap::getActiveData();
1245
1246definesString += "#define HAS_CUBE_MAP 1\n";
1247
1248bool bHasIrradiance = false;
1249bool bPreFilteredMap = false;
1250bool bBrdfLutTex = false;
1251for( auto cmdWeak : ofCubeMapsData() ) {
1252auto cmd = cmdWeak.lock();
1253if( !cmd ) continue;
1254if( cmd->bIrradianceAllocated ) {
1255bHasIrradiance=true;
1256}
1257if( cmd->bPreFilteredMapAllocated ) {
1258bPreFilteredMap=true;
1259}
1260if( cmd->settings.useLutTex && ofCubeMap::getBrdfLutTexture().isAllocated() ) {
1261bBrdfLutTex=true;
1262}
1263}
1264
1265if(bHasIrradiance) {
1266definesString += "#define HAS_TEX_ENV_IRRADIANCE 1\n";
1267}
1268if(bPreFilteredMap) {
1269definesString += "#define HAS_TEX_ENV_PRE_FILTER 1\n";
1270}
1271if(bBrdfLutTex) {
1272definesString += "#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
1279definesString += ofShadow::getShaderDefinesAsString();
1280return 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
1299namespace{
1300string shaderHeader(string header, int maxLights, bool hasTexture, bool hasColor){
1301// header += "#define MAX_LIGHTS " + ofToString(std::max(1,maxLights)) + "\n";
1302header += "#define MAX_LIGHTS " + ofToString(maxLights) + "\n";
1303
1304if(hasTexture){
1305header += "#define HAS_TEXTURE 1\n";
1306} else {
1307header += "#define HAS_TEXTURE 0\n";
1308}
1309if(hasColor){
1310header += "#define HAS_COLOR 1\n";
1311} else {
1312header += "#define HAS_COLOR 0\n";
1313}
1314
1315return header;
1316}
1317
1318//string vertexSource(bool bPBR, string defaultHeader, int maxLights, bool hasTexture, bool hasColor, std::string addShaderSrc){
1319string vertexSource(bool bPBR, string defaultHeader, int maxLights, bool hasTexture, bool hasColor, std::string addShaderSrc, const ofMaterialSettings& adata){
1320auto source = bPBR ? shader_pbr_vert : vertexShader;
1321if( bPBR ) {
1322ofStringReplace(source, "%additional_includes%", addShaderSrc);
1323} else {
1324ofStringReplace(source, "%additional_includes%", "");
1325}
1326
1327if( bPBR ) {
1328string mainVertex = adata.mainVertex;
1329if( mainVertex.empty() ) {
1330mainVertex = shader_pbr_main_vert;
1331}
1332ofStringReplace(source, "%mainVertex%", mainVertex);
1333}
1334
1335return shaderHeader(defaultHeader, maxLights, hasTexture, hasColor) + source;
1336}
1337// const ofMaterialSettings& adata
1338string 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){
1340auto source = bPBR ? shader_pbr_frag : fragmentShader;
1341
1342string postFragment = adata.postFragment;
1343if(postFragment.empty()){
1344postFragment = "vec4 postFragment(vec4 localColor){ return localColor; }";
1345}
1346ofStringReplace(source, "%postFragment%", postFragment);
1347ofStringReplace(source, "%custom_uniforms%", customUniforms);
1348
1349if( bPBR ) {
1350string mainFrag = adata.mainFragment;
1351if( mainFrag.empty() ) {
1352if(bPBR) {
1353mainFrag = shader_pbr_main_frag;
1354}
1355}
1356ofStringReplace(source, "%mainFragment%", mainFrag);
1357}
1358
1359if(bPBR) {
1360string addIncludes = shader_utils;
1361addIncludes += shader_pbr_material;
1362addIncludes += shader_pbr_lighting_funcs;
1363addIncludes += shader_pbr_data;
1364addIncludes += shader_pbr_lighting;
1365addIncludes += shader_pbr_lighting_ibl;
1366// set PBR includes here
1367ofStringReplace(source, "%additional_includes%", addIncludes);
1368}
1369
1370
1371if( ofIsGLProgrammableRenderer() ) {
1372#if defined(TARGET_OPENGLES)
1373#if defined(TARGET_EMSCRIPTEN)
1374ofStringReplace(source, "%shader_shadow_include%", shadow_shader_include );
1375#else
1376ofStringReplace(source, "%shader_shadow_include%", "" );
1377#endif
1378#else
1379ofStringReplace(source, "%shader_shadow_include%", shadow_shader_include );
1380#endif
1381} else {
1382ofStringReplace(source, "%shader_shadow_include%", "" );
1383}
1384
1385source = shaderHeader(defaultHeader, maxLights, hasTexture, hasColor) + definesString + source;
1386return source;
1387}
1388}
1389