18auto cull_type_to_string(
cull_type value) ->
const char*
27 return "counter_clockwise";
29 return "counter_clockwise";
32auto cull_type_from_string(std::string_view value,
cull_type& out) ->
bool
39 if(value ==
"clockwise")
44 if(value ==
"counter_clockwise" || value ==
"counter-clockwise" || value ==
"ccw")
52auto alpha_mode_to_string(
alpha_mode value) ->
const char*
66auto alpha_mode_from_string(std::string_view value,
alpha_mode& out) ->
bool
86auto color_to_json(
const math::color& c) -> std::string
88 const math::vec4
v =
c;
89 return fmt::format(
"[{:.6g},{:.6g},{:.6g},{:.6g}]",
v.x,
v.y,
v.z,
v.w);
92auto vec2_to_json(
const math::vec2&
v) -> std::string
94 return fmt::format(
"[{:.6g},{:.6g}]",
v.x,
v.y);
106auto read_color(
const simdjson::dom::element& el,
math::color& out) ->
bool
108 simdjson::dom::array arr;
113 std::vector<double> values;
123 if(values.size() == 3)
126 static_cast<float>(values[1]),
127 static_cast<float>(values[2]),
131 if(values.size() == 4)
134 static_cast<float>(values[1]),
135 static_cast<float>(values[2]),
136 static_cast<float>(values[3]));
142auto read_vec2(
const simdjson::dom::element& el, math::vec2& out) ->
bool
144 simdjson::dom::array arr;
149 std::vector<double> values;
159 if(values.size() != 2)
163 out = math::vec2{
static_cast<float>(values[0]),
static_cast<float>(values[1])};
176 std::string_view key_view;
179 error =
"Texture map value must be a string asset key or null";
188 auto& am = ctx.get_cached<asset_manager>();
192 error =
"Texture not found: " + std::string(key_view);
203{"name":"cull_type","type":"string","enum":["none","clockwise","counter_clockwise"]},
204{"name":"base_color","type":"array","items":"number","minItems":3,"maxItems":4},
205{"name":"subsurface_color","type":"array","items":"number","minItems":3,"maxItems":4},
206{"name":"emissive_color","type":"array","items":"number","minItems":3,"maxItems":4},
207{"name":"emissive_intensity","type":"number"},
208{"name":"roughness","type":"number"},
209{"name":"metalness","type":"number"},
210{"name":"bumpiness","type":"number"},
211{"name":"alpha_mode","type":"string","enum":["opaque","mask","blend"]},
212{"name":"alpha_cutoff","type":"number"},
213{"name":"tiling","type":"array","items":"number","minItems":2,"maxItems":2},
214{"name":"dither_threshold","type":"array","items":"number","minItems":2,"maxItems":2},
215{"name":"color_map","type":"string","description":"Texture asset key or null"},
216{"name":"normal_map","type":"string"},
217{"name":"roughness_map","type":"string"},
218{"name":"metalness_map","type":"string"},
219{"name":"emissive_map","type":"string"},
220{"name":"ao_map","type":"string"}
226 auto key = path_or_key;
233 const fs::path as_path(key);
234 if(as_path.is_absolute() && fs::exists(as_path, ec))
238 if(key.size() < 4 || key.substr(key.size() - 4) !=
".mat")
254 error =
"Material not found: " + key;
261 auto uuid = hpp::uuid::from_string(uid);
264 error =
"Invalid material uid";
270 error =
"Material not found for uid: " + uid;
275 error =
"Provide key or uid";
283 error =
"Null material";
286 auto pbr = std::dynamic_pointer_cast<pbr_material>(mat);
289 error =
"Material is not a pbr_material";
297 std::string json =
"{";
298 json += fmt::format(R
"("cull_type":{},)", make_json_string(std::string(cull_type_to_string(mat.get_cull_type()))));
303 json += R
"("type":"material"})";
307 json += R
"("type":"pbr_material",)";
308 json += fmt::format(R"("base_color":{},)", color_to_json(pbr->get_base_color()));
309 json += fmt::format(R"("subsurface_color":{},)", color_to_json(pbr->get_subsurface_color()));
310 json += fmt::format(R"("emissive_color":{},)", color_to_json(pbr->get_emissive_color()));
311 json += fmt::format(R"("emissive_intensity":{:.6g},)", pbr->get_emissive_intensity());
312 json += fmt::format(R"("roughness":{:.6g},)", pbr->get_roughness());
313 json += fmt::format(R"("metalness":{:.6g},)", pbr->get_metalness());
314 json += fmt::format(R"("bumpiness":{:.6g},)", pbr->get_bumpiness());
315 json += fmt::format(R"("alpha_mode":{},)", make_json_string(std::string(alpha_mode_to_string(pbr->get_alpha_mode()))));
316 json += fmt::format(R"("alpha_cutoff":{:.6g},)", pbr->get_alpha_cutoff());
317 json += fmt::format(R"("tiling":{},)", vec2_to_json(pbr->get_tiling()));
318 json += fmt::format(R"("dither_threshold":{},)", vec2_to_json(pbr->get_dither_threshold()));
319 json += fmt::format(R"("color_map":{},)", texture_key_json(pbr->get_color_map()));
320 json += fmt::format(R"("normal_map":{},)", texture_key_json(pbr->get_normal_map()));
321 json += fmt::format(R"("roughness_map":{},)", texture_key_json(pbr->get_roughness_map()));
322 json += fmt::format(R"("metalness_map":{},)", texture_key_json(pbr->get_metalness_map()));
323 json += fmt::format(R"("emissive_map":{},)", texture_key_json(pbr->get_emissive_map()));
324 json += fmt::format(R"("ao_map":{})", texture_key_json(pbr->get_ao_map()));
333 std::string cast_error;
338 result.
errors.push_back(cast_error);
342 for(
auto field : properties)
344 const std::string key(field.key);
345 const auto& value = field.value;
348 auto mark_applied = [&]()
352 auto mark_error = [&](
const std::string& msg)
355 result.
errors.push_back(key +
": " + msg);
358 if(key ==
"cull_type")
362 if(value.get(s) || !cull_type_from_string(s, cull))
364 mark_error(
"expected none|clockwise|counter_clockwise");
367 pbr->set_cull_type(cull);
371 if(key ==
"base_color")
374 if(!read_color(value, c))
376 mark_error(
"expected [r,g,b] or [r,g,b,a]");
379 pbr->set_base_color(c);
383 if(key ==
"subsurface_color")
386 if(!read_color(value, c))
388 mark_error(
"expected [r,g,b] or [r,g,b,a]");
391 pbr->set_subsurface_color(c);
395 if(key ==
"emissive_color")
398 if(!read_color(value, c))
400 mark_error(
"expected [r,g,b] or [r,g,b,a]");
403 pbr->set_emissive_color(c);
407 if(key ==
"emissive_intensity")
412 mark_error(
"expected number");
415 pbr->set_emissive_intensity(
static_cast<float>(
v));
419 if(key ==
"roughness")
424 mark_error(
"expected number");
427 pbr->set_roughness(
static_cast<float>(
v));
431 if(key ==
"metalness")
436 mark_error(
"expected number");
439 pbr->set_metalness(
static_cast<float>(
v));
443 if(key ==
"bumpiness")
448 mark_error(
"expected number");
451 pbr->set_bumpiness(
static_cast<float>(
v));
455 if(key ==
"alpha_mode")
459 if(value.get(s) || !alpha_mode_from_string(s, mode))
461 mark_error(
"expected opaque|mask|blend");
464 pbr->set_alpha_mode(mode);
468 if(key ==
"alpha_cutoff")
473 mark_error(
"expected number");
476 pbr->set_alpha_cutoff(
static_cast<float>(
v));
483 if(!read_vec2(value,
v))
485 mark_error(
"expected [x,y]");
492 if(key ==
"dither_threshold")
495 if(!read_vec2(value,
v))
497 mark_error(
"expected [x,y]");
500 pbr->set_dither_threshold(
v);
505 auto apply_map = [&](
auto setter)
508 if(!resolve_texture(ctx, value, tex,
error))
513 (pbr.get()->*setter)(tex);
517 if(key ==
"color_map")
522 if(key ==
"normal_map")
527 if(key ==
"roughness_map")
532 if(key ==
"metalness_map")
537 if(key ==
"emissive_map")
558 error =
"Invalid material handle";
Manages assets, including loading, unloading, and storage.
Base class for materials used in rendering.
std::shared_ptr< material > sptr
Class for physically-based rendering (PBR) materials.
void set_roughness_map(const asset_handle< gfx::texture > &val)
Sets the roughness map of the material.
void set_color_map(const asset_handle< gfx::texture > &val)
Sets the color map of the material.
void set_ao_map(const asset_handle< gfx::texture > &val)
Sets the ambient occlusion map of the material.
void set_emissive_map(const asset_handle< gfx::texture > &val)
Sets the emissive map of the material.
void set_normal_map(const asset_handle< gfx::texture > &val)
Sets the normal map of the material.
void set_metalness_map(const asset_handle< gfx::texture > &val)
Sets the metalness map of the material.
path convert_to_protocol(const path &_path)
Oposite of the resolve_protocol this function tries to convert to protocol path from an absolute one.
auto atomic_save_to_file(const fs::path &key, const asset_handle< T > &obj) -> bool
auto list_material_property_schema_json() -> std::string
auto resolve_material_asset(rtti::context &ctx, const std::string &key, const std::string &uid, std::string &error) -> asset_handle< material >
auto material_to_json(const material &mat) -> std::string
auto make_json_string(const std::string &value) -> std::string
auto as_pbr_material(const material::sptr &mat, std::string &error) -> std::shared_ptr< pbr_material >
auto apply_material_properties(rtti::context &ctx, material::sptr mat, const simdjson::dom::object &properties) -> material_apply_result
auto save_material_asset(rtti::context &ctx, const asset_handle< material > &handle, std::string &error) -> bool
auto normalize_material_key(const std::string &path_or_key) -> std::string
cull_type
Enum representing the type of culling to be used.
@ counter_clockwise
Cull counter-clockwise faces.
@ clockwise
Cull clockwise faces.
alpha_mode
glTF-aligned surface alpha behavior (default: opaque).
@ opaque
No alpha clip; casts solid shadows.
@ blend
Transparent (lit pass); does not cast shadows.
@ mask
Hard alpha cutoff; casts cutout shadows.
Thread-safe handle to an asset.
std::vector< std::string > unknown
std::vector< std::string > errors
std::vector< std::string > applied