Extensible barycentric interpolator
This commit is contained in:
parent
0b816497e9
commit
9e58b48034
@ -1,6 +1,7 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <numbers>
|
#include <numbers>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <bgtu/computer_graphics_lab_work/renderer_api/point.hpp>
|
||||||
#include <bgtu/computer_graphics_lab_work/utilities/shader.hpp>
|
#include <bgtu/computer_graphics_lab_work/utilities/shader.hpp>
|
||||||
#include <bgtu/computer_graphics_lab_work/utilities/shapes/triangle.hpp>
|
#include <bgtu/computer_graphics_lab_work/utilities/shapes/triangle.hpp>
|
||||||
|
|
||||||
@ -24,10 +25,9 @@ namespace BGTU::ComputerGraphicsLabWork::Impl {
|
|||||||
RendererApi::PointF<3> tc = data->transform * this->c;
|
RendererApi::PointF<3> tc = data->transform * this->c;
|
||||||
|
|
||||||
Utilities::Shapes::triangle_barycentric_interpolator<double> z_interpolator{
|
Utilities::Shapes::triangle_barycentric_interpolator<double> z_interpolator{
|
||||||
{ta.x, ta.y},
|
{ta.x, ta.y}, ta.z,
|
||||||
{tb.x, tb.y},
|
{tb.x, tb.y}, tb.z,
|
||||||
{tc.x, tc.y},
|
{tc.x, tc.y}, tc.z
|
||||||
ta.z, tb.z, tc.z
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Utilities::Shapes::iterate_triangle_fill(
|
Utilities::Shapes::iterate_triangle_fill(
|
||||||
|
@ -27,6 +27,9 @@ namespace BGTU::ComputerGraphicsLabWork::RendererApi {
|
|||||||
return !(*this == other);
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Transparent;
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr Transparent with_alpha(component_fast_t alpha) const noexcept;
|
||||||
|
|
||||||
class Transparent {
|
class Transparent {
|
||||||
public:
|
public:
|
||||||
@ -43,6 +46,8 @@ namespace BGTU::ComputerGraphicsLabWork::RendererApi {
|
|||||||
|
|
||||||
constexpr Transparent(Color c) noexcept: red{c.red}, green{c.green}, blue{c.blue}, alpha{component_max_value} {}
|
constexpr Transparent(Color c) noexcept: red{c.red}, green{c.green}, blue{c.blue}, alpha{component_max_value} {}
|
||||||
|
|
||||||
|
constexpr Transparent(Color c, component_fast_t alpha) noexcept: red{c.red}, green{c.green}, blue{c.blue}, alpha{alpha} {}
|
||||||
|
|
||||||
constexpr bool operator==(Color::Transparent const &other) const noexcept {
|
constexpr bool operator==(Color::Transparent const &other) const noexcept {
|
||||||
return this->red == other.red && this->green == other.green && this->blue == other.blue && this->alpha == other.alpha;
|
return this->red == other.red && this->green == other.green && this->blue == other.blue && this->alpha == other.alpha;
|
||||||
}
|
}
|
||||||
@ -56,4 +61,8 @@ namespace BGTU::ComputerGraphicsLabWork::RendererApi {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr Color::Transparent Color::with_alpha(Color::component_fast_t alpha) const noexcept {
|
||||||
|
return Color::Transparent{*this, alpha};
|
||||||
|
};
|
||||||
}
|
}
|
@ -248,8 +248,8 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities::Shapes {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class variable_t>
|
template<class variable_t, auto transform>
|
||||||
struct triangle_barycentric_interpolator {
|
struct _triangle_barycentric_interpolator {
|
||||||
private:
|
private:
|
||||||
long double full_square;
|
long double full_square;
|
||||||
RendererApi::PointF<2> p0;
|
RendererApi::PointF<2> p0;
|
||||||
@ -259,11 +259,6 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities::Shapes {
|
|||||||
variable_t v1;
|
variable_t v1;
|
||||||
variable_t v2;
|
variable_t v2;
|
||||||
|
|
||||||
struct _empty {
|
|
||||||
};
|
|
||||||
|
|
||||||
std::conditional_t<std::is_same_v<variable_t, RendererApi::Color::Transparent>, bool, _empty> skip_alpha;
|
|
||||||
|
|
||||||
static long double calculate_square_2(
|
static long double calculate_square_2(
|
||||||
RendererApi::PointF<2> p0,
|
RendererApi::PointF<2> p0,
|
||||||
RendererApi::PointF<2> p1,
|
RendererApi::PointF<2> p1,
|
||||||
@ -272,53 +267,161 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities::Shapes {
|
|||||||
return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
|
return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
triangle_barycentric_interpolator(
|
_triangle_barycentric_interpolator(
|
||||||
RendererApi::PointF<2> p0, RendererApi::PointF<2> p1, RendererApi::PointF<2> p2,
|
RendererApi::PointF<2> p0, variable_t v0,
|
||||||
variable_t v0, variable_t v1, variable_t v2
|
RendererApi::PointF<2> p1, variable_t v1,
|
||||||
|
RendererApi::PointF<2> p2, variable_t v2
|
||||||
) : p0{p0}, p1{p1}, p2{p2}, v0{v0}, v1{v1}, v2{v2}, full_square{calculate_square_2(p0, p1, p2)} {
|
) : p0{p0}, p1{p1}, p2{p2}, v0{v0}, v1{v1}, v2{v2}, full_square{calculate_square_2(p0, p1, p2)} {
|
||||||
if constexpr (std::is_same_v<variable_t, RendererApi::Color::Transparent>) {
|
|
||||||
this->skip_alpha = v0.alpha == v1.alpha && v0.alpha == v2.alpha;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
variable_t interpolate_point(RendererApi::PointF<2> p) const {
|
[[nodiscard]] variable_t interpolate_point(RendererApi::PointF<2> p) const {
|
||||||
const double k0 = calculate_square_2(p, this->p1, this->p2) / this->full_square;
|
const double k0 = calculate_square_2(p, this->p1, this->p2) / this->full_square;
|
||||||
const double k1 = calculate_square_2(p, this->p2, this->p0) / this->full_square;
|
const double k1 = calculate_square_2(p, this->p2, this->p0) / this->full_square;
|
||||||
const double k2 = calculate_square_2(p, this->p0, this->p1) / this->full_square;
|
const double k2 = calculate_square_2(p, this->p0, this->p1) / this->full_square;
|
||||||
|
|
||||||
if constexpr (std::is_same_v<variable_t, RendererApi::Color::Transparent> || std::is_same_v<variable_t, RendererApi::Color>) {
|
return transform([=, this]<class property_getter_t>(property_getter_t pg) -> auto { return pg(this->v0) * k0 + pg(this->v1) * k1 + pg(this->v2) * k2; });
|
||||||
auto f = [&]<class intermediate_t>(intermediate_t (variable_t::*offset)) -> intermediate_t {
|
|
||||||
return static_cast<intermediate_t>((this->v0.*offset) * k0 + (this->v1.*offset) * k1 + (this->v2.*offset) * k2);
|
|
||||||
};
|
|
||||||
if constexpr (std::is_same_v<variable_t, RendererApi::Color::Transparent>) {
|
|
||||||
RendererApi::Color base{
|
|
||||||
f(&RendererApi::Color::Transparent::red),
|
|
||||||
f(&RendererApi::Color::Transparent::green),
|
|
||||||
f(&RendererApi::Color::Transparent::blue),
|
|
||||||
};
|
|
||||||
return RendererApi::Color::Transparent{
|
|
||||||
base.red, base.green, base.blue,
|
|
||||||
(this->skip_alpha ? this->v0.alpha : f(&RendererApi::Color::Transparent::alpha))
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return RendererApi::Color{
|
|
||||||
f(&RendererApi::Color::red),
|
|
||||||
f(&RendererApi::Color::green),
|
|
||||||
f(&RendererApi::Color::blue)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return static_cast<variable_t>((this->v0) * k0 + (this->v1) * k1 + (this->v2) * k2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
variable_t interpolate_point(RendererApi::PointF<2>::component_t x, RendererApi::PointF<2>::component_t y) const {
|
[[nodiscard]] variable_t interpolate_point(RendererApi::PointF<2>::component_t x, RendererApi::PointF<2>::component_t y) const {
|
||||||
return this->interpolate_point(RendererApi::PointF<2>{x, y});
|
return this->interpolate_point(RendererApi::PointF<2>{x, y});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<class variable_t>
|
||||||
|
struct triangle_barycentric_interpolator {
|
||||||
|
private:
|
||||||
|
_triangle_barycentric_interpolator<variable_t, []<class interpolator_t>(interpolator_t interpolator) {
|
||||||
|
return static_cast<variable_t>(interpolator([](variable_t v) { return v; }));
|
||||||
|
}> impl;
|
||||||
|
public:
|
||||||
|
triangle_barycentric_interpolator(
|
||||||
|
RendererApi::PointF<2> p0, variable_t v0,
|
||||||
|
RendererApi::PointF<2> p1, variable_t v1,
|
||||||
|
RendererApi::PointF<2> p2, variable_t v2
|
||||||
|
) : impl{p0, v0, p1, v1, p2, v2} {};
|
||||||
|
|
||||||
|
[[nodiscard]] variable_t interpolate_point(RendererApi::PointF<2> p) const {
|
||||||
|
return this->impl.interpolate_point(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] variable_t interpolate_point(RendererApi::PointF<2>::component_t x, RendererApi::PointF<2>::component_t y) const {
|
||||||
|
return this->impl.interpolate_point(x, y);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct triangle_barycentric_interpolator<RendererApi::Color> {
|
||||||
|
private:
|
||||||
|
_triangle_barycentric_interpolator<RendererApi::Color, []<class interpolator_t>(interpolator_t interpolator) {
|
||||||
|
return RendererApi::Color{
|
||||||
|
static_cast<RendererApi::Color::component_fast_t>(interpolator([](RendererApi::Color const &c) { return c.red; })),
|
||||||
|
static_cast<RendererApi::Color::component_fast_t>(interpolator([](RendererApi::Color const &c) { return c.green; })),
|
||||||
|
static_cast<RendererApi::Color::component_fast_t>(interpolator([](RendererApi::Color const &c) { return c.blue; }))
|
||||||
|
};
|
||||||
|
}> impl;
|
||||||
|
public:
|
||||||
|
inline triangle_barycentric_interpolator(
|
||||||
|
RendererApi::PointF<2> p0, RendererApi::Color v0,
|
||||||
|
RendererApi::PointF<2> p1, RendererApi::Color v1,
|
||||||
|
RendererApi::PointF<2> p2, RendererApi::Color v2
|
||||||
|
) : impl{p0, v0, p1, v1, p2, v2} {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[[nodiscard]] inline RendererApi::Color interpolate_point(RendererApi::PointF<2> p) const {
|
||||||
|
return this->impl.interpolate_point(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline RendererApi::Color interpolate_point(RendererApi::PointF<2>::component_t x, RendererApi::PointF<2>::component_t y) const {
|
||||||
|
return this->impl.interpolate_point(x, y);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct triangle_barycentric_interpolator<RendererApi::Color::Transparent> {
|
||||||
|
private:
|
||||||
|
union _interpolators_t {
|
||||||
|
triangle_barycentric_interpolator<RendererApi::Color> ignore_alpha;
|
||||||
|
_triangle_barycentric_interpolator<RendererApi::Color::Transparent, []<class interpolator_t>(interpolator_t interpolator) {
|
||||||
|
return RendererApi::Color::Transparent{
|
||||||
|
static_cast<RendererApi::Color::component_fast_t>(interpolator([](RendererApi::Color::Transparent const &c) { return c.red; })),
|
||||||
|
static_cast<RendererApi::Color::component_fast_t>(interpolator([](RendererApi::Color::Transparent const &c) { return c.green; })),
|
||||||
|
static_cast<RendererApi::Color::component_fast_t>(interpolator([](RendererApi::Color::Transparent const &c) { return c.blue; })),
|
||||||
|
static_cast<RendererApi::Color::component_fast_t>(interpolator([](RendererApi::Color::Transparent const &c) { return c.alpha; }))
|
||||||
|
};
|
||||||
|
}> transparent;
|
||||||
|
} interpolators;
|
||||||
|
bool is_alpha_const;
|
||||||
|
RendererApi::Color::component_fast_t const_alpha_value;
|
||||||
|
|
||||||
|
inline triangle_barycentric_interpolator(
|
||||||
|
bool is_alpha_const,
|
||||||
|
RendererApi::PointF<2> p0, RendererApi::Color::Transparent v0,
|
||||||
|
RendererApi::PointF<2> p1, RendererApi::Color::Transparent v1,
|
||||||
|
RendererApi::PointF<2> p2, RendererApi::Color::Transparent v2
|
||||||
|
) : interpolators{is_alpha_const ? _interpolators_t{.ignore_alpha{p0, v0.without_alpha(), p1, v1.without_alpha(), p2, v2.without_alpha()}} : _interpolators_t{.transparent{p0, v0, p1, v1, p2, v2}}},
|
||||||
|
is_alpha_const{is_alpha_const}, const_alpha_value{v0.alpha} {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
inline triangle_barycentric_interpolator(
|
||||||
|
RendererApi::PointF<2> p0, RendererApi::Color::Transparent v0,
|
||||||
|
RendererApi::PointF<2> p1, RendererApi::Color::Transparent v1,
|
||||||
|
RendererApi::PointF<2> p2, RendererApi::Color::Transparent v2
|
||||||
|
) : triangle_barycentric_interpolator{
|
||||||
|
v0.alpha == v1.alpha && v0.alpha == v2.alpha,
|
||||||
|
p0, v0, p1, v1, p2, v2
|
||||||
|
} {}
|
||||||
|
|
||||||
|
[[nodiscard]] inline RendererApi::Color::Transparent interpolate_point(RendererApi::PointF<2> p) const {
|
||||||
|
if (this->is_alpha_const)
|
||||||
|
return this->interpolators.ignore_alpha.interpolate_point(p).with_alpha(this->const_alpha_value);
|
||||||
|
else
|
||||||
|
return this->interpolators.transparent.interpolate_point(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline RendererApi::Color::Transparent interpolate_point(RendererApi::PointF<2>::component_t x, RendererApi::PointF<2>::component_t y) const {
|
||||||
|
return this->interpolate_point(RendererApi::PointF<2>{x, y});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<unsigned DIMENSIONS, class component_t>
|
||||||
|
struct triangle_barycentric_interpolator<RendererApi::Point<DIMENSIONS, component_t>> {
|
||||||
|
private:
|
||||||
|
using point_t = RendererApi::Point<DIMENSIONS, component_t>;
|
||||||
|
|
||||||
|
_triangle_barycentric_interpolator<RendererApi::Color, []<class interpolator_t>(interpolator_t interpolator) {
|
||||||
|
if constexpr (DIMENSIONS == 2)
|
||||||
|
return point_t{
|
||||||
|
static_cast<point_t::component_fast_t>(interpolator([](point_t const &p) { return p.x; })),
|
||||||
|
static_cast<point_t::component_fast_t>(interpolator([](point_t const &p) { return p.y; }))
|
||||||
|
};
|
||||||
|
else
|
||||||
|
return RendererApi::Point<3, component_t>{
|
||||||
|
static_cast<point_t::component_fast_t>(interpolator([](point_t const &p) { return p.x; })),
|
||||||
|
static_cast<point_t::component_fast_t>(interpolator([](point_t const &p) { return p.y; })),
|
||||||
|
static_cast<point_t::component_fast_t>(interpolator([](point_t const &p) { return p.z; }))
|
||||||
|
};
|
||||||
|
}> impl;
|
||||||
|
public:
|
||||||
|
triangle_barycentric_interpolator(
|
||||||
|
RendererApi::PointF<2> p0, point_t v0,
|
||||||
|
RendererApi::PointF<2> p1, point_t v1,
|
||||||
|
RendererApi::PointF<2> p2, point_t v2
|
||||||
|
) : impl{p0, v0, p1, v1, p2, v2} {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[[nodiscard]] RendererApi::Color interpolate_point(RendererApi::PointF<2> p) const {
|
||||||
|
return this->impl.interpolate_point(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] RendererApi::Color interpolate_point(RendererApi::PointF<2>::component_t x, RendererApi::PointF<2>::component_t y) const {
|
||||||
|
return this->impl.interpolate_point(x, y);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class triangle_barycentric_shader : public Shader {
|
class triangle_barycentric_shader : public Shader {
|
||||||
private:
|
private:
|
||||||
triangle_barycentric_interpolator<RendererApi::Color::Transparent> interpolator;
|
triangle_barycentric_interpolator<RendererApi::Color::Transparent> interpolator;
|
||||||
@ -326,7 +429,7 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities::Shapes {
|
|||||||
inline triangle_barycentric_shader(
|
inline triangle_barycentric_shader(
|
||||||
RendererApi::PointF<2> p0, RendererApi::PointF<2> p1, RendererApi::PointF<2> p2,
|
RendererApi::PointF<2> p0, RendererApi::PointF<2> p1, RendererApi::PointF<2> p2,
|
||||||
RendererApi::Color::Transparent c0, RendererApi::Color::Transparent c1, RendererApi::Color::Transparent c2
|
RendererApi::Color::Transparent c0, RendererApi::Color::Transparent c1, RendererApi::Color::Transparent c2
|
||||||
) noexcept: interpolator{p0, p1, p2, c0, c1, c2} {}
|
) noexcept: interpolator{p0, c0, p1, c1, p2, c2} {}
|
||||||
|
|
||||||
|
|
||||||
[[nodiscard]] inline RendererApi::Color::Transparent get_color(RendererApi::PointF<2>::component_t x, RendererApi::PointF<2>::component_t y) const final {
|
[[nodiscard]] inline RendererApi::Color::Transparent get_color(RendererApi::PointF<2>::component_t x, RendererApi::PointF<2>::component_t y) const final {
|
||||||
|
Loading…
Reference in New Issue
Block a user