Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #pragma once
- #include "options/camera_options.h"
- #include "options/render_options.h"
- #include "image.h"
- #include <filesystem>
- #include <object.h>
- #include <scene.h>
- #include <intersection.h>
- #include <geometry.h>
- std::pair<Vector, Vector> ScreenVectors(Vector from, Vector to) {
- Vector forward = to - from;
- Vector right = CrossProduct(Vector(0, -1, 0), forward);
- if (right[0] == 0 && right[1] == 0 && right[2] == 0) {
- right = Vector(1, 0, 0);
- } else {
- right.Normalize();
- }
- Vector up = CrossProduct(forward, right);
- up.Normalize();
- return {right, up};
- }
- struct DebugInfo {
- double min_dist;
- double max_dist;
- Vector normal;
- };
- constexpr double kDoubleInf = std::numeric_limits<double>::max();
- DebugInfo ObjectProcessing(const std::vector<Object>& objects,
- const std::vector<SphereObject>& sphere_objects, const Ray& ray) {
- double min_dist = kDoubleInf;
- double max_dist = 0;
- Vector normal;
- for (const auto& obj : sphere_objects) {
- std::optional<Intersection> inter = GetIntersection(ray, obj.sphere);
- if (inter.has_value()) {
- double dist = inter->GetDistance();
- if (dist < min_dist) {
- max_dist = dist;
- min_dist = dist;
- normal = inter->GetNormal();
- assert(std::isfinite(normal[0]) && std::isfinite(normal[1]) &&
- std::isfinite(normal[2]));
- }
- }
- }
- for (const auto& obj : objects) {
- std::optional<Intersection> inter = GetIntersection(ray, obj.polygon);
- if (inter.has_value()) {
- double dist = inter->GetDistance();
- if (dist < min_dist) {
- max_dist = dist;
- min_dist = dist;
- normal = inter->GetNormal();
- assert(std::isfinite(normal[0]) && std::isfinite(normal[1]) &&
- std::isfinite(normal[2]));
- if (obj.GetNormal(0) != nullptr) {
- Vector bars = GetBarycentricCoords(obj.polygon, inter->GetPosition());
- normal = *(obj.GetNormal(0)) * bars[0] + *(obj.GetNormal(1)) * bars[1] +
- *(obj.GetNormal(2)) * bars[2];
- }
- }
- }
- }
- return {min_dist, max_dist, normal};
- }
- Image Render(const std::filesystem::path& path, const CameraOptions& camera_options,
- const RenderOptions& render_options) {
- Image image = Image(camera_options.screen_width, camera_options.screen_height);
- Scene scene = ReadScene(path);
- std::vector<Object> objects = scene.GetObjects();
- std::vector<SphereObject> sphere_objects = scene.GetSphereObjects();
- std::vector<Light> lights = scene.GetLights();
- std::unordered_map<std::string, Material> materials = scene.GetMaterials();
- double half_pixel_size = Length(camera_options.look_to - camera_options.look_from) *
- std::tan(camera_options.fov / 2) / camera_options.screen_height;
- double max_dist = 0;
- std::vector<std::vector<double>> min_dists(camera_options.screen_width,
- std::vector<double>(camera_options.screen_height));
- for (int x = 0; x < camera_options.screen_width; ++x) {
- for (int y = 0; y < camera_options.screen_height; ++y) {
- double cur_x = (-camera_options.screen_width + 1 + 2 * x) * half_pixel_size;
- double cur_y = (-camera_options.screen_height + 1 + 2 * y) * half_pixel_size;
- auto [right, up] = ScreenVectors(camera_options.look_from, camera_options.look_to);
- Vector pixel_coord = cur_x * right + cur_y * up + camera_options.look_to;
- Ray ray = Ray(camera_options.look_from, pixel_coord - camera_options.look_from);
- if (render_options.mode == RenderMode::kDepth ||
- render_options.mode == RenderMode::kNormal) {
- auto [min_dist, max_dist_cur, normal] =
- ObjectProcessing(objects, sphere_objects, ray);
- max_dist = std::max(max_dist, max_dist_cur);
- min_dists[x][y] = min_dist;
- if (render_options.mode == RenderMode::kNormal) {
- if (min_dist == kDoubleInf) {
- image.SetPixel({0, 0, 0}, y, x);
- } else {
- RGB val{};
- assert(std::isfinite(normal[0]) && std::isfinite(normal[1]) &&
- std::isfinite(normal[2]));
- normal = 0.5 * (normal + Vector(1, 1, 1));
- val.r = std::round(255 * normal[0]);
- val.g = std::round(255 * normal[1]);
- val.b = std::round(255 * normal[2]);
- image.SetPixel(val, y, x);
- }
- }
- }
- }
- }
- if (render_options.mode == RenderMode::kDepth) {
- for (int x = 0; x < camera_options.screen_width; ++x) {
- for (int y = 0; y < camera_options.screen_height; ++y) {
- if (min_dists[x][y] == kDoubleInf) {
- image.SetPixel({255, 255, 255}, y, x);
- } else {
- int c = std::round(min_dists[x][y] / max_dist * 255);
- image.SetPixel({c, c, c}, y, x);
- }
- }
- }
- }
- return image;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement