summaryrefslogtreecommitdiff
path: root/viewport.h
diff options
context:
space:
mode:
Diffstat (limited to 'viewport.h')
-rw-r--r--viewport.h74
1 files changed, 42 insertions, 32 deletions
diff --git a/viewport.h b/viewport.h
index 2924582..02c1466 100644
--- a/viewport.h
+++ b/viewport.h
@@ -18,6 +18,7 @@
#include <iostream>
#include <cstdint>
#include <random>
+#include <cmath>
// bias context, used for placing sub-pixels
class bias_ctx {
@@ -41,32 +42,40 @@ public:
}
};
-template<typename T>
-class viewport {
-public:
- virtual bitmap<T> render(const hitlist &world, vec3d viewpoint, uint16_t image_width, uint16_t image_height) = 0;
-
- virtual ~viewport() = default;
-};
-
+// TODO rename to camera
// Single sampled viewport which supports bias sampling
-template<typename T>
-class basic_viewport : public viewport<T> {
- const double half_width, half_height; // viewport size
- const vec3d center; // coordinate of the viewport center point
-
+// U: color depth, V: pos
+template<typename U, typename V>
+class basic_viewport {
+ vec3<V> cxyz; // coordinate of the focus point
+ vec3<V> screen_center;
+// double pitch; // TODO implement
+// double yaw; // TODO implement
+ uint32_t image_width; // how many pixels every row has
+ uint32_t image_height; // how many pixels every column has
+ V screen_hw; // determined if screen_height is known
+ V screen_hh; // determined if screen_width is known
+// double fov_h; // horizontal FOV, determined if screen_width or screen_height is known
+// double focus_length; // distance between the focus point and the image screen
+ hitlist &world;
public:
- basic_viewport() = delete;
- basic_viewport(double width, double height, vec3d viewport_center) :
- half_width(width / 2.0), half_height(height / 2.0), center(viewport_center) {}
+ basic_viewport(const vec3<V> &cxyz, const vec3<V> &screen_center,
+ uint32_t image_width, uint32_t image_height,
+ double fov_h, hitlist &world) :
+ cxyz{cxyz}, screen_center{screen_center}, image_width{image_width}, image_height{image_height},
+ screen_hw{(cxyz - screen_center).norm() * tan((double) fov_h / 2.0)},
+ screen_hh{screen_hw * ((double) image_height / image_width)},
+ world{world} {}
- virtual bitmap<T>
- render(const hitlist &world, vec3d viewpoint, uint16_t image_width, uint16_t image_height) override {
- bias_ctx bc{};
- static constexpr uint64_t default_diffuse_seed = 123456789012345678ULL;
- return render(world, viewpoint, image_width, image_height, bc, default_diffuse_seed);
- }
+ basic_viewport(const vec3<V> &cxyz, const vec3<V> &screen_center,
+ uint32_t image_width, uint32_t image_height,
+ double screen_hw, double screen_hh,
+ hitlist &world) :
+ cxyz{cxyz}, screen_center{screen_center}, image_width{image_width}, image_height{image_height},
+ screen_hw{screen_hw},
+ screen_hh{screen_hh},
+ world{world} {}
/**
* Generate the image seen on given viewpoint.
@@ -74,13 +83,14 @@ public:
* @param by bias on y axis (0.0 <= by < 1.0)
* @return
*/
- virtual bitmap<T> render(const hitlist &world, vec3d viewpoint,
- uint16_t image_width, uint16_t image_height,
- bias_ctx &bias, uint64_t diffuse_seed) const {
- bitmap<T> image{image_width, image_height};
+ bitmap<U> render(uint64_t diffuse_seed, bias_ctx &bias
+ /* by putting thread-specific parameters in call argument list, make users convenient*/) const {
+ // The implementation keep all mutable state in local stack,
+ // keeping the class immutable and thread-safe.
+ bitmap<U> image{image_width, image_height};
random_uv_gen_3d ruvg{diffuse_seed};
- double bx, by;
- const auto r = center - viewpoint;
+ V bx, by;
+ const auto r = screen_center - cxyz;
const int img_hw = image_width / 2, img_hh = image_height / 2;
// iterate over every pixel on the image
for (int j = -img_hh + 1; j <= img_hh; ++j) { // axis y, transformation is needed
@@ -91,13 +101,13 @@ public:
assert(bx < 1.0);
assert(by < 1.0);
const vec3d off{
- .x=(1.0 * i + bx) / img_hw * half_width,
- .y=(1.0 * j + by) / img_hh * half_height,
+ .x=(1.0 * i + bx) / img_hw * screen_hw,
+ .y=(1.0 * j + by) / img_hh * screen_hh,
.z=0.0
}; // offset on screen plane
const auto dir = r + off; // direction vector from camera to current pixel on screen
- ray3d ray{viewpoint, dir}; // from camera to pixel (on the viewport)
- const auto pixel = world.color<T>(ray, ruvg);
+ ray3d ray{cxyz, dir}; // from camera to pixel (on the viewport)
+ const auto pixel = world.color<U>(ray, ruvg);
const auto x_ = i + img_hw, y_ = -j + img_hh;
image.set(x_, y_, pixel);