EG/RenderPipelineFile/rpcore/native/source/shadow_source.I
2025-12-12 16:16:15 +08:00

262 lines
9.9 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 Returns whether the shadow source needs an update.
* @details This returns the update flag, which was previously set with
* ShadowSource::set_needs_update. If the value is true, it means that the
* ShadowSource is invalid and should be regenerated. This can either be the
* case because the scene changed and affected the shadow source, or the light
* moved.
* @return Update-Flag
*/
inline bool ShadowSource::get_needs_update() const {
return !has_region() || _needs_update;
}
/**
* @brief Returns the slot of the shadow source.
* @details This returns the assigned slot of the ShadowSource, or -1 if no slot
* was assigned yet. You can check if a slot exists with ShadowSource::has_slot.
* The slot is the index of the ShadowSource in the global source buffer.
* @return Slot, or -1 to indicate no slot.
*/
inline int ShadowSource::get_slot() const {
return _slot;
}
/**
* @brief Returns whether the source has a slot.
* @details This returns whether the ShadowSource currently has an assigned slot.
* If the source has a slot assigned, this returns true, otherwise false. Cases
* where the source has no slot might be when the source just got attached, but
* never got rendered yet.
* @return [description]
*/
inline bool ShadowSource::has_slot() const {
return _slot >= 0;
}
/**
* @brief Assigns the source a slot
* @details This assigns a slot to the ShadowSource. This is called from the
* ShadowManager, when the source gets attached first time. This should not
* get called by the user.
*
* @param slot Slot of the source, or -1 to indicate no slot.
*/
inline void ShadowSource::set_slot(int slot) {
_slot = slot;
}
/**
* @brief Setups a perspective lens for the source.
* @details This makes the shadow source behave like a perspective lens. The
* parameters are similar to the ones of a PerspectiveLens.
*
* @param fov FoV of the lens
* @param near_plane The near plane of the lens, to avoid artifacts at low distance
* @param far_plane The far plane of the lens
* @param pos Position of the lens, in world space
* @param direction Direction (Orientation) of the lens
*/
inline void ShadowSource::set_perspective_lens(float fov, float near_plane,
float far_plane, LVecBase3f pos,
LVecBase3f direction) {
// Construct the transformation matrix
LMatrix4f transform_mat = LMatrix4f::translate_mat(-pos);
// Construct a temporary lens to generate the lens matrix
PerspectiveLens temp_lens = PerspectiveLens(fov, fov);
temp_lens.set_film_offset(0, 0);
temp_lens.set_near_far(near_plane, far_plane);
temp_lens.set_view_vector(direction, LVector3::up());
set_matrix_lens(transform_mat * temp_lens.get_projection_mat());
// Set new bounds, approximate with sphere
CPT(BoundingHexahedron) hexahedron = DCAST(BoundingHexahedron, temp_lens.make_bounds());
LPoint3 center = (hexahedron->get_min() + hexahedron->get_max()) * 0.5f;
_bounds = BoundingSphere(pos + center, (hexahedron->get_max() - center).length());
}
/**
* @brief Sets a custom matrix for the source.
* @details This tells the source to use a custom matrix for rendering, just like
* the matrix lens. The matrix should include all transformations, rotations and
* scales. No other matrices will be used for rendering this shadow source (not
* even a coordinate system conversion).
*
* @param mvp Custom View-Projection matrix
*/
inline void ShadowSource::set_matrix_lens(const LMatrix4f& mvp) {
_mvp = mvp;
set_needs_update(true);
}
/**
* @brief Sets the update flag of the source.
* @details Sets whether the source is still valid, or needs to get regenerated.
* Usually you only want to flag the shadow source as invalid, by passing
* true as the flag. However, the ShadowManager will set the flag to false
* after updating the source.
*
* @param flag The update flag
*/
inline void ShadowSource::set_needs_update(bool flag) {
_needs_update = flag;
}
/**
* @brief Returns whether the source has a valid region.
* @details This returns whether the ShadowSource has a valid shadow atlas region
* assigned. This might be not the case when the source never was rendered yet,
* or is about to get updated.
* @return true if the source has a valid region, else false.
*/
inline bool ShadowSource::has_region() const {
return _region.get_x() >= 0 && _region.get_y() >= 0 && _region.get_z() >= 0 && _region.get_w() >= 0;
}
/**
* @brief Returns the resolution of the source.
* @details Returns the shadow map resolution of source, in pixels. This is the
* space the source takes in the shadow atlas, in pixels.
* @return Resolution in pixels
*/
inline size_t ShadowSource::get_resolution() const {
return _resolution;
}
/**
* @brief Returns the assigned region of the source in atlas space.
* @details This returns the region of the source, in atlas space. This is the
* region set by ShadowSource::set_region. If no region was set yet, returns
* a 4-component integer vector with all components set to -1. To check this,
* you should call ShadowSource::has_region() first.
*
* @return [description]
*/
inline const LVecBase4i& ShadowSource::get_region() const {
return _region;
}
/**
* @brief Returns the assigned region of the source in UV space.
* @details This returns the region of the source, in UV space. This is the
* region set by ShadowSource::set_region. If no region was set yet, returns
* a 4-component integer vector with all components set to -1. To check this,
* you should call ShadowSource::has_region() first.
*
* @return [description]
*/
inline const LVecBase4f& ShadowSource::get_uv_region() const {
return _region_uv;
}
/**
* @brief Sets the assigned region of the source in atlas and uv space.
* @details This sets the assigned region of the ShadowSource. The region in
* atlas space should be the region returned from the
* ShadowAtlas::find_and_reserve_region. The uv-region should be the same region,
* but in the 0 .. 1 range (can be converted with ShadowAtlas::region_to_uv).
* This is required for the shaders, because they expect coordinates in the
* 0 .. 1 range for sampling.
*
* @param region Atlas-Space region
* @param region_uv UV-Space region
*/
inline void ShadowSource::set_region(const LVecBase4i& region, const LVecBase4f& region_uv) {
_region = region;
_region_uv = region_uv;
}
/**
* @brief Returns the View-Projection matrix of the source.
* @details This returns the current view-projection matrix of the ShadowSource.
* If no matrix was set yet, returns a matrix with all components zero.
* If a matrix was set with ShadowSource::set_matrix_lens, returns the matrix
* set by that function call.
*
* If a matrix was set with ShadowSource::set_perspective_lens, returns a
* perspective view-projection matrix setup by those parameters.
*
* The matrix returned is the matrix used for rendering the shadow map, and
* includes the camera transform as well as the projection matrix.
*
* @return View-Projection matrix.
*/
inline const LMatrix4f& ShadowSource::get_mvp() const {
return _mvp;
}
/**
* @brief Writes the source to a GPUCommand.
* @details This writes the ShadowSource to a GPUCommand. This stores the
* mvp and the uv-region in the command.
*
* @param cmd GPUCommand to write to.
*/
inline void ShadowSource::write_to_command(GPUCommand &cmd) const {
// When storing on the gpu, we should already have a valid slot
nassertv(_slot >= 0);
cmd.push_mat4(_mvp);
cmd.push_vec4(_region_uv);
}
/**
* @brief Sets the resolution of the source.
* @details This sets the resolution of the ShadowSource, in pixels. It should be
* a multiple of the tile size of the ShadowAtlas, and greater than zero.
*
* @param resolution [description]
*/
inline void ShadowSource::set_resolution(size_t resolution) {
nassertv(resolution > 0);
_resolution = resolution;
set_needs_update(true);
}
/**
* @brief Returns the shadow sources bounds
* @details This returns the bounds of the shadow source, approximated as a sphere
* @return Bounds as a BoundingSphere
*/
inline const BoundingSphere& ShadowSource::get_bounds() const {
return _bounds;
}
/**
* @brief Clears the assigned region of the source
* @details This unassigns any shadow atlas region from the source, previously
* set with set_region
*/
inline void ShadowSource::clear_region() {
_region.fill(-1);
_region_uv.fill(0);
}