summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeuin <[email protected]>2022-04-12 11:01:32 +0800
committerKeuin <[email protected]>2022-04-12 11:01:32 +0800
commita97b38299d5f8297d15077160df5439d274bd571 (patch)
treeb2f86794894561a853a6873a37ea14e4f7e7387c
parente83da6c36b39e6f8de35fc7e1c3caf8041cfe325 (diff)
Make object::hit provides hit time t.
Visualize normal vector at hit point. Add pixel<T>::from_normalized(const vec3d&) for visualizing normal vector.
-rw-r--r--bitmap.h7
-rw-r--r--main_simple_scanner.cpp31
2 files changed, 31 insertions, 7 deletions
diff --git a/bitmap.h b/bitmap.h
index 31b9053..09f3711 100644
--- a/bitmap.h
+++ b/bitmap.h
@@ -31,10 +31,15 @@ struct pixel {
* Create a pixel with given depth, from normalized color values.
* For example: for 8bit pixel, with (1, 0.5, 0.25), we get: (255, 127, 63).
*/
- static pixel<T> from_normalized(double r, double g, double b) {
+ static inline pixel<T> from_normalized(double r, double g, double b) {
const auto mod = (1ULL << (sizeof(T) * 8U)) - 1ULL;
return pixel<T>{.r = (T) (mod * r), .g = (T) (mod * g), .b = (T) (mod * b)};
}
+
+ // v3d must be a normalized vector
+ static inline pixel<T> from_normalized(const vec3d &v3d) {
+ return from_normalized(v3d.x / 2.0 + 0.5, v3d.y / 2.0 + 0.5, v3d.z / 2.0 + 0.5);
+ }
};
// Mix two colors a and b. Returns a*u + b*v
diff --git a/main_simple_scanner.cpp b/main_simple_scanner.cpp
index 7279e12..e57ef03 100644
--- a/main_simple_scanner.cpp
+++ b/main_simple_scanner.cpp
@@ -17,8 +17,11 @@
class object {
public:
- // Will the given ray hit.
- virtual bool hit(const ray3d &r) const = 0;
+ // Will the given ray hit. Returns time t if hits.
+ virtual bool hit(const ray3d &r, double &t) const = 0;
+
+ // Given a point on the surface, returns the normalized normal vector on that point.
+ virtual vec3d normal_vector(const vec3d &where) const = 0;
// object color, currently not parameterized
virtual pixel8b color() const = 0;
@@ -38,7 +41,12 @@ public:
~sphere() override = default;
- bool hit(const ray3d &r) const override {
+ vec3d normal_vector(const vec3d &where) const override {
+ // We assume the point is on surface, speeding up the normalization
+ return (where - center) / radius;
+ }
+
+ bool hit(const ray3d &r, double &t) const override {
// Ray: {Source, Direction, time}
// Sphere: {Center, radius}
// sphere hit formula: |Source + Direction * time - Center| = radius
@@ -51,7 +59,13 @@ public:
const auto rel_src = r.source() - center; // relative position of ray source
// C = (S - C) dot (S - C) - radius^2
const double c = dot(rel_src, rel_src) - radius * radius;
- return b * b - 4 * a * c >= 0;
+ const auto delta = b * b - 4 * a * c;
+ const auto hit = delta >= 0;
+ if (hit) {
+ // the smaller root is the first point the ray hits, so return that one
+ t = (-b - sqrt(delta)) / (2.0 * a);
+ }
+ return hit;
}
pixel8b color() const override {
@@ -67,9 +81,14 @@ class viewport {
// Given a ray from the camera, generate a color the camera seen on the viewport.
pixel8b color(const ray3d &r) {
// Detect hits
+ double hit_t;
for (const auto &obj: objects) {
- if (obj->hit(r)) {
- return obj->color();
+ if (obj->hit(r, hit_t)) {
+ // normal vector on hit point
+ const auto nv = obj->normal_vector(r.at(hit_t));
+// return obj->color();
+ // visualize normal vector at hit point
+ return pixel8b::from_normalized(nv);
}
}