cgfs:shaded_triangles
文書の過去の版を表示しています。
<codeprism lang=cpp el=true css=full> #include <raylib.h>
#include <cassert> #include <cmath> #include <iterator> #include <vector>
#include “vmath.h”
int const Cw = 600; int const Ch = 600;
using vec2 = vmath::vec2<float>;
void PutPixel(int x, int y, Color const &color) {
DrawPixel(x + Cw / 2, -y + Ch / 2, color);
}
template <typename Iter>
requires std::output_iterator<Iter, float>
void Interpolate(int i0, float d0, int i1, float d1, Iter out) {
if (i0 == i1) { *out = d0; return; }
auto a = (d1 - d0) / (i1 - i0); auto d = d0;
for (int i = i0; i <= i1; ++i) { *out++ = d; d += a; }
}
void DrawLine(vec2 const &p0, vec2 const &p1, Color const &color) {
auto x0 = p0.x; auto y0 = p0.y; auto x1 = p1.x; auto y1 = p1.y;
if (std::abs(x1 - x0) > std::abs(y1 - y0)) { if (x0 > x1) { std::swap(x0, x1); std::swap(y0, y1); } auto i0 = static_cast<int>(std::floor(x0)); auto i1 = static_cast<int>(std::floor(x1)); auto ys = std::vector<float>(i1 - i0 + 1); Interpolate(i0, y0, i1, y1, ys.begin()); for (int i = i0; i <= i1; ++i) { PutPixel(i, ys[i - i0], color); } } else { if (y0 > y1) { std::swap(y0, y1); std::swap(x0, x1); } auto i0 = static_cast<int>(std::floor(y0)); auto i1 = static_cast<int>(std::floor(y1)); auto xs = std::vector<float>(i1 - i0 + 1); Interpolate(i0, x0, i1, x1, xs.begin()); for (int i = i0; i <= i1; ++i) { PutPixel(xs[i - i0], i, color); } }
}
void DrawWireframeTriangle(vec2 const &p0,
vec2 const &p1, vec2 const &p2, Color const &color) { DrawLine(p0, p1, color); DrawLine(p1, p2, color); DrawLine(p2, p0, color);
}
void DrawFilledTriangle(vec2 const &p0,
vec2 const &p1, vec2 const &p2, Color const &color) { vec2 P0{p0}, P1{p1}, P2{p2}; if (P1.y < P0.y) { std::swap(P1, P0); } if (P2.y < P0.y) { std::swap(P2, P0); } if (P2.y < P1.y) { std::swap(P2, P1); }
auto i0 = static_cast<int>(std::floor(P0.y)); auto i1 = static_cast<int>(std::floor(P1.y)); auto i2 = static_cast<int>(std::floor(P2.y)); auto x01 = std::vector<float>(i1 - i0 + 1); auto x12 = std::vector<float>(i2 - i1 + 1); auto x02 = std::vector<float>(i2 - i0 + 1);
Interpolate(i0, P0.x, i1, P1.x, x01.begin()); Interpolate(i1, P1.x, i2, P2.x, x12.begin()); Interpolate(i0, P0.x, i2, P2.x, x02.begin());
x01.pop_back();
auto x012 = std::vector<float>(x01.size() + x12.size()); assert(x012.size() == x02.size());
auto corner = std::copy(x01.begin(), x01.end(), x012.begin()); std::copy(x12.begin(), x12.end(), corner);
auto x_left = x012; auto x_right = x02; auto m = x012.size() / 2; if (x02[m] < x012[m]) { x_left = x02; x_right = x012; }
for (int y = i0; y < i2; ++y) { auto x_begin = static_cast<int>(std::floor(x_left[y - i0])); auto x_end = static_cast<int>(std::floor(x_right[y - i0])); for (int x = x_begin; x < x_end; ++x) { PutPixel(x, y, color); } }
}
struct IntensiveVertex {
float x, y; float h;
IntensiveVertex() = default; IntensiveVertex(vec2 const &p, float intensity) : x{p.x}, y{p.y}, h{intensity} {}
};
Color color_scaled(Color const &color, float scale) {
auto r = static_cast<unsigned char>( std::min(static_cast<int>(scale * color.r), 255)); auto g = static_cast<unsigned char>( std::min(static_cast<int>(scale * color.g), 255)); auto b = static_cast<unsigned char>( std::min(static_cast<int>(scale * color.b), 255)); return {r, g, b, color.a};
}
void DrawShadedTriangle(IntensiveVertex const &p0,
IntensiveVertex const &p1, IntensiveVertex const &p2, Color const &color) { IntensiveVertex P0{p0}, P1{p1}, P2{p2}; if (p1.y < p0.y) { std::swap(P1, P0); } if (p2.y < p0.y) { std::swap(P2, P0); } if (p2.y < p1.y) { std::swap(P2, P1); }
auto yi0 = static_cast<int>(std::floor(P0.y)); auto yi1 = static_cast<int>(std::floor(P1.y)); auto yi2 = static_cast<int>(std::floor(P2.y));
auto x01 = std::vector<float>(yi1 - yi0 + 1); auto h01 = std::vector<float>(yi1 - yi0 + 1); Interpolate(yi0, P0.x, yi1, P1.x, x01.begin()); Interpolate(yi0, P0.h, yi1, P1.h, h01.begin());
auto x12 = std::vector<float>(yi2 - yi1 + 1); auto h12 = std::vector<float>(yi2 - yi1 + 1); Interpolate(yi1, P1.x, yi2, P2.x, x12.begin()); Interpolate(yi1, P1.h, yi2, P2.h, h12.begin());
auto x02 = std::vector<float>(yi2 - yi0 + 1); auto h02 = std::vector<float>(yi2 - yi0 + 1); Interpolate(yi0, P0.x, yi2, P2.x, x02.begin()); Interpolate(yi0, P0.h, yi2, P2.h, h02.begin());
x01.pop_back(); assert(x01.size() + x12.size() == x02.size());
h01.pop_back(); assert(h01.size() + h12.size() == h02.size());
auto x012 = std::vector<float>(x01.size() + x12.size() + 1); auto corner_x012 = std::copy(x01.begin(), x01.end(), x012.begin()); std::copy(x12.begin(), x12.end(), corner_x012);
auto h012 = std::vector<float>(h01.size() + h12.size() + 1); auto corner_h012 = std::copy(h01.begin(), h01.end(), h012.begin()); std::copy(h12.begin(), h12.end(), corner_h012);
auto m = x012.size() / 2; auto &x_left = x012; auto &h_left = h012; auto &x_right = x02; auto &h_right = h02;
if (x02[m] < x012[m]) { std::swap(x_left, x_right); std::swap(h_left, h_right); }
auto h_segment = std::vector<float>();
for (int y = yi0; y <= yi2; ++y) { auto x_l = static_cast<int>(std::floor(x_left[y - yi0])); auto x_r = static_cast<int>(std::floor(x_right[y - yi0]));
h_segment.resize(x_r - x_l + 1); Interpolate(x_l, h_left[y - yi0], x_r, h_right[y - yi0], h_segment.begin());
for (int x = x_l; x <= x_r; ++x) { auto shaded_color = color_scaled(color, h_segment[x - x_l]); PutPixel(x, y, shaded_color); } }
}
int main() {
InitWindow(Cw, Ch, "Draw Lines");
IntensiveVertex p0{{-100, 200}, 1.0}; IntensiveVertex p1{{100, 100}, 0.2}; IntensiveVertex p2{{-200, -200}, 0.0};
while (!WindowShouldClose()) { BeginDrawing();
ClearBackground(RAYWHITE);
//~ PutPixel(p0.x, p0.y, RED); //~ PutPixel(p1.x, p1.y, RED); //~ PutPixel(p2.x, p2.y, RED);
DrawShadedTriangle(p0, p1, p2, GREEN);
EndDrawing(); }
} </codeprism>
cgfs/shaded_triangles.1718072027.txt.gz · 最終更新: 2024/06/11 11:13 by freemikan