Size: 3149 bytes.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
// cs/renderer/sphere_renderer.hh
#ifndef CS_RENDERER_SPHERE_RENDERER_HH
#define CS_RENDERER_SPHERE_RENDERER_HH

#include <stdio.h>

#include <vector>

#include "cs/renderer/film.hh"
#include "cs/renderer/geo/dist.hh"
#include "cs/renderer/geo/point3.h"
#include "cs/renderer/geo/ray3.h"
#include "cs/renderer/geo/vector3.h"
#include "cs/renderer/numbers/map_value.hh"
#include "cs/renderer/shapes/sphere.hh"
#include "cs/result.hh"

using p3 = ::cs::renderer::geo::Point3;
using v3 = ::cs::renderer::geo::Vector3;
using r3 = ::cs::renderer::geo::Ray3;
using ::cs::Error;
using ::cs::Ok;
using ::cs::Result;
using ::cs::ResultOr;
using ::cs::numbers::map_value;
using ::cs::renderer::Film;
using ::cs::renderer::geo::dist;
using ::cs::renderer::shapes::Sphere;

namespace cs::renderer {
class SphereRenderer {
 public:
  p3 focal_point_ = p3(0, 0, -2);
  p3 film_center_ = p3(0, 0, 1);
  Film film_ = Film(256, 256);
  float pixels_per_unit_ = 128;
  Sphere sphere_ =
      Sphere(/*center=*/p3(0, 0, 5), /*radius=*/1);

  ResultOr<Film> render() {
    float min_distance =
        dist(focal_point_, sphere_.center) - sphere_.radius;
    float max_distance =
        dist(focal_point_, sphere_.center) + sphere_.radius;

    float x_units = film_.width / pixels_per_unit_;
    float y_units = film_.height / pixels_per_unit_;
    float film_x_start = film_center_.x - x_units / 2.f;
    float film_x_end = film_center_.x + x_units / 2.f;
    float film_y_start = film_center_.y + y_units / 2.f;
    float film_y_end = film_center_.y - y_units / 2.f;
    for (uint32_t fx = 0; fx < film_.width; fx++) {
      float real_x = map_value<float>(
          fx, 0, film_.width, film_x_start, film_x_end);
      for (uint32_t fy = 0; fy < film_.height; fy++) {
        float real_y = map_value<float>(
            fy, 0, film_.height, film_y_start, film_y_end);
        float real_z = film_center_.z;
        r3 ray(focal_point_, p3(real_x, real_y, real_z));

        p3 intersection_point;
        v3 normal;
        if (sphere_.intersected_by(ray, &intersection_point,
                                   &normal)) {
          float distance = cs::renderer::geo::dist(
              ray.origin, intersection_point);
#if 0
          if (distance > max_distance) {
            max_distance = distance;
            std::cout
                << "Film point fx=" << fx << ",fy=" << fx
                << " max_distance=" << max_distance << "\n";
          }
#endif
          if (!(distance >= min_distance)) {
            return TRACE(Error("distance < min_distance"));
          }
          if (!(distance <= max_distance)) {
            return TRACE(Error("distance > max_distance"));
          }
          float rgb = map_value<float>(
              distance, min_distance, max_distance, 255, 0);
          if (!(0 <= rgb && rgb <= 255.f)) {
            return TRACE(Error("rgb out of bounds"));
          }
          film_.pixels[fx][fy] = Pixel(rgb, rgb, rgb, 255);
        } else {
          film_.pixels[fx][fy] = Pixel(0, 0, 0, 0);
        }
      }
    }
    return film_;
  }
};
}  // namespace cs::renderer

#endif  // CS_RENDERER_SPHERE_RENDERER_HH
v0 (commit) © 2025 @p13i.io | Load balancer proxied to: cs-code-viewer-1:8080 in 4ms.