MetaCoreEngineV2/rpcore/native/source/shadow_manager.I
2026-01-13 17:06:06 +08:00

193 lines
7.2 KiB
Plaintext

/**
*
* RenderPipeline
*
* Copyright (c) 2014-2016 tobspr <tobias.springer1@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
/**
* @brief Sets the maximum amount of updates per frame.
* @details This controls the maximum amount of updated ShadowSources per frame.
* The ShadowManager will take the first <max_updates> ShadowSources, and
* generate shadow maps for them every frame. If there are more ShadowSources
* waiting to get updated than available updates, the sources are sorted by
* priority, and the update of the less important sources is delayed to the
* next frame.
*
* If the update count is set too low, and there are a lot of ShadowSources
* waiting to get updated, artifacts will occur, and there might be ShadowSources
* which never get updated, due to low priority.
*
* If an update count of 0 is passed, no updates will happen. This also means
* that there are no shadows. This is not recommended.
*
* If an update count < 0 is passed, undefined behaviour occurs.
*
* This method has to get called before ShadowManager::init, otherwise an
* assertion will get triggered.
*
* @param max_updates Maximum amoumt of updates
*/
inline void ShadowManager::set_max_updates(size_t max_updates) {
nassertv(max_updates >= 0);
nassertv(_atlas == NULL); // ShadowManager was already initialized
if (max_updates == 0) {
shadowmanager_cat.warning() << "max_updates set to 0, no shadows will be updated." << endl;
}
_max_updates = max_updates;
}
/**
* @brief Sets the shadow atlas size
* @details This sets the desired shadow atlas size. It should be big enough
* to store all important shadow sources, with some buffer, because the shadow
* maps usually won't be fitted perfectly, so gaps can occur.
*
* This has to get called before calling ShadowManager::init. When calling this
* method after initialization, an assertion will get triggered.
*
* @param atlas_size Size of the shadow atlas in pixels
*/
inline void ShadowManager::set_atlas_size(size_t atlas_size) {
nassertv(atlas_size >= 16 && atlas_size <= 16384);
nassertv(_atlas == NULL); // ShadowManager was already initialized
_atlas_size = atlas_size;
}
/**
* @brief Returns the shadow atlas size.
* @details This returns the shadow atlas size previously set with
* ShadowManager::set_atlas_size.
* @return Shadow atlas size in pixels
*/
inline size_t ShadowManager::get_atlas_size() const {
return _atlas_size;
}
/**
* @brief Returns a handle to the shadow atlas.
* @details This returns a handle to the internal shadow atlas instance. This
* is only valid after calling ShadowManager::init. Calling this earlier will
* trigger an assertion and undefined behaviour.
* @return The internal ShadowAtlas instance
*/
inline ShadowAtlas* ShadowManager::get_atlas() const {
nassertr(_atlas != NULL, NULL); // Can't hurt to check
return _atlas;
}
/**
* @brief Sets the target scene
* @details This sets the target scene for rendering shadows. All shadow cameras
* will be parented to this scene to render shadows.
*
* Usually the scene will be ShowBase.render. If the scene is an empty or
* invalid NodePath, an assertion will be triggered.
*
* This method has to get called before calling ShadowManager::init, or an
* assertion will get triggered.
*
* @param scene_parent The target scene
*/
inline void ShadowManager::set_scene(NodePath scene_parent) {
nassertv(!scene_parent.is_empty());
nassertv(_atlas == NULL); // ShadowManager was already initialized
_scene_parent = scene_parent;
}
/**
* @brief Sets the handle to the TagStageManager.
* @details This sets the handle to the TagStateManager used by the pipeline.
* Usually this is RenderPipeline.get_tag_mgr().
*
* This has to get called before ShadowManager::init, otherwise an assertion
* will get triggered.
*
* @param tag_mgr [description]
*/
inline void ShadowManager::set_tag_state_manager(TagStateManager* tag_mgr) {
nassertv(tag_mgr != NULL);
nassertv(_atlas == NULL); // ShadowManager was already initialized
_tag_state_mgr = tag_mgr;
}
/**
* @brief Sets the handle to the Shadow targets output
* @details This sets the handle to the GraphicsOutput of the shadow atlas.
* Usually this is RenderTarget.get_internal_buffer(), whereas the RenderTarget
* is the target of the ShadowStage.
*
* This is used for creating display regions and attaching cameras to them,
* for performing shadow updates.
*
* This has to get called before ShadowManager::init, otherwise an assertion
* will be triggered.
*
* @param graphics_output [description]
*/
inline void ShadowManager::set_atlas_graphics_output(GraphicsOutput* graphics_output) {
nassertv(graphics_output != NULL);
nassertv(_atlas == NULL); // ShadowManager was already initialized
_atlas_graphics_output = graphics_output;
}
/**
* @brief Adds a new shadow update
* @details This adds a new update to the update queue. When the queue is already
* full, this method returns false, otherwise it returns true. The next time
* the manager is updated, the shadow source will recieve an update of its
* shadow map.
*
* @param source The shadow source to update
*
* @return Whether the shadow source udpate was sucessfully queued.
*/
inline bool ShadowManager::add_update(const ShadowSource* source) {
nassertr(_atlas != NULL, false); // ShadowManager::init not called yet.
nassertr(source != NULL, false); // NULL-Pointer passed
if (_queued_updates.size() >= _max_updates) {
if (shadowmanager_cat.is_debug()) {
shadowmanager_cat.debug() << "cannot update source, out of update slots" << endl;
}
return false;
}
// Add the update to the queue
_queued_updates.push_back(source);
return true;
}
/**
* @brief Returns how many update slots are left.
* @details This returns how many update slots are left. You can assume the
* next n calls to add_update will succeed, whereas n is the value returned
* by this function.
* @return Number of update slots left.
*/
inline size_t ShadowManager::get_num_update_slots_left() const {
return _max_updates - _queued_updates.size();
}