-
Notifications
You must be signed in to change notification settings - Fork 455
/
Copy pathRenderer.h
948 lines (819 loc) · 37.5 KB
/
Renderer.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
// Copyright (c) Meta Platforms, Inc. and its affiliates.
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.
#ifndef ESP_GFX_BATCH_RENDERER_H_
#define ESP_GFX_BATCH_RENDERER_H_
#include <Corrade/Containers/Pointer.h>
#include <Magnum/GL/GL.h>
#include <Magnum/Magnum.h>
#include <Magnum/Math/Vector2.h>
#include <cstddef>
namespace esp {
namespace gfx_batch {
/**
@brief Global batch renderer flag
@see @ref RendererFlags, @ref RendererConfiguration::setFlags()
*/
enum class RendererFlag {
/**
* Render without textures.
*
* Causes textures to not even get loaded, potentially saving significant
* amount of memory. Only material and vertex colors are used for rendering.
*/
NoTextures = 1 << 0
// TODO memory-map
};
/**
@brief Global batch renderer flags
@see @ref RendererConfiguration::setFlags()
*/
typedef Corrade::Containers::EnumSet<RendererFlag> RendererFlags;
CORRADE_ENUMSET_OPERATORS(RendererFlags)
/**
@brief Output rendered by a particular batch camera
@see @ref RendererBatchCameraOutputs, @ref RendererBatchCamera,
@ref RendererConfiguration::setBatchCameras()
*/
enum class RendererBatchCameraOutput {
Color = 1 << 0, /**< Color buffer */
Depth = 1 << 1, /**< Depth buffer */
Semantic = 1 << 2 /**< Semantic buffer */
};
/**
@brief Buffers rendered by a particular batch camera
@see @ref RendererBatchCamera, @ref RendererConfiguration::setBatchCameras()
*/
typedef Corrade::Containers::EnumSet<RendererBatchCameraOutput> RendererBatchCameraOutputs;
CORRADE_ENUMSET_OPERATORS(RendererBatchCameraOutputs)
/**
@brief Batch camera setup
@see @ref RendererConfiguration::setBatchCameras()
*/
struct RendererBatchCamera {
/** @brief Outputs rendered by the batch camera */
RendererBatchCameraOutputs outputs;
/** @brief Tile size, in pixels */
Magnum::Vector2i tileSize;
/** @brief Tile count */
Magnum::Vector2i tileCount;
};
class Renderer;
/**
@brief Global renderer configuration
Passed to @ref Renderer::Renderer(const RendererConfiguration&) and
@ref RendererStandalone::RendererStandalone(const RendererConfiguration&, const RendererStandaloneConfiguration&).
@see @ref Renderer, @ref RendererStandaloneConfiguration
*/
struct RendererConfiguration {
explicit RendererConfiguration();
~RendererConfiguration();
/**
* @brief Set renderer flags
*
* By default no flags are set.
* @see @ref Renderer::flags()
*/
RendererConfiguration& setFlags(RendererFlags flags);
/**
* @brief Set batch camera properties
*
* For each batch camera there's one framebuffer with tiles organized in a
* grid and @ref RendererBatchCamera::tileCount implies an upper bound on
* number of scenes rendered by that particular camera. To avoid hitting GPU
* limits with large tile counts and/or sizes, it's best to aim for the total
* framebuffer size given by @cpp tileSize*tileCount @ce to be a power-of-two
* square. On the other hand, having tiles organized in a single column may
* make it easier for external libraries to consume the data tile-by-tile, as
* there's no row stride to account for.
*
* Assigning of scenes to particular cameras is done in
* @ref setSceneBatchCameras(). Tiles that are empty are not rendered at all,
* so it's fine to have unused tiles, they only occupy space in given
* camera's framebuffer. For example, if you need a particular camera to
* render 13 scenes, set its @ref RendererBatchCamera::tileCount to
* @cpp {4, 4} @ce and ignore the last 3.
*
* By default there's a single color + depth batch camera with a single
* @cpp {128, 128} @ce tile, corresponding to a single rendered scene.
* @see @ref Renderer::batchCameraCount(), @ref Renderer::tileSize(),
* @ref Renderer::tileCount()
*/
RendererConfiguration& setBatchCameras(Corrade::Containers::ArrayView<const RendererBatchCamera> cameras);
/** @overload */
RendererConfiguration& setBatchCameras(std::initializer_list<RendererBatchCamera> cameras);
/**
* @brief Set scene count and scene to batch camera assignment
*
* Size of the first dimension is the total scene count, which will become
* @ref Renderer::sceneCount(). The second dimension then becomes
* @ref Renderer::sceneBatchCameras(), is expected to be contiguous and have
* the same size as camera count passed to @ref setBatchCameras(). A bit set
* at position @cpp [i, j] @ce means scene `i` will be shown in camera `j`.
* The total count of bits set for a particular camera is expected to not
* exceed the total tile count set for that camera in @ref setBatchCameras().
*
* By default, each scene gets assigned to all cameras, i.e. as if this
* function was called with @p assignment being all ones.
*/
RendererConfiguration& setSceneBatchCameras(const Corrade::Containers::StridedBitArrayView2D& cameras);
/**
* @brief Set max light count per draw
*
* By default no lights are used, i.e. flat-shaded rendering. At the moment
* there's no light culling in place, which means that light count per draw
* is equivalent to the total light count used per scene.
* @see @ref Renderer::maxLightCount()
*/
RendererConfiguration& setMaxLightCount(Magnum::UnsignedInt count);
/**
* @brief Set ambient factor
*
* How much of the diffuse color / texture is used for ambient light in
* Phong-shaded materials. Default value is @cpp 0.1f @ce, setting it to
* @cpp 0.0f @ce will make the render completely black in areas without light
* contribution. In comparison, flat-shaded materials (i.e., imported with
* @ref Magnum::Trade::MaterialType::Flat) have the ambient factor always
* @cpp 1.0 @ce and are unaffected by lights.
*
* This value can currently only set upfront due to how materials are
* implemented internally.
*/
RendererConfiguration& setAmbientFactor(Magnum::Float factor);
private:
friend Renderer;
struct State;
Corrade::Containers::Pointer<State> state;
};
/**
@brief Batch renderer file treatment flag
@see @ref RendererFileFlags, @ref Renderer::addFile()
*/
enum class RendererFileFlag {
/**
* Treat the file as a whole.
*
* By default a file is treated as a so-called *composite* --- a collection
* of *node hierarchy templates* --- which you then add with
* @ref Renderer::addNodeHierarchy() using a name corresponding to one of the
* root nodes. With this flag set, the whole file is treated as a single
* hierarchy instead, with the @p filename (or @p name, if present) argument
* of @ref Renderer::addFile() used as a name.
*
* @m_class{m-note m-warning}
*
* @par
* This flag is required to be set when importing scene-less files such as
* STL or PLY.
*/
Whole = 1 << 0,
/**
* Generate a mipmap out of single-level uncompressed textures.
*
* By default, no renderer-side processing of imported textures is done ---
* if the image contains multiple levels, they're imported as well, otherwise
* just a single level is uploaded, regardless of whether the texture has a
* filtering across mip levels set up.
*
* With this option enabled, if the input image is uncompressed and there's
* just a single level, the texture is created with a full mip pyramid and
* the lower levels get generated on the fly, leading to a smoother look with
* large textures. On-the-fly mip level generation is impossible for
* compressed formats, there this option is ignored.
*/
GenerateMipmap = 1 << 1
};
/**
@brief Batch renderer file treatment flags
@see @ref Renderer::addFile()
*/
typedef Corrade::Containers::EnumSet<RendererFileFlag> RendererFileFlags;
CORRADE_ENUMSET_OPERATORS(RendererFileFlags)
/**
@brief Renderer light type
@see @ref Renderer::addLight()
*/
enum class RendererLightType {
Directional = 0, /**< Directional */
Point = 1 /**< Point */
};
struct SceneStats;
// Even though Clang Format is told to skip formatting comments containing
// @section or @ref which can't be wrapped to prevent Doxygen bugs, it still
// wants to do that here. So I'm disabling it for this doc block altogether.
// clang-format off
/**
@brief Batch renderer
A renderer optimized for drawing multiple scenes at once, applying multi-draw
optimizations where possible to reduce draw overhead. While all scenes are
rendered at once, each scene contains an independent set of rendered objects.
This class expects an active @ref Magnum::GL::Context and renders into a
provided framebuffer, making it suitable for use in GUI applications. For
standalone operation use the @ref RendererStandalone subclass instead, which
manages the OpenGL context and a framebuffer on its own. Apart from the context
and framebuffer, the high-level usage is same for both.
@section gfx_batch-Renderer-terms Terms used
- **Model file** is a regular glTF, OBJ, PLY, ... model, with no restrictions
on its contents. The whole file is treated as a single *node heirarchy*.
- **Composite file** is a set of regular *model files* brought together into a
single file with various optimizations applied. Often it's a single
*composite mesh* together with a single *composite texture*. The original
model files form *node hierarchies* in the composite file and are referenced
using string identifiers.
- **Node hierarchy** is a hierarchy of nodes with meshes, materials or lights
attached. It's referenced using a string identifier in a *composite file*,
using a filename in a model and using a numeric ID when added to a *scene*.
- **Scene** is a set of *node hierarchies* added either from *model files* or
*composite files*. A single scene can appear in multiple *batch cameras*,
rendered by multiple *cameras*.
- **Batch camera** has a framebuffer with various *batch camera outputs*
attached and renders a grid of *scenes* assigned to it. All tiles in the grid
have the same size and each is a single *camera*.
- **Batch camera output** is a color, depth or semantic buffer to which a
*batch camera* renders.
- **Camera** is what a *batch camera* uses to render a particular *scene*. Its
output size is given by the *batch camera* tile size, contains a projection
and a transformation matrix and a mask of *node hierarchies* that it should
render from given *scene*.
@section gfx_batch-Renderer-usage Usage
The renderer gets constructed using a @ref RendererConfiguration with desired
tile size and count set via @ref RendererConfiguration::setTileSizeCount() as
described in its documentation. Each tile corresponds to one rendered scene,
organized in a grid, all scenes have the same rendered size.
First, files with meshes, materials and textures that are meant to be rendered
from should get added via @ref addFile(). The file itself isn't directly
rendered, instead it's treated as a *composite file* with named root scene
nodes being *node hierarchy templates* to be selectively added to particular
scenes. Apart from picking particular root nodes, it's also possible to treat
the whole file as a single hierarchy using @ref RendererFileFlag::Whole. See
the flag documentation for more information.
@m_class{m-note m-warning}
@par
All needed files should be added upfront, before populating the scenes or
drawing anything. This is currently not enforced in any way, but is subject
to change.
Then, particular scenes are populated using @ref addNodeHierarchy(),
referencing the node hierarchy templates via their names. The function takes an
initial transformation and returns an ID of the node added into the scene. The
ID can then be used to subsequently update its transformation via
@ref transformations(), for example in respose to a physics simulation or an
animation. Each scene also has an associated camera and its combined projection
and transformation matrix can be updated using @ref updateCamera().
Finally, the @ref draw() function renders the grid of scenes into a provided
framebuffer.
@section gfx_batch-Renderer-workflow Inner workflow of the batch renderer
The goal of the renderer is to do as much as possible using the least amount of
draw calls. For that, it relies heavily on multi-draw and texture array support
implemented in @ref shaders-usage-multidraw "Magnum shaders".
- At the beginning, all data from files added by @ref addFile() get uploaded to
the GPU. The data consists of meshes, texture image levels and packed
material uniforms. Such data are uploaded only once and treated as immutable
for the rest of the renderer lifetime.
- On each @ref addNodeHierarchy() call, a list of mesh views each together with
material association, texture layer and transform and node assignment is
added to a *draw list*. The draw list is
@ref gfx_batch-Renderer-workflow-draw-list "further detailed below".
- For each @ref draw() and each non-empty scene, the following is done:
- The transformation passed to @ref updateCamera() is uploaded to a uniform buffer.
- The renderer calculates hierarchical transformations for all nodes based on
the matrices supplied via @ref transformations(). Each item in the draw
list is then assigned a corresponding calculated absolute transformation,
and the list of transformations corresponding to all draws is uploaded to a
uniform buffer.
- Then the draw list is processed, resulting in one or more multi-draw calls
@ref gfx_batch-Renderer-workflow-draw-list "as described below".
@subsection gfx_batch-Renderer-workflow-draw-list Draw list and multi-draw call submission
In the ideal (and often impossible) case, there would be just a single file
added with @ref addFile(), containing exactly one mesh and exactly one texture
array, with scene nodes referring to sub-views of them --- i.e., mesh index
ranges, texture layer indices and texture transformation matrices. Then, no
matter how many times @ref addNodeHierarchy() gets called, the whole draw list
populated by it can be drawn with a single multi-draw call.
@m_class{m-note m-info}
@par
When @ref sceneStats() would be retrieved for such a case,
@ref SceneStats::nodeCount and @ref SceneStats::drawCount would be both high
numbers, while @ref SceneStats::drawBatchCount would be exactly @cpp 1 @ce.
In practice however, the files may contain meshes with different vertex layouts
(such as some having vertex colors and some not), textures of different formats
and sizes, and different materials requiring different shaders (such as
vertex-colored, alpha-masked etc.). Draw lists populated with
@ref addNodeHierarchy() are then partitioned into *draw batches*, where a
particular draw batch contains all draws with a particular shader, from a
particular mesh and with a particular texture. Each draw batch then corresponds
to a single multi-draw call issued on the GPU.
@subsection gfx_batch-Renderer-workflow-tradeoffs Performance tradeoffs
The optimization goal here is to pick a balance between minimizing driver
overhead from submitting many draw calls and paying extra cost for shader
features, texture fetches and vertex attributes present also for draws that
don't need them.
@m_class{m-note m-info}
@par
In other words, trying to maximize the ratio of @ref SceneStats::drawCount
and @ref SceneStats::drawBatchCount for as long as CPU usage gets lower but
GPU usage doesn't get higher.
For example, if only some meshes use vertex colors, it's possible to add white
vertex colors to the remaining meshes, unifying their layout and making it
possible to draw them together in a single draw call. The cost of extra vertex
processing bandwidth would probably be rather minimal. On the other hand, if
some materials need alpha masking and some not, attempting to draw everything
with alpha masking enabled may have a much larger cost than the additional draw
call saved by this change.
Here it's important to also take into account differences on the web --- there
the driver overhead is significantly higher and it might be beneficial to put
extra effort into reducing draw batch count even though it may result in
slightly worse performance natively.
@section gfx_batch-Renderer-files Creating batch-optimized files
While @ref addFile() can consume any count of any regular scene/model files
@ref file-formats "supported by Magnum", in order to properly take advantage of
all performance features it's needed to combine the files into batch-optimized
* *composite files* containing mesh views and texture arrays.
Batch-optimized files can be stored in any file format that has sufficient
flexibility for @ref Magnum::Trade::MeshData layouts, is capable of storing 2D
array textures and supports storing custom @ref Magnum::Trade::SceneData
fields. At the moment, a file format supporting all this is glTF, with files
produced using the @relativeref{Magnum::Trade,GltfSceneConverter} plugin.
@m_class{m-note m-info}
@par
For an overview of how a fully manual process of creating a batch-optimized
glTF file looks like, have a look at the `generateTestData()` function in the
[GfxBatchRendererTest.cpp](https://github.com/facebookresearch/habitat-sim/blob/main/src/tests/GfxBatchRendererTest.cpp)
file. Practical cases of dataset conversion would be more focused on reusing
and combining data imported from other files instead of creating them from
scratch, but the overall process is similar.
@subsection gfx_batch-Renderer-files-meshes Meshes and mesh views
* *Composite meshes*, which concatenate several meshes of the same layout
together, can be added with the general
@ref Magnum::Trade::AbstractSceneConverter::add(const MeshData&, Containers::StringView)
API and referenced from scene nodes via @ref Magnum::Trade::SceneField::Mesh.
* *Mesh views*, referencing sub-ranges of the composite mesh, aren't a builtin
@ref Magnum::Trade::SceneData feature at the moment however, and thus have to
be added as @ref Trade-SceneData-populating-custom "custom scene fields" of the
following names:
- `meshViewIndexOffset` of type @ref Magnum::Trade::SceneFieldType::UnsignedInt,
containing offset of the mesh view in the index buffer *in bytes*,
- `meshViewIndexCount` of type @ref Magnum::Trade::SceneFieldType::UnsignedInt,
containing index count, and
- `meshViewMaterial` of type @ref Magnum::Trade::SceneFieldType::Int containing
the corresponding material ID. The builtin
@ref Magnum::Trade::SceneField::MeshMaterial is not used, because glTF bakes
the material reference into the mesh itself, which means referencing the same
mesh multiple times with different materials would cause it to be
unnecessarily duplicated in the glTF.
The custom field IDs can be arbitrary, what's important is that they are
associated with corresponding names using
@ref Magnum::Trade::AbstractSceneConverter::setSceneFieldName(). Furthermore,
to prevent the file from being opened by unsuspecting glTF viewers, a private
`MAGNUMX_mesh_views` extension should be added as both
@cb{.ini} extensionUsed @ce and @cb{.ini} extensionRequired @ce in the
@ref Trade-GltfSceneConverter-configuration "plugin configuration". Inspecting
the resulting file with @ref magnum-sceneconverter "magnum-sceneconverter" may
look similarly to this:
@m_class{m-console-figure}
@parblock
@code{.sh}
magnum-sceneconverter --info-scenes -i ignoreRequiredExtensions batch.gltf
@endcode
<b><!-- don't remove, Doxygen workaround --></b>
@m_class{m-nopad}
@include gfx-batch-info-scenes.ansi
@endparblock
<b><!-- don't remove, Doxygen workaround --></b>
@m_class{m-note m-info}
@par
This implementation of mesh views is a temporary solution. Eventually mesh
views will become a builtin Magnum feature, being implicitly encoded in glTF
accessor properties in a way that's compatible with 3rd party glTF tools as
well.
<b><!-- don't remove, Doxygen workaround --></b>
@m_class{m-note m-success}
@par
Meshes can be concatenated together for example using
@ref Magnum::MeshTools::concatenate().
@subsection gfx_batch-Renderer-files-textures Texture arrays
For 2D texture arrays the
[KHR_texture_ktx](https://github.com/KhronosGroup/glTF/pull/1964) extension is
used. Because it's not approved by Khronos yet, it needs the
@cb{.ini} experimentalKhrTextureKtx @ce
@ref Trade-GltfSceneConverter-configuration "configuration option"
enabled in the converter plugin. Materials should reference layers of it via
@ref Magnum::Trade::MaterialAttribute::BaseColorTextureLayer and related
attributes, together with supplying
@relativeref{Magnum::Trade::MaterialAttribute,BaseColorTextureMatrix}
describing a sub-image of a particular layer. Inspecting the resulting file
with @ref magnum-sceneconverter "magnum-sceneconverter" may look similarly to
this:
@m_class{m-console-figure}
@parblock
@m_class{m-console-wrap}
@code{.sh}
magnum-sceneconverter --info-textures --info-images --info-materials \
-i experimentalKhrTextureKtx,ignoreRequiredExtensions batch.gltf
@endcode
<b></b>
@m_class{m-nopad}
@include gfx-batch-info-textures.ansi
@endparblock
@m_class{m-note m-success}
@par
2D textures with power-of-two sizes can be atlased into a texture array for
example using @ref Magnum::TextureTools::atlasArrayPowerOfTwo(). If a certain
texture needs @ref Magnum::SamplerWrapping::Repeat or
@relativeref{Magnum::SamplerWrapping,MirroredRepeat}, it has to occupy a
whole layer, or be a separate texture altogether.
*/
// clang-format on
class Renderer {
public:
/**
* @brief Constructor
* @param configuration Renderer configuration
*
* Expects an active @ref Magnum::GL::Context to be present.
*/
explicit Renderer(const RendererConfiguration& configuration)
: Renderer{Magnum::NoCreate} {
create(configuration);
}
virtual ~Renderer();
/**
* @brief Global renderer flags
*
* By default, no flags are set.
* @see @ref RendererConfiguration::setFlags()
*/
RendererFlags flags() const;
/**
* @brief Total batch camera count
*
* See @ref sceneBatchCameras() for an information about what scenes is given
* batch camera rendering. By default there's a single batch camera.
*/
Magnum::UnsignedInt batchCameraCount() const;
/**
* @brief Outputs enabled for given batch camera
* @param batchCameraId Batch camera ID, expected to be less than
* @ref batchCameraCount()
*/
RendererBatchCameraOutputs batchCameraOutputs(Magnum::UnsignedInt batchCameraId) const;
/**
* @brief Tile size
* @param batchCameraId Batch camera ID, expected to be less than
* @ref batchCameraCount()
*
* The default tile size is @cpp {128, 128} @ce.
* @see @ref RendererConfiguration::setTileSizeCount()
*/
Magnum::Vector2i tileSize(Magnum::UnsignedInt batchCameraId) const;
/**
* @brief Tile count
* @param batchCameraId Batch camera ID, expected to be less than
* @ref batchCameraCount()
*
* By default there's a single tile.
* @see @ref RendererConfiguration::setTileSizeCount()
*/
Magnum::Vector2i tileCount(Magnum::UnsignedInt batchCameraId) const;
/**
* @brief Total scene count
*
* See @ref sceneBatchCameras() for an information about what batch cameras
* is given scene included in and @ref sceneBatchCameraIndex() for the tile
* index in given batch camera. By default there's a single scene.
*/
Magnum::UnsignedInt sceneCount() const;
/**
* @brief Batch cameras which render given scene
* @param sceneId Scene ID, expected to be less than
* @ref sceneCount()
*
* The returned view has a size equal to @ref batchCameraCount(), with bits
* set for each batch camera that includes @p sceneId. By default there's a
* single scene rendered by a single camera, so this function returns a
* single bit that's set.
*/
Corrade::Containers::BitArrayView sceneBatchCameras(Magnum::UnsignedInt sceneId) const;
/**
* @brief Tile index at which given scene is rendered in given batch camera
* @param sceneId Scene ID, expected to be less than
* @ref sceneCount()
* @param batchCameraId Batch camera ID, expected to be less than
* @ref batchCameraCount()
*
* The @ref sceneBatchCameras() for given @p sceneId is expected to include
* @p batchCameraId. By default there's a single scene rendered by a single
* camera, so this function returns @cpp {0, 0} @ce.
*/
Magnum::Vector2i sceneBatchCameraIndex(Magnum::UnsignedInt sceneId, Magnum::UnsignedInt batchCameraId);
/**
* @brief Max light count
*
* By default there's zero lights, i.e. flat-shaded rendering.
* @see @ref RendererConfiguration::setMaxLightCount()
*/
Magnum::UnsignedInt maxLightCount() const;
#ifdef DOXYGEN_GENERATING_OUTPUT
/**
* @brief Add a file
* @param filename File to add
* @param flags File flags
* @param name Hierarchy name. Ignored if
* @ref RendererFileFlag::Whole isn't set.
*
* By default a file is treated as a so-called *composite* --- a collection
* of *node hierarchy templates*, which you then add with
* @ref Renderer::addNodeHierarchy() using a name corresponding to one of the
* root nodes. This means all root nodes have to be named and have their
* names unique.
*
* If @ref RendererFileFlag::Whole is set, the whole file is treated as a
* single mesh hierarchy template instead, named @p name, or if @p name is
* empty with the @p filename used as a name.
*
* Returns @cpp true @ce on success. Prints a message to @ref Magnum::Error
* and returns @cpp false @ce if the file can't be imported or the names are
* conflicting.
*/
// TODO the name could be used as a prefix for hierarchy template names to
// make it possible to add several files of the same name
bool addFile(Corrade::Containers::StringView filename,
RendererFileFlags flags = {},
Corrade::Containers::StringView name = {});
#else
/* To avoid having to include StringView in the header */
bool addFile(Corrade::Containers::StringView filename,
RendererFileFlags flags,
Corrade::Containers::StringView name);
bool addFile(Corrade::Containers::StringView filename,
RendererFileFlags flags = {});
#endif
#ifdef DOXYGEN_GENERATING_OUTPUT
/**
* @brief Add a file using a custom importer plugin
* @param filename File to add
* @param importerPlugin Importer plugin name or path
* @param flags File flags
* @param name Hierarchy name. Ignored if
* @ref RendererFileFlag::Whole isn't set.
*
* See @ref addFile(Corrade::Containers::StringView, RendererFileFlags, Corrade::Containers::StringView)
* for more information.
*/
// TODO take an importer instead? that way the consumer can configure it,
// retrieve its own data from it...
bool addFile(Corrade::Containers::StringView filename,
Corrade::Containers::StringView importerPlugin,
RendererFileFlags flags = {},
Corrade::Containers::StringView name = {});
#else
/* To avoid having to include StringView in the header */
bool addFile(Corrade::Containers::StringView filename,
Corrade::Containers::StringView importerPlugin,
RendererFileFlags flags,
Corrade::Containers::StringView name);
bool addFile(Corrade::Containers::StringView filename,
Corrade::Containers::StringView importerPlugin,
RendererFileFlags flags = {});
#endif
/**
* @brief If given mesh hierarchy exists
*
* Returns @cpp true @ce if @p name is a mesh hierarchy name added by any
* previous @ref addFile() call, @cpp false @ce otherwise.
*/
bool hasNodeHierarchy(Corrade::Containers::StringView name) const;
#ifdef DOXYGEN_GENERATING_OUTPUT
/**
* @brief Add a mesh hierarchy
* @param sceneId Scene ID, expected to be less than
* @ref sceneCount()
* @param cameras Camears to include the hierarchy in
* @param name *Node hierarchy template* name, added with
* @ref addFile() earlier
* @param bakeTransformation Transformation to bake into the hierarchy
* @return ID of the newly added node
*
* Size of the @p cameras view is expected to be the same as
* @ref batchCameraCount(), bits that are zero in @ref sceneBatchCameras()
* for given @p sceneId are expected to be zero in @p cameras as well.
*
* The returned ID can be subsequently used to update transformations via
* @ref transformations(). The returned IDs are *not* contiguous, the gaps
* correspond to number of child nodes in the hierarchy.
*
* The @p bakeTransformation is baked into the added hierarchy, i.e.
* @ref transformations() at the returned ID is kept as an identity transform
* and writing to it will not overwrite the baked transformation. This
* parameter is useful for correcting orientation/scale of the imported mesh.
* @see @ref hasNodeHierarchy(), @ref clear()
*/
std::size_t addNodeHierarchy(Magnum::UnsignedInt sceneId,
Corrade::Containers::StringView name,
Corrade::Containers::BitArrayView cameras,
const Magnum::Matrix4& bakeTransformation = {});
#else
/* To avoid having to include Matrix4 in the header */
std::size_t addNodeHierarchy(Magnum::UnsignedInt sceneId,
Corrade::Containers::StringView name,
Corrade::Containers::BitArrayView cameras,
const Magnum::Matrix4& bakeTransformation);
std::size_t addNodeHierarchy(Magnum::UnsignedInt sceneId,
Corrade::Containers::StringView name,
Corrade::Containers::BitArrayView cameras);
#endif
/**
* @brief Add an empty node
* @param sceneId Scene ID, expected to be less than
* @ref sceneCount()
* @param cameras Camears to include the node in
*
* Size of the @p cameras view is expected to be the same as
* @ref batchCameraCount(), bits that are zero in @ref sceneBatchCameras()
* for given @p sceneId are expected to be zero in @p cameras as well.
*/
std::size_t addEmptyNode(Magnum::UnsignedInt sceneId,
Corrade::Containers::BitArrayView cameras);
/**
* @brief Add a light
* @param sceneId Scene ID, expected to be less than
* @ref sceneCount()
* @param nodeId Node ID to inherit transformation from, returned
* from @ref addNodeHierarchy() or @ref addEmptyNode() earlier
* @param type Light type. Can't be changed after adding the
* light.
*
* The light is used for all cameras that the @p nodeId is included in. If
* @p type is @ref RendererLightType::Directional, a negative
* @ref Magnum::Matrix4::backwards() is taken from @p nodeId transformation
* as the direction, if @p type is @ref RendererLightType::Point,
* @ref Magnum::Matrix4::translation() is taken from @p nodeId transformation
* as the position. The ID returned from this function can be subsequently
* used to update light properties via @ref lightColors() and
* @ref lightRanges().
* @see @ref clearLights(), @ref clear()
*/
std::size_t addLight(Magnum::UnsignedInt sceneId,
std::size_t nodeId,
RendererLightType type);
/**
* @brief Clear a scene
* @param sceneId Scene ID, expected to be less than @ref sceneCount()
*
* Clears everything added by @ref addNodeHierarchy(),
* @ref addEmptyNode() and @ref addLight().
* @see @ref clearLights()
*/
void clear(Magnum::UnsignedInt sceneId);
/**
* @brief Clear lights in a scene
* @param sceneId Scene ID, expected to be less than @ref sceneCount()
*
* Clears everything added by @ref addLight().
* @see @ref clear()
*/
void clearLights(Magnum::UnsignedInt sceneId);
/**
* @brief Get the combined projection and view matrices of a camera
* @param sceneId Scene ID, expected to be less than
* @ref sceneCount()
* @param batchCameraId Batch camera ID, expected to be less than
* @ref batchCameraCount()
*
* The @ref sceneBatchCameras() for given @p sceneId is expected to include
* @p batchCameraId.
*/
Magnum::Matrix4 camera(Magnum::UnsignedInt sceneId,
Magnum::UnsignedInt batchCameraId) const;
/**
* @brief Get the depth unprojection parameters of a camera
* @param sceneId Scene ID, expected to be less than
* @ref sceneCount()
* @param batchCameraId Batch camera ID, expected to be less than
* @ref batchCameraCount()
*
* The @ref sceneBatchCameras() for given @p sceneId is expected to include
* @p batchCameraId.
*/
Magnum::Vector2 cameraDepthUnprojection(Magnum::UnsignedInt sceneId,
Magnum::UnsignedInt batchCameraId) const;
/**
* @brief Set the camera projection and view matrices
* @param sceneId Scene ID, expected to be less than
* @ref sceneCount()
* @param batchCameraId Batch camera ID, expected to be less than
* @ref batchCameraCount()
* @param view View matrix of the camera (inverse transform)
* @param projection Projection matrix of the camera
*
* The @ref sceneBatchCameras() for given @p sceneId is expected to include
* @p batchCameraId. Also computes the camera unprojection. Modifications to
* the transformation are taken into account in the next @ref draw().
*/
void updateCamera(Magnum::UnsignedInt sceneId,
Magnum::UnsignedInt batchCameraId,
const Magnum::Matrix4& projection,
const Magnum::Matrix4& view);
/**
* @brief Transformations of all nodes in the scene
* @param sceneId Scene ID, expected to be less than @ref sceneCount()
*
* Returns a view on all node transformations in given scene. Desired usage
* is to update only transformations at indices returned by
* @ref addNodeHierarchy() and @ref addEmptyNode(), updating transformations
* at other indices is possible but could have unintended consequences.
* Modifications to the transformations are taken into account in the next
* @ref draw(). By default, transformations of root nodes (those which IDs
* were returned from @ref addNodeHierarchy() or @ref addEmptyNode()) are
* identities, transformations of other nodes are unspecified.
*/
Corrade::Containers::StridedArrayView1D<Magnum::Matrix4> transformations(
Magnum::UnsignedInt sceneId);
/**
* @brief Colors of all lights in the scene
* @param sceneId Scene ID, expected to be less than @ref sceneCount()
*
* Returns a view on colors of all lights in given scene. Desired usage is to
* update only colors at indices returned by @ref addLight(), updating colors
* at other indices is possible but could have unintended consequences.
* Modifications to the lights are taken into account in the next
* @ref draw(). By default, colors of root lights (those which IDs were
* returned from @ref addLight()) are @cpp 0xffffff_rgbf @ce, colors of other
* lights are unspecified.
*/
Corrade::Containers::StridedArrayView1D<Magnum::Color3> lightColors(
Magnum::UnsignedInt sceneId);
/**
* @brief Ranges of all lights in the scene
* @param sceneId Scene ID, expected to be less than @ref sceneCount()
*
* Returns a view on ranges of all lights in given scene. Desired usage is to
* update only ranges at indices returned by @ref addLight(), updating ranges
* at other indices is possible but could have unintended consequences.
* Modifications to the lights are taken into account in the next
* @ref draw(). The value range is ignored for
* @ref RendererLightType::Directional. By default, ranges of root lights
* (those which IDs were returned from @ref addLight()) are
* @ref Magnum::Constants::inf(), ranges of other lights are unspecified.
*/
Corrade::Containers::StridedArrayView1D<Magnum::Float> lightRanges(
Magnum::UnsignedInt sceneId);
/**
* @brief Draw all scenes associated with given batch camera into provided framebuffer
* @param batchCameraId Batch camera ID, expected to be less than
* @ref batchCameraCount()
*
* The @p framebuffer is expected to have a size at least as larger as the
* product of @ref tileSize() and @ref tileCount() and contain attachments
* for all @ref batchCameraOutputs() for given @p batchCameraId. You can use
* @ref sceneBatchCameraIndex() to query tile index for a particular scene in
* the output.
*/
void draw(Magnum::UnsignedInt batchCameraId, Magnum::GL::AbstractFramebuffer& framebuffer);
/**
* @brief Scene stats
*
* Mainly for testing and introspection purposes. The returned info is
* up-to-date only if @ref draw() has been called before.
*/
SceneStats sceneStats(Magnum::UnsignedInt sceneId) const;
#ifndef DOXYGEN_GENERATING_OUTPUT
protected:
/* used by RendererStandalone */
explicit Renderer(Magnum::NoCreateT);
void create(const RendererConfiguration& configuration);
void destroy();
#endif
private:
struct State;
Corrade::Containers::Pointer<State> state_;
};
/**
@brief Statistics for a single renderer scene
Returned by @ref Renderer::sceneStats().
*/
struct SceneStats {
/**
* @brief Count of transformable nodes
*
* Same as size of the array returned by @ref Renderer::transformations().
*/
std::size_t nodeCount;
/**
* @brief Count of draws across all draw batches
*
* Never larger than @ref nodeCount. Usually much smaller, as certain nodes
* are only manipulators grouping a set of other actually renderable nodes.
*/
std::size_t drawCount;
/**
* @brief Count of draw batches
*
* Ideal case is just one, but if there's more files or more textures, then
* each such combination needs a dedicated draw batch. Never larger than
* @ref drawCount.
*/
std::size_t drawBatchCount;
};
} // namespace gfx_batch
} // namespace esp
#endif