14#include <lagrange/AttributeValueType.h>
15#include <lagrange/Logger.h>
16#include <lagrange/image/Array3D.h>
17#include <lagrange/image/View3D.h>
18#include <lagrange/scene/Scene.h>
19#include <lagrange/scene/scene_utils.h>
20#include <lagrange/transform_mesh.h>
24namespace lagrange::scene::internal {
26using Array3Df = image::experimental::Array3D<float>;
27using View3Df = image::experimental::View3D<float>;
28using ConstView3Df = image::experimental::View3D<const float>;
31inline Array3Df convert_from(
const ImageBufferExperimental& image)
33 size_t nc = std::min(image.num_channels,
size_t(3));
36 auto copy_buffer = [&](
auto scalar) {
37 using T = std::decay_t<
decltype(scalar)>;
38 constexpr bool IsChar = std::is_integral_v<T> &&
sizeof(T) == 1;
40 auto rawbuf =
reinterpret_cast<const T*
>(image.data.data());
41 for (
size_t y = 0, i = 0; y < image.height; ++y) {
42 for (
size_t x = 0; x < image.width; ++x) {
43 for (
size_t c = 0; c < image.num_channels; ++c) {
48 if constexpr (IsChar) {
49 result(x, y, c) =
static_cast<float>(rawbuf[i++]) / 255.f;
51 result(x, y, c) = rawbuf[i++];
58 switch (image.element_type) {
59 case AttributeValueType::e_uint8_t: copy_buffer(uint8_t());
break;
60 case AttributeValueType::e_int8_t: copy_buffer(int8_t());
break;
61 case AttributeValueType::e_uint32_t: copy_buffer(uint32_t());
break;
62 case AttributeValueType::e_int32_t: copy_buffer(int32_t());
break;
63 case AttributeValueType::e_float: copy_buffer(
float());
break;
64 case AttributeValueType::e_double: copy_buffer(
double());
break;
65 default:
throw std::runtime_error(
"Unsupported image scalar type");
74inline ImageBufferExperimental convert_to(
const ConstView3Df& image)
76 ImageBufferExperimental result;
77 result.width = image.extent(0);
78 result.height = image.extent(1);
79 const size_t num_channels = image.extent(2);
81 num_channels == 1 || num_channels == 3 || num_channels == 4,
82 "ImageBufferExperimental requires 1, 3, or 4 channels");
83 result.num_channels = num_channels;
84 result.element_type = AttributeValueType::e_uint8_t;
85 result.data.resize(result.width * result.height * result.num_channels);
86 for (
size_t y = 0, i = 0; y < result.height; ++y) {
87 for (
size_t x = 0; x < result.width; ++x) {
88 for (
size_t c = 0; c < result.num_channels; ++c) {
90 static_cast<unsigned char>(std::clamp(image(x, y, c), 0.0f, 1.0f) * 255.0f);
99 MaterialExperimental::AlphaMode alpha_mode = MaterialExperimental::AlphaMode::Opaque;
100 float alpha_cutoff = 0.5f;
105template <
typename Scalar,
typename Index>
108 const ConstView3Df&
image,
113 auto mesh_id = scene.
add(std::move(mesh));
116 scene_image.
name =
"base_color";
118 auto image_id = scene.add(std::move(scene_image));
121 texture.name =
"base_color";
122 texture.image = image_id;
123 auto texture_id = scene.add(std::move(texture));
126 material.name =
"material";
127 material.alpha_mode = options.alpha_mode;
128 material.alpha_cutoff = options.alpha_cutoff;
129 material.base_color_texture.
index = texture_id;
130 material.base_color_texture.
texcoord = 0;
131 auto material_id = scene.add(std::move(material));
136 instance.mesh = mesh_id;
137 instance.materials.push_back(material_id);
138 node.meshes.push_back(std::move(instance));
139 auto node_id = scene.add(std::move(node));
140 scene.root_nodes.push_back(node_id);
146template <
typename Scalar,
typename Index>
147std::tuple<SurfaceMesh<Scalar, Index>, std::optional<Array3Df>> single_mesh_from_scene(
148 const Scene<Scalar, Index>& scene)
150 using ElementId = scene::ElementId;
153 std::vector<ElementId> mesh_node_ids;
154 for (ElementId node_id = 0; node_id < scene.nodes.size(); ++node_id) {
155 const auto& node = scene.nodes[node_id];
156 if (!node.meshes.empty()) {
157 mesh_node_ids.push_back(node_id);
161 if (mesh_node_ids.size() != 1) {
162 throw std::runtime_error(
164 "Input scene contains {} mesh nodes. Expected exactly 1 mesh node.",
165 mesh_node_ids.size()));
167 const auto& mesh_node = scene.nodes[mesh_node_ids.front()];
169 if (mesh_node.meshes.size() != 1) {
170 throw std::runtime_error(
172 "Input scene has a mesh node with {} instance per node. Expected "
173 "exactly 1 instance per node",
174 mesh_node.meshes.size()));
176 const auto& mesh_instance = mesh_node.meshes.front();
178 [[maybe_unused]]
const auto mesh_id = mesh_instance.mesh;
180 SurfaceMesh<Scalar, Index> mesh = scene.meshes[mesh_instance.mesh];
183 auto world_from_mesh = utils::compute_global_node_transform(scene, mesh_node_ids.front())
184 .template cast<Scalar>();
189 if (
auto num_mats = mesh_instance.materials.size(); num_mats != 1) {
191 "Mesh node has {} materials. Expected exactly 1 material. Ignoring materials.",
193 return {mesh, std::nullopt};
195 const auto& material = scene.materials[mesh_instance.materials.front()];
196 if (material.base_color_texture.
texcoord != 0) {
198 "Mesh node material texcoord is {} != 0. Expected 0. Ignoring texcoord.",
199 material.base_color_texture.
texcoord);
201 const auto texture_id = material.base_color_texture.
index;
203 const auto& texture = scene.textures[texture_id];
205 const auto image_id = texture.image;
207 const auto& image_ = scene.images[image_id].image;
208 Array3Df image = convert_from(image_);
210 return {mesh, image};
A general purpose polygonal mesh class.
Definition SurfaceMesh.h:73
LA_CORE_API spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:40
void transform_mesh(SurfaceMesh< Scalar, Index > &mesh, const Eigen::Transform< Scalar, Dimension, Eigen::Affine > &transform, const TransformOptions &options={})
Apply an affine transform to a mesh in-place.
Definition transform_mesh.cpp:199
#define la_runtime_assert(...)
Runtime assertion check.
Definition assert.h:174
#define la_debug_assert(...)
Debug assertion check.
Definition assert.h:194
Array3D< T > create_image(size_t width, size_t height, size_t num_channels)
Create an image with the given dimensions and number of channels.
Definition Array3D.h:46
Basic image data structure.
Image structure that can store either image data or reference to an image file.
Definition Scene.h:116
ImageBufferExperimental image
Image data.
Definition Scene.h:121
std::string name
Image name. Not guaranteed to be unique and can be empty.
Definition Scene.h:118
ElementId add(T &&value)
Add an element to the scene.
Definition Scene.h:417
int texcoord
Index of UV coordinates.
Definition Scene.h:141
ElementId index
Texture index. Index in scene.textures vector.
Definition Scene.h:137
Definition shared_utils.h:98