Visual Computing Library  devel
Loading...
Searching...
No Matches
load.h
1/*****************************************************************************
2 * VCLib *
3 * Visual Computing Library *
4 * *
5 * Copyright(C) 2021-2025 *
6 * Visual Computing Lab *
7 * ISTI - Italian National Research Council *
8 * *
9 * All rights reserved. *
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the Mozilla Public License Version 2.0 as published *
13 * by the Mozilla Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * Mozilla Public License Version 2.0 *
20 * (https://www.mozilla.org/en-US/MPL/2.0/) for more details. *
21 ****************************************************************************/
22
23#ifndef VCL_RENDER_IO_CAMERA_GLTF_LOAD_H
24#define VCL_RENDER_IO_CAMERA_GLTF_LOAD_H
25
26#include <vclib/io/file_info.h>
27
28#include <vclib/render/concepts/camera.h>
29#include <vclib/render/viewer/camera.h>
30
31#include <tiny_gltf.h>
32
33#include <stdexcept>
34#include <string>
35#include <vector>
36
37namespace vcl {
38
39// Internal helper to load the glTF model once (no duplication).
40namespace detail {
41inline tinygltf::Model loadTinyGltfCameraModel(const std::string& filename)
42{
43 tinygltf::TinyGLTF loader;
44 tinygltf::Model model;
45 std::string err, warn;
46
47 std::string ext = toLower(FileInfo::extension(filename));
48 bool ret = false;
49 if (ext == ".gltf")
50 ret = loader.LoadASCIIFromFile(&model, &err, &warn, filename);
51 else if (ext == ".glb")
52 ret = loader.LoadBinaryFromFile(&model, &err, &warn, filename);
53 else
54 throw UnknownFileFormatException(ext);
55
56 if (!ret)
57 throw std::runtime_error(
58 "Failed to load glTF cameras: " + err +
59 (warn.empty() ? "" : " " + warn));
60 return model;
61}
62} // namespace detail
63
64// Load all cameras from a glTF file.
65template<CameraConcept CameraType = Camera<float>>
66inline std::vector<CameraType> loadCamerasGltf(const std::string& filename)
67{
68 using Scalar = typename CameraType::ScalarType;
69 tinygltf::Model model = detail::loadTinyGltfCameraModel(filename);
70
71 std::vector<CameraType> cams;
72 cams.reserve(model.cameras.size());
73
74 for (size_t cameraIdx = 0; cameraIdx < model.cameras.size(); ++cameraIdx) {
75 const tinygltf::Camera& gltfCamera = model.cameras[cameraIdx];
76 CameraType camera;
77
78 if (gltfCamera.type == "perspective") {
79 camera.projectionMode() = CameraType::ProjectionMode::PERSPECTIVE;
80 camera.fieldOfView() = gltfCamera.perspective.yfov * 180.0 / M_PI;
81 // TODO check what to do with the aspect ratio
82 camera.aspectRatio() = gltfCamera.perspective.aspectRatio;
83 camera.nearPlane() = gltfCamera.perspective.znear;
84 camera.farPlane() = gltfCamera.perspective.zfar;
85 }
86 else if (gltfCamera.type == "orthographic") {
87 camera.projectionMode() = CameraType::ProjectionMode::ORTHO;
88 camera.verticalHeight() = gltfCamera.orthographic.ymag * 2.0;
89 // TODO check what to do with the aspect ratio
90 camera.aspectRatio() =
91 gltfCamera.orthographic.xmag / gltfCamera.orthographic.ymag;
92 camera.nearPlane() = gltfCamera.orthographic.znear;
93 camera.farPlane() = gltfCamera.orthographic.zfar;
94 }
95
96 bool foundNode = false;
97 for (const auto& node : model.nodes) {
98 if (node.camera == static_cast<int>(cameraIdx)) {
99 // create a vcl matrix44 of double, not typededuced
101 if (node.matrix.size() == 16) {
102 // copy node matrix to vcl matrix
103 mat = vcl::Matrix44d(node.matrix.data());
104 }
105 else {
106 // construct matrix from TRS
107 vcl::Point3d translation(0, 0, 0);
109 vcl::Point3d scale(1, 1, 1);
110 if (node.translation.size() == 3) {
111 translation = vcl::Point3d(
112 node.translation[0],
113 node.translation[1],
114 node.translation[2]);
115 }
116 if (node.rotation.size() == 4) {
117 rotation = vcl::Quaterniond(
118 node.rotation[0],
119 node.rotation[1],
120 node.rotation[2],
121 node.rotation[3]);
122 }
123 if (node.scale.size() == 3) {
124 scale = vcl::Point3d(
125 node.scale[0], node.scale[1], node.scale[2]);
126 }
127 // robut contruction from TRS use affine type then convert
128 // to matrix44
130 affine.translate(translation);
131 affine.rotate(rotation);
132 affine.scale(scale);
133 mat = affine.matrix();
134 }
135 // Use mat instead of node.matrix
136 typename CameraType::PointType eye(
137 mat(0, 3), mat(1, 3), mat(2, 3));
138 camera.eye() = eye;
139
140 typename CameraType::PointType forward(
141 -mat(0, 2), -mat(1, 2), -mat(2, 2));
142 forward = forward.normalized();
143
144 typename CameraType::PointType up(
145 mat(0, 1), mat(1, 1), mat(2, 1));
146 camera.up() = up.normalized();
147
148 Scalar distance = 1.0;
149 camera.center() = eye + forward * distance;
150 foundNode = true;
151 break;
152 }
153 }
154
155 if (!foundNode) {
156 // Invalid gltf camera: no node references it.
157 throw std::runtime_error(
158 "Invalid glTF camera: no node references camera index " +
159 std::to_string(cameraIdx));
160 }
161
162 cams.push_back(camera);
163 }
164
165 assert(cams.size() == model.cameras.size());
166 return cams;
167}
168
169// Single camera loader now delegates to the vector version.
170template<CameraConcept CameraType = Camera<float>>
171inline CameraType loadCameraGltf(
172 const std::string& filename,
173 uint cameraIdx = 0)
174{
175 auto cams = loadCamerasGltf<CameraType>(filename);
176 if (cameraIdx >= cams.size())
177 throw std::out_of_range(
178 "Camera index " + std::to_string(cameraIdx) +
179 " is out of range. Total cameras: " + std::to_string(cams.size()));
180 return cams[cameraIdx];
181}
182
183} // namespace vcl
184
185#endif // VCL_RENDER_IO_CAMERA_GLTF_LOAD_H
A class representing a box in N-dimensional space.
Definition box.h:46
void translate(const PointT &p)
Translates the box by summing the values of p.
Definition box.h:456
Box()
The Empty constructor of a box, initializes a null box.
Definition box.h:65
PointT center() const
Calculates the center point of the box.
Definition box.h:259
static std::string extension(const std::string &filename)
Get the extension of a file.
Definition file_info.h:260
The Point class represents an N-dimensional point containing N scalar values.
Definition point.h:55
auto distance(const PointType &point0, const PointType &point1)
Compute the distance between two Points of any dimension.
Definition distance.h:45
Quaternion< double > Quaterniond
A convenience alias for Quaternion with double-precision floating-point components.
Definition quaternion.h:201
Point3< double > Point3d
A convenience alias for a 3-dimensional Point with double-precision floating-point components.
Definition point.h:780