Panda3D
shadowManager.cxx
1 /**
2  *
3  * RenderPipeline
4  *
5  * Copyright (c) 2014-2016 tobspr <tobias.springer1@gmail.com>
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23  * THE SOFTWARE.
24  *
25  */
26 
27 
28 #include "shadowManager.h"
29 
30 NotifyCategoryDef(shadowmanager, "");
31 
32 /**
33  * @brief Constructs a new shadow atlas
34  * @details This constructs a new shadow atlas. There are a set of properties
35  * which should be set before calling ShadowManager::init, see the set-Methods.
36  * After all properties are set, ShadowManager::init should get called.
37  * ShadowManager::update should get called on a per frame basis.
38  */
40  _max_updates = 10;
41  _atlas = nullptr;
42  _atlas_size = 4096;
43  _tag_state_mgr = nullptr;
44  _atlas_graphics_output = nullptr;
45 }
46 
47 /**
48  * @brief Destructs the ShadowManager
49  * @details This destructs the shadow manager, clearing all resources used
50  */
52  delete _atlas;
53 
54  // Todo: Could eventually unregister all shadow cameras. Since the tag state
55  // manager does this on cleanup already, and we get destructed at the same
56  // time (if at all), this is not really necessary
57 }
58 
59 
60 /**
61  * @brief Initializes the ShadowManager.
62  * @details This initializes the ShadowManager. All properties should have
63  * been set before calling this, otherwise assertions will get triggered.
64  *
65  * This setups everything required for rendering shadows, including the
66  * shadow atlas and the various shadow cameras. After calling this method,
67  * no properties can be changed anymore.
68  */
70  nassertv(!_scene_parent.is_empty()); // Scene parent not set, call set_scene_parent before init!
71  nassertv(_tag_state_mgr != nullptr); // TagStateManager not set, call set_tag_state_mgr before init!
72  nassertv(_atlas_graphics_output != nullptr); // AtlasGraphicsOutput not set, call set_atlas_graphics_output before init!
73 
74  _cameras.resize(_max_updates);
75  _display_regions.resize(_max_updates);
76  _camera_nps.reserve(_max_updates);
77 
78  // Create the cameras and regions
79  for(size_t i = 0; i < _max_updates; ++i) {
80 
81  // Create the camera
82  PT(Camera) camera = new Camera("ShadowCam-" + format_string(i));
83  camera->set_lens(new MatrixLens());
84  camera->set_active(false);
85  camera->set_scene(_scene_parent);
86  _tag_state_mgr->register_camera("shadow", camera);
87  _camera_nps.push_back(_scene_parent.attach_new_node(camera));
88  _cameras[i] = camera;
89 
90  // Create the display region
91  PT(DisplayRegion) region = _atlas_graphics_output->make_display_region();
92  region->set_sort(1000);
93  region->set_clear_depth_active(true);
94  region->set_clear_depth(1.0);
95  region->set_clear_color_active(false);
96  region->set_camera(_camera_nps[i]);
97  region->set_active(false);
98  _display_regions[i] = region;
99  }
100 
101  // Create the atlas
102  _atlas = new ShadowAtlas(_atlas_size);
103 
104  // Reserve enough space for the updates
105  _queued_updates.reserve(_max_updates);
106 }
107 
108 
109 /**
110  * @brief Updates the ShadowManager
111  * @details This updates the ShadowManager, processing all shadow sources which
112  * need to get updated.
113  *
114  * This first collects all sources which require an update, sorts them by priority,
115  * and then processes the first <max_updates> ShadowSources.
116  *
117  * This may not get called before ShadowManager::init, or an assertion will be
118  * thrown.
119  */
121  nassertv(_atlas != nullptr); // ShadowManager::init not called yet
122  nassertv(_queued_updates.size() <= _max_updates); // Internal error, should not happen
123 
124  // Disable all cameras and regions which will not be used
125  for (size_t i = _queued_updates.size(); i < _max_updates; ++i) {
126  _cameras[i]->set_active(false);
127  _display_regions[i]->set_active(false);
128  }
129 
130  // Iterate over all queued updates
131  for (size_t i = 0; i < _queued_updates.size(); ++i) {
132  const ShadowSource* source = _queued_updates[i];
133 
134  // Enable the camera and display region, so they perform a render
135  _cameras[i]->set_active(true);
136  _display_regions[i]->set_active(true);
137 
138  // Set the view projection matrix
139  DCAST(MatrixLens, _cameras[i]->get_lens())->set_user_mat(source->get_mvp());
140 
141  // Optional: Show the camera frustum for debugging
142  // _cameras[i]->show_frustum();
143 
144  // Set the correct dimensions on the display region
145  const LVecBase4& uv = source->get_uv_region();
146  _display_regions[i]->set_dimensions(
147  uv.get_x(), // left
148  uv.get_x() + uv.get_z(), // right
149  uv.get_y(), // bottom
150  uv.get_y() + uv.get_w() // top
151  );
152  }
153 
154  // Clear the update list
155  _queued_updates.clear();
156  _queued_updates.reserve(_max_updates);
157 }
RenderPipeline.
Definition: shadowSource.h:51
A completely generic linear lens.
Definition: matrixLens.h:28
bool is_empty() const
Returns true if the NodePath contains no nodes.
Definition: nodePath.I:188
void update()
Updates the ShadowManager.
DisplayRegion * make_display_region()
Creates a new DisplayRegion that covers the entire window.
const LVecBase4 & get_uv_region() const
Returns the assigned region of the source in UV space.
Definition: shadowSource.I:178
~ShadowManager()
Destructs the ShadowManager.
NodePath attach_new_node(PandaNode *node, int sort=0, Thread *current_thread=Thread::get_current_thread()) const
Attaches a new node, with or without existing parents, to the scene graph below the referenced node o...
Definition: nodePath.cxx:563
Class which manages distributing shadow maps in an atlas.
Definition: shadowAtlas.h:41
ShadowManager()
Constructs a new shadow atlas.
A rectangular subregion within a window for rendering into.
Definition: displayRegion.h:57
void init()
Initializes the ShadowManager.
A node that can be positioned around in the scene graph to represent a point of view for rendering a ...
Definition: camera.h:35
void register_camera(const std::string &state, Camera *source)
RenderPipeline.
set_sort
Sets the sort value associated with the DisplayRegion.
const LMatrix4 & get_mvp() const
Returns the View-Projection matrix of the source.
Definition: shadowSource.I:214