diff --git a/include/inexor/vulkan-renderer/bezier_curve.hpp b/include/inexor/vulkan-renderer/bezier_curve.hpp deleted file mode 100644 index 11c13a383..000000000 --- a/include/inexor/vulkan-renderer/bezier_curve.hpp +++ /dev/null @@ -1,97 +0,0 @@ -#pragma once - -// TODO: Implement a curve manager. - -// INTRODUCTION -// A bezier curve (named after french mathematician PIERRE ETIENNE BEZIER) is a parametric curve -// whose only purpose is to look soft and smooth. Bezier curves are all about elegance! -// Those curves can be used to represent the path of a everything (imagine a camera which is moving along a path for -// example). -// -// Bezier curves are fast, flexible, beautiful and easy to compute. You just pass a bunch of parameter points to -// your code and the final curve will be computed. Because every complex curve can be represented with a -// chain of smaller curves, it is recommended to create a chain of curves. Bezier curves are essential -// in the field of computer graphics and image processing. They can also be used for approximation, interpolation and -// more. -// -// COMPUTING -// There are two ways to generate a bezier curves from a group of [n] points. -// You can either write a code that uses recursion to solve the problem or use Bernstein polynomials. -// This engine uses Bernstein polynomial, because we want to avoid the recursion in de-casteljau algorithm. -// -// Pierre Etienne BEZIER (September 1, 1910 - November 25, 1999), French mathematician and engineer at RENAULT. -// Paul de CASTELJAU (November 19, 1930), French mathematician and physicist and engineer ar Citroen. -// Sergei Natanovich BERNSTEIN (March 5, 1880 - October 26, 1968), Russian mathematician. -// Charles HERMITE (December 24, 1822 - January 14, 1901), French mathematician. - -// http://pomax.github.io/bezierinfo/ -// http://en.wikipedia.org/wiki/B%C3%A9zier_curve -// http://mathworld.wolfram.com/BezierCurve.html -// http://theagsc.com/community/tutorials/so-whats-the-big-deal-with-horizontal-vertical-bezier-handles-anyway#comment-1351842776 -// http://learn.scannerlicker.net/2014/04/16/bezier-curves-and-type-design-a-tutorial/ -// https://geom.ivd.kit.edu/downloads/pubs/pub-boehm-prautzsch_2002_preview.pdf -// https://www.clear.rice.edu/comp360/lectures/BezSubd.pdf - -#include - -#include -#include - -namespace inexor::vulkan_renderer { - -/// @brief Those are the points that we pass into the bezier curve generator. -/// Every bezier curve will be generated from a list of BezierInputPoint. -/// Every input point can have a custom weight coefficient. -struct BezierInputPoint { - glm::vec3 pos{0.0f, 0.0f, 0.0f}; - - float weight{1.0f}; -}; - -/// @brief Those are the points which will be generated from the bezier curve generator. -/// How many BezierOutputPoint points will be generated depends on the required precision. -/// The higher the requested precision, the more points will be -struct BezierOutputPoint : public BezierInputPoint { - glm::vec3 normal{0.0f, 0.0f, 0.0f}; - - glm::vec3 tangent{0.0f, 0.0f, 0.0f}; -}; - -/// @brief This struct bundles describes everything about the bezier curve. -/// It contains both the input points and the generated output points. -class BezierCurve { - bool m_curve_generated{false}; - - float m_curve_precision{0.0f}; - - std::vector m_input_points; - - std::vector m_output_points; - - static uint32_t binomial_coefficient(uint32_t n, uint32_t k); - - static float bernstein_polynomial(uint32_t n, uint32_t k, float curve_precision, float coordinate_value); - - BezierOutputPoint calculate_point_on_curve(float curve_precision); - -public: - void add_input_point(const BezierInputPoint &input_point); - - void add_input_point(const glm::vec3 &position, float weight = 1.0f); - - void calculate_bezier_curve(std::uint32_t curve_segments); - - [[nodiscard]] std::vector output_points(); - - void clear_output(); - - void clear_input(); - - void clear(); - - [[nodiscard]] bool is_curve_generated() const { - return m_curve_generated; - } -}; - -} // namespace inexor::vulkan_renderer diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 521d466e2..801a7e491 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,5 @@ set(INEXOR_SOURCE_FILES vulkan-renderer/application.cpp - vulkan-renderer/bezier_curve.cpp vulkan-renderer/camera.cpp vulkan-renderer/exception.cpp vulkan-renderer/fps_counter.cpp diff --git a/src/vulkan-renderer/bezier_curve.cpp b/src/vulkan-renderer/bezier_curve.cpp deleted file mode 100644 index bef87f905..000000000 --- a/src/vulkan-renderer/bezier_curve.cpp +++ /dev/null @@ -1,132 +0,0 @@ -#include "inexor/vulkan-renderer/bezier_curve.hpp" - -namespace inexor::vulkan_renderer { - -std::uint32_t BezierCurve::binomial_coefficient(std::uint32_t n, const std::uint32_t k) { - std::uint32_t r = 1; - if (k > n) { - return 0; - } - - for (std::uint32_t d = 1; d <= k; d++) { - r *= n--; - r /= d; - } - - return r; -} - -float BezierCurve::bernstein_polynomial(std::uint32_t n, std::uint32_t k, const float curve_precision, - const float coordinate_value) { - return static_cast(binomial_coefficient(n, k)) * static_cast(pow(curve_precision, k)) * - static_cast(pow(1 - curve_precision, n - k)) * coordinate_value; -} - -void BezierCurve::clear_output() { - m_output_points.clear(); -} - -void BezierCurve::clear_input() { - m_input_points.clear(); -} - -void BezierCurve::clear() { - clear_input(); - clear_output(); -} - -std::vector BezierCurve::output_points() { - assert(m_curve_generated); - assert(!m_output_points.empty()); - return m_output_points; -} - -void BezierCurve::add_input_point(const BezierInputPoint &input_point) { - assert(!m_curve_generated); - m_input_points.push_back(input_point); -} - -void BezierCurve::add_input_point(const glm::vec3 &position, const float weight) { - assert(!m_curve_generated); - assert(weight > 0.0f); - - BezierInputPoint input_point; - input_point.pos = position; - input_point.weight = weight; - - m_input_points.push_back(input_point); -} - -BezierOutputPoint BezierCurve::calculate_point_on_curve(const float curve_precision) { - BezierOutputPoint temp_output; - - const auto n = static_cast(m_input_points.size() - 1); - - // Calculate the coordinates of the output points of the bezier curve. - for (std::size_t i = 0; i < m_input_points.size(); i++) { - auto current_point = m_input_points[i]; - - const auto index = static_cast(i); - - // Compute bezier curve coordinates using bernstein polynomials. - temp_output.pos.x += bernstein_polynomial(n, index, curve_precision, current_point.pos.x); - temp_output.pos.y += bernstein_polynomial(n, index, curve_precision, current_point.pos.y); - temp_output.pos.z += bernstein_polynomial(n, index, curve_precision, current_point.pos.z); - } - - // Calculate the derivatives of bezier curves. - // https://www.rose-hulman.edu/~finn/CCLI/Notes/day13.pdf - - // An easier way would be to take the vector to the next point on the curve and calculate the difference. - // This would lead to a direction vector with satisfying precision. But this would implicate that the - // precision of the derivation depends on the curve precision! - // With this technique, we can have precise derivations even if we have a precision of only 10.0f units! - for (std::size_t i = 0; i < n; i++) { - auto current_point = m_input_points[i]; - auto next_point = m_input_points[i + 1]; - - const auto index = static_cast(i); - - // Compute bezier curve point's first derivative. - temp_output.tangent.x += bernstein_polynomial(n - 1, index, curve_precision, current_point.pos.x); - temp_output.tangent.y += bernstein_polynomial(n - 1, index, curve_precision, current_point.pos.y); - temp_output.tangent.z += bernstein_polynomial(n - 1, index, curve_precision, current_point.pos.z); - } - - // Subtract point position from tangent vector so the tangent vector is relative. - temp_output.tangent -= temp_output.pos; - - // Calculate a relative normal vector. - // Please note that there is an infinite amount of normal vectors from vector a to b. - - const float length = glm::length(temp_output.tangent); - temp_output.normal = glm::vec3(-temp_output.tangent.y / length, temp_output.tangent.x / length, 0); - - // Do not normalize tangent vectors before you have copied the normal vector! They will be incorrect! - - // Normalize the vectors: divide them by length so their length is 1. - // You could rescale the vectors to change the length to your wishes. - temp_output.normal = glm::normalize(temp_output.normal); - temp_output.tangent = glm::normalize(temp_output.tangent); - - // Store the output. - return temp_output; -} - -void BezierCurve::calculate_bezier_curve(const uint32_t curve_segments) { - // We need at least 2 input points! - assert(m_input_points.size() > 2); - - if (m_curve_generated) { - clear(); - m_curve_generated = false; - } - - for (std::uint32_t i = 0; i < curve_segments; i += curve_segments / static_cast(1000)) { - m_output_points.push_back(calculate_point_on_curve(static_cast(i) / static_cast(curve_segments))); - } - - m_curve_generated = true; -} - -} // namespace inexor::vulkan_renderer