EG/RenderPipelineFile/rpcore/native/source/pssm_helper.cpp
2025-07-24 11:37:46 +08:00

117 lines
5.2 KiB
C++

/**
*
* 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.
*
*/
// Only include the pssm helper if actually required
#ifdef RP_REQ_PSSM_HELPER
#include "pssm_helper.h"
#include <Eigen/Dense>
/**
* @brief Internal method to generate a set of equations
* @details This generates a set of equations into a given equation system.
* Based on a given start point and end point, it inserts an equation to the
* system which will, when solved, solve the following equation:
* vec * <SOLVED-TRANSFORM> = expected
*
* @param eq_system The equation system
* @param eq_results The target result vector of the equation system
* @param vec The actual vector to be transformed
* @param expected The expected output of the transformation
* @param offset The index of the equation
*/
void generate_equations(Eigen::MatrixXf &eq_system, Eigen::VectorXf &eq_results, const LVector4f &vec, LVector4f expected, size_t offset) {
size_t write_offset = offset * 4;
for (size_t row = 0; row < 4; ++row) {
float expected_coeff = expected.get_cell(row);
size_t col_offset = row * 4;
for (size_t col = 0; col < 4; ++col) {
eq_system(write_offset, col_offset + col) = vec.get_cell(col);
}
eq_results(write_offset++) = expected_coeff;
}
}
/**
* @brief Finds a projection mat arround the given set of points.
* @details This methods finds a projection matrix which projects the given set
* of frustum points to a unit cube, which can be used as a camera matrix.
* The eight points should determine the frustum uniquely.
*
* @param near_ul The Upper-Left point of the frustum on the near plane
* @param near_ur The Upper-Right point of the frustum on the near plane
* @param near_ll The Lower-Left point of the frustum on the near plane
* @param near_lr The Lower-Right point of the frustum on the near plane
* @param far_ul The Upper-Left point of the frustum on the far plane
* @param far_ur The Upper-Right point of the frustum on the far plane
* @param far_ll The Lower-Left point of the frustum on the far plane
* @param far_lr The Lower-Right point of the frustum on the far plane
*
*/
LMatrix4f PSSMHelper::find_projection_mat(
const LVector4f &near_ul,
const LVector4f &near_ur,
const LVector4f &near_ll,
const LVector4f &near_lr,
const LVector4f &far_ul,
const LVector4f &far_ur,
const LVector4f &far_ll,
const LVector4f &far_lr) {
// We have 8*4 = 32 equations, which require 16 coefficients each
Eigen::MatrixXf equation_system(32, 16);
Eigen::VectorXf equation_results(32);
equation_system.fill(0);
// Generate the equations
size_t offset = 0;
generate_equations(equation_system, equation_results, near_ul, LVector4f(-1, 1, 0, 1), offset++);
generate_equations(equation_system, equation_results, near_ur, LVector4f( 1, 1, 0, 1), offset++);
generate_equations(equation_system, equation_results, near_ll, LVector4f(-1, -1, 0, 1), offset++);
generate_equations(equation_system, equation_results, near_lr, LVector4f( 1, -1, 0, 1), offset++);
generate_equations(equation_system, equation_results, far_ul, LVector4f(-1, 1, 1, 1), offset++);
generate_equations(equation_system, equation_results, far_ur, LVector4f( 1, 1, 1, 1), offset++);
generate_equations(equation_system, equation_results, far_ll, LVector4f(-1, -1, 1, 1), offset++);
generate_equations(equation_system, equation_results, far_lr, LVector4f( 1, -1, 1, 1), offset++);
// Solve the equation system
Eigen::VectorXf solved_system = equation_system.colPivHouseholderQr().solve(equation_results);
// Construct result matrix and return it. We also need to transpose the matrix.
LMatrix4f result(
solved_system(0), solved_system(4), solved_system(8), solved_system(12),
solved_system(1), solved_system(5), solved_system(9), solved_system(13),
solved_system(2), solved_system(6), solved_system(10), solved_system(14),
solved_system(3), solved_system(7), solved_system(11), solved_system(15)
);
return result;
}
#endif // RP_REQ_PSSM_HELPER