Visual Computing Library  devel
Loading...
Searching...
No Matches
load.h
1/*****************************************************************************
2 * VCLib *
3 * Visual Computing Library *
4 * *
5 * Copyright(C) 2021-2026 *
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_IO_CAMERA_GLTF_LOAD_H
24#define VCL_IO_CAMERA_GLTF_LOAD_H
25
26#include <vclib/io/file_info.h>
27
28#include <vclib/space/core.h>
29
30#include <tiny_gltf.h>
31
32#include <stdexcept>
33#include <string>
34#include <vector>
35
36namespace vcl {
37
38// Internal helper to load the glTF model once (no duplication).
39namespace detail {
40inline tinygltf::Model loadTinyGltfCameraModel(const std::string& filename)
41{
42 tinygltf::TinyGLTF loader;
43 tinygltf::Model model;
44 std::string err, warn;
45
46 std::string ext = toLower(FileInfo::extension(filename));
47 bool ret = false;
48 if (ext == ".gltf")
49 ret = loader.LoadASCIIFromFile(&model, &err, &warn, filename);
50 else if (ext == ".glb")
51 ret = loader.LoadBinaryFromFile(&model, &err, &warn, filename);
52 else
53 throw UnknownFileFormatException(ext);
54
55 if (!ret)
56 throw std::runtime_error(
57 "Failed to load glTF cameras: " + err +
58 (warn.empty() ? "" : " " + warn));
59 return model;
60}
61} // namespace detail
62
63// Load all cameras from a glTF file.
64template<CameraConcept CameraType = Camera<float>>
65inline std::vector<CameraType> loadCamerasGltf(const std::string& filename)
66{
67 using Scalar = typename CameraType::ScalarType;
68 tinygltf::Model model = detail::loadTinyGltfCameraModel(filename);
69
70 std::vector<CameraType> cams;
71 cams.reserve(model.cameras.size());
72
73 for (size_t cameraIdx = 0; cameraIdx < model.cameras.size(); ++cameraIdx) {
74 const tinygltf::Camera& gltfCamera = model.cameras[cameraIdx];
75 CameraType camera;
76
77 if (gltfCamera.type == "perspective") {
78 camera.projectionMode() = CameraType::ProjectionMode::PERSPECTIVE;
79 camera.fieldOfView() = gltfCamera.perspective.yfov * 180.0 / M_PI;
80 // TODO check what to do with the aspect ratio
81 camera.aspectRatio() = gltfCamera.perspective.aspectRatio;
82 camera.nearPlane() = gltfCamera.perspective.znear;
83 camera.farPlane() = gltfCamera.perspective.zfar;
84 }
85 else if (gltfCamera.type == "orthographic") {
86 camera.projectionMode() = CameraType::ProjectionMode::ORTHO;
87 camera.verticalHeight() = gltfCamera.orthographic.ymag * 2.0;
88 // TODO check what to do with the aspect ratio
89 camera.aspectRatio() =
90 gltfCamera.orthographic.xmag / gltfCamera.orthographic.ymag;
91 camera.nearPlane() = gltfCamera.orthographic.znear;
92 camera.farPlane() = gltfCamera.orthographic.zfar;
93 }
94
95 bool foundNode = false;
96 for (const auto& node : model.nodes) {
97 if (node.camera == static_cast<int>(cameraIdx)) {
98 // create a vcl matrix44 of double, not typededuced
100 if (node.matrix.size() == 16) {
101 // copy node matrix to vcl matrix
102 mat = vcl::Matrix44d(node.matrix.data());
103 }
104 else {
105 // construct matrix from TRS
106 vcl::Point3d translation(0, 0, 0);
108 vcl::Point3d scale(1, 1, 1);
109 if (node.translation.size() == 3) {
110 translation = vcl::Point3d(
111 node.translation[0],
112 node.translation[1],
113 node.translation[2]);
114 }
115 if (node.rotation.size() == 4) {
116 rotation = vcl::Quaterniond(
117 node.rotation[0],
118 node.rotation[1],
119 node.rotation[2],
120 node.rotation[3]);
121 }
122 if (node.scale.size() == 3) {
123 scale = vcl::Point3d(
124 node.scale[0], node.scale[1], node.scale[2]);
125 }
126 // robut contruction from TRS use affine type then convert
127 // to matrix44
129 affine.translate(translation);
130 affine.rotate(rotation);
131 affine.scale(scale);
132 mat = affine.matrix();
133 }
134 // Use mat instead of node.matrix
135 typename CameraType::PointType eye(
136 mat(0, 3), mat(1, 3), mat(2, 3));
137 camera.eye() = eye;
138
139 typename CameraType::PointType forward(
140 -mat(0, 2), -mat(1, 2), -mat(2, 2));
141 forward = forward.normalized();
142
143 typename CameraType::PointType up(
144 mat(0, 1), mat(1, 1), mat(2, 1));
145 camera.up() = up.normalized();
146
147 Scalar distance = 1.0;
148 camera.center() = eye + forward * distance;
149 foundNode = true;
150 break;
151 }
152 }
153
154 if (!foundNode) {
155 // Invalid gltf camera: no node references it.
156 throw std::runtime_error(
157 "Invalid glTF camera: no node references camera index " +
158 std::to_string(cameraIdx));
159 }
160
161 cams.push_back(camera);
162 }
163
164 assert(cams.size() == model.cameras.size());
165 return cams;
166}
167
168// Single camera loader now delegates to the vector version.
169template<CameraConcept CameraType = Camera<float>>
170inline CameraType loadCameraGltf(
171 const std::string& filename,
172 uint cameraIdx = 0)
173{
174 auto cams = loadCamerasGltf<CameraType>(filename);
175 if (cameraIdx >= cams.size())
176 throw std::out_of_range(
177 "Camera index " + std::to_string(cameraIdx) +
178 " is out of range. Total cameras: " + std::to_string(cams.size()));
179 return cams[cameraIdx];
180}
181
182} // namespace vcl
183
184#endif // VCL_IO_CAMERA_GLTF_LOAD_H
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
A class representing a line segment in n-dimensional space. The class is parameterized by a PointConc...
Definition segment.h:41
Segment()
Default constructor. Creates a segment with endpoints at the origin.
Definition segment.h:66
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