Applying perspective interpolation to textures

This commit is contained in:
Andrew Golovashevich 2025-03-20 18:19:44 +03:00
parent ff43f035b1
commit 8ec2ea1b58
2 changed files with 202 additions and 0 deletions

View File

@ -43,6 +43,16 @@ namespace BGTU::ComputerGraphicsLabWork::Impl {
RendererApi::PointF<3> tb{tb4[0] / tb4[3], tb4[1] / tb4[3], tb4[2] / tb4[3]}; RendererApi::PointF<3> tb{tb4[0] / tb4[3], tb4[1] / tb4[3], tb4[2] / tb4[3]};
RendererApi::PointF<3> tc{tc4[0] / tc4[3], tc4[1] / tc4[3], tc4[2] / tc4[3]}; RendererApi::PointF<3> tc{tc4[0] / tc4[3], tc4[1] / tc4[3], tc4[2] / tc4[3]};
#if 1
Utilities::Shapes::triangle_perspective_interpolator<RendererApi::PointF<3>> interpolator{
{ta.x, ta.y, ta4[3]},
{this->shader_p0.x, this->shader_p0.y, ta.z},
{tb.x, tb.y, tb4[3]},
{this->shader_p1.x, this->shader_p1.y, tb.z},
{tc.x, tc.y, tc4[3]},
{this->shader_p2.x, this->shader_p2.y, tc.z},
};
#else
Utilities::Shapes::triangle_barycentric_interpolator<RendererApi::PointF<3>> interpolator{ Utilities::Shapes::triangle_barycentric_interpolator<RendererApi::PointF<3>> interpolator{
{ta.x, ta.y}, {ta.x, ta.y},
{this->shader_p0.x, this->shader_p0.y, ta.z}, {this->shader_p0.x, this->shader_p0.y, ta.z},
@ -51,6 +61,7 @@ namespace BGTU::ComputerGraphicsLabWork::Impl {
{tc.x, tc.y}, {tc.x, tc.y},
{this->shader_p2.x, this->shader_p2.y, tc.z}, {this->shader_p2.x, this->shader_p2.y, tc.z},
}; };
#endif
Utilities::Shapes::iterate_triangle_fill( Utilities::Shapes::iterate_triangle_fill(
{static_cast<RendererApi::PointI<2>::component_t>(ta.x), static_cast<RendererApi::PointI<2>::component_t>(ta.y)}, {static_cast<RendererApi::PointI<2>::component_t>(ta.x), static_cast<RendererApi::PointI<2>::component_t>(ta.y)},

View File

@ -433,6 +433,197 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities::Shapes {
) noexcept: interpolator{p0, c0, p1, c1, p2, 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 {
return this->interpolator.interpolate_point(x, y);
}
};
template<class variable_t, auto transform>
struct _triangle_perspective_interpolator {
private:
long double full_square;
RendererApi::PointF<3> p0;
RendererApi::PointF<3> p1;
RendererApi::PointF<3> p2;
variable_t v0;
variable_t v1;
variable_t v2;
static long double calculate_square_2(
RendererApi::PointF<2> p0,
RendererApi::PointF<3> p1,
RendererApi::PointF<3> p2
) noexcept {
return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
}
public:
_triangle_perspective_interpolator(
RendererApi::PointF<3> p0, variable_t v0,
RendererApi::PointF<3> p1, variable_t v1,
RendererApi::PointF<3> p2, variable_t v2
) : p0{p0}, p1{p1}, p2{p2}, v0{v0}, v1{v1}, v2{v2}, full_square{calculate_square_2({p0.x, p0.y}, p1, p2)} {
}
[[nodiscard]] variable_t interpolate_point(RendererApi::PointF<2> p) const {
const double k0 = calculate_square_2(p, this->p1, this->p2) / (this->full_square * this->p0.z);
const double k1 = calculate_square_2(p, this->p2, this->p0) / (this->full_square * this->p1.z);
const double k2 = calculate_square_2(p, this->p0, this->p1) / (this->full_square * this->p2.z);
const double divider = k0 + k1 + k2;
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) / divider; });
}
[[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});
}
};
template<class variable_t>
struct triangle_perspective_interpolator {
private:
_triangle_perspective_interpolator<variable_t, []<class interpolator_t>(interpolator_t interpolator) {
return static_cast<variable_t>(interpolator([](variable_t v) { return v; }));
}> impl;
public:
triangle_perspective_interpolator(
RendererApi::PointF<3> p0, variable_t v0,
RendererApi::PointF<3> p1, variable_t v1,
RendererApi::PointF<3> 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_perspective_interpolator<RendererApi::Color> {
private:
_triangle_perspective_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_perspective_interpolator(
RendererApi::PointF<3> p0, RendererApi::Color v0,
RendererApi::PointF<3> p1, RendererApi::Color v1,
RendererApi::PointF<3> 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_perspective_interpolator<RendererApi::Color::Transparent> {
private:
union _interpolators_t {
triangle_perspective_interpolator<RendererApi::Color> ignore_alpha;
_triangle_perspective_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_perspective_interpolator(
bool is_alpha_const,
RendererApi::PointF<3> p0, RendererApi::Color::Transparent v0,
RendererApi::PointF<3> p1, RendererApi::Color::Transparent v1,
RendererApi::PointF<3> 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_perspective_interpolator(
RendererApi::PointF<3> p0, RendererApi::Color::Transparent v0,
RendererApi::PointF<3> p1, RendererApi::Color::Transparent v1,
RendererApi::PointF<3> p2, RendererApi::Color::Transparent v2
) : triangle_perspective_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_perspective_interpolator<RendererApi::Point<DIMENSIONS, component_t>> {
private:
using point_t = RendererApi::Point<DIMENSIONS, component_t>;
_triangle_perspective_interpolator<point_t, []<class interpolator_t>(interpolator_t interpolator) {
if constexpr (DIMENSIONS == 2)
return point_t{
static_cast<point_t::component_t>(interpolator([](point_t const &p) { return p.x; })),
static_cast<point_t::component_t>(interpolator([](point_t const &p) { return p.y; }))
};
else
return point_t{
static_cast<point_t::component_t>(interpolator([](point_t const &p) { return p.x; })),
static_cast<point_t::component_t>(interpolator([](point_t const &p) { return p.y; })),
static_cast<point_t::component_t>(interpolator([](point_t const &p) { return p.z; }))
};
}> impl;
public:
triangle_perspective_interpolator(
RendererApi::PointF<3> p0, point_t v0,
RendererApi::PointF<3> p1, point_t v1,
RendererApi::PointF<3> p2, point_t v2
) : impl{p0, v0, p1, v1, p2, v2} {
}
[[nodiscard]] point_t interpolate_point(RendererApi::PointF<2> p) const {
return this->impl.interpolate_point(p);
}
[[nodiscard]] point_t interpolate_point(RendererApi::PointF<2>::component_t x, RendererApi::PointF<2>::component_t y) const {
return this->impl.interpolate_point(x, y);
}
};
class triangle_perspective_shader : public Shader {
private:
triangle_perspective_interpolator<RendererApi::Color::Transparent> interpolator;
public:
inline triangle_perspective_shader(
RendererApi::PointF<3> p0, RendererApi::Color::Transparent c0,
RendererApi::PointF<3> p1, RendererApi::Color::Transparent c1,
RendererApi::PointF<3> p2, RendererApi::Color::Transparent 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 {
return this->interpolator.interpolate_point(x, y); return this->interpolator.interpolate_point(x, y);
} }