more restructuring including separated frustum and added quaternion slerp
This commit is contained in:
parent
f3365d0669
commit
51bc5203ae
6 changed files with 136 additions and 38 deletions
|
@ -28,7 +28,7 @@
|
|||
|
||||
namespace pw {
|
||||
|
||||
template <typename T> struct axisangle {
|
||||
template <typename T> struct axisangle final {
|
||||
|
||||
using value_type = T;
|
||||
using axis_type = vector3<T>;
|
||||
|
|
65
src/core/include/pw/core/frustum.hpp
Normal file
65
src/core/include/pw/core/frustum.hpp
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2021 Hartmut Seichter
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PW_CORE_FRUSTUM_HPP
|
||||
#define PW_CORE_FRUSTUM_HPP
|
||||
|
||||
#include <pw/core/globals.hpp>
|
||||
|
||||
namespace pw {
|
||||
|
||||
template <typename Scalar> struct frustum final {
|
||||
Scalar left{-1}, right{1}, bottom{-1}, top{1}, z_near{-1}, z_far{1};
|
||||
|
||||
static constexpr auto make_perspective_symmetric(Scalar fov_h_deg,
|
||||
Scalar aspect_ratio,
|
||||
Scalar z_near,
|
||||
Scalar z_far) -> frustum {
|
||||
const auto tangent_half{std::tan(pw::deg_to_rad(fov_h_deg / 2))};
|
||||
const auto top{tangent_half * z_near};
|
||||
const auto right{top * aspect_ratio};
|
||||
|
||||
return {.left = -right,
|
||||
.right = right,
|
||||
.bottom = -top,
|
||||
.top = top,
|
||||
.z_near = z_near,
|
||||
.z_far = z_far};
|
||||
}
|
||||
|
||||
static constexpr auto make_orthographic_symmetric(Scalar scale,
|
||||
Scalar aspect_ratio,
|
||||
Scalar z_near,
|
||||
Scalar z_far) -> frustum {
|
||||
return {.left = -scale,
|
||||
.right = scale,
|
||||
.bottom = -scale * aspect_ratio,
|
||||
.top = scale * aspect_ratio,
|
||||
.z_near = z_near,
|
||||
.z_far = z_far};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace pw
|
||||
|
||||
#endif
|
|
@ -23,7 +23,6 @@
|
|||
#ifndef PW_CORE_MATRIX_HPP
|
||||
#define PW_CORE_MATRIX_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <pw/core/globals.hpp>
|
||||
#include <pw/core/math.hpp>
|
||||
#include <pw/core/vector.hpp>
|
||||
|
|
|
@ -26,41 +26,10 @@
|
|||
#include <pw/core/math.hpp>
|
||||
#include <pw/core/matrix.hpp>
|
||||
#include <pw/core/vector.hpp>
|
||||
#include <pw/core/frustum.hpp>
|
||||
|
||||
namespace pw {
|
||||
|
||||
template <typename Scalar> struct frustum final {
|
||||
Scalar left{-1}, right{1}, bottom{-1}, top{1}, z_near{-1}, z_far{1};
|
||||
|
||||
static constexpr auto make_perspective_symmetric(Scalar fov_h_deg,
|
||||
Scalar aspect_ratio,
|
||||
Scalar z_near,
|
||||
Scalar z_far) -> frustum {
|
||||
const auto tangent_half{std::tan(pw::deg_to_rad(fov_h_deg / 2))};
|
||||
const auto top{tangent_half * z_near};
|
||||
const auto right{top * aspect_ratio};
|
||||
|
||||
return {.left = -right,
|
||||
.right = right,
|
||||
.bottom = -top,
|
||||
.top = top,
|
||||
.z_near = z_near,
|
||||
.z_far = z_far};
|
||||
}
|
||||
|
||||
static constexpr auto make_orthographic_symmetric(Scalar scale,
|
||||
Scalar aspect_ratio,
|
||||
Scalar z_near,
|
||||
Scalar z_far) -> frustum {
|
||||
return {.left = -scale,
|
||||
.right = scale,
|
||||
.bottom = -scale * aspect_ratio,
|
||||
.top = scale * aspect_ratio,
|
||||
.z_near = z_near,
|
||||
.z_far = z_far};
|
||||
}
|
||||
};
|
||||
|
||||
struct matrix_transform {
|
||||
|
||||
template <typename Scalar>
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
#ifndef PW_CORE_QUATERNION_HPP
|
||||
#define PW_CORE_QUATERNION_HPP
|
||||
|
||||
#include <pw/core/matrix.hpp>
|
||||
#include <pw/core/axisangle.hpp>
|
||||
#include <pw/core/matrix.hpp>
|
||||
#include <pw/core/vector.hpp>
|
||||
|
||||
#include <concepts>
|
||||
|
@ -83,6 +83,10 @@ template <std::floating_point Scalar> struct quaternion final {
|
|||
return conjugate() / this->norm();
|
||||
}
|
||||
|
||||
constexpr auto dot(const quaternion& b) const noexcept -> Scalar {
|
||||
return q_.dot(b.q_);
|
||||
}
|
||||
|
||||
constexpr auto to_matrix() const noexcept -> matrix<Scalar, 3, 3> {
|
||||
|
||||
const Scalar xx = x() * x();
|
||||
|
@ -119,9 +123,61 @@ template <std::floating_point Scalar> struct quaternion final {
|
|||
}
|
||||
|
||||
static constexpr auto lerp(const quaternion& a, const quaternion& b,
|
||||
const Scalar& t) -> quaternion {
|
||||
const Scalar& t) -> quaternion {
|
||||
return {value_type::lerp(a.q_, b.q_, t).normalized()};
|
||||
}
|
||||
|
||||
/**
|
||||
* @note: a and b need to be normalized
|
||||
*/
|
||||
static constexpr auto
|
||||
slerp(const quaternion& a, const quaternion& b, const Scalar& t,
|
||||
const Scalar& eps = Scalar{0.001}) -> quaternion {
|
||||
|
||||
// Calculate angle between them.
|
||||
const Scalar cos_half_theta{a.dot(b)};
|
||||
|
||||
// if qa=qb or qa=-qb then theta = 0 and we can return a
|
||||
if (std::fabs(cos_half_theta) >= Scalar{1}) {
|
||||
return a;
|
||||
}
|
||||
|
||||
// Calculate temporary values.
|
||||
const Scalar half_theta{std::acos(cos_half_theta)};
|
||||
const Scalar sin_half_theta{
|
||||
std::sqrt(Scalar{1} - cos_half_theta * cos_half_theta)};
|
||||
|
||||
// if theta = 180 degrees then result is not fully defined
|
||||
// we could rotate around any axis normal to a or b
|
||||
const auto is_pi = std::fabs(sin_half_theta) < eps;
|
||||
|
||||
// now do the lerp either halfway or across unit sphere
|
||||
const Scalar ratio_a{is_pi ? Scalar{0.5}
|
||||
: std::sin((Scalar{1} - t) * half_theta) /
|
||||
sin_half_theta};
|
||||
|
||||
const Scalar ratio_b{is_pi ? Scalar{0.5}
|
||||
: std::sin(t * half_theta) / sin_half_theta};
|
||||
return {
|
||||
(a.x() * ratio_a + b.x() * ratio_b), // x
|
||||
(a.y() * ratio_a + b.y() * ratio_b), // y
|
||||
(a.z() * ratio_a + b.z() * ratio_b), // z
|
||||
(a.w() * ratio_a + b.w() * ratio_b) // w
|
||||
};
|
||||
}
|
||||
|
||||
static constexpr auto
|
||||
from_axisangle(const axisangle<Scalar>& aa) -> quaternion {
|
||||
|
||||
const auto sin_half_angle{std::sin(aa.angle / Scalar{2})};
|
||||
|
||||
return {
|
||||
aa.axis.x() * sin_half_angle, // x
|
||||
aa.axis.y() * sin_half_angle, // y
|
||||
aa.axis.z() * sin_half_angle, // z
|
||||
std::cos(aa.angle / Scalar{2}) // w
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// deduction guide for quaternion
|
||||
|
|
|
@ -13,6 +13,10 @@ auto main() -> int {
|
|||
pw::debug::d() << "q1 = quaternion{1,2,3,4} -> \n"
|
||||
<< pw::serialize::to_string(q1);
|
||||
|
||||
q1 = q1.normalized();
|
||||
pw::debug::d() << "q1 = quaternion{1,2,3,4}.normalized() -> \n"
|
||||
<< pw::serialize::to_string(q1);
|
||||
|
||||
auto q0_x_q1 = q0 * q1;
|
||||
pw::debug::d() << "q0 * q1 -> \n" << pw::serialize::to_string(q0_x_q1);
|
||||
|
||||
|
@ -28,10 +32,15 @@ auto main() -> int {
|
|||
pw::debug::d() << "q1.conjugate().inverse() -> \n"
|
||||
<< pw::serialize::to_string(q1_conj_inv);
|
||||
|
||||
auto lerp_q0_q1_half = decltype(q0)::lerp(q0, q1, 0.5f);
|
||||
pw::debug::d() << "quaternion::lerp(q0,q1,0.5) -> \n"
|
||||
pw::debug::d() << "quaternion::dot(q0,q1) -> " << q0.dot(q1);
|
||||
|
||||
auto lerp_q0_q1_half = decltype(q0)::lerp(q0, q1, 0.3f);
|
||||
pw::debug::d() << "quaternion::lerp(q0,q1,0.3) -> \n"
|
||||
<< pw::serialize::to_string(lerp_q0_q1_half);
|
||||
|
||||
auto slerp_q0_q1_half = decltype(q0)::slerp(q0, q1, 0.3f);
|
||||
pw::debug::d() << "quaternion::slerp(q0,q1,0.3) -> \n"
|
||||
<< pw::serialize::to_string(slerp_q0_q1_half);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue