11#include <initializer_list>
12#include <unordered_map>
30 for (
const char* name : names) {
31 if (
const auto* value = material->
parameter(name)) {
43 if (
const auto* v = std::get_if<float>(value)) {
47 if (
const auto* v = std::get_if<int32_t>(value)) {
48 out =
static_cast<float>(*v);
51 if (
const auto* v = std::get_if<uint32_t>(value)) {
52 out =
static_cast<float>(*v);
63 if (
const auto* v = std::get_if<int32_t>(value)) {
64 out =
static_cast<int>(*v);
67 if (
const auto* v = std::get_if<uint32_t>(value)) {
68 out =
static_cast<int>(*v);
71 if (
const auto* v = std::get_if<float>(value)) {
72 out =
static_cast<int>(*v);
75 if (
const auto* v = std::get_if<bool>(value)) {
87 if (
const auto* v = std::get_if<Color>(value)) {
94 if (
const auto* v = std::get_if<Vector3>(value)) {
101 if (
const auto* v = std::get_if<Vector4>(value)) {
108 if (
const auto* v = std::get_if<float>(value)) {
123 if (
const auto* v = std::get_if<Texture*>(value)) {
132 constexpr float DEG_TO_RAD = 3.14159265358979323846f / 180.0f;
151 _blendState = std::make_shared<BlendState>();
152 _depthState = std::make_shared<DepthState>();
160 _parameters[
name] = value;
168 return _parameters.erase(
name) > 0;
178 const auto it = _parameters.find(
name);
179 return it == _parameters.end() ? nullptr : &it->second;
185 uniforms.
baseColor[0] = _baseColorFactor.r;
186 uniforms.
baseColor[1] = _baseColorFactor.g;
187 uniforms.
baseColor[2] = _baseColorFactor.b;
188 uniforms.
baseColor[3] = _baseColorFactor.a;
203 readColor4(getParam(
this, {
"material_baseColor",
"baseColorFactor"}), uniforms.
baseColor);
204 readColor4(getParam(
this, {
"material_emissive",
"emissiveFactor"}), uniforms.
emissiveColor);
205 readFloat(getParam(
this, {
"material_alphaCutoff",
"alphaCutoff"}), uniforms.
alphaCutoff);
206 readFloat(getParam(
this, {
"material_metallic",
"metallicFactor"}), uniforms.
metallicFactor);
207 readFloat(getParam(
this, {
"material_roughness",
"roughnessFactor"}), uniforms.
roughnessFactor);
208 readFloat(getParam(
this, {
"material_normalScale",
"normalScale"}), uniforms.
normalScale);
209 readFloat(getParam(
this, {
"material_occlusionStrength",
"occlusionStrength"}), uniforms.
occlusionStrength);
210 readFloat(getParam(
this, {
"material_occludeSpecularIntensity",
"occludeSpecularIntensity"}),
214 readInt(getParam(
this, {
"material_occludeSpecular",
"occludeSpecular"}), occludeSpecularMode);
215 occludeSpecularMode = std::clamp(occludeSpecularMode,
221 if (_hasBaseColorTexture) {
222 uniforms.
flags |= 1u;
225 uniforms.
flags |= (1u << 1);
227 if (_hasNormalTexture) {
228 uniforms.
flags |= (1u << 2);
231 uniforms.
flags |= (1u << 3);
235 int baseUvSet = _baseColorUvSet;
237 int metallicUvSet = _metallicRoughnessUvSet;
240 readInt(getParam(
this, {
"baseColorUvSet"}), baseUvSet);
241 readInt(getParam(
this, {
"normalUvSet"}),
normalUvSet);
242 readInt(getParam(
this, {
"metallicRoughnessUvSet"}), metallicUvSet);
245 if (baseUvSet == 1) uniforms.
flags |= (1u << 4);
247 if (_hasMetallicRoughnessTexture) uniforms.
flags |= (1u << 6);
248 if (metallicUvSet == 1) uniforms.
flags |= (1u << 7);
249 if (_isSkybox) uniforms.
flags |= (1u << 8);
250 if (_hasOcclusionTexture) uniforms.
flags |= (1u << 9);
252 if (_hasEmissiveTexture) uniforms.
flags |= (1u << 11);
256 readInt(getParam(
this, {
"material_occludeDirect",
"occludeDirect"}),
occludeDirect);
261 readTexture(getParam(
this, {
"texture_heightMap"}), heightTex);
262 if (heightTex) uniforms.
flags |= (1u << 17);
263 readFloat(getParam(
this, {
"material_heightMapFactor",
"heightMapFactor"}), uniforms.
heightMapFactor);
266 readFloat(getParam(
this, {
"material_anisotropy",
"anisotropy"}), uniforms.
anisotropy);
269 readFloat(getParam(
this, {
"material_transmissionFactor",
"transmissionFactor"}), uniforms.
transmissionFactor);
270 readFloat(getParam(
this, {
"material_refractionIndex",
"refractionIndex"}), uniforms.
refractionIndex);
271 readFloat(getParam(
this, {
"material_thickness",
"thickness"}), uniforms.
thickness);
274 readColor4(getParam(
this, {
"material_sheenColor",
"sheenColor"}), uniforms.
sheenColor);
275 readFloat(getParam(
this, {
"material_sheenRoughness",
"sheenRoughness"}), uniforms.
sheenColor[3]);
278 readTexture(getParam(
this, {
"texture_sheenMap"}), sheenTex);
279 if (sheenTex) uniforms.
flags |= (1u << 18);
283 readFloat(getParam(
this, {
"material_iridescenceIntensity",
"iridescenceIntensity"}), uniforms.
iridescenceParams[0]);
284 readFloat(getParam(
this, {
"material_iridescenceIOR",
"iridescenceIOR"}), uniforms.
iridescenceParams[1]);
285 readFloat(getParam(
this, {
"material_iridescenceThicknessMin",
"iridescenceThicknessMin"}), uniforms.
iridescenceParams[2]);
286 readFloat(getParam(
this, {
"material_iridescenceThicknessMax",
"iridescenceThicknessMax"}), uniforms.
iridescenceParams[3]);
289 readTexture(getParam(
this, {
"texture_iridescenceMap"}), iriTex);
290 if (iriTex) uniforms.
flags |= (1u << 19);
291 Texture* iriThickTex =
nullptr;
292 readTexture(getParam(
this, {
"texture_iridescenceThicknessMap"}), iriThickTex);
293 if (iriThickTex) uniforms.
flags |= (1u << 20);
297 readColor4(getParam(
this, {
"material_specularColor",
"specularColor"}), uniforms.
specGlossParams);
298 readFloat(getParam(
this, {
"material_glossiness",
"glossiness"}), uniforms.
specGlossParams[3]);
301 readTexture(getParam(
this, {
"texture_specGlossMap"}), sgTex);
302 if (sgTex) uniforms.
flags |= (1u << 21);
306 readFloat(getParam(
this, {
"material_detailNormalScale",
"detailNormalScale"}), uniforms.
detailDisplacementParams[0]);
309 readTexture(getParam(
this, {
"texture_detailNormalMap"}), detailTex);
310 if (detailTex) uniforms.
flags |= (1u << 22);
314 readFloat(getParam(
this, {
"material_displacementScale",
"displacementScale"}), uniforms.
detailDisplacementParams[1]);
318 readTexture(getParam(
this, {
"texture_displacementMap"}), dispTex);
319 if (dispTex) uniforms.
flags |= (1u << 24);
335 Texture* baseColorTex = _baseColorTexture;
336 readTexture(getParam(
this, {
"texture_baseColorMap",
"texture_diffuseMap",
"baseColorTexture"}), baseColorTex);
337 if (baseColorTex) slots.push_back({0, baseColorTex});
339 Texture* normalTex = _normalTexture;
340 readTexture(getParam(
this, {
"texture_normalMap",
"normalTexture"}), normalTex);
341 if (normalTex) slots.push_back({1, normalTex});
343 Texture* mrTex = _metallicRoughnessTexture;
344 readTexture(getParam(
this, {
"texture_metallicRoughnessMap",
"metallicRoughnessTexture"}), mrTex);
345 if (mrTex) slots.push_back({3, mrTex});
347 Texture* occlusionTex = _occlusionTexture;
348 readTexture(getParam(
this, {
"texture_occlusionMap",
"occlusionTexture"}), occlusionTex);
349 if (occlusionTex) slots.push_back({4, occlusionTex});
351 Texture* emissiveTex = _emissiveTexture;
352 readTexture(getParam(
this, {
"texture_emissiveMap",
"emissiveTexture"}), emissiveTex);
353 if (emissiveTex) slots.push_back({5, emissiveTex});
358 const auto blendKey =
static_cast<uint64_t
>(_blendState ? _blendState->key() : 0);
359 const auto depthKey =
static_cast<uint64_t
>(_depthState ? _depthState->key() : 0);
360 const auto alphaModeKey =
static_cast<uint64_t
>(_alphaMode);
361 const auto baseTextureBit = _hasBaseColorTexture ? 1ull : 0ull;
362 const auto normalTextureBit = _hasNormalTexture ? 1ull : 0ull;
363 const auto mrTextureBit = _hasMetallicRoughnessTexture ? 1ull : 0ull;
364 const auto occlusionTextureBit = _hasOcclusionTexture ? 1ull : 0ull;
365 const auto emissiveTextureBit = _hasEmissiveTexture ? 1ull : 0ull;
366 const auto skyboxBit = _isSkybox ? 1ull : 0ull;
367 return (_shaderVariantKey << 32) ^ (blendKey << 16) ^ (depthKey << 4) ^ (alphaModeKey << 3) ^
368 (skyboxBit << 5) ^ (emissiveTextureBit << 4) ^ (occlusionTextureBit << 3) ^
369 (mrTextureBit << 2) ^ (normalTextureBit << 1) ^ baseTextureBit;
372 void setDefaultMaterial(
const std::shared_ptr<GraphicsDevice>& device,
const std::shared_ptr<Material>& material) {
373 assert(material !=
nullptr &&
"Cannot set null as default material");
Base class for GPU materials — owns uniform data, texture bindings, blend/depth state,...
virtual void getTextureSlots(std::vector< TextureSlot > &slots) const
std::variant< float, int32_t, uint32_t, bool, Color, Vector2, Vector3, Vector4, Matrix4, Texture * > ParameterValue
virtual void updateUniforms(MaterialUniforms &uniforms) const
int emissiveUvSet() const
bool removeParameter(const std::string &name)
int occlusionUvSet() const
const std::string & name() const
void setParameter(const std::string &name, const ParameterValue &value)
bool occludeDirect() const
const ParameterValue * parameter(const std::string &name) const
GPU texture resource supporting 2D, cubemap, volume, and array formats with mipmap management.
constexpr uint32_t SPECOCC_GLOSSDEPENDENT
std::shared_ptr< Material > getDefaultMaterial(const std::shared_ptr< GraphicsDevice > &device)
constexpr uint32_t SPECOCC_NONE
void setDefaultMaterial(const std::shared_ptr< GraphicsDevice > &device, const std::shared_ptr< Material > &material)
std::unordered_map< GraphicsDevice *, std::shared_ptr< Material > > defaultMaterials
constexpr float DEG_TO_RAD
DeviceCache defaultMaterialDeviceCache