Circular shaders

This commit is contained in:
Andrew Golovashevich 2024-12-24 17:10:11 +03:00
parent 3360e35186
commit 9f129fcbe4
4 changed files with 246 additions and 43 deletions

View File

@ -1,3 +1,4 @@
#include <cmath>
#include <array>
#include <iostream>
#include <QApplication>
@ -77,12 +78,19 @@ namespace BGTU::ComputerGraphicsLabWork::Impl {
return 0;
#else
for (int y = 3; y >= -3; y--) {
for (int x = -3; x <= 3; x++) {
// if (x != 0) {
std::cout /*<< '(' << y << ',' << x << '|' << (double)y / (double)x << '|'*/ << std::atan2((double) y , (double) x) / std::numbers::pi_v<double> * 360 << "\t ";
// }
}
std::cout << std::endl;
}
// auto c = Utilities::apply_transparent_color(*(RendererApi::Color *) &bg, fg);
// std::cout << c.red << c.green << c.blue << std::endl;
auto c = Utilities::apply_transparent_color(*(RendererApi::Color*)&bg, fg);
std::cout << c.red << c.green << c.blue << std::endl;
return 0;
return 0;
#endif
}
}

View File

@ -1,3 +1,5 @@
#include <cmath>
#include <numbers>
#include <QMutex>
#include <bgtu/computer_graphics_lab_work/utilities/shapes/circle.hpp>
#include <bgtu/computer_graphics_lab_work/utilities/shader.hpp>
@ -9,7 +11,51 @@ namespace BGTU::ComputerGraphicsLabWork::Impl::Variants::Lab2 {
template<double z, RendererApi::Color::Transparent edge_color, double center_distance_multiplier, double center_angle_degrees, double radius_multiplier>
class Circle : public RendererApi::Sprite<SpriteData::ShapeData, Utilities::ZoomedVoxelPainter<Utilities::DefaultVoxelDrawerCache::VoxelPainterImpl>> {
private:
QMutex sync;
template<RendererApi::Color::Transparent c1, RendererApi::Color::Transparent c2>
class RadialShader : public Utilities::Shader {
private:
RendererApi::PointF<2>::component_t cx, cy;
RendererApi::PointF<2>::component_t radius;
public:
RadialShader(RendererApi::PointF<2>::component_t cx, RendererApi::PointF<2>::component_t cy, RendererApi::PointF<2>::component_t radius) : cx{cx}, cy{cy}, radius{radius} {}
RadialShader(RendererApi::PointF<2> c, RendererApi::PointF<2>::component_t radius) : cx{c.x}, cy{c.y}, radius{radius} {}
RadialShader(RendererApi::PointI<2> c, RendererApi::PointF<2>::component_t radius) : cx{(double) c.x}, cy{(double) c.y}, radius{radius} {}
[[nodiscard]] RendererApi::Color::Transparent get_color(RendererApi::PointF<2>::component_t x, RendererApi::PointF<2>::component_t y) const final {
RendererApi::PointF<2>::component_t distance = std::hypot(x - this->cx, y - this->cy);
double ratio = distance / this->radius;
float c1v;
if (ratio < 0.5) {
c1v = (float) (std::fabs(ratio - 0.25) * 4);
} else if (ratio < 1.0) {
c1v = (float) (std::fabs(ratio - 0.75) * 4);
} else {
return c1;
}
return Utilities::colors_gradient(c1, c1v, c2);
}
};
class HsvSectorShader : public Utilities::Shader {
private:
RendererApi::PointF<2>::component_t cx, cy;
double angle_offset_radians;
public:
HsvSectorShader(RendererApi::PointF<2>::component_t cx, RendererApi::PointF<2>::component_t cy, double angle_offset_radians) : cx{cx}, cy{cy}, angle_offset_radians{angle_offset_radians} {}
HsvSectorShader(RendererApi::PointF<2> c, double angle_offset_radians) : cx{c.x}, cy{c.y}, angle_offset_radians{angle_offset_radians} {}
HsvSectorShader(RendererApi::PointI<2> c, double angle_offset_radians) : cx{(double) c.x}, cy{(double) c.y}, angle_offset_radians{angle_offset_radians} {}
[[nodiscard]] RendererApi::Color::Transparent get_color(RendererApi::PointF<2>::component_t x, RendererApi::PointF<2>::component_t y) const final {
double angle = std::atan2(static_cast<double>(y - this->cy), static_cast<double>(x - this->cx)) + this->angle_offset_radians;
return Utilities::hsv_to_rgb_360_1_1(std::fmod(std::fmod(angle / std::numbers::pi_v<double> * 180, 360.0) + 360, 360.0), 1.0, 1.0);
}
};
enum class ShaderType : unsigned {
SOLID_RED,
@ -29,8 +75,31 @@ namespace BGTU::ComputerGraphicsLabWork::Impl::Variants::Lab2 {
SECTOR_ROTATED_NEG,
};
static inline ShaderType const next_shader_type[] = {
ShaderType::SOLID_GREEN,
ShaderType::SOLID_BLUE,
ShaderType::RADIAL_DARK_RED,
ShaderType::RADIAL_DARK_GREEN,
ShaderType::RADIAL_DARK_BLUE,
ShaderType::RADIAL_LIGHT_RED,
ShaderType::RADIAL_LIGHT_GREEN,
ShaderType::RADIAL_LIGHT_BLUE,
ShaderType::RADIAL_TRANSPARENT_RED,
ShaderType::RADIAL_TRANSPARENT_GREEN,
ShaderType::RADIAL_TRANSPARENT_BLUE,
ShaderType::SECTOR_STATIC,
ShaderType::SECTOR_ROTATED_POS,
ShaderType::SECTOR_ROTATED_NEG,
ShaderType::SOLID_RED
};
QMutex sync;
ShaderType current_shader;
RendererApi::PointI<2> center(SpriteData::ShapeData const *data) const {
return data->pos_rotated(data->radius * center_distance_multiplier, center_angle_degrees);
}
template<class receiver_t>
void _select_shader(SpriteData::ShapeData const *data, receiver_t receiver) const {
const_cast<QMutex *>(&(this->sync))->lock();
@ -52,45 +121,73 @@ namespace BGTU::ComputerGraphicsLabWork::Impl::Variants::Lab2 {
receiver(s);
return;
}
case ShaderType::RADIAL_DARK_RED:
case ShaderType::RADIAL_DARK_GREEN:
case ShaderType::RADIAL_DARK_BLUE:
case ShaderType::RADIAL_LIGHT_RED:
case ShaderType::RADIAL_LIGHT_GREEN:
case ShaderType::RADIAL_LIGHT_BLUE:
case ShaderType::RADIAL_TRANSPARENT_RED:
case ShaderType::RADIAL_TRANSPARENT_GREEN:
case ShaderType::RADIAL_TRANSPARENT_BLUE:
case ShaderType::SECTOR_STATIC:
case ShaderType::SECTOR_ROTATED_POS:
case ShaderType::SECTOR_ROTATED_NEG:;
case ShaderType::RADIAL_DARK_RED: {
RadialShader<RendererApi::Color{255, 0, 0}, RendererApi::Color{0, 0, 0}> s{this->center(data), data->radius * radius_multiplier - 1};
receiver(s);
return;
}
case ShaderType::RADIAL_DARK_GREEN: {
RadialShader<RendererApi::Color{0, 255, 0}, RendererApi::Color{0, 0, 0}> s{this->center(data), data->radius * radius_multiplier - 1};
receiver(s);
return;
}
case ShaderType::RADIAL_DARK_BLUE: {
RadialShader<RendererApi::Color{0, 0, 255}, RendererApi::Color{0, 0, 0}> s{this->center(data), data->radius * radius_multiplier - 1};
receiver(s);
return;
}
case ShaderType::RADIAL_LIGHT_RED: {
RadialShader<RendererApi::Color{255, 0, 0}, RendererApi::Color{255, 255, 255}> s{this->center(data), data->radius * radius_multiplier - 1};
receiver(s);
return;
}
case ShaderType::RADIAL_LIGHT_GREEN: {
RadialShader<RendererApi::Color{0, 255, 0}, RendererApi::Color{255, 255, 255}> s{this->center(data), data->radius * radius_multiplier - 1};
receiver(s);
return;
}
case ShaderType::RADIAL_LIGHT_BLUE: {
RadialShader<RendererApi::Color{0, 0, 255}, RendererApi::Color{255, 255, 255}> s{this->center(data), data->radius * radius_multiplier - 1};
receiver(s);
return;
}
case ShaderType::RADIAL_TRANSPARENT_RED: {
RadialShader<RendererApi::Color::Transparent{255, 0, 0, 255}, RendererApi::Color::Transparent{255, 0, 0, 0}> s{this->center(data), data->radius * radius_multiplier - 1};
receiver(s);
return;
}
case ShaderType::RADIAL_TRANSPARENT_GREEN: {
RadialShader<RendererApi::Color::Transparent{0, 255, 0, 255}, RendererApi::Color::Transparent{0, 255, 0, 0}> s{this->center(data), data->radius * radius_multiplier - 1};
receiver(s);
return;
}
case ShaderType::RADIAL_TRANSPARENT_BLUE: {
RadialShader<RendererApi::Color::Transparent{0, 0, 255, 255}, RendererApi::Color::Transparent{0, 0, 255, 0}> s{this->center(data), data->radius * radius_multiplier - 1};
receiver(s);
return;
}
case ShaderType::SECTOR_STATIC: {
HsvSectorShader s{this->center(data), 0};
receiver(s);
return;
}
case ShaderType::SECTOR_ROTATED_POS: {
HsvSectorShader s{this->center(data), data->rotation_radians};
receiver(s);
return;
}
case ShaderType::SECTOR_ROTATED_NEG: {
HsvSectorShader s{this->center(data), -data->rotation_radians};
receiver(s);
return;
}
}
};
static inline ShaderType const next_shader_type[] = {
ShaderType::SOLID_GREEN,
ShaderType::SOLID_BLUE,
ShaderType::RADIAL_DARK_RED,
ShaderType::RADIAL_DARK_GREEN,
ShaderType::RADIAL_DARK_BLUE,
ShaderType::RADIAL_LIGHT_RED,
ShaderType::RADIAL_LIGHT_GREEN,
ShaderType::RADIAL_LIGHT_BLUE,
ShaderType::RADIAL_TRANSPARENT_RED,
ShaderType::RADIAL_TRANSPARENT_GREEN,
ShaderType::RADIAL_TRANSPARENT_BLUE,
ShaderType::SECTOR_STATIC,
ShaderType::SECTOR_ROTATED_POS,
ShaderType::SECTOR_ROTATED_NEG,
ShaderType::SOLID_RED
};
public:
Circle() : sync{}, current_shader{ShaderType::SOLID_RED} {}
Circle(Circle &&other) : sync{}, current_shader{other.current_shader} {
Circle(Circle &&other) noexcept: sync{}, current_shader{other.current_shader} {
}
@ -99,7 +196,7 @@ namespace BGTU::ComputerGraphicsLabWork::Impl::Variants::Lab2 {
data,
[&]<class shader_t>(shader_t const &shader) {
Utilities::Shapes::iterate_circle_fill(
data->pos_rotated(data->radius * center_distance_multiplier, center_angle_degrees),
this->center(data),
data->radius * radius_multiplier,
[&](bool is_edge, RendererApi::PointI<2>::component_t x, RendererApi::PointI<2>::component_t y) {
if (is_edge) {
@ -115,7 +212,7 @@ namespace BGTU::ComputerGraphicsLabWork::Impl::Variants::Lab2 {
void clicked() final {
this->sync.lock();
this->current_shader = next_shader_type[(unsigned)this->current_shader];
this->current_shader = next_shader_type[(unsigned) this->current_shader];
this->sync.unlock();
}
};

View File

@ -1,6 +1,7 @@
#pragma once
#include <climits>
#include <cmath>
#include <bgtu/computer_graphics_lab_work/renderer_api/color.hpp>
@ -24,8 +25,8 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities {
const float neg_alpha_f = 255.f - alpha_f;
// mulps
const float bg_alpha[4]{bg_f[0] * neg_alpha_f, bg_f[1] * neg_alpha_f, bg_f[1] * neg_alpha_f};
const float fg_alpha[4]{fg_f[0] * alpha_f, fg_f[1] * alpha_f, fg_f[1] * alpha_f};
const float bg_alpha[4]{bg_f[0] * neg_alpha_f, bg_f[1] * neg_alpha_f, bg_f[2] * neg_alpha_f};
const float fg_alpha[4]{fg_f[0] * alpha_f, fg_f[1] * alpha_f, fg_f[2] * alpha_f};
// addps
const float sum_f[4]{bg_alpha[0] + fg_alpha[0], bg_alpha[1] + fg_alpha[1], bg_alpha[2] + fg_alpha[2]};
@ -185,4 +186,88 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities {
buffer[offset + 2] = color.red;
}
}
constexpr RendererApi::Color::Transparent colors_gradient(RendererApi::Color::Transparent c1, float c1v, RendererApi::Color::Transparent c2) {
// pmovzxbd
const std::uint_fast32_t c1_i32[4]{c1.red, c1.green, c1.blue, c1.alpha};
const std::uint_fast32_t c2_i32[4]{c2.red, c2.green, c2.blue, c2.alpha};
// cvtdq2pd
const float c1_f[4]{(float) c1_i32[0], (float) c1_i32[1], (float) c1_i32[2], (float) c1_i32[3]};
const float c2_f[4]{(float) c2_i32[0], (float) c2_i32[1], (float) c2_i32[2], (float) c2_i32[3]};
float c2v = 1 - c1v;
// mulps
const float c1_part[4]{c1_f[0] * c1v, c1_f[1] * c1v, c1_f[2] * c1v, c1_f[3] * c1v};
const float c2_part[4]{c2_f[0] * c2v, c2_f[1] * c2v, c2_f[2] * c2v, c2_f[3] * c2v};
// addps
const float sum_f[4]{c1_part[0] + c2_part[0], c1_part[1] + c2_part[1], c1_part[2] + c2_part[2], c1_part[3] + c2_part[3]};
return {
(RendererApi::Color::component_compact_t) sum_f[0],
(RendererApi::Color::component_compact_t) sum_f[1],
(RendererApi::Color::component_compact_t) sum_f[2],
(RendererApi::Color::component_compact_t) sum_f[3],
};
}
constexpr RendererApi::Color::Transparent colors_gradient(RendererApi::Color::Transparent c1, float c1v, RendererApi::Color::Transparent c2, float c2v, RendererApi::Color::Transparent c3) {
// pmovzxbd
const std::uint_fast32_t c1_i32[4]{c1.red, c1.green, c1.blue, c1.alpha};
const std::uint_fast32_t c2_i32[4]{c2.red, c2.green, c2.blue, c2.alpha};
const std::uint_fast32_t c3_i32[4]{c3.red, c3.green, c3.blue, c3.alpha};
// cvtdq2pd
const float c1_f[4]{(float) c1_i32[0], (float) c1_i32[1], (float) c1_i32[2], (float) c1_i32[3]};
const float c2_f[4]{(float) c2_i32[0], (float) c2_i32[1], (float) c2_i32[2], (float) c2_i32[3]};
const float c3_f[4]{(float) c3_i32[0], (float) c3_i32[1], (float) c3_i32[2], (float) c3_i32[3]};
float c3v = 1 - c1v - c2v;
// mulps
const float c1_part[4]{c1_f[0] * c1v, c1_f[1] * c1v, c1_f[2] * c1v, c1_f[3] * c1v};
const float c2_part[4]{c2_f[0] * c2v, c2_f[1] * c2v, c2_f[2] * c2v, c2_f[3] * c2v};
const float c3_part[4]{c3_f[0] * c3v, c3_f[1] * c3v, c3_f[2] * c3v, c3_f[3] * c3v};
// addps
const float sum_f[4]{
c1_part[0] + c2_part[0] + c3_part[0],
c1_part[1] + c2_part[1] + c3_part[1],
c1_part[2] + c2_part[2] + c3_part[2],
c1_part[3] + c2_part[3] + c3_part[3]
};
return {
(RendererApi::Color::component_compact_t) sum_f[0],
(RendererApi::Color::component_compact_t) sum_f[1],
(RendererApi::Color::component_compact_t) sum_f[2],
(RendererApi::Color::component_compact_t) sum_f[3],
};
}
[[deprecated]] inline RendererApi::Color hsv_to_rgb_360_1_1(double hue, double saturation, double value) {
int hi = int(std::floor(hue / 60)) % 6;
double f = hue / 60 - std::floor(hue / 60);
value = value * 255;
const auto v = (RendererApi::Color::component_fast_t) (value);
const auto p = (RendererApi::Color::component_fast_t) (value * (1 - saturation));
const auto q = (RendererApi::Color::component_fast_t) (value * (1 - f * saturation));
const auto t = (RendererApi::Color::component_fast_t) (value * (1 - (1 - f) * saturation));
switch (hi) {
case 0:
return {v, t, p};
case 1:
return {q, v, p};
case 2:
return {p, v, t};
case 3:
return {p, q, v};
case 4:
return {t, p, v};
default:
return {v, p, q};
}
}
}

View File

@ -20,7 +20,7 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities::Shapes {
RendererApi::PointI<2>::component_t x = 0, y = r;
RendererApi::PointI<2>::component_t last_y = r + 1;
RendererApi::PointI<2>::component_t _r2 = r * r;
while (x < y) {
while (true) {
RendererApi::PointI<2>::component_t _x2 = x * x;
RendererApi::PointI<2>::component_t _y_1 = y - 1;
RendererApi::PointI<2>::component_t D1 = _x2 + y * y - _r2;
@ -29,6 +29,19 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities::Shapes {
if (D1 > -D2)
y--;
if (x == y) {
edge_point_receiver(cx - x, cy + y);
fill_line_receiver(cy + y, cx - x + 1, cx + x);
edge_point_receiver(cx + x, cy + y);
edge_point_receiver(cx - x, cy - y);
fill_line_receiver(cy - y, cx - x + 1, cx + x);
edge_point_receiver(cx + x, cy - y);
break;
} else if (x > y) {
break;
}
if (y < last_y) {
edge_point_receiver(cx - x, cy + y);
fill_line_receiver(cy + y, cx - x + 1, cx + x);