ユーザ用ツール

サイト用ツール


cgfs:shaded_triangles

文書の過去の版を表示しています。


<codeprism lang=cpp el=true css=full> #include <raylib.h>

#include <algorithm> #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;
  }

}

struct VertexPositionIntensity : vec2 {

  float h;
  VertexPositionIntensity() = default;
  VertexPositionIntensity(float x, float y, float intensity)
      : vec2{x, y}, h{intensity} {}

};

Color color_scaled(Color const &color, float scale) {

  auto r = static_cast<unsigned char>(
      std::clamp(static_cast<int>(scale * color.r), 0, 255));
  auto g = static_cast<unsigned char>(
      std::clamp(static_cast<int>(scale * color.g), 0, 255));
  auto b = static_cast<unsigned char>(
      std::clamp(static_cast<int>(scale * color.b), 0, 255));
  return {r, g, b, color.a};

}

void DrawShadedTriangle(VertexPositionIntensity const &p0,

                      VertexPositionIntensity const &p1,
                      VertexPositionIntensity const &p2,
                      Color const &color) {
  VertexPositionIntensity 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.clear();
      Interpolate(x_l, h_left[y - yi0], x_r, h_right[y - yi0],
                  std::back_inserter(h_segment));
      for (int x = x_l; x <= x_r; ++x) {
          float h = h_segment[x - x_l];
          PutPixel(x, y, color_scaled(color, h));
      }
  }

}

int main() {

  InitWindow(Cw, Ch, "Shaded Triangles");
  VertexPositionIntensity p0{-100, 200, 1.0};
  VertexPositionIntensity p1{100, 100, 0.2};
  VertexPositionIntensity p2{-200, -200, 0.0};
  while (!WindowShouldClose()) {
      BeginDrawing();
      ClearBackground(RAYWHITE);
      DrawShadedTriangle(p0, p1, p2, GREEN);
      EndDrawing();
  }

} </codeprism>

cgfs/shaded_triangles.1720627350.txt.gz · 最終更新: 2024/07/11 01:02 by freemikan

特に明示されていない限り、本Wikiの内容は次のライセンスに従います: CC0 1.0 Universal
CC0 1.0 Universal Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki