From ef6ef081d8e412d89b688fbc25ece6ee81e57337 Mon Sep 17 00:00:00 2001 From: lisyarus Date: Wed, 15 Mar 2023 15:57:12 +0300 Subject: [PATCH] Support KHR_lights_punctual in gltf parser --- libs/gfx/include/psemek/gfx/gltf_parser.hpp | 19 ++++++ libs/gfx/source/gltf_parser.cpp | 72 +++++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/libs/gfx/include/psemek/gfx/gltf_parser.hpp b/libs/gfx/include/psemek/gfx/gltf_parser.hpp index baeb754d..ede3613c 100644 --- a/libs/gfx/include/psemek/gfx/gltf_parser.hpp +++ b/libs/gfx/include/psemek/gfx/gltf_parser.hpp @@ -8,6 +8,7 @@ #include #include #include +#include namespace psemek::gfx { @@ -18,6 +19,7 @@ namespace psemek::gfx { std::string name; std::optional mesh; + std::optional light; // KHR_lights_punctual std::vector children; geom::vector translation; @@ -75,6 +77,22 @@ namespace psemek::gfx std::string uri; }; + // KHR_lights_punctual + struct light + { + enum + { + directional, + point, + spot, + } type; + + gfx::color_3f color; + float intensity; + float range; + geom::interval cone_angle; + }; + std::vector nodes; std::vector meshes; std::vector materials; @@ -82,6 +100,7 @@ namespace psemek::gfx std::vector accessors; std::vector buffer_views; std::vector buffers; + std::vector lights; // KHR_lights_punctual std::unordered_map node_index; std::unordered_map material_index; diff --git a/libs/gfx/source/gltf_parser.cpp b/libs/gfx/source/gltf_parser.cpp index f329bbca..73b40b52 100644 --- a/libs/gfx/source/gltf_parser.cpp +++ b/libs/gfx/source/gltf_parser.cpp @@ -9,6 +9,8 @@ #include #include +#include + namespace psemek::gfx { @@ -56,6 +58,11 @@ namespace psemek::gfx throw std::runtime_error(util::to_string("Unknown accessor component type: ", type)); } + static std::unordered_set supported_extensions = + { + "KHR_lights_punctual", + }; + } gltf_asset parse_gltf(io::istream && stream) @@ -70,6 +77,11 @@ namespace psemek::gfx gltf_asset result; + if (document.HasMember("extensionsRequired")) + for (auto const & extension : document["extensionsRequired"].GetArray()) + if (!supported_extensions.contains(extension.GetString())) + throw std::runtime_error("glTF extension " + std::string(extension.GetString()) + " is not supported"); + for (auto const & node : document["nodes"].GetArray()) { auto & target = result.nodes.emplace_back(); @@ -106,6 +118,15 @@ namespace psemek::gfx for (auto const & child : node["children"].GetArray()) target.children.push_back(child.GetUint64()); } + + if (node.HasMember("extensions")) + for (auto const & extension : node["extensions"].GetObject()) + { + if (extension.name == "KHR_lights_punctual") + { + target.light = extension.value["light"].GetUint64(); + } + } } for (auto const & mesh : document["meshes"].GetArray()) @@ -199,6 +220,57 @@ namespace psemek::gfx target.uri = buffer["uri"].GetString(); } + if (document.HasMember("extensions")) + for (auto const & extension : document["extensions"].GetObject()) + { + if (extension.name == "KHR_lights_punctual") + { + for (auto const & light : extension.value["lights"].GetArray()) + { + auto & target = result.lights.emplace_back(); + target.color = {1.f, 1.f, 1.f}; + target.intensity = 1.f; + target.range = std::numeric_limits::infinity(); + target.cone_angle = {0.f, geom::pi / 4.f}; + + std::string type = light["type"].GetString(); + + if (type == "directional") + target.type = gltf_asset::light::directional; + else if (type == "point") + target.type = gltf_asset::light::point; + else if (type == "spot") + target.type = gltf_asset::light::spot; + else + throw std::runtime_error("unknown light type: " + type); + + if (light.HasMember("color")) + { + auto const & color = light["color"].GetArray(); + for (std::size_t i = 0; i < 3; ++i) + target.color[i] = color[i].GetFloat(); + } + + if (light.HasMember("intensity")) + target.intensity = light["intensity"].GetFloat(); + + if (light.HasMember("range")) + target.range = light["range"].GetFloat(); + + if (target.type == gltf_asset::light::spot) + { + auto const & spot = light["spot"].GetObject(); + + if (spot.HasMember("innerConeAngle")) + target.cone_angle.min = spot["innerConeAngle"].GetFloat(); + + if (spot.HasMember("outerConeAngle")) + target.cone_angle.max = spot["outerConeAngle"].GetFloat(); + } + } + } + } + for (std::size_t i = 0; i < result.nodes.size(); ++i) result.node_index[result.nodes[i].name] = i;