Lagrange
Scene.h
1/*
2 * Copyright 2023 Adobe. All rights reserved.
3 * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License. You may obtain a copy
5 * of the License at http://www.apache.org/licenses/LICENSE-2.0
6 *
7 * Unless required by applicable law or agreed to in writing, software distributed under
8 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9 * OF ANY KIND, either express or implied. See the License for the specific language
10 * governing permissions and limitations under the License.
11 */
12#pragma once
13
14#include <lagrange/SurfaceMesh.h>
15#include <lagrange/common.h>
16#include <lagrange/fs/filesystem.h>
17#include <lagrange/scene/SceneExtension.h>
18#include <lagrange/scene/api.h>
19#include <lagrange/utils/invalid.h>
20
21#include <Eigen/Geometry>
22
23#include <string>
24#include <vector>
25
26namespace lagrange {
27
32enum class AttributeValueType : uint8_t;
33
34} // namespace lagrange
35
36namespace lagrange::scene {
37
38using ElementId = size_t;
39constexpr ElementId invalid_element = lagrange::invalid<ElementId>();
40
41// Used in Node, it pairs a mesh with its materials (zero, one, or more).
42struct LA_SCENE_API SceneMeshInstance
43{
44 // Mesh index. Has to be a valid index in the scene.meshes vector.
45 ElementId mesh = invalid_element;
46
47 // Material indices in the scene.materials vector.
48 // When a single mesh uses multiple materials,
49 // the AttributeName::material_id facet attribute should be defined.
50 std::vector<ElementId> materials;
51};
52
53// Represents a node in the scene hierarchy.
54struct LA_SCENE_API Node
55{
56 // Note that the node name may not be unique, and can be empty.
57 std::string name;
58
59 // Transform of the node, relative to its parent.
60 Eigen::Affine3f transform = Eigen::Affine3f::Identity();
61
62 // parent index. May be invalid if the node has no parent (e.g. the root).
63 ElementId parent = invalid_element;
64
65 // children indices. May be empty.
66 std::vector<ElementId> children;
67
68 // List of meshes contained in this node.
69 // Node that some file formats only allow 1 mesh per node (gltf). In this case we treat
70 // multiple meshes as one mesh with multiple primitives, and only one material per mesh is
71 // allowed.
72 std::vector<SceneMeshInstance> meshes;
73
74 // List of cameras contained in this node.
75 std::vector<ElementId> cameras;
76
77 // List of lights contained in this node.
78 std::vector<ElementId> lights;
79
80 Extensions extensions;
81};
82
86struct LA_SCENE_API ImageBufferExperimental
87{
89 size_t width = 0;
90
92 size_t height = 0;
93
95 size_t num_channels = 4;
96
99
101 std::vector<unsigned char> data;
102
106 size_t get_bits_per_element() const;
107};
108
112struct LA_SCENE_API ImageExperimental
113{
115 std::string name;
116
119
122 fs::path uri;
123
126};
127
128
129// Pair of texture index (which texture to use) and texture coordinate index (which set of UVs to
130// use).
131struct LA_SCENE_API TextureInfo
132{
133 // Texture index. Index in scene.textures vector.
134 ElementId index = invalid_element;
135
136 // Index of UV coordinates. Usually stored in the mesh as `texcoord_x` attribute where x is this
137 // variable. This is typically 0.
138 int texcoord = 0;
139};
140
141// PBR material, based on the gltf specification.
142// This is subject to change, to support more material models.
143struct LA_SCENE_API MaterialExperimental
144{
145 // Note that material name may not be unique, and can be empty.
146 std::string name;
147
148 Eigen::Vector4f base_color_value = Eigen::Vector4f::Ones();
149 TextureInfo base_color_texture;
150
151 Eigen::Vector3f emissive_value = Eigen::Vector3f::Zero();
152 TextureInfo emissive_texture;
153
154 // metalness and roughness are packed together in a single texture.
155 // green channel has roughness, blue channel has metalness.
156 TextureInfo metallic_roughness_texture;
157 float metallic_value = 1.f;
158 float roughness_value = 1.f;
159
160 // The alpha mode specifies how to interpret the alpha value of the base color.
161 enum class AlphaMode {
162 Opaque, // Alpha is ignored, and rendered output is opaque
163 Mask, // Output is either opaque or transparent depending on the alpha value and the
164 // alpha_cutoff value.
165 Blend // Alpha value is used to composite source and destination.
166 };
167 AlphaMode alpha_mode = AlphaMode::Opaque;
168 float alpha_cutoff = 0.5f;
169
170
171 // normal = normalize(<sampled tex value> * 2 - 1) * vec3(scale, scale, 1)
172 float normal_scale = 1.f;
173 TextureInfo normal_texture;
174
175 // color = lerp(color, color * <sampled tex value>, strength)
176 float occlusion_strength = 1.f;
177 TextureInfo occlusion_texture;
178
179 bool double_sided = false;
180
181 Extensions extensions;
182};
183
184struct LA_SCENE_API Texture
185{
186 std::string name;
187 ElementId image = invalid<ElementId>(); // index of image in scene.images vector
188
189 enum TextureFilter : int {
190 Undefined = 0,
191 Nearest = 9728,
192 Linear = 9729,
193 NearestMimpapNearest = 9984,
194 LinearMipmapNearest = 9985,
195 NearestMipmapLinear = 9986,
196 LinearMipmapLinear = 9987
197 };
198 // Texture magnification filter, used when texture appears larger on screen than the source
199 // image. Allowed values are UNDEFINED, NEAREST, LINEAR
200 TextureFilter mag_filter = TextureFilter::Undefined;
201
202 // Texture minification filter, used when the texture appears smaller on screen than the source
203 // image. Allowed values are: UNDEFINED, NEAREST, LINEAR, NEAREST_MIPMAP_NEAREST,
204 // LINEAR_MIPMAP_NEAREST, NEAREST_MIPMAP_LINEAR, LINEAR_MIPMAP_LINEAR
205 TextureFilter min_filter = TextureFilter::Undefined;
206
207 enum class WrapMode {
208 Wrap, // u|v becomes u%1|v%1
209 Clamp, // coordinates outside [0, 1] are clamped to the nearest value
210 Decal, // If the texture coordinates for a pixel are outside [0, 1], the texture is not
211 // applied
212 Mirror
213 };
214 WrapMode wrap_u = WrapMode::Wrap;
215 WrapMode wrap_v = WrapMode::Wrap;
216
217 Eigen::Vector2f scale = Eigen::Vector2f::Ones();
218 Eigen::Vector2f offset = Eigen::Vector2f::Zero();
219 float rotation = 0.0f;
220
221 Extensions extensions;
222};
223
224struct LA_SCENE_API Light
225{
226 std::string name;
227
228 enum class Type { Undefined, Directional, Point, Spot, Ambient, Area };
229 Type type = Type::Undefined;
230
231 // note that the light is part of the scene graph, and has an associated transform in its node.
232 // The values below (position, up, look_at) are relative to the coordinate system defined by the
233 // node.
234 Eigen::Vector3f position = Eigen::Vector3f::Zero();
235 Eigen::Vector3f direction = Eigen::Vector3f(0, 1, 0);
236 Eigen::Vector3f up = Eigen::Vector3f(0, 0, 1);
237
238 // Attenuation factor. Intensity of light at a given distance 'd' is:
239 // intensity / (attenuation_constant
240 // + attenuation_linear * d
241 // + attenuation_quadratic * d * d
242 // + attenuation_cubic * d * d * d)
243 float intensity = 1.f;
244 float attenuation_constant = 1.f;
245 float attenuation_linear = 0.f;
246 float attenuation_quadratic = 0.f;
247 float attenuation_cubic = 0.f;
248
249 // Range is defined for point and spot lights. It defines a distance cutoff at which the
250 // light intensity is to be considered zero, so the light does not affects objects beyond this
251 // range. When the value is 0, range is assumed to be infinite.
252 float range = 0.0;
253
254 // Colors
255 Eigen::Vector3f color_diffuse = Eigen::Vector3f::Zero();
256 Eigen::Vector3f color_specular = Eigen::Vector3f::Zero();
257 Eigen::Vector3f color_ambient = Eigen::Vector3f::Zero();
258
259 // inner and outer angle of a spot light's light cone
260 // they are both 2PI for point lights, and undefined for directional lights.
261 float angle_inner_cone;
262 float angle_outer_cone;
263
264 // size of area light source
265 Eigen::Vector2f size = Eigen::Vector2f::Zero();
266
267 Extensions extensions;
268};
269
270struct LA_SCENE_API Camera
271{
272 // note that the camera is part of the scene graph, and has an associated transform in its node.
273 // The values below (position, up, look_at) are relative to the coordinate system defined by the
274 // node.
275 std::string name;
276 Eigen::Vector3f position = Eigen::Vector3f::Zero();
277 Eigen::Vector3f up = Eigen::Vector3f(0, 1, 0);
278 Eigen::Vector3f look_at = Eigen::Vector3f(0, 0, 1);
279
280 // Distance of the near clipping plane. This value cannot be 0.
281 float near_plane = 0.1f;
282
283 // Distance of the far clipping plane.
284 float far_plane = 1000.f;
285
286 enum class Type { Perspective, Orthographic };
287 Type type = Type::Perspective;
288
289 // Half width of the orthographic view box. Or horizontal magnification.
290 //
291 // This is only defined when the camera type is orthographic, otherwise it should be 0.
292 float orthographic_width = 0.f;
293
294 // Screen aspect ratio. This is the value of width / height of the screen.
295 //
296 // aspect_ratio = tan(horizontal_fov / 2) / tan(vertical_fov / 2)
297 //
298 // So we can compute any of those 3 variables from any 2. We store 2 (aspect_ratio and
299 // horizontal_fov) and provide utilities below to compute any of them from the other 2.
300 float aspect_ratio = 1.f;
301
302 // horizontal field of view angle, in radians.
303 //
304 // This is the angle between the left and right borders of the viewport.
305 // It should not be greater than Pi.
306 //
307 // fov is only defined when the camera type is perspective, otherwise it should be 0.
308 float horizontal_fov = (float)M_PI_2;
309
310 // convenience methods to get or set the vertical fov instead.
311 // make sure aspect_ratio is set before calling those!
312 float get_vertical_fov() const
313 {
314 return 2.f * std::atan(std::tan(horizontal_fov * 0.5f) / aspect_ratio);
315 }
316 void set_horizontal_fov_from_vertical_fov(float vfov)
317 {
318 horizontal_fov = 2.f * std::atan(std::tan(vfov * 0.5f) * aspect_ratio);
319 }
320 void set_aspect_ratio_from_fov(float vfov, float hfov)
321 {
322 aspect_ratio = std::tan(hfov * 0.5f) / std::tan(vfov * 0.5f);
323 }
324
325 Extensions extensions;
326};
327
328struct LA_SCENE_API Animation
329{
330 std::string name;
331 // TODO
332
333 Extensions extensions;
334};
335
336struct LA_SCENE_API Skeleton
337{
338 // This skeleton is used to deform those meshes.
339 // This will typically contain one value, but can have zero or multiple meshes.
340 // The value is the index in the scene meshes.
341 std::vector<ElementId> meshes;
342 // TODO
343
344 Extensions extensions;
345};
346
347template <typename Scalar, typename Index>
348struct Scene
349{
351
352 // Name of the scene
353 std::string name;
354
355 // Scene nodes. This is a list of nodes, the hierarchy information is contained by each
356 // node having a list of children as indices to this vector.
357 std::vector<Node> nodes;
358
359 // Root nodes. This is typically one. Must be at least one.
360 std::vector<ElementId> root_nodes;
361
362 // Scene meshes.
363 std::vector<MeshType> meshes;
364
365 // Images.
366 std::vector<ImageExperimental> images;
367
368 // Textures. They can reference images;
369 std::vector<Texture> textures;
370
371 // Materials. They can reference textures.
372 std::vector<MaterialExperimental> materials;
373
374 // Lights in the scene.
375 std::vector<Light> lights;
376
377 // Cameras. The first camera (if any) is the default camera view.
378 std::vector<Camera> cameras;
379
380 // Scene skeletons.
381 std::vector<Skeleton> skeletons;
382
383 // Unused for now.
384 std::vector<Animation> animations;
385
386 // Extensions.
387 Extensions extensions;
388
389public:
398 template <typename T>
399 ElementId add(T&& value);
400
408 void add_child(ElementId parent_id, ElementId child_id);
409};
410
411template <typename Scalar, typename Index>
412template <typename T>
413ElementId Scene<Scalar, Index>::add(T&& value)
414{
415 using ElementType = std::decay_t<T>;
416 if constexpr (std::is_same_v<ElementType, Node>) {
417 nodes.emplace_back(std::forward<T>(value));
418 return nodes.size() - 1;
419 } else if constexpr (std::is_same_v<ElementType, MeshType>) {
420 meshes.emplace_back(std::forward<T>(value));
421 return meshes.size() - 1;
422 } else if constexpr (std::is_same_v<ElementType, ImageExperimental>) {
423 images.emplace_back(std::forward<T>(value));
424 return images.size() - 1;
425 } else if constexpr (std::is_same_v<ElementType, Texture>) {
426 textures.emplace_back(std::forward<T>(value));
427 return textures.size() - 1;
428 } else if constexpr (std::is_same_v<ElementType, MaterialExperimental>) {
429 materials.emplace_back(std::forward<T>(value));
430 return materials.size() - 1;
431 } else if constexpr (std::is_same_v<ElementType, Light>) {
432 lights.emplace_back(std::forward<T>(value));
433 return lights.size() - 1;
434 } else if constexpr (std::is_same_v<ElementType, Camera>) {
435 cameras.emplace_back(std::forward<T>(value));
436 return cameras.size() - 1;
437 } else if constexpr (std::is_same_v<ElementType, Skeleton>) {
438 skeletons.emplace_back(std::forward<T>(value));
439 return skeletons.size() - 1;
440 } else if constexpr (std::is_same_v<ElementType, Animation>) {
441 animations.emplace_back(std::forward<T>(value));
442 return animations.size() - 1;
443 } else {
444 static_assert(StaticAssertableBool<T>::False, "Unsupported type");
445 }
446}
447
452
453} // namespace lagrange::scene
AttributeValueType
Enum describing at runtime the value type of an attribute.
Definition: AttributeValueType.h:25
internal::Range< Index > range(Index end)
Returns an iterable object representing the range [0, end).
Definition: range.h:176
Main namespace for Lagrange.
Definition: AABBIGL.h:30
Compilers might complain about static_assert(false, "").
Definition: common.h:96
Definition: Scene.h:329
Definition: Scene.h:271
Definition: SceneExtension.h:192
Minimalistic image data structure that stores the raw image data.
Definition: Scene.h:87
AttributeValueType element_type
The scalar type of the elements in the buffer.
Definition: Scene.h:98
std::vector< unsigned char > data
Raw buffer of size (width * height * num_channels * num_bits_per_element / 8) bytes containing image ...
Definition: Scene.h:101
Image structure that can store either image data or reference to an image file.
Definition: Scene.h:113
Extensions extensions
Image extensions.
Definition: Scene.h:125
ImageBufferExperimental image
Image data.
Definition: Scene.h:118
std::string name
Image name. Not guaranteed to be unique and can be empty.
Definition: Scene.h:115
fs::path uri
Image file path.
Definition: Scene.h:122
Definition: Scene.h:225
Definition: Scene.h:55
Definition: Scene.h:349
void add_child(ElementId parent_id, ElementId child_id)
Add a child node to a given parent node.
Definition: Scene.cpp:19
ElementId add(T &&value)
Add an element to the scene.
Definition: Scene.h:413
Definition: Scene.h:337
Definition: Scene.h:185
Definition: Scene.h:132