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 IntersectionInfo {
- Intersection intersection;
- const Material* material;
- };
- std::optional<IntersectionInfo> SceneIntersection(const Ray& ray, const Scene& scene) {
- Intersection intersection{Vector(1, 0, 0), Vector(1, 0, 0),
- std::numeric_limits<double>::infinity()};
- const Material* material = nullptr;
- Vector normal;
- for (const auto& obj : scene.GetSphereObjects()) {
- std::optional<Intersection> cur_inter = GetIntersection(ray, obj.sphere);
- if (cur_inter.has_value() && cur_inter->GetDistance() < intersection.GetDistance()) {
- intersection = *cur_inter;
- material = obj.material;
- }
- }
- for (const auto& obj : scene.GetObjects()) {
- std::optional<Intersection> cur_inter = GetIntersection(ray, obj.polygon);
- if (cur_inter.has_value() && cur_inter->GetDistance() < intersection.GetDistance()) {
- intersection = *cur_inter;
- material = obj.material;
- if (obj.GetNormal(0) != nullptr) {
- Vector bars = GetBarycentricCoords(obj.polygon, cur_inter->GetPosition());
- normal = *(obj.GetNormal(0)) * bars[0] + *(obj.GetNormal(1)) * bars[1] +
- *(obj.GetNormal(2)) * bars[2];
- intersection =
- Intersection(intersection.GetPosition(), normal, intersection.GetDistance());
- }
- }
- }
- if (!material) {
- return {};
- }
- return IntersectionInfo{intersection, material};
- }
- Vector GetColor(const Ray& ray, const Scene& scene) {
- constexpr double kEps = 1e-6;
- std::optional<IntersectionInfo> inter_info_optional = SceneIntersection(ray, scene);
- if (!inter_info_optional.has_value()) {
- return {0, 0, 0};
- }
- return {1, 1, 1};
- IntersectionInfo& inter_info = *inter_info_optional;
- Intersection intersection = inter_info.intersection;
- const Material* material = inter_info.material;
- Vector color;
- Vector light_color;
- for (const auto& light : scene.GetLights()) {
- auto to_light = light.position - intersection.GetPosition();
- auto sect = SceneIntersection(
- {intersection.GetPosition() + kEps * intersection.GetNormal(), to_light}, scene);
- if (sect && Length(to_light) > sect->intersection.GetDistance()) {
- continue;
- }
- return Vector(1, 1, 1);
- auto diffuse_part = DotProduct(to_light.Normalize(), intersection.GetNormal());
- auto specular_part =
- DotProduct(ray.GetDirection(),
- Reflect(to_light.Normalize(), intersection.GetNormal()).Normalize());
- light_color +=
- light.intensity * (material->diffuse_color * std::max(0.0, diffuse_part) +
- material->specular_color * std::pow(std::max(0.0, specular_part),
- material->specular_exponent));
- }
- color = material->ambient_color + material->intensity + material->albedo[0] * light_color;
- return color;
- }
- 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::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;
- 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::kFull) {
- Vector color = GetColor(ray, scene);
- RGB rgb{static_cast<int>(color[0] * 255), static_cast<int>(color[1] * 255),
- static_cast<int>(color[2] * 255)};
- image.SetPixel(rgb, y, x);
- }
- }
- }
- return image;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement