12 #ifndef hifi_model_Material_h
13 #define hifi_model_Material_h
18 #include <unordered_map>
21 #include <ColorUtils.h>
23 #include <gpu/Resource.h>
24 #include <gpu/TextureTable.h>
26 #include "MaterialMappingMode.h"
33 typedef std::shared_ptr< TextureMap > TextureMapPointer;
47 OPACITY_TRANSLUCENT_MAP_BIT,
49 OPACITY_CUTOFF_VAL_BIT,
70 typedef std::bitset<NUM_FLAGS> Flags;
86 OPACITY_MAP_OPAQUE = 0,
90 static std::string getOpacityMapModeName(OpacityMapMode mode);
92 static bool getOpacityMapModeFromName(
const std::string& modeName, OpacityMapMode& mode);
101 static std::string getCullFaceModeName(CullFaceMode mode);
102 static bool getCullFaceModeFromName(
const std::string& modeName, CullFaceMode& mode);
107 MaterialKey() : _flags(0) {}
108 MaterialKey(
const Flags& flags) : _flags(flags) {}
115 MaterialKey build()
const {
return MaterialKey(_flags); }
117 Builder& withEmissive() { _flags.set(EMISSIVE_VAL_BIT);
return (*
this); }
118 Builder& withUnlit() { _flags.set(UNLIT_VAL_BIT);
return (*
this); }
120 Builder& withAlbedo() { _flags.set(ALBEDO_VAL_BIT);
return (*
this); }
121 Builder& withMetallic() { _flags.set(METALLIC_VAL_BIT);
return (*
this); }
122 Builder& withGlossy() { _flags.set(GLOSSY_VAL_BIT);
return (*
this); }
124 Builder& withTranslucentFactor() { _flags.set(OPACITY_VAL_BIT);
return (*
this); }
125 Builder& withTranslucentMap() { _flags.set(OPACITY_TRANSLUCENT_MAP_BIT);
return (*
this); }
126 Builder& withMaskMap() { _flags.set(OPACITY_MASK_MAP_BIT);
return (*
this); }
127 Builder& withOpacityMapMode(OpacityMapMode mode) {
129 case OPACITY_MAP_OPAQUE:
130 _flags.reset(OPACITY_TRANSLUCENT_MAP_BIT);
131 _flags.reset(OPACITY_MASK_MAP_BIT);
133 case OPACITY_MAP_MASK:
134 _flags.reset(OPACITY_TRANSLUCENT_MAP_BIT);
135 _flags.set(OPACITY_MASK_MAP_BIT);
137 case OPACITY_MAP_BLEND:
138 _flags.set(OPACITY_TRANSLUCENT_MAP_BIT);
139 _flags.reset(OPACITY_MASK_MAP_BIT);
142 _flags.set(OPACITY_MAP_MODE_BIT);
145 Builder& withOpacityCutoff() { _flags.set(OPACITY_CUTOFF_VAL_BIT);
return (*
this); }
147 Builder& withScattering() { _flags.set(SCATTERING_VAL_BIT);
return (*
this); }
149 Builder& withEmissiveMap() { _flags.set(EMISSIVE_MAP_BIT);
return (*
this); }
150 Builder& withAlbedoMap() { _flags.set(ALBEDO_MAP_BIT);
return (*
this); }
151 Builder& withMetallicMap() { _flags.set(METALLIC_MAP_BIT);
return (*
this); }
152 Builder& withRoughnessMap() { _flags.set(ROUGHNESS_MAP_BIT);
return (*
this); }
154 Builder& withNormalMap() { _flags.set(NORMAL_MAP_BIT);
return (*
this); }
155 Builder& withOcclusionMap() { _flags.set(OCCLUSION_MAP_BIT);
return (*
this); }
156 Builder& withLightMap() { _flags.set(LIGHT_MAP_BIT);
return (*
this); }
157 Builder& withScatteringMap() { _flags.set(SCATTERING_MAP_BIT);
return (*
this); }
160 static MaterialKey opaqueAlbedo() {
return Builder().withAlbedo().build(); }
163 void setEmissive(
bool value) { _flags.set(EMISSIVE_VAL_BIT, value); }
164 bool isEmissive()
const {
return _flags[EMISSIVE_VAL_BIT]; }
166 void setUnlit(
bool value) { _flags.set(UNLIT_VAL_BIT, value); }
167 bool isUnlit()
const {
return _flags[UNLIT_VAL_BIT]; }
169 void setEmissiveMap(
bool value) { _flags.set(EMISSIVE_MAP_BIT, value); }
170 bool isEmissiveMap()
const {
return _flags[EMISSIVE_MAP_BIT]; }
172 void setAlbedo(
bool value) { _flags.set(ALBEDO_VAL_BIT, value); }
173 bool isAlbedo()
const {
return _flags[ALBEDO_VAL_BIT]; }
175 void setAlbedoMap(
bool value) { _flags.set(ALBEDO_MAP_BIT, value); }
176 bool isAlbedoMap()
const {
return _flags[ALBEDO_MAP_BIT]; }
178 void setMetallic(
bool value) { _flags.set(METALLIC_VAL_BIT, value); }
179 bool isMetallic()
const {
return _flags[METALLIC_VAL_BIT]; }
181 void setMetallicMap(
bool value) { _flags.set(METALLIC_MAP_BIT, value); }
182 bool isMetallicMap()
const {
return _flags[METALLIC_MAP_BIT]; }
184 void setGlossy(
bool value) { _flags.set(GLOSSY_VAL_BIT, value); }
185 bool isGlossy()
const {
return _flags[GLOSSY_VAL_BIT]; }
186 bool isRough()
const {
return !_flags[GLOSSY_VAL_BIT]; }
188 void setRoughnessMap(
bool value) { _flags.set(ROUGHNESS_MAP_BIT, value); }
189 bool isRoughnessMap()
const {
return _flags[ROUGHNESS_MAP_BIT]; }
191 void setTranslucentFactor(
bool value) { _flags.set(OPACITY_VAL_BIT, value); }
192 bool isTranslucentFactor()
const {
return _flags[OPACITY_VAL_BIT]; }
194 void setTranslucentMap(
bool value) { _flags.set(OPACITY_TRANSLUCENT_MAP_BIT, value); }
195 bool isTranslucentMap()
const {
return _flags[OPACITY_TRANSLUCENT_MAP_BIT]; }
197 void setOpacityMaskMap(
bool value) { _flags.set(OPACITY_MASK_MAP_BIT, value); }
198 bool isOpacityMaskMap()
const {
return _flags[OPACITY_MASK_MAP_BIT]; }
200 void setOpacityCutoff(
bool value) { _flags.set(OPACITY_CUTOFF_VAL_BIT, value); }
201 bool isOpacityCutoff()
const {
return _flags[OPACITY_CUTOFF_VAL_BIT]; }
203 void setNormalMap(
bool value) { _flags.set(NORMAL_MAP_BIT, value); }
204 bool isNormalMap()
const {
return _flags[NORMAL_MAP_BIT]; }
206 void setOcclusionMap(
bool value) { _flags.set(OCCLUSION_MAP_BIT, value); }
207 bool isOcclusionMap()
const {
return _flags[OCCLUSION_MAP_BIT]; }
209 void setLightMap(
bool value) { _flags.set(LIGHT_MAP_BIT, value); }
210 bool isLightMap()
const {
return _flags[LIGHT_MAP_BIT]; }
212 void setScattering(
bool value) { _flags.set(SCATTERING_VAL_BIT, value); }
213 bool isScattering()
const {
return _flags[SCATTERING_VAL_BIT]; }
215 void setScatteringMap(
bool value) { _flags.set(SCATTERING_MAP_BIT, value); }
216 bool isScatteringMap()
const {
return _flags[SCATTERING_MAP_BIT]; }
218 void setMapChannel(MapChannel channel,
bool value) { _flags.set(EMISSIVE_MAP_BIT + channel, value); }
219 bool isMapChannel(MapChannel channel)
const {
return _flags[EMISSIVE_MAP_BIT + channel]; }
223 void setOpacityMapMode(OpacityMapMode mode) {
225 case OPACITY_MAP_OPAQUE:
226 _flags.reset(OPACITY_TRANSLUCENT_MAP_BIT);
227 _flags.reset(OPACITY_MASK_MAP_BIT);
229 case OPACITY_MAP_MASK:
230 _flags.reset(OPACITY_TRANSLUCENT_MAP_BIT);
231 _flags.set(OPACITY_MASK_MAP_BIT);
233 case OPACITY_MAP_BLEND:
234 _flags.set(OPACITY_TRANSLUCENT_MAP_BIT);
235 _flags.reset(OPACITY_MASK_MAP_BIT);
238 _flags.set(OPACITY_MAP_MODE_BIT);
240 bool isOpacityMapMode()
const {
return _flags[OPACITY_MAP_MODE_BIT]; }
241 OpacityMapMode getOpacityMapMode()
const {
return (isOpacityMaskMap() ? OPACITY_MAP_MASK : (isTranslucentMap() ? OPACITY_MAP_BLEND : OPACITY_MAP_OPAQUE)); }
243 bool isTranslucent()
const {
return isTranslucentFactor() || isTranslucentMap(); }
244 bool isOpaque()
const {
return !isTranslucent(); }
245 bool isSurfaceOpaque()
const {
return isOpaque() && !isOpacityMaskMap(); }
246 bool isTexelOpaque()
const {
return isOpaque() && isOpacityMaskMap(); }
249 class MaterialFilter {
251 MaterialKey::Flags _value{ 0 };
252 MaterialKey::Flags _mask{ 0 };
255 MaterialFilter(
const MaterialKey::Flags& value = MaterialKey::Flags(0),
const MaterialKey::Flags& mask = MaterialKey::Flags(0)) : _value(value), _mask(mask) {}
258 MaterialKey::Flags _value{ 0 };
259 MaterialKey::Flags _mask{ 0 };
263 MaterialFilter build()
const {
return MaterialFilter(_value, _mask); }
265 Builder& withoutEmissive() { _value.reset(MaterialKey::EMISSIVE_VAL_BIT); _mask.set(MaterialKey::EMISSIVE_VAL_BIT);
return (*
this); }
266 Builder& withEmissive() { _value.set(MaterialKey::EMISSIVE_VAL_BIT); _mask.set(MaterialKey::EMISSIVE_VAL_BIT);
return (*
this); }
268 Builder& withoutEmissiveMap() { _value.reset(MaterialKey::EMISSIVE_MAP_BIT); _mask.set(MaterialKey::EMISSIVE_MAP_BIT);
return (*
this); }
269 Builder& withEmissiveMap() { _value.set(MaterialKey::EMISSIVE_MAP_BIT); _mask.set(MaterialKey::EMISSIVE_MAP_BIT);
return (*
this); }
271 Builder& withoutUnlit() { _value.reset(MaterialKey::UNLIT_VAL_BIT); _mask.set(MaterialKey::UNLIT_VAL_BIT);
return (*
this); }
272 Builder& withUnlit() { _value.set(MaterialKey::UNLIT_VAL_BIT); _mask.set(MaterialKey::UNLIT_VAL_BIT);
return (*
this); }
274 Builder& withoutAlbedo() { _value.reset(MaterialKey::ALBEDO_VAL_BIT); _mask.set(MaterialKey::ALBEDO_VAL_BIT);
return (*
this); }
275 Builder& withAlbedo() { _value.set(MaterialKey::ALBEDO_VAL_BIT); _mask.set(MaterialKey::ALBEDO_VAL_BIT);
return (*
this); }
277 Builder& withoutAlbedoMap() { _value.reset(MaterialKey::ALBEDO_MAP_BIT); _mask.set(MaterialKey::ALBEDO_MAP_BIT);
return (*
this); }
278 Builder& withAlbedoMap() { _value.set(MaterialKey::ALBEDO_MAP_BIT); _mask.set(MaterialKey::ALBEDO_MAP_BIT);
return (*
this); }
280 Builder& withoutMetallic() { _value.reset(MaterialKey::METALLIC_VAL_BIT); _mask.set(MaterialKey::METALLIC_VAL_BIT);
return (*
this); }
281 Builder& withMetallic() { _value.set(MaterialKey::METALLIC_VAL_BIT); _mask.set(MaterialKey::METALLIC_VAL_BIT);
return (*
this); }
283 Builder& withoutMetallicMap() { _value.reset(MaterialKey::METALLIC_MAP_BIT); _mask.set(MaterialKey::METALLIC_MAP_BIT);
return (*
this); }
284 Builder& withMetallicMap() { _value.set(MaterialKey::METALLIC_MAP_BIT); _mask.set(MaterialKey::METALLIC_MAP_BIT);
return (*
this); }
286 Builder& withoutGlossy() { _value.reset(MaterialKey::GLOSSY_VAL_BIT); _mask.set(MaterialKey::GLOSSY_VAL_BIT);
return (*
this); }
287 Builder& withGlossy() { _value.set(MaterialKey::GLOSSY_VAL_BIT); _mask.set(MaterialKey::GLOSSY_VAL_BIT);
return (*
this); }
289 Builder& withoutRoughnessMap() { _value.reset(MaterialKey::ROUGHNESS_MAP_BIT); _mask.set(MaterialKey::ROUGHNESS_MAP_BIT);
return (*
this); }
290 Builder& withRoughnessMap() { _value.set(MaterialKey::ROUGHNESS_MAP_BIT); _mask.set(MaterialKey::ROUGHNESS_MAP_BIT);
return (*
this); }
292 Builder& withoutTranslucentFactor() { _value.reset(MaterialKey::OPACITY_VAL_BIT); _mask.set(MaterialKey::OPACITY_VAL_BIT);
return (*
this); }
293 Builder& withTranslucentFactor() { _value.set(MaterialKey::OPACITY_VAL_BIT); _mask.set(MaterialKey::OPACITY_VAL_BIT);
return (*
this); }
295 Builder& withoutTranslucentMap() { _value.reset(MaterialKey::OPACITY_TRANSLUCENT_MAP_BIT); _mask.set(MaterialKey::OPACITY_TRANSLUCENT_MAP_BIT);
return (*
this); }
296 Builder& withTranslucentMap() { _value.set(MaterialKey::OPACITY_TRANSLUCENT_MAP_BIT); _mask.set(MaterialKey::OPACITY_TRANSLUCENT_MAP_BIT);
return (*
this); }
298 Builder& withoutMaskMap() { _value.reset(MaterialKey::OPACITY_MASK_MAP_BIT); _mask.set(MaterialKey::OPACITY_MASK_MAP_BIT);
return (*
this); }
299 Builder& withMaskMap() { _value.set(MaterialKey::OPACITY_MASK_MAP_BIT); _mask.set(MaterialKey::OPACITY_MASK_MAP_BIT);
return (*
this); }
301 Builder& withoutOpacityMapMode() { _value.reset(MaterialKey::OPACITY_MAP_MODE_BIT); _mask.set(MaterialKey::OPACITY_MAP_MODE_BIT);
return (*
this); }
302 Builder& withOpacityMapMode() { _value.set(MaterialKey::OPACITY_MAP_MODE_BIT); _mask.set(MaterialKey::OPACITY_MAP_MODE_BIT);
return (*
this); }
304 Builder& withoutOpacityCutoff() { _value.reset(MaterialKey::OPACITY_CUTOFF_VAL_BIT); _mask.set(MaterialKey::OPACITY_CUTOFF_VAL_BIT);
return (*
this); }
305 Builder& withOpacityCutoff() { _value.set(MaterialKey::OPACITY_CUTOFF_VAL_BIT); _mask.set(MaterialKey::OPACITY_CUTOFF_VAL_BIT);
return (*
this); }
307 Builder& withoutNormalMap() { _value.reset(MaterialKey::NORMAL_MAP_BIT); _mask.set(MaterialKey::NORMAL_MAP_BIT);
return (*
this); }
308 Builder& withNormalMap() { _value.set(MaterialKey::NORMAL_MAP_BIT); _mask.set(MaterialKey::NORMAL_MAP_BIT);
return (*
this); }
310 Builder& withoutOcclusionMap() { _value.reset(MaterialKey::OCCLUSION_MAP_BIT); _mask.set(MaterialKey::OCCLUSION_MAP_BIT);
return (*
this); }
311 Builder& withOcclusionMap() { _value.set(MaterialKey::OCCLUSION_MAP_BIT); _mask.set(MaterialKey::OCCLUSION_MAP_BIT);
return (*
this); }
313 Builder& withoutLightMap() { _value.reset(MaterialKey::LIGHT_MAP_BIT); _mask.set(MaterialKey::LIGHT_MAP_BIT);
return (*
this); }
314 Builder& withLightMap() { _value.set(MaterialKey::LIGHT_MAP_BIT); _mask.set(MaterialKey::LIGHT_MAP_BIT);
return (*
this); }
316 Builder& withoutScattering() { _value.reset(MaterialKey::SCATTERING_VAL_BIT); _mask.set(MaterialKey::SCATTERING_VAL_BIT);
return (*
this); }
317 Builder& withScattering() { _value.set(MaterialKey::SCATTERING_VAL_BIT); _mask.set(MaterialKey::SCATTERING_VAL_BIT);
return (*
this); }
319 Builder& withoutScatteringMap() { _value.reset(MaterialKey::SCATTERING_MAP_BIT); _mask.set(MaterialKey::SCATTERING_MAP_BIT);
return (*
this); }
320 Builder& withScatteringMap() { _value.set(MaterialKey::SCATTERING_MAP_BIT); _mask.set(MaterialKey::SCATTERING_MAP_BIT);
return (*
this); }
324 static MaterialFilter opaqueAlbedo() {
return Builder().withAlbedo().withoutTranslucentFactor().build(); }
328 bool test(
const MaterialKey& key)
const {
return (key._flags & _mask) == (_value & _mask); }
332 bool operator() (
const MaterialFilter& left,
const MaterialFilter& right)
const {
333 if (left._value.to_ulong() == right._value.to_ulong()) {
334 return left._mask.to_ulong() < right._mask.to_ulong();
336 return left._value.to_ulong() < right._value.to_ulong();
344 typedef MaterialKey::MapChannel MapChannel;
345 typedef std::map<MapChannel, TextureMapPointer> TextureMaps;
348 Material(
const Material& material);
349 virtual ~Material() =
default;
350 Material& operator= (
const Material& material);
352 virtual MaterialKey getKey()
const {
return _key; }
354 static const float DEFAULT_EMISSIVE;
355 void setEmissive(
const glm::vec3& emissive,
bool isSRGB =
true);
356 virtual glm::vec3 getEmissive(
bool SRGB =
true)
const {
return (SRGB ? ColorUtils::tosRGBVec3(_emissive) : _emissive); }
358 static const float DEFAULT_OPACITY;
359 void setOpacity(
float opacity);
360 virtual float getOpacity()
const {
return _opacity; }
362 static const MaterialKey::OpacityMapMode DEFAULT_OPACITY_MAP_MODE;
363 void setOpacityMapMode(MaterialKey::OpacityMapMode opacityMapMode);
364 virtual MaterialKey::OpacityMapMode getOpacityMapMode()
const;
366 static const float DEFAULT_OPACITY_CUTOFF;
367 void setOpacityCutoff(
float opacityCutoff);
368 virtual float getOpacityCutoff()
const {
return _opacityCutoff; }
370 static const MaterialKey::CullFaceMode DEFAULT_CULL_FACE_MODE;
371 void setCullFaceMode(MaterialKey::CullFaceMode cullFaceMode) { _cullFaceMode = cullFaceMode; }
372 virtual MaterialKey::CullFaceMode getCullFaceMode()
const {
return _cullFaceMode; }
374 void setUnlit(
bool value);
375 virtual bool isUnlit()
const {
return _key.isUnlit(); }
377 static const float DEFAULT_ALBEDO;
378 void setAlbedo(
const glm::vec3& albedo,
bool isSRGB =
true);
379 virtual glm::vec3 getAlbedo(
bool SRGB =
true)
const {
return (SRGB ? ColorUtils::tosRGBVec3(_albedo) : _albedo); }
381 static const float DEFAULT_METALLIC;
382 void setMetallic(
float metallic);
383 virtual float getMetallic()
const {
return _metallic; }
385 static const float DEFAULT_ROUGHNESS;
386 void setRoughness(
float roughness);
387 virtual float getRoughness()
const {
return _roughness; }
389 static const float DEFAULT_SCATTERING;
390 void setScattering(
float scattering);
391 virtual float getScattering()
const {
return _scattering; }
394 static const int NUM_TEXCOORD_TRANSFORMS { 2 };
395 void setTextureMap(MapChannel channel,
const TextureMapPointer& textureMap);
396 virtual TextureMaps getTextureMaps()
const {
return _textureMaps; }
397 const TextureMapPointer getTextureMap(MapChannel channel)
const;
402 virtual bool resetOpacityMap()
const;
405 static float shininessToRoughness(
float shininess) {
return 1.0f - shininess / 100.0f; }
407 void setTextureTransforms(
const Transform& transform, MaterialMappingMode mode,
bool repeat);
409 const std::string& getName()
const {
return _name; }
410 void setName(
const std::string& name) { _name = name; }
412 const std::string& getModel()
const {
return _model; }
413 void setModel(
const std::string& model) { _model = model; }
415 virtual glm::mat4 getTexCoordTransform(uint i)
const {
return _texcoordTransforms[i]; }
416 void setTexCoordTransform(uint i,
const glm::mat4& mat4) { _texcoordTransforms[i] = mat4; }
417 virtual glm::vec2 getLightmapParams()
const {
return _lightmapParams; }
418 virtual glm::vec2 getMaterialParams()
const {
return _materialParams; }
420 virtual bool getDefaultFallthrough()
const {
return _defaultFallthrough; }
421 void setDefaultFallthrough(
bool defaultFallthrough) { _defaultFallthrough = defaultFallthrough; }
424 TEXCOORDTRANSFORM0 = MaterialKey::NUM_FLAGS,
436 std::unordered_map<uint, bool> getPropertyFallthroughs() {
return _propertyFallthroughs; }
437 bool getPropertyFallthrough(uint property) {
return _propertyFallthroughs[property]; }
438 void setPropertyDoesFallthrough(uint property) { _propertyFallthroughs[property] =
true; }
440 virtual bool isProcedural()
const {
return false; }
441 virtual bool isEnabled()
const {
return true; }
442 virtual bool isReady()
const {
return true; }
443 virtual QString getProceduralString()
const {
return QString(); }
445 virtual bool isReference()
const {
return false; }
447 virtual bool isMToon()
const {
return false; }
448 static const glm::vec3 DEFAULT_SHADE;
449 virtual glm::vec3 getShade(
bool SRGB =
true)
const {
return glm::vec3(0.0f); }
450 static const float DEFAULT_SHADING_SHIFT;
451 virtual float getShadingShift()
const {
return 0.0f; }
452 static const float DEFAULT_SHADING_TOONY;
453 virtual float getShadingToony()
const {
return 0.0f; }
454 static const glm::vec3 DEFAULT_MATCAP;
455 virtual glm::vec3 getMatcap(
bool SRGB =
true)
const {
return glm::vec3(0.0f); }
456 static const glm::vec3 DEFAULT_PARAMETRIC_RIM;
457 virtual glm::vec3 getParametricRim(
bool SRGB =
true)
const {
return glm::vec3(0.0f); }
458 static const float DEFAULT_PARAMETRIC_RIM_FRESNEL_POWER;
459 virtual float getParametricRimFresnelPower()
const {
return 0.0f; }
460 static const float DEFAULT_PARAMETRIC_RIM_LIFT;
461 virtual float getParametricRimLift()
const {
return 0.0f; }
462 static const float DEFAULT_RIM_LIGHTING_MIX;
463 virtual float getRimLightingMix()
const {
return 0.0f; }
464 static const float DEFAULT_UV_ANIMATION_SCROLL_SPEED;
465 virtual float getUVAnimationScrollXSpeed()
const {
return 0.0f; }
466 virtual float getUVAnimationScrollYSpeed()
const {
return 0.0f; }
467 virtual float getUVAnimationRotationSpeed()
const {
return 0.0f; }
469 static const glm::vec3 DEFAULT_OUTLINE;
470 virtual uint8_t getOutlineWidthMode() {
return 0; }
471 virtual float getOutlineWidth() {
return 0.0f; }
472 virtual glm::vec3 getOutline(
bool SRGB =
true)
const {
return glm::vec3(0.0f); }
474 static const std::string HIFI_PBR;
475 static const std::string HIFI_SHADER_SIMPLE;
476 static const std::string VRM_MTOON;
479 std::string _name {
"" };
480 mutable MaterialKey _key { 0 };
481 std::string _model { HIFI_PBR };
485 glm::vec3 _emissive { DEFAULT_EMISSIVE };
486 float _opacity { DEFAULT_OPACITY };
487 glm::vec3 _albedo { DEFAULT_ALBEDO };
488 float _roughness { DEFAULT_ROUGHNESS };
489 float _metallic { DEFAULT_METALLIC };
490 float _scattering { DEFAULT_SCATTERING };
491 float _opacityCutoff { DEFAULT_OPACITY_CUTOFF };
492 std::array<glm::mat4, NUM_TEXCOORD_TRANSFORMS> _texcoordTransforms;
493 glm::vec2 _lightmapParams { 0.0, 1.0 };
494 glm::vec2 _materialParams { 0.0, 1.0 };
495 MaterialKey::CullFaceMode _cullFaceMode { DEFAULT_CULL_FACE_MODE };
496 TextureMaps _textureMaps;
498 bool _defaultFallthrough {
false };
499 std::unordered_map<uint, bool> _propertyFallthroughs { NUM_TOTAL_FLAGS };
501 mutable std::recursive_mutex _textureMapsMutex;
503 typedef std::shared_ptr<Material> MaterialPointer;
505 class MaterialLayer {
507 MaterialLayer(MaterialPointer material, quint16 priority) : material(material), priority(priority) {}
509 MaterialPointer material {
nullptr };
510 quint16 priority { 0 };
513 class MaterialLayerCompare {
515 bool operator() (MaterialLayer left, MaterialLayer right) {
516 return left.priority < right.priority;
519 typedef std::priority_queue<MaterialLayer, std::vector<MaterialLayer>, MaterialLayerCompare> MaterialLayerQueue;
521 class MultiMaterial :
public MaterialLayerQueue {
525 void push(
const MaterialLayer& value) {
526 MaterialLayerQueue::push(value);
527 _hasCalculatedTextureInfo =
false;
531 bool remove(
const MaterialPointer& value) {
533 while (it != c.end()) {
534 if (it->material == value) {
541 std::make_heap(c.begin(), c.end(), comp);
542 _hasCalculatedTextureInfo =
false;
553 glm::vec3 _emissive { Material::DEFAULT_EMISSIVE };
554 float _opacity { Material::DEFAULT_OPACITY };
556 glm::vec3 _albedo { Material::DEFAULT_ALBEDO };
557 float _roughness { Material::DEFAULT_ROUGHNESS };
559 float _metallic { Material::DEFAULT_METALLIC };
560 float _scattering { Material::DEFAULT_SCATTERING };
561 float _opacityCutoff { Material::DEFAULT_OPACITY_CUTOFF };
565 glm::mat4 _texcoordTransforms[Material::NUM_TEXCOORD_TRANSFORMS];
569 glm::vec2 _materialParams { 0.0, 1.0 };
571 glm::vec2 _lightmapParams { 0.0, 1.0 };
574 for (
auto& transform : _texcoordTransforms) {
575 transform = glm::mat4();
582 glm::vec3 _emissive { Material::DEFAULT_EMISSIVE };
583 float _opacity { Material::DEFAULT_OPACITY };
585 glm::vec3 _albedo { Material::DEFAULT_ALBEDO };
586 float _opacityCutoff { Material::DEFAULT_OPACITY_CUTOFF };
588 glm::vec3 _shade { Material::DEFAULT_SHADE };
589 float _shadingShift { Material::DEFAULT_SHADING_SHIFT };
591 glm::vec3 _matcap { Material::DEFAULT_MATCAP };
592 float _shadingToony { Material::DEFAULT_SHADING_TOONY };
594 glm::vec3 _parametricRim { Material::DEFAULT_PARAMETRIC_RIM };
595 float _parametricRimFresnelPower { Material::DEFAULT_PARAMETRIC_RIM_FRESNEL_POWER };
597 float _parametricRimLift { Material::DEFAULT_PARAMETRIC_RIM_LIFT };
598 float _rimLightingMix { Material::DEFAULT_RIM_LIGHTING_MIX };
599 glm::vec2 _uvAnimationScrollSpeed { Material::DEFAULT_UV_ANIMATION_SCROLL_SPEED };
601 float _uvAnimationScrollRotationSpeed { Material::DEFAULT_UV_ANIMATION_SCROLL_SPEED };
602 float _time { 0.0f };
604 float _spare { 0.0f };
607 glm::mat4 _texcoordTransforms[Material::NUM_TEXCOORD_TRANSFORMS];
611 glm::vec2 _materialParams { 0.0, 1.0 };
614 for (
auto& transform : _texcoordTransforms) {
615 transform = glm::mat4();
620 gpu::BufferView& getSchemaBuffer() {
return _schemaBuffer; }
621 graphics::MaterialKey getMaterialKey()
const {
623 return graphics::MaterialKey(_schemaBuffer.get<graphics::MultiMaterial::MToonSchema>()._key);
625 return graphics::MaterialKey(_schemaBuffer.get<graphics::MultiMaterial::Schema>()._key);
628 glm::vec4 getColor()
const {
632 const auto& schema = _schemaBuffer.get<graphics::MultiMaterial::MToonSchema>();
633 albedo = schema._albedo;
634 opacity = schema._opacity;
636 const auto& schema = _schemaBuffer.get<graphics::MultiMaterial::Schema>();
637 albedo = schema._albedo;
638 opacity = schema._opacity;
640 return glm::vec4(ColorUtils::tosRGBVec3(albedo), opacity);
642 const gpu::TextureTablePointer& getTextureTable()
const {
return _textureTable; }
644 void setCullFaceMode(graphics::MaterialKey::CullFaceMode cullFaceMode) { _cullFaceMode = cullFaceMode; }
645 graphics::MaterialKey::CullFaceMode getCullFaceMode()
const {
return _cullFaceMode; }
647 void setNeedsUpdate(
bool needsUpdate) { _needsUpdate = needsUpdate; }
648 void setTexturesLoading(
bool value) { _texturesLoading = value; }
649 void setInitialized() { _initialized =
true; }
651 bool shouldUpdate()
const {
return !_initialized || _needsUpdate || _texturesLoading || anyReferenceMaterialsOrTexturesChanged(); }
653 int getTextureCount()
const { calculateMaterialInfo();
return _textureCount; }
654 size_t getTextureSize()
const { calculateMaterialInfo();
return _textureSize; }
655 bool hasTextureInfo()
const {
return _hasCalculatedTextureInfo; }
657 void resetReferenceTexturesAndMaterials();
658 void addReferenceTexture(
const std::function<gpu::TexturePointer()>& textureOperator);
659 void addReferenceMaterial(
const std::function<graphics::MaterialPointer()>& materialOperator);
661 void setisMToon(
bool isMToon);
662 bool isMToon()
const {
return _isMToon; }
664 bool hasOutline()
const {
return _outlineWidthMode != 0 && _outlineWidth > 0.0f; }
665 uint8_t getOutlineWidthMode()
const {
return _outlineWidthMode; }
666 float getOutlineWidth()
const {
return _outlineWidth; }
667 glm::vec3 getOutline()
const {
return _outline; }
668 void resetOutline() { _outlineWidthMode = 0; _outlineWidth = 0.0f; _outline = glm::vec3(0.0f); }
669 void setOutlineWidthMode(uint8_t mode) { _outlineWidthMode = mode; }
670 void setOutlineWidth(
float width) { _outlineWidth = width; }
671 void setOutline(
const glm::vec3& outline) { _outline = outline; }
674 gpu::BufferView _schemaBuffer;
675 graphics::MaterialKey::CullFaceMode _cullFaceMode { graphics::Material::DEFAULT_CULL_FACE_MODE };
676 gpu::TextureTablePointer _textureTable { std::make_shared<gpu::TextureTable>() };
677 bool _needsUpdate {
false };
678 bool _texturesLoading {
false };
679 bool _initialized {
false };
681 mutable size_t _textureSize { 0 };
682 mutable int _textureCount { 0 };
683 mutable bool _hasCalculatedTextureInfo {
false };
684 void calculateMaterialInfo()
const;
686 bool anyReferenceMaterialsOrTexturesChanged()
const;
688 std::vector<std::pair<std::function<gpu::TexturePointer()>, gpu::TexturePointer>> _referenceTextures;
689 std::vector<std::pair<std::function<graphics::MaterialPointer()>, graphics::MaterialPointer>> _referenceMaterials;
691 bool _isMToon {
false };
692 uint8_t _outlineWidthMode { 0 };
693 float _outlineWidth { 0.0f };
694 glm::vec3 _outline { graphics::Material::DEFAULT_OUTLINE };