From 21e46afb95ece963bfe62281c10cbe1f24ff552d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Guimar=C3=A3es?= Date: Tue, 15 Jul 2025 14:21:37 -0300 Subject: [PATCH 1/7] fix(build & log) (#21) --- CMakeLists.txt | 16 +++++++++++++++- src/CMakeLists.txt | 23 +++++++++++++++++++++++ src/include/Prism/core/style.hpp | 4 ++-- src/include/Prism/objects/ObjReader.hpp | 2 ++ 4 files changed, 42 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ca556e..20ee4b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,16 +21,30 @@ set(CMAKE_CXX_EXTENSIONS OFF) set(BUILD_SHARED_LIBS ON CACHE BOOL "Build shared libraries" FORCE) option(PRISM_BUILD_DEMO "Build the Prism demo application" ON) +if (CMAKE_BUILD_TYPE STREQUAL "Debug") + message(STATUS "Building in Debug mode.") + set(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "Suffix for debug binaries" FORCE) +else() + set(CMAKE_DEBUG_POSTFIX "" CACHE STRING "Suffix for non-debug binaries" FORCE) +endif() + # Set a common output directory for all executables. set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) # --- Sub-projects --- add_subdirectory(src) # The Prism library -add_subdirectory(demo) # The demo application + +if (PRISM_BUILD_DEMO) + message(STATUS "Building the Prism demo application.") + add_subdirectory(demo) # The demo application +else() + message(STATUS "Skipping the Prism demo application build.") +endif() # --- Testing --- enable_testing() if(BUILD_TESTING) + message(STATUS "Building tests for the Prism library.") # Fetch GoogleTest only when tests are enabled. include(FetchContent) FetchContent_Declare( diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fba2e22..ea93b20 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,6 +5,8 @@ # manages its dependencies, and sets up installation rules. # =================================================================== +message(STATUS "Configuring Prism Library (v${PROJECT_VERSION}).") + # --- Dependencies --- include(FetchContent) @@ -16,6 +18,8 @@ FetchContent_Declare( ) FetchContent_MakeAvailable(yaml-cpp) +message(STATUS "Configuring yaml-cpp dependency: building SHARED library, tests/tools DISABLED.") + set(YAML_CPP_BUILD_CONTRIB OFF CACHE BOOL "Disable building yaml-cpp contrib tools" FORCE) set(YAML_CPP_BUILD_TOOLS OFF CACHE BOOL "Disable building yaml-cpp parse tools" FORCE) set(YAML_CPP_BUILD_TESTS OFF CACHE BOOL "Disable building yaml-cpp tests" FORCE) @@ -31,11 +35,23 @@ option(PRISM_BUILD_CORE "Build the Core module (math, etc.)" ON) option(PRISM_BUILD_OBJECTS "Build the Objects module (Sphere, Plane, Mesh, etc.)" ON) option(PRISM_BUILD_SCENE "Build the Scene module (Scene, Camera)" ON) +# --- Dependecy Management --- + # The CORE module is essential for all other parts of the library. if(NOT PRISM_BUILD_CORE) message(FATAL_ERROR "PRISM_BUILD_CORE is a required module and cannot be disabled.") endif() +# The OBJECTS module depends on the CORE module. +if(PRISM_BUILD_OBJECTS AND NOT PRISM_BUILD_CORE) + message(FATAL_ERROR "PRISM_BUILD_OBJECTS requires PRISM_BUILD_CORE to be enabled. Please enable PRISM_BUILD_CORE.") +endif() + +# The SCENE module depends on the OBJECTS module. +if(PRISM_BUILD_SCENE AND NOT PRISM_BUILD_OBJECTS) + message(FATAL_ERROR "PRISM_BUILD_SCENE requires PRISM_BUILD_OBJECTS to be enabled. Please enable PRISM_BUILD_OBJECTS.") +endif() + # --- Build Source File Collection --- @@ -44,19 +60,26 @@ set(PRISM_SOURCES "") # Always add the core source files. if(PRISM_BUILD_CORE) + message(STATUS "Prism Library: Core module ENABLED.") file(GLOB CORE_SOURCES CONFIGURE_DEPENDS "src/core/*.cpp") list(APPEND PRISM_SOURCES ${CORE_SOURCES}) endif() # Conditionally add sources for the other modules. if(PRISM_BUILD_OBJECTS) + message(STATUS "Prism Library: Objects module ENABLED.") file(GLOB GEOMETRY_SOURCES CONFIGURE_DEPENDS "src/objects/*.cpp") list(APPEND PRISM_SOURCES ${GEOMETRY_SOURCES}) +else() + message(STATUS "Prism Library: Objects module DISABLED.") endif() if(PRISM_BUILD_SCENE) + message(STATUS "Prism Library: Scene module ENABLED.") file(GLOB SCENE_SOURCES CONFIGURE_DEPENDS "src/scene/*.cpp") list(APPEND PRISM_SOURCES ${SCENE_SOURCES}) +else() + message(STATUS "Prism Library: Scene module DISABLED.") endif() # Add any remaining top-level source files (e.g., init.cpp) diff --git a/src/include/Prism/core/style.hpp b/src/include/Prism/core/style.hpp index 4b53364..e2457b1 100644 --- a/src/include/Prism/core/style.hpp +++ b/src/include/Prism/core/style.hpp @@ -36,7 +36,7 @@ const std::string BOLD_YELLOW = "\033[1;33m"; * @param message The message to display. */ inline void logInfo(const std::string& message) { - std::clog << YELLOW << "[INFO] " << RESET << message << std::endl; + std::clog << YELLOW << "[INFO] " << RESET << message << RESET << std::endl; } /** @@ -44,7 +44,7 @@ inline void logInfo(const std::string& message) { * @param message The message to display. */ inline void logDone(const std::string& message) { - std::clog << GREEN << "[DONE] " << RESET << message << std::endl; + std::clog << GREEN << "[DONE] " << RESET << message << RESET << std::endl; } /** diff --git a/src/include/Prism/objects/ObjReader.hpp b/src/include/Prism/objects/ObjReader.hpp index 929f725..5ef134b 100644 --- a/src/include/Prism/objects/ObjReader.hpp +++ b/src/include/Prism/objects/ObjReader.hpp @@ -22,6 +22,8 @@ class ObjReader { std::vector> triangles; ObjReader(const std::string& filename) { + curMaterial = std::make_shared(); + file.open(filename); if (!file.is_open()) { Style::logError("Erro ao abrir o arquivo: " + filename); From 7f7e027edcd4062a079cc05893540dd5938c1a44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Guimar=C3=A3es?= Date: Tue, 15 Jul 2025 16:01:33 -0300 Subject: [PATCH 2/7] feat(render): add phong logic to render --- demo/data/input/scene.yml | 112 ++++++++++++++----------- src/include/Prism/core/color.hpp | 12 +++ src/include/Prism/core/material.hpp | 11 ++- src/include/Prism/objects/Colormap.hpp | 6 +- src/include/Prism/objects/mesh.hpp | 2 + src/include/Prism/scene/light.hpp | 32 +++++++ src/include/Prism/scene/scene.hpp | 14 +++- src/src/core/color.cpp | 26 ++++++ src/src/objects/mesh.cpp | 4 + src/src/scene/scene.cpp | 48 ++++++++++- src/src/scene/scene_parser.cpp | 37 ++++++-- 11 files changed, 234 insertions(+), 70 deletions(-) create mode 100644 src/include/Prism/scene/light.hpp diff --git a/demo/data/input/scene.yml b/demo/data/input/scene.yml index 1572623..d691847 100644 --- a/demo/data/input/scene.yml +++ b/demo/data/input/scene.yml @@ -1,93 +1,103 @@ # ----------------------------------------------------------------- -# Exemplo de Arquivo de Cena para o Renderizador Prism -# Este arquivo demonstra o uso de múltiplos objetos, materiais -# e transformações para criar uma cena complexa. +# Arquivo de Cena Completo para o Renderizador Prism com Iluminação Phong # ----------------------------------------------------------------- -# Definições reutilizáveis da cena, como materiais. +# Luz ambiente global que afeta todos os objetos da cena. +ambient_light: [0.15, 0.15, 0.15] + +# Definições reutilizáveis, como materiais, para manter o arquivo organizado. # Usamos âncoras (&) para definir um material e aliases (*) para reutilizá-lo. definitions: materials: - # Material fosco para o chão + # Material fosco para o chão com pouca especularidade. chao_cinza: &material_chao color: [0.8, 0.8, 0.8] - ka: [0.1, 0.1, 0.1] # Pouca reflexão ambiente - ks: [0.1, 0.1, 0.1] # Pouco brilho especular - ns: 10 + ka: [0.9, 0.9, 0.9] # Reflete bastante a luz ambiente + ks: [0.1, 0.1, 0.1] # Pouco brilho especular + ns: 10 # Expoente de brilho baixo - # Material de plástico vermelho, com brilho moderado + # Material de plástico vermelho, com brilho moderado e cor forte. plastico_vermelho: &material_esfera_vermelha color: [1.0, 0.2, 0.2] - ka: [0.2, 0.05, 0.05] - ks: [0.7, 0.7, 0.7] # Brilho especular forte - ns: 128 # Expoente de brilho alto para um highlight pequeno e intenso + ka: [0.2, 0.05, 0.05] # Coeficiente ambiente baixo para não "lavar" a cor + ks: [0.7, 0.7, 0.7] # Brilho especular branco e forte + ns: 128 # Expoente de brilho alto para um highlight pequeno e intenso - # Material metálico/refletivo para o cubo + # Material que simula um metal azul, altamente reflexivo. metal_azul: &material_cubo_metalico - color: [0.2, 0.3, 1.0] - ka: [0.1, 0.1, 0.2] - ks: [0.9, 0.9, 0.9] # Reflexão especular muito alta - ns: 256 + color: [0.2, 1.0, 0.2] + ka: [0.1, 0.15, 0.3] # Baixa reflexão ambiente + ks: [0.9, 0.9, 0.9] # Reflexão especular muito alta + ns: 256 # Expoente de brilho muito alto, para um reflexo nítido - # Material de vidro para o triângulo + # Material que simula vidro, com um leve tom e reflexo agudo. vidro_transparente: &material_vidro - color: [0.9, 0.9, 1.0] # Cor levemente azulada + color: [0.9, 0.9, 1.0] # Cor de base levemente azulada ka: [0.1, 0.1, 0.1] - ks: [0.8, 0.8, 0.8] - ns: 200 - ni: 1.5 # Índice de refração (típico para vidro) - d: 0.1 # Opacidade (valor 'd' baixo significa mais transparente) + ks: [0.9, 0.9, 0.9] # Reflexo especular forte como vidro + ns: 512 # Expoente de brilho altíssimo + # ni: 1.5 # (Índice de refração, para uso futuro com transparência) + # d: 0.1 # (Opacidade, para uso futuro com transparência) # ----------------------------------------------------------------- # Configurações da Câmera # ----------------------------------------------------------------- camera: - image_width: 960 - image_height: 540 - screen_distance: 1.5 + image_width: 1280 + image_height: 720 + screen_distance: 1.0 viewport_width: 2.0 + # A altura do viewport é calculada para manter a proporção da imagem (16:9) viewport_height: 1.125 - lookfrom: [0, 2, 8] # Posição da câmera - lookat: [0, 0, 0] # Ponto para onde a câmera olha + lookfrom: [0, 2, 8] # Posição da câmera um pouco elevada e para trás + lookat: [0, 0.5, 0] # Ponto para onde a câmera olha, um pouco acima do chão vup: [0, 1, 0] # Vetor "para cima" +# ----------------------------------------------------------------- +# Fontes de Luz na Cena +# ----------------------------------------------------------------- +lights: + - name: Luz Principal + position: [-8, 10, 8] + color: [1.0, 1.0, 1.0] # Luz branca, forte e principal + + - name: Luz de Preenchimento (Fill Light) + position: [8, 4, 6] + color: [0.8, 0.8, 1.0] # Luz fria para preencher as sombras + # ----------------------------------------------------------------- # Lista de Objetos na Cena # ----------------------------------------------------------------- objects: - - name: Chão + - name: Chao type: plane - point_on_plane: [0, -1, 0] # Ponto que define a altura do plano + point_on_plane: [0, -1, 0] # Ponto que define a altura do plano no Y=-1 normal: [0, 1, 0] # Vetor normal aponta para cima - material: *material_chao # Reutiliza o material do chão definido acima + material: *material_chao # Reutiliza o material do chão - - name: Esfera Vermelha Principal + - name: Esfera Vermelha type: sphere - center: [-1.5, 0, 0] + center: [-2, 0, 0] radius: 1.0 material: *material_esfera_vermelha # Reutiliza o material de plástico - - name: Malha de Cubo Metálico + - name: Esfera de vidro + type: sphere + center: [2, 1, -1] + radius: 0.8 + material: *material_vidro # Reutiliza o material de vidro + + - name: Malha de Cubo Metalico type: mesh - path: "./cubo.obj" # Caminho para o arquivo .obj + # Certifique-se que o caminho para o .obj está correto em relação ao executável + path: "cubo.obj" material: *material_cubo_metalico # Reutiliza o material metálico - # Múltiplas transformações são aplicadas em ordem + # Múltiplas transformações são aplicadas em ordem (de baixo para cima) transform: - type: scaling - factors: [0.7, 0.7, 0.7] # Primeiro, diminui a escala do cubo + factors: [0.7, 0.7, 0.7] # 3. Diminui a escala do cubo - type: rotation - angle: 45 # Em graus (o parser converterá para radianos) - axis: [0, 1, 0] # Rotaciona em torno do eixo Y - - type: translation - vector: [1.5, 0, -1] # Por último, move o cubo para sua posição final - - - name: Triângulo de Vidro - type: triangle - # Vértices definidos diretamente no arquivo de cena - p1: [-3, -1, -5] - p2: [3, -1, -5] - p3: [0, 4, -5] - material: *material_vidro # Reutiliza o material de vidro - transform: + angle: 45 # 2. Rotaciona 45 graus em torno do eixo Y + axis: [0, 1, 0] - type: translation - vector: [0, 0, 2] # Move o triângulo um pouco para frente \ No newline at end of file + vector: [2, -0.3, -1] # 1. Move o cubo para sua posição final diff --git a/src/include/Prism/core/color.hpp b/src/include/Prism/core/color.hpp index 72d7e21..06282e7 100644 --- a/src/include/Prism/core/color.hpp +++ b/src/include/Prism/core/color.hpp @@ -42,6 +42,18 @@ class PRISM_EXPORT Color { */ Color(const Color& other); + Color operator* (Color other) const; + + Color operator* (double scalar) const; + + Color operator+ (Color other) const; + + Color operator+= (Color other); + + void clamp(); + + + double r; ///< Red component of the color (0.0 to 1.0) double g; ///< Green component of the color (0.0 to 1.0) double b; ///< Blue component of the color (0.0 to 1.0) diff --git a/src/include/Prism/core/material.hpp b/src/include/Prism/core/material.hpp index 6908211..9597905 100644 --- a/src/include/Prism/core/material.hpp +++ b/src/include/Prism/core/material.hpp @@ -30,18 +30,17 @@ class PRISM_EXPORT Material { * - Index of refraction (ni): 0 * - Transparency (d): 0 */ - Material(Color color = Color(), Vector3 ka = Vector3(), Vector3 ks = Vector3(), - Vector3 ke = Vector3(), double ns = 0, double ni = 0, double d = 0) + Material(Color color = Color(), Color ka = Color(), Color ks = Color(), + Color ke = Color(), double ns = 0, double ni = 0, double d = 0) : color(color), ka(ka), ks(ks), ke(ke), ns(ns), ni(ni), d(d) { } Color color; ///< The color of the material, typically used for diffuse reflection. - Vector3 ka; ///< Ambient reflectivity of the material, representing how much ambient light it + Color ka; ///< Ambient reflectivity of the material, representing how much ambient light it ///< reflects. - Vector3 ks; ///< Specular reflectivity of the material, representing how much specular light it + Color ks; ///< Specular reflectivity of the material, representing how much specular light it ///< reflects. - Vector3 - ke; ///< Emissive color of the material, representing light emitted by the material itself. + Color ke; ///< Emissive color of the material, representing light emitted by the material itself. double ns; ///< Shininess factor of the material, affecting the size and intensity of specular ///< highlights. double ni; ///< Index of refraction of the material, used for simulating refraction effects. diff --git a/src/include/Prism/objects/Colormap.hpp b/src/include/Prism/objects/Colormap.hpp index 2938691..1007365 100644 --- a/src/include/Prism/objects/Colormap.hpp +++ b/src/include/Prism/objects/Colormap.hpp @@ -72,19 +72,19 @@ class colormap { double ksR, ksG, ksB; iss >> ksR >> ksG >> ksB; if (!currentMaterial.empty()) { - mp[currentMaterial].ks = Vector3(ksR, ksG, ksB); + mp[currentMaterial].ks = Color(ksR, ksG, ksB); } } else if (keyword == "Ke") { double keR, keG, keB; iss >> keR >> keG >> keB; if (!currentMaterial.empty()) { - mp[currentMaterial].ke = Vector3(keR, keG, keB); + mp[currentMaterial].ke = Color(keR, keG, keB); } } else if (keyword == "Ka") { double kaR, kaG, kaB; iss >> kaR >> kaG >> kaB; if (!currentMaterial.empty()) { - mp[currentMaterial].ka = Vector3(kaR, kaG, kaB); + mp[currentMaterial].ka = Color(kaR, kaG, kaB); } } else if (keyword == "Ns") { iss >> mp[currentMaterial].ns; diff --git a/src/include/Prism/objects/mesh.hpp b/src/include/Prism/objects/mesh.hpp index b400f8a..e4411de 100644 --- a/src/include/Prism/objects/mesh.hpp +++ b/src/include/Prism/objects/mesh.hpp @@ -56,6 +56,8 @@ class PRISM_EXPORT Mesh : public Object { */ virtual bool hit(const Ray& ray, double t_min, double t_max, HitRecord& rec) const override; + void setMaterial(std::shared_ptr new_material); + private: std::vector> points; ///< Points that define the vertices of the mesh std::vector diff --git a/src/include/Prism/scene/light.hpp b/src/include/Prism/scene/light.hpp new file mode 100644 index 0000000..09a2eab --- /dev/null +++ b/src/include/Prism/scene/light.hpp @@ -0,0 +1,32 @@ +#ifndef PRISM_LIGHT_HPP_ +#define PRISM_LIGHT_HPP_ + +#include "prism_export.h" +#include "Prism/core/point.hpp" +#include "Prism/core/color.hpp" + +namespace Prism { + +/** + * @class Light + * @brief Represents a point light source in the scene. + */ +class PRISM_EXPORT Light { +public: + Point3 position; ///< The position of the light in 3D space. + Color color; ///< The color of the light, typically used to determine how it illuminates objects. + + /** + * @brief Default constructor that initializes the light with default values. + * The default values are: + * - Position: (0, 0, 0) + * - Color: White (1, 1, 1) + * - Intensity: 1.0 + */ + Light(const Point3& pos, const Color& col) + : position(pos), color(col) {} +}; + +} // namespace Prism + +#endif // PRISM_LIGHT_HPP_ \ No newline at end of file diff --git a/src/include/Prism/scene/scene.hpp b/src/include/Prism/scene/scene.hpp index 97f767d..f2ec1de 100644 --- a/src/include/Prism/scene/scene.hpp +++ b/src/include/Prism/scene/scene.hpp @@ -5,6 +5,8 @@ #include "Prism/objects/objects.hpp" #include "Prism/scene/camera.hpp" +#include "Prism/scene/light.hpp" +#include "Prism/core/color.hpp" #include #include @@ -28,7 +30,7 @@ class PRISM_EXPORT Scene { * @param camera The Camera object that defines the viewpoint and projection parameters for * rendering the scene. */ - explicit Scene(Camera camera); + explicit Scene(Camera camera, Color ambient_light = Color(0.1, 0.1, 0.1)); Scene(const Scene&) = delete; Scene& operator=(const Scene&) = delete; @@ -43,6 +45,14 @@ class PRISM_EXPORT Scene { */ void addObject(std::unique_ptr object); + /** + * @brief Adds a light source to the scene. + * @param light The Light object to be added to the scene. + * This method stores the light in the scene's collection, allowing it to be used during + * rendering for illumination calculations. + */ + void addLight(std::unique_ptr light); + /** * @brief Renders the scene from the camera's perspective. * This method iterates over all objects in the scene, checks for ray-object intersections, and @@ -54,6 +64,8 @@ class PRISM_EXPORT Scene { private: std::vector> objects_; ///< Collection of objects in the scene + std::vector> lights_; ///< Collection of light sources in the scene + Color ambient_color_ = Color(0.1, 0.1, 0.1); ///< Ambient color for the scene Camera camera_; ///< The camera used to view the scene }; } // namespace Prism diff --git a/src/src/core/color.cpp b/src/src/core/color.cpp index b8e69f2..3aa65fd 100644 --- a/src/src/core/color.cpp +++ b/src/src/core/color.cpp @@ -1,4 +1,5 @@ #include "Prism/core/color.hpp" +#include namespace Prism { @@ -13,4 +14,29 @@ Color::Color(int red, int green, int blue) Color::Color(const Color& other) : r(other.r), g(other.g), b(other.b) { } +Color Color::operator*(Color other) const { + return Color(r * other.r, g * other.g, b * other.b); +} + +Color Color::operator*(double scalar) const { + return Color(r * scalar, g * scalar, b * scalar); +} + +Color Color::operator+(Color other) const { + return Color(r + other.r, g + other.g, b + other.b); +} + +Color Color::operator+=(Color other) { + r += other.r; + g += other.g; + b += other.b; + return *this; +} + +void Color::clamp() { + r = std::min(r, 1.0); + g = std::min(g, 1.0); + b = std::min(b, 1.0); +} + } // namespace Prism \ No newline at end of file diff --git a/src/src/objects/mesh.cpp b/src/src/objects/mesh.cpp index 9cb88ee..e73d977 100644 --- a/src/src/objects/mesh.cpp +++ b/src/src/objects/mesh.cpp @@ -47,4 +47,8 @@ bool Mesh::hit(const Ray& ray, double t_min, double t_max, HitRecord& rec) const return false; }; +void Mesh::setMaterial(std::shared_ptr new_material) { + material = std::move(new_material); +} + }; // namespace Prism diff --git a/src/src/scene/scene.cpp b/src/src/scene/scene.cpp index 8e6dd2f..17a2d77 100644 --- a/src/src/scene/scene.cpp +++ b/src/src/scene/scene.cpp @@ -25,13 +25,17 @@ PRISM_EXPORT std::ostream& operator<<(std::ostream& os, const Color& color) { return os; } -Scene::Scene(Camera camera) : camera_(std::move(camera)) { +Scene::Scene(Camera camera, Color ambient_light) : camera_(std::move(camera)), ambient_color_(ambient_light) { } void Scene::addObject(std::unique_ptr object) { objects_.push_back(std::move(object)); } +void Scene::addLight(std::unique_ptr light) { + lights_.push_back(std::move(light)); +} + bool get_local_time(std::tm* tm_out, const std::time_t* time_in) { #if defined(_WIN32) || defined(_MSC_VER) // Usa a versão segura do Windows (MSVC) @@ -99,9 +103,45 @@ void Scene::render() const { Color pixel_color; if (hit_anything) { - pixel_color = closest_hit_rec.material->color; + Point3 hit_point = closest_hit_rec.p; + Vector3 normal = closest_hit_rec.normal; + Vector3 view_dir = (ray.origin() - hit_point).normalize(); + auto mat = closest_hit_rec.material; + + for (const auto& light_ptr : lights_) { + Vector3 light_dir = (light_ptr->position - hit_point).normalize(); + double light_distance = (light_ptr->position - hit_point).magnitude(); + + Ray shadow_ray(hit_point, light_dir); + bool in_shadow = false; + for (const auto& obj_ptr : objects_) { + HitRecord shadow_rec; + if (obj_ptr->hit(shadow_ray, 0.001, light_distance, shadow_rec)) { + in_shadow = true; + break; + } + } + + Color ambient = mat->ka * this->ambient_color_; + + if (in_shadow) { + pixel_color += ambient; + continue; + } + + double diff_factor = std::max(0.0, normal.dot(light_dir)); + Color diffuse = mat->color * diff_factor * light_ptr->color; + + Vector3 reflect_dir = (normal * 2 * (light_dir.dot(normal))) - light_dir; + double spec_factor = std::pow(std::max(0.0, view_dir.dot(reflect_dir)), mat->ns); + Color specular = mat->ks * spec_factor * light_ptr->color; + + pixel_color += ambient + diffuse + specular; + } + + pixel_color.clamp(); + } else { - Vector3 unit_direction = ray.direction().normalize(); pixel_color = Color(0, 0, 0); } @@ -120,7 +160,7 @@ void Scene::render() const { image_file.close(); Style::logDone("Rendering complete."); - Style::logDone("Image saved as: " + Prism::Style::CYAN + generate_filename().string()); + Style::logDone("Image saved as: " + Prism::Style::CYAN + full_path.string()); } } // namespace Prism \ No newline at end of file diff --git a/src/src/scene/scene_parser.cpp b/src/src/scene/scene_parser.cpp index 4ee4210..9c257c6 100644 --- a/src/src/scene/scene_parser.cpp +++ b/src/src/scene/scene_parser.cpp @@ -45,6 +45,13 @@ Vector3 parseVector(const YAML::Node& node) { return Vector3(node[0].as(), node[1].as(), node[2].as()); } +Color parseColor(const YAML::Node& node) { + if (!node.IsSequence() || node.size() != 3) { + throw std::runtime_error("Parsing error: Malformed color."); + } + return Color(node[0].as(), node[1].as(), node[2].as()); +} + // Converts a YAML node with material properties to a Material std::shared_ptr parseMaterial(const YAML::Node& node) { auto mat = std::make_shared(); @@ -54,11 +61,11 @@ std::shared_ptr parseMaterial(const YAML::Node& node) { mat->color = Color(v.x, v.y, v.z); } if (node["ka"]) - mat->ka = parseVector(node["ka"]); + mat->ka = parseColor(node["ka"]); if (node["ks"]) - mat->ks = parseVector(node["ks"]); + mat->ks = parseColor(node["ks"]); if (node["ke"]) - mat->ke = parseVector(node["ke"]); + mat->ke = parseColor(node["ke"]); if (node["ns"]) mat->ns = node["ns"].as(); if (node["ni"]) @@ -125,7 +132,15 @@ Scene SceneParser::parse() { cam_node["viewport_height"].as(), cam_node["viewport_width"].as(), cam_node["image_height"].as(), cam_node["image_width"].as()); - Scene scene(std::move(camera)); + Color ambient_light(0.1, 0.1, 0.1); // Valor padrão + if (root["ambient_light"]) { + Vector3 v = parseVector(root["ambient_light"]); + ambient_light = Color(v.x, v.y, v.z); + } else { + Style::logWarning("Ambient light not defined. Using default (0.1, 0.1, 0.1)."); + } + + Scene scene(std::move(camera), ambient_light); // Parse Material Definitions (for reuse) std::map> materials; @@ -136,6 +151,18 @@ Scene SceneParser::parse() { } } + if (root["lights"] && root["lights"].IsSequence()) { + for (const auto& light_node : root["lights"]) { + Point3 pos = parsePoint(light_node["position"]); + Vector3 color_vec = parseVector(light_node["color"]); + Color color(color_vec.x, color_vec.y, color_vec.z); + scene.addLight(std::make_unique(pos, color)); + } + } + else { + Style::logWarning("'lights' node not found or is not a list. No lights will be added."); + } + // Parse Objects if (!root["objects"] || !root["objects"].IsSequence()) { throw std::runtime_error("'objects' node not found or is not a list."); @@ -180,7 +207,7 @@ Scene SceneParser::parse() { // Overrides the .obj material with the one from the .yml, if specified if (obj_node["material"]) { auto mesh_ptr = static_cast(object.get()); - // (A material setter would be needed in the Mesh class here) + mesh_ptr->setMaterial(material); } } else { Style::logWarning("Unknown object type: " + type + ". Skipping this object."); From 8f3623d9c78560747d8d8f77994c64217789e24a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Guimar=C3=A3es?= Date: Tue, 15 Jul 2025 16:45:44 -0300 Subject: [PATCH 3/7] feat(render): smooth shader meshs by reading vertices normals --- src/include/Prism/objects/ObjReader.hpp | 32 ++++++++++++++++++------- src/include/Prism/objects/mesh.hpp | 1 + src/include/Prism/objects/triangle.hpp | 10 +++++++- src/src/objects/mesh.cpp | 32 +++++++++++++++++++++---- src/src/objects/triangle.cpp | 10 +++++--- 5 files changed, 68 insertions(+), 17 deletions(-) diff --git a/src/include/Prism/objects/ObjReader.hpp b/src/include/Prism/objects/ObjReader.hpp index 5ef134b..5b102b8 100644 --- a/src/include/Prism/objects/ObjReader.hpp +++ b/src/include/Prism/objects/ObjReader.hpp @@ -12,15 +12,22 @@ #include #include #include +#include namespace Prism { class ObjReader { public: + struct FaceIndices { + std::array vertex_indices; + std::array normal_indices; + }; + std::shared_ptr curMaterial; std::vector> vertices; - std::vector> triangles; - + std::vector> normals; + std::vector faces; + ObjReader(const std::string& filename) { curMaterial = std::make_shared(); @@ -51,16 +58,23 @@ class ObjReader { double x, y, z; iss >> x >> y >> z; vertices.push_back({x, y, z}); + } else if (prefix == "vn") { + double nx, ny, nz; + iss >> nx >> ny >> nz; + normals.push_back({nx, ny, nz}); } else if (prefix == "f") { - unsigned int vi[3], ni[3]; - char slash; - int _; // for skipping texture indices + FaceIndices face; + std::string vertex_info; for (int i = 0; i < 3; ++i) { - iss >> vi[i] >> slash >> _ >> slash >> ni[i]; - --vi[i]; - --ni[i]; + iss >> vertex_info; + std::replace(vertex_info.begin(), vertex_info.end(), '/', ' '); + std::istringstream v_iss(vertex_info); + unsigned int t_idx; + v_iss >> face.vertex_indices[i] >> t_idx >> face.normal_indices[i]; + --face.vertex_indices[i]; // Convert to 0-based index + --face.normal_indices[i]; // Convert to 0-based index } - triangles.push_back({vi[0], vi[1], vi[2]}); + faces.push_back(face); } } diff --git a/src/include/Prism/objects/mesh.hpp b/src/include/Prism/objects/mesh.hpp index e4411de..0ca1fe9 100644 --- a/src/include/Prism/objects/mesh.hpp +++ b/src/include/Prism/objects/mesh.hpp @@ -60,6 +60,7 @@ class PRISM_EXPORT Mesh : public Object { private: std::vector> points; ///< Points that define the vertices of the mesh + std::vector> normals; ///< Normals for each vertex in the mesh std::vector mesh; ///< Triangles that make up the mesh, each defined by three points std::shared_ptr diff --git a/src/include/Prism/objects/triangle.hpp b/src/include/Prism/objects/triangle.hpp index 38ffc6b..fad0a68 100644 --- a/src/include/Prism/objects/triangle.hpp +++ b/src/include/Prism/objects/triangle.hpp @@ -92,10 +92,14 @@ class PRISM_EXPORT MeshTriangle { * @param p1 The first point of the triangle. * @param p2 The second point of the triangle. * @param p3 The third point of the triangle. + * @param n1 The normal vector at the first point. + * @param n2 The normal vector at the second point. + * @param n3 The normal vector at the third point. * This constructor initializes the MeshTriangle with the specified points. */ MeshTriangle(std::shared_ptr p1, std::shared_ptr p2, - std::shared_ptr p3); + std::shared_ptr p3, std::shared_ptr n1, + std::shared_ptr n2, std::shared_ptr n3); /** * @brief Constructs a MeshTriangle given three Point3 objects. @@ -148,6 +152,10 @@ class PRISM_EXPORT MeshTriangle { std::shared_ptr point1; ///< The first point of the triangle std::shared_ptr point2; ///< The second point of the triangle std::shared_ptr point3; ///< The third point of the triangle + + std::shared_ptr normal1; ///< The normal vector at the first point + std::shared_ptr normal2; ///< The normal vector at the second point + std::shared_ptr normal3; ///< The normal vector at the third point }; } // namespace Prism diff --git a/src/src/objects/mesh.cpp b/src/src/objects/mesh.cpp index e73d977..d2b63e1 100644 --- a/src/src/objects/mesh.cpp +++ b/src/src/objects/mesh.cpp @@ -13,8 +13,20 @@ Mesh::Mesh(std::filesystem::path& path) { for (auto& point : reader.vertices) { points.emplace_back(std::make_shared(point[0], point[1], point[2])); } - for (auto& triangle : reader.triangles) { - mesh.push_back({points[triangle[0]], points[triangle[1]], points[triangle[2]]}); + + for (auto& normal : reader.normals) { + normals.emplace_back(std::make_shared(normal[0], normal[1], normal[2])); + } + + for (auto& face : reader.faces) { + mesh.emplace_back( + points[face.vertex_indices[0]], + points[face.vertex_indices[1]], + points[face.vertex_indices[2]], + normals[face.normal_indices[0]], + normals[face.normal_indices[1]], + normals[face.normal_indices[2]] + ); } }; @@ -23,8 +35,20 @@ Mesh::Mesh(ObjReader& reader) : material(std::move(reader.curMaterial)) { for (auto& point : reader.vertices) { points.emplace_back(std::make_shared(point[0], point[1], point[2])); } - for (auto& triangle : reader.triangles) { - mesh.push_back({points[triangle[0]], points[triangle[1]], points[triangle[2]]}); + + for (auto& normal : reader.normals) { + normals.emplace_back(std::make_shared(normal[0], normal[1], normal[2])); + } + + for (auto& face : reader.faces) { + mesh.emplace_back( + points[face.vertex_indices[0]], + points[face.vertex_indices[1]], + points[face.vertex_indices[2]], + normals[face.normal_indices[0]], + normals[face.normal_indices[1]], + normals[face.normal_indices[2]] + ); } }; diff --git a/src/src/objects/triangle.cpp b/src/src/objects/triangle.cpp index 03f8de1..450a8d7 100644 --- a/src/src/objects/triangle.cpp +++ b/src/src/objects/triangle.cpp @@ -67,8 +67,10 @@ bool Triangle::hit(const Ray& ray, double t_min, double t_max, HitRecord& rec) c } MeshTriangle::MeshTriangle(std::shared_ptr p1, std::shared_ptr p2, - std::shared_ptr p3) - : point1(std::move(p1)), point2(std::move(p2)), point3(std::move(p3)) { + std::shared_ptr p3, std::shared_ptr n1, + std::shared_ptr n2, std::shared_ptr n3) + : point1(std::move(p1)), point2(std::move(p2)), point3(std::move(p3)), + normal1(std::move(n1)), normal2(std::move(n2)), normal3(std::move(n3)) { } MeshTriangle::MeshTriangle(Point3 p1, Point3 p2, Point3 p3) @@ -124,8 +126,10 @@ bool MeshTriangle::hit(const Ray& ray, double t_min, double t_max, HitRecord& re const double t = f * (edge2 * q); if (t > t_min && t < t_max) { + + const double w = 1.0 - u - v;; rec.t = t; - rec.normal = edge1 ^ edge2; + rec.normal = ((*normal1 * w) + (*normal2 * u) + (*normal3 * v)).normalize(); return true; } return false; From 77e342cdb85fa36e1574f87fff8a6df6b1d9b449 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Guimar=C3=A3es?= Date: Tue, 15 Jul 2025 19:19:26 -0300 Subject: [PATCH 4/7] feat(render): reflections and refrations --- demo/data/input/scene.yml | 127 ++++++++++++-------------- src/include/Prism/core/color.hpp | 2 +- src/include/Prism/core/material.hpp | 22 +++-- src/include/Prism/core/point.hpp | 6 ++ src/include/Prism/core/utils.hpp | 11 +++ src/include/Prism/core/vector.hpp | 6 ++ src/include/Prism/scene/scene.hpp | 2 + src/src/core/color.cpp | 10 +- src/src/core/point.cpp | 4 + src/src/core/utils.cpp | 7 ++ src/src/core/vector.cpp | 4 + src/src/scene/scene.cpp | 136 ++++++++++++++++------------ 12 files changed, 196 insertions(+), 141 deletions(-) diff --git a/demo/data/input/scene.yml b/demo/data/input/scene.yml index d691847..15be8ad 100644 --- a/demo/data/input/scene.yml +++ b/demo/data/input/scene.yml @@ -1,103 +1,96 @@ # ----------------------------------------------------------------- -# Arquivo de Cena Completo para o Renderizador Prism com Iluminação Phong +# Cena de Demonstração Final (Versão Corrigida) # ----------------------------------------------------------------- -# Luz ambiente global que afeta todos os objetos da cena. -ambient_light: [0.15, 0.15, 0.15] +ambient_light: [0.1, 0.1, 0.1] -# Definições reutilizáveis, como materiais, para manter o arquivo organizado. -# Usamos âncoras (&) para definir um material e aliases (*) para reutilizá-lo. definitions: materials: - # Material fosco para o chão com pouca especularidade. - chao_cinza: &material_chao - color: [0.8, 0.8, 0.8] - ka: [0.9, 0.9, 0.9] # Reflete bastante a luz ambiente - ks: [0.1, 0.1, 0.1] # Pouco brilho especular - ns: 10 # Expoente de brilho baixo + chao_fosco: &chao + color: [0.5, 0.5, 0.5] + ka: [1.0, 1.0, 1.0] + ks: [0.1, 0.1, 0.1] + ns: 10 - # Material de plástico vermelho, com brilho moderado e cor forte. - plastico_vermelho: &material_esfera_vermelha - color: [1.0, 0.2, 0.2] - ka: [0.2, 0.05, 0.05] # Coeficiente ambiente baixo para não "lavar" a cor - ks: [0.7, 0.7, 0.7] # Brilho especular branco e forte - ns: 128 # Expoente de brilho alto para um highlight pequeno e intenso + plastico_magenta: &plastico + color: [0.8, 0.1, 0.4] + ka: [0.2, 0.2, 0.2] + ks: [0.8, 0.8, 0.8] + ns: 128 - # Material que simula um metal azul, altamente reflexivo. - metal_azul: &material_cubo_metalico - color: [0.2, 1.0, 0.2] - ka: [0.1, 0.15, 0.3] # Baixa reflexão ambiente - ks: [0.9, 0.9, 0.9] # Reflexão especular muito alta - ns: 256 # Expoente de brilho muito alto, para um reflexo nítido + metal_dourado: &metal + color: [0.8, 0.6, 0.2] + ka: [0.2, 0.2, 0.2] + ks: [0.9, 0.9, 0.9] + ns: 512 - # Material que simula vidro, com um leve tom e reflexo agudo. - vidro_transparente: &material_vidro - color: [0.9, 0.9, 1.0] # Cor de base levemente azulada - ka: [0.1, 0.1, 0.1] - ks: [0.9, 0.9, 0.9] # Reflexo especular forte como vidro - ns: 512 # Expoente de brilho altíssimo - # ni: 1.5 # (Índice de refração, para uso futuro com transparência) - # d: 0.1 # (Opacidade, para uso futuro com transparência) + vidro_cristalino: &vidro + color: [1.0, 1.0, 1.0] + ka: [0.0, 0.0, 0.0] + ks: [0.1, 0.1, 0.1] + ns: 256 + ni: 1.52 + d: 0.05 + + mercurio_reflexivo: &espelho + color: [0.0, 0.0, 0.0] # Espelhos não têm cor difusa + ka: [0.0, 0.0, 0.0] + ks: [0.98, 0.98, 0.98] # Quase 100% reflexivo + ns: 2048 -# ----------------------------------------------------------------- -# Configurações da Câmera -# ----------------------------------------------------------------- camera: image_width: 1280 image_height: 720 - screen_distance: 1.0 + screen_distance: 1.5 viewport_width: 2.0 - # A altura do viewport é calculada para manter a proporção da imagem (16:9) viewport_height: 1.125 - lookfrom: [0, 2, 8] # Posição da câmera um pouco elevada e para trás - lookat: [0, 0.5, 0] # Ponto para onde a câmera olha, um pouco acima do chão - vup: [0, 1, 0] # Vetor "para cima" + lookfrom: [0, 2.5, 10] + lookat: [0, 1, 0] + vup: [0, 1, 0] -# ----------------------------------------------------------------- -# Fontes de Luz na Cena -# ----------------------------------------------------------------- lights: - name: Luz Principal - position: [-8, 10, 8] - color: [1.0, 1.0, 1.0] # Luz branca, forte e principal + position: [-10, 10, 10] + color: [1.0, 1.0, 1.0] - - name: Luz de Preenchimento (Fill Light) - position: [8, 4, 6] - color: [0.8, 0.8, 1.0] # Luz fria para preencher as sombras + - name: Luz de Preenchimento + position: [10, 5, -5] + color: [0.3, 0.5, 1.0] -# ----------------------------------------------------------------- -# Lista de Objetos na Cena -# ----------------------------------------------------------------- objects: - name: Chao type: plane - point_on_plane: [0, -1, 0] # Ponto que define a altura do plano no Y=-1 - normal: [0, 1, 0] # Vetor normal aponta para cima - material: *material_chao # Reutiliza o material do chão + point_on_plane: [0, -0.01, 0] # Chão um pouco mais baixo + normal: [0, 1, 0] + material: *chao - - name: Esfera Vermelha + - name: Esfera de Espelho (Esquerda) type: sphere - center: [-2, 0, 0] + center: [-2.5, 1, 1] radius: 1.0 - material: *material_esfera_vermelha # Reutiliza o material de plástico + material: *espelho - - name: Esfera de vidro + - name: Esfera de Vidro (Direita) type: sphere - center: [2, 1, -1] - radius: 0.8 - material: *material_vidro # Reutiliza o material de vidro + center: [2.5, 1, 1] + radius: 1.0 + material: *vidro + + - name: Esfera de Plástico (Frente) + type: sphere + center: [0, 0.5, 4] + radius: 1.0 + material: *plastico - - name: Malha de Cubo Metalico + - name: Cubo de Metal (Fundo) type: mesh - # Certifique-se que o caminho para o .obj está correto em relação ao executável path: "cubo.obj" - material: *material_cubo_metalico # Reutiliza o material metálico - # Múltiplas transformações são aplicadas em ordem (de baixo para cima) + material: *metal transform: - type: scaling - factors: [0.7, 0.7, 0.7] # 3. Diminui a escala do cubo + factors: [1.2, 1.2, 1.2] - type: rotation - angle: 45 # 2. Rotaciona 45 graus em torno do eixo Y + angle: 25 # Ângulo ajustado axis: [0, 1, 0] - type: translation - vector: [2, -0.3, -1] # 1. Move o cubo para sua posição final + vector: [0, 0.7, -2.5] # Posição ajustada \ No newline at end of file diff --git a/src/include/Prism/core/color.hpp b/src/include/Prism/core/color.hpp index 06282e7..8726ac7 100644 --- a/src/include/Prism/core/color.hpp +++ b/src/include/Prism/core/color.hpp @@ -50,7 +50,7 @@ class PRISM_EXPORT Color { Color operator+= (Color other); - void clamp(); + Color& clamp(); diff --git a/src/include/Prism/core/material.hpp b/src/include/Prism/core/material.hpp index 9597905..fdb3b29 100644 --- a/src/include/Prism/core/material.hpp +++ b/src/include/Prism/core/material.hpp @@ -22,25 +22,27 @@ class PRISM_EXPORT Material { * @brief * Default constructor that initializes the material with default values. * The default values are: - * - Color: Black (0, 0, 0) - * - Ambient reflectivity (ka): (0, 0, 0) + * - Color: white (1,1,1) + * - Ambient reflectivity (ka): (0.1, 0.1, 0.1) * - Specular reflectivity (ks): (0, 0, 0) * - Emissive color (ke): (0, 0, 0) - * - Shininess (ns): 0 - * - Index of refraction (ni): 0 - * - Transparency (d): 0 + * - Shininess (ns): 1 + * - Index of refraction (ni): 1 + * - Transparency (d): 1 */ - Material(Color color = Color(), Color ka = Color(), Color ks = Color(), - Color ke = Color(), double ns = 0, double ni = 0, double d = 0) + Material(Color color = Color(1, 1, 1), Color ka = Color(0.1, 0.1, 0.1), + Color ks = Color(0, 0, 0), Color ke = Color(0, 0, 0), double ns = 1.0, double ni = 1.0, + double d = 1.0) : color(color), ka(ka), ks(ks), ke(ke), ns(ns), ni(ni), d(d) { } Color color; ///< The color of the material, typically used for diffuse reflection. - Color ka; ///< Ambient reflectivity of the material, representing how much ambient light it + Color ka; ///< Ambient reflectivity of the material, representing how much ambient light it ///< reflects. - Color ks; ///< Specular reflectivity of the material, representing how much specular light it + Color ks; ///< Specular reflectivity of the material, representing how much specular light it ///< reflects. - Color ke; ///< Emissive color of the material, representing light emitted by the material itself. + Color + ke; ///< Emissive color of the material, representing light emitted by the material itself. double ns; ///< Shininess factor of the material, affecting the size and intensity of specular ///< highlights. double ni; ///< Index of refraction of the material, used for simulating refraction effects. diff --git a/src/include/Prism/core/point.hpp b/src/include/Prism/core/point.hpp index 77e148c..cf76e7d 100644 --- a/src/include/Prism/core/point.hpp +++ b/src/include/Prism/core/point.hpp @@ -57,6 +57,12 @@ class PRISM_EXPORT Point3 { */ bool operator==(const Point3& p) const; + /** + * @brief Negates the point. + * @return A new point that is the negation of this point. + */ + Point3 operator-() const; + /** * @brief Gets a vector from this point to another point. * @param p The point to get the vector to. diff --git a/src/include/Prism/core/utils.hpp b/src/include/Prism/core/utils.hpp index 53bd7f7..49382e8 100644 --- a/src/include/Prism/core/utils.hpp +++ b/src/include/Prism/core/utils.hpp @@ -42,6 +42,17 @@ template T sqr(const T& value) { return value * value; } +/** + * @brief Computes the refracted vector based on Snell's law. + * This function calculates the refracted vector given an incident vector, a normal vector, + * and the ratio of indices of refraction. + * @param uv The incident vector (unit vector). + * @param n The normal vector at the point of incidence (unit vector). + * @param etai_over_etat The ratio of indices of refraction (etai/etat). + * @return The refracted vector as a Vector3. + */ +Vector3 refract(const Vector3& uv, const Vector3& n, double etai_over_etat); + } // namespace Prism #endif // PRISM_UTILS_HPP_ \ No newline at end of file diff --git a/src/include/Prism/core/vector.hpp b/src/include/Prism/core/vector.hpp index b88fb08..a3faad0 100644 --- a/src/include/Prism/core/vector.hpp +++ b/src/include/Prism/core/vector.hpp @@ -67,6 +67,12 @@ class PRISM_EXPORT Vector3 { */ Vector3& operator=(const Vector3& v); + /** + * @brief Negates the vector. + * @return A new vector that is the negation of this vector. + */ + Vector3 operator-() const; + /** * @brief Adds two vectors. * @param v The vector to add. diff --git a/src/include/Prism/scene/scene.hpp b/src/include/Prism/scene/scene.hpp index f2ec1de..beb8d5f 100644 --- a/src/include/Prism/scene/scene.hpp +++ b/src/include/Prism/scene/scene.hpp @@ -63,6 +63,8 @@ class PRISM_EXPORT Scene { void render() const; private: + Color trace(const Ray& ray, int depth) const; + std::vector> objects_; ///< Collection of objects in the scene std::vector> lights_; ///< Collection of light sources in the scene Color ambient_color_ = Color(0.1, 0.1, 0.1); ///< Ambient color for the scene diff --git a/src/src/core/color.cpp b/src/src/core/color.cpp index 3aa65fd..76729e0 100644 --- a/src/src/core/color.cpp +++ b/src/src/core/color.cpp @@ -33,10 +33,12 @@ Color Color::operator+=(Color other) { return *this; } -void Color::clamp() { - r = std::min(r, 1.0); - g = std::min(g, 1.0); - b = std::min(b, 1.0); +Color& Color::clamp() { + r = std::max(0.0,std::min(r, 1.0)); + g = std::max(0.0,std::min(g, 1.0)); + b = std::max(0.0,std::min(b, 1.0)); + + return *this; } } // namespace Prism \ No newline at end of file diff --git a/src/src/core/point.cpp b/src/src/core/point.cpp index adf5a46..386c9e3 100644 --- a/src/src/core/point.cpp +++ b/src/src/core/point.cpp @@ -38,6 +38,10 @@ bool Point3::operator==(const Point3& p) const { return (x == p.x && y == p.y && z == p.z); } +Point3 Point3::operator-() const { + return Point3(-x, -y, -z); +} + Vector3 Point3::operator-(const Point3& p) const { return Vector3(x - p.x, y - p.y, z - p.z); } diff --git a/src/src/core/utils.cpp b/src/src/core/utils.cpp index 81c1976..092bf56 100644 --- a/src/src/core/utils.cpp +++ b/src/src/core/utils.cpp @@ -48,4 +48,11 @@ Matrix orthonormalBasisContaining(const Vector3& v) { return basis; } +Vector3 refract(const Vector3& uv, const Vector3& n, double etai_over_etat) { + auto cos_theta = std::fmin((-uv).dot(n), 1.0); + Vector3 r_out_perp = (uv + n * cos_theta) * etai_over_etat; + Vector3 r_out_parallel = n * -sqrt(std::abs(1.0 - r_out_perp.magnitude() * r_out_perp.magnitude())); + return r_out_perp + r_out_parallel; +} + } // namespace Prism \ No newline at end of file diff --git a/src/src/core/vector.cpp b/src/src/core/vector.cpp index e078ffd..0fefece 100644 --- a/src/src/core/vector.cpp +++ b/src/src/core/vector.cpp @@ -43,6 +43,10 @@ Vector3& Vector3::operator=(const Vector3& v) { return *this; } +Vector3 Vector3::operator-() const { + return Vector3(-x, -y, -z); +} + Vector3 Vector3::operator+(const Vector3& v) const { return Vector3(x + v.x, y + v.y, z + v.z); } diff --git a/src/src/scene/scene.cpp b/src/src/scene/scene.cpp index 17a2d77..fb9fa40 100644 --- a/src/src/scene/scene.cpp +++ b/src/src/scene/scene.cpp @@ -3,6 +3,7 @@ #include "Prism/core/color.hpp" #include "Prism/core/material.hpp" #include "Prism/core/style.hpp" +#include "Prism/core/utils.hpp" #include #include @@ -25,7 +26,8 @@ PRISM_EXPORT std::ostream& operator<<(std::ostream& os, const Color& color) { return os; } -Scene::Scene(Camera camera, Color ambient_light) : camera_(std::move(camera)), ambient_color_(ambient_light) { +Scene::Scene(Camera camera, Color ambient_light) + : camera_(std::move(camera)), ambient_color_(ambient_light) { } void Scene::addObject(std::unique_ptr object) { @@ -63,6 +65,79 @@ std::filesystem::path generate_filename() { return "render_fallback.ppm"; } +Color Scene::trace(const Ray& ray, int depth) const { + if (depth <= 0) { + return Color(0, 0, 0); // Base case for recursion, return black color + } + + HitRecord rec; + bool hit_anything = false; + double closest_t = INFINITY; + + for (const auto& object_ptr : objects_) { + HitRecord temp_rec; + if (object_ptr->hit(ray, 0.001, closest_t, temp_rec)) { + hit_anything = true; + closest_t = temp_rec.t; + rec = temp_rec; + } + } + + if (!hit_anything) { + return ambient_color_; // Return ambient color if no hit + } + + auto mat = rec.material; + + Vector3 view_dir = (ray.origin() - rec.p).normalize(); + + Color surface_color = mat->ka * ambient_color_; + + for (const auto& light_ptr : lights_) { + Vector3 light_dir = (light_ptr->position - rec.p).normalize(); + double light_distance = (light_ptr->position - rec.p).magnitude(); + + Ray shadow_ray(rec.p, light_dir); + bool in_shadow = false; + for (const auto& obj_ptr : objects_) { + HitRecord shadow_rec; + if (obj_ptr->hit(shadow_ray, 0.001, light_distance, shadow_rec)) { + in_shadow = true; + break; + } + } + + if (!in_shadow) { + double diff_factor = std::max(rec.normal.dot(light_dir), 0.0); + surface_color += mat->color * diff_factor * light_ptr->color; + + Vector3 reflect_dir = (-light_dir) - rec.normal * 2 * (-light_dir).dot(rec.normal); + double spec_factor = std::pow(std::max(view_dir.dot(reflect_dir), 0.0), mat->ns); + surface_color += mat->ks * spec_factor * light_ptr->color; + } + } + + if (mat->ks.r > 0 || mat->ks.g > 0 || mat->ks.b > 0) { + Vector3 reflect_dir = ray.direction() - rec.normal * 2 * ray.direction().dot(rec.normal); + Ray reflection_ray(rec.p, reflect_dir); + surface_color += mat->ks * trace(reflection_ray, depth - 1); + } + + double opacity = mat->d; + if (opacity < 1.0) { + double refraction_ratio = rec.front_face ? (1.0 / mat->ni) : mat->ni; + + Vector3 refracted_dir = refract(ray.direction().normalize(), rec.normal, refraction_ratio); + Ray refracted_ray(rec.p, refracted_dir); + + Color refracted_color = trace(refracted_ray, depth - 1); + + surface_color = (surface_color * opacity) + (refracted_color * (1.0 - opacity)); + } + + return surface_color.clamp(); +} + void Scene::render() const { std::filesystem::path output_dir = "./data/output"; std::filesystem::create_directories(output_dir); @@ -88,64 +163,7 @@ void Scene::render() const { int last_progress_percent = -1; for (Ray const& ray : camera_) { - HitRecord closest_hit_rec; - bool hit_anything = false; - double closest_t = INFINITY; - - for (const auto& object_ptr : objects_) { - HitRecord temp_rec; - if (object_ptr->hit(ray, 0.001, closest_t, temp_rec)) { - hit_anything = true; - closest_t = temp_rec.t; - closest_hit_rec = temp_rec; - } - } - - Color pixel_color; - if (hit_anything) { - Point3 hit_point = closest_hit_rec.p; - Vector3 normal = closest_hit_rec.normal; - Vector3 view_dir = (ray.origin() - hit_point).normalize(); - auto mat = closest_hit_rec.material; - - for (const auto& light_ptr : lights_) { - Vector3 light_dir = (light_ptr->position - hit_point).normalize(); - double light_distance = (light_ptr->position - hit_point).magnitude(); - - Ray shadow_ray(hit_point, light_dir); - bool in_shadow = false; - for (const auto& obj_ptr : objects_) { - HitRecord shadow_rec; - if (obj_ptr->hit(shadow_ray, 0.001, light_distance, shadow_rec)) { - in_shadow = true; - break; - } - } - - Color ambient = mat->ka * this->ambient_color_; - - if (in_shadow) { - pixel_color += ambient; - continue; - } - - double diff_factor = std::max(0.0, normal.dot(light_dir)); - Color diffuse = mat->color * diff_factor * light_ptr->color; - - Vector3 reflect_dir = (normal * 2 * (light_dir.dot(normal))) - light_dir; - double spec_factor = std::pow(std::max(0.0, view_dir.dot(reflect_dir)), mat->ns); - Color specular = mat->ks * spec_factor * light_ptr->color; - - pixel_color += ambient + diffuse + specular; - } - - pixel_color.clamp(); - - } else { - pixel_color = Color(0, 0, 0); - } - - image_file << pixel_color << '\n'; + image_file << trace(ray, 5) << '\n'; pixels_done++; int current_progress_percent = From b2e246b3333e35513fcac14f59383e1bfb5a5942 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Guimar=C3=A3es?= Date: Tue, 15 Jul 2025 21:13:13 -0300 Subject: [PATCH 5/7] . --- demo/data/input/scene.yml | 158 ++++++++++++++++++++----------- src/include/Prism/core/utils.hpp | 15 ++- src/src/core/utils.cpp | 6 ++ src/src/scene/camera.cpp | 10 +- src/src/scene/scene.cpp | 41 ++++++-- 5 files changed, 156 insertions(+), 74 deletions(-) diff --git a/demo/data/input/scene.yml b/demo/data/input/scene.yml index 15be8ad..16a9a2b 100644 --- a/demo/data/input/scene.yml +++ b/demo/data/input/scene.yml @@ -1,30 +1,51 @@ # ----------------------------------------------------------------- -# Cena de Demonstração Final (Versão Corrigida) +# Cena da Cornell Box Final - Com Esferas em Destaque (Avançadas) # ----------------------------------------------------------------- ambient_light: [0.1, 0.1, 0.1] +# --- Definições de Materiais --- definitions: materials: - chao_fosco: &chao - color: [0.5, 0.5, 0.5] + # Materiais das paredes + parede_branca: &branco + color: [0.73, 0.73, 0.73] ka: [1.0, 1.0, 1.0] - ks: [0.1, 0.1, 0.1] + ks: [0.0, 0.0, 0.0] ns: 10 - plastico_magenta: &plastico - color: [0.8, 0.1, 0.4] - ka: [0.2, 0.2, 0.2] - ks: [0.8, 0.8, 0.8] - ns: 128 + parede_vermelha: &vermelho + color: [0.65, 0.05, 0.05] + ka: [1.0, 1.0, 1.0] + ks: [0.0, 0.0, 0.0] + ns: 10 - metal_dourado: &metal - color: [0.8, 0.6, 0.2] - ka: [0.2, 0.2, 0.2] - ks: [0.9, 0.9, 0.9] - ns: 512 + parede_verde: &verde + color: [0.12, 0.45, 0.15] + ka: [1.0, 1.0, 1.0] + ks: [0.0, 0.0, 0.0] + ns: 10 + + # Materiais para os objetos internos + bloco_azul: &azul + color: [0.1, 0.2, 0.8] + ka: [0.8, 0.8, 0.8] + ks: [0.3, 0.3, 0.3] + ns: 64 - vidro_cristalino: &vidro + bloco_laranja: &laranja + color: [0.9, 0.5, 0.1] + ka: [0.8, 0.8, 0.8] + ks: [0.2, 0.2, 0.2] + ns: 32 + + esfera_espelho: &espelho + color: [0.0, 0.0, 0.0] + ka: [0.0, 0.0, 0.0] + ks: [0.98, 0.98, 0.98] + ns: 2048 + + esfera_vidro: &vidro color: [1.0, 1.0, 1.0] ka: [0.0, 0.0, 0.0] ks: [0.1, 0.1, 0.1] @@ -32,65 +53,88 @@ definitions: ni: 1.52 d: 0.05 - mercurio_reflexivo: &espelho - color: [0.0, 0.0, 0.0] # Espelhos não têm cor difusa - ka: [0.0, 0.0, 0.0] - ks: [0.98, 0.98, 0.98] # Quase 100% reflexivo - ns: 2048 - +# --- Configurações da Câmera --- camera: - image_width: 1280 - image_height: 720 + image_width: 800 + image_height: 800 screen_distance: 1.5 viewport_width: 2.0 - viewport_height: 1.125 - lookfrom: [0, 2.5, 10] - lookat: [0, 1, 0] + viewport_height: 2.0 + lookfrom: [278, 278, -800] + lookat: [278, 278, 0] vup: [0, 1, 0] +# --- Fontes de Luz --- lights: - - name: Luz Principal - position: [-10, 10, 10] + - name: Luz do Teto + position: [278, 548, 278] color: [1.0, 1.0, 1.0] - - name: Luz de Preenchimento - position: [10, 5, -5] - color: [0.3, 0.5, 1.0] - +# --- Objetos na Cena --- objects: - - name: Chao + # As 5 paredes da caixa + - name: Chão type: plane - point_on_plane: [0, -0.01, 0] # Chão um pouco mais baixo + point_on_plane: [0, 0, 0] normal: [0, 1, 0] - material: *chao - - - name: Esfera de Espelho (Esquerda) - type: sphere - center: [-2.5, 1, 1] - radius: 1.0 - material: *espelho - - - name: Esfera de Vidro (Direita) - type: sphere - center: [2.5, 1, 1] - radius: 1.0 - material: *vidro + material: *branco + - name: Teto + type: plane + point_on_plane: [0, 555, 0] + normal: [0, -1, 0] + material: *branco + - name: Parede do Fundo + type: plane + point_on_plane: [0, 0, 555] + normal: [0, 0, -1] + material: *branco + - name: Parede Direita (Verde) + type: plane + point_on_plane: [555, 0, 0] + normal: [-1, 0, 0] + material: *verde + - name: Parede Esquerda (Vermelha) + type: plane + point_on_plane: [0, 0, 0] + normal: [1, 0, 0] + material: *vermelho - - name: Esfera de Plástico (Frente) - type: sphere - center: [0, 0.5, 4] - radius: 1.0 - material: *plastico + # Blocos com tamanho e posição originais + - name: Bloco Alto (Laranja) + type: mesh + path: "cubo.obj" + material: *laranja + transform: + - type: scaling + factors: [82.5, 165, 82.5] + - type: rotation + angle: 18 + axis: [0, 1, 0] + - type: translation + vector: [180, 165, 250] - - name: Cubo de Metal (Fundo) + - name: Bloco Baixo (Azul) type: mesh path: "cubo.obj" - material: *metal + material: *azul transform: - type: scaling - factors: [1.2, 1.2, 1.2] + factors: [82.5, 82.5, 82.5] - type: rotation - angle: 25 # Ângulo ajustado + angle: -20 axis: [0, 1, 0] - type: translation - vector: [0, 0.7, -2.5] # Posição ajustada \ No newline at end of file + vector: [370, 82.5, 150] + + # ESFERAS COM POSIÇÃO AJUSTADA (AINDA MAIS PERTO) + - name: Esfera de Vidro + type: sphere + center: [380, 90, -140] # Z foi de 120 para 80 + radius: 90 + material: *vidro + + - name: Esfera de Espelho + type: sphere + center: [180, 90, -200] # Z foi de 180 para 100 + radius: 90 + material: *espelho \ No newline at end of file diff --git a/src/include/Prism/core/utils.hpp b/src/include/Prism/core/utils.hpp index 49382e8..ea7260a 100644 --- a/src/include/Prism/core/utils.hpp +++ b/src/include/Prism/core/utils.hpp @@ -51,7 +51,20 @@ template T sqr(const T& value) { * @param etai_over_etat The ratio of indices of refraction (etai/etat). * @return The refracted vector as a Vector3. */ -Vector3 refract(const Vector3& uv, const Vector3& n, double etai_over_etat); +Vector3 PRISM_EXPORT refract(const Vector3& uv, const Vector3& n, double etai_over_etat); + +/** + * @brief Calcs the reflectance using Schlick's approximation. + * This function computes the reflectance based on the angle of incidence and the index of refraction + * using Schlick's approximation. + * @param cosine The cosine of the angle between the incident vector and the normal. + * @param ref_idx The index of refraction of the material. + * @return The reflectance value as a double, which is the probability of reflection at the + * interface. + * This value is used in ray tracing to determine how much light is reflected versus refracted. + */ +double PRISM_EXPORT schlick(double cosine, double ref_idx); + } // namespace Prism diff --git a/src/src/core/utils.cpp b/src/src/core/utils.cpp index 092bf56..957ae14 100644 --- a/src/src/core/utils.cpp +++ b/src/src/core/utils.cpp @@ -55,4 +55,10 @@ Vector3 refract(const Vector3& uv, const Vector3& n, double etai_over_etat) { return r_out_perp + r_out_parallel; } +double schlick(double cos, double ref_idx) { + auto r0 = (1.0 - ref_idx) / (1.0 + ref_idx); + r0 = r0 * r0; + return r0 + (1.0 - r0) * pow((1.0 - cos), 5); +} + } // namespace Prism \ No newline at end of file diff --git a/src/src/scene/camera.cpp b/src/src/scene/camera.cpp index 04bff16..0335874 100644 --- a/src/src/scene/camera.cpp +++ b/src/src/scene/camera.cpp @@ -9,15 +9,13 @@ namespace Prism { Camera::Camera(const Point3& position, const Point3& target, const Vector3& upvec, double distance, double viewport_height, double viewport_width, int image_height, int image_width) - : pos(position), aim(target), up(upvec), coordinate_basis(), screen_distance(distance), + : pos(position), aim(target), up(upvec), screen_distance(distance), screen_height(viewport_height), screen_width(viewport_width), pixel_height(image_height), pixel_width(image_width) { - coordinate_basis = orthonormalBasisContaining(pos - aim); - const auto& basis = coordinate_basis; - Vector3 w = Vector3{basis[0][0], basis[1][0], basis[2][0]}; - Vector3 u = Vector3{basis[0][1], basis[1][1], basis[2][1]}; - Vector3 v = Vector3{basis[0][2], basis[1][2], basis[2][2]}; + Vector3 w = (pos - aim).normalize(); + Vector3 u = (up.cross(w)).normalize(); + Vector3 v = w.cross(u); Point3 screen_center = pos - (w * screen_distance); Point3 top_left_corner = diff --git a/src/src/scene/scene.cpp b/src/src/scene/scene.cpp index fb9fa40..1a5ca95 100644 --- a/src/src/scene/scene.cpp +++ b/src/src/scene/scene.cpp @@ -117,25 +117,46 @@ Color Scene::trace(const Ray& ray, int depth) const { } } - if (mat->ks.r > 0 || mat->ks.g > 0 || mat->ks.b > 0) { - Vector3 reflect_dir = ray.direction() - rec.normal * 2 * ray.direction().dot(rec.normal); - Ray reflection_ray(rec.p, reflect_dir); - surface_color += mat->ks * trace(reflection_ray, depth - 1); - } + Color final_color = mat->ke + surface_color; double opacity = mat->d; if (opacity < 1.0) { + double reflectance; double refraction_ratio = rec.front_face ? (1.0 / mat->ni) : mat->ni; + Vector3 unit_direction = ray.direction().normalize(); + + double cos_theta = fmin((-unit_direction).dot(rec.normal), 1.0); + double sin_theta = sqrt(1.0 - cos_theta * cos_theta); + + if (refraction_ratio * sin_theta > 1.0) { + reflectance = 1.0; + } else { + reflectance = schlick(cos_theta, refraction_ratio); + } - Vector3 refracted_dir = refract(ray.direction().normalize(), rec.normal, refraction_ratio); - Ray refracted_ray(rec.p, refracted_dir); + Color reflection_color = Color(0, 0, 0); + Color refraction_color = Color(0, 0, 0); - Color refracted_color = trace(refracted_ray, depth - 1); + Vector3 reflect_dir = ray.direction() - rec.normal * 2 * ray.direction().dot(rec.normal); + Ray reflection_ray(rec.p, reflect_dir); + reflection_color = trace(reflection_ray, depth - 1); + + if (reflectance < 1.0) { + Vector3 refracted_dir = refract(unit_direction, rec.normal, refraction_ratio); + Ray refracted_ray(rec.p, refracted_dir); + refraction_color = trace(refracted_ray, depth - 1); + } - surface_color = (surface_color * opacity) + (refracted_color * (1.0 - opacity)); + Color trasmited_color = reflection_color * reflectance + refraction_color * (1.0 - reflectance); + final_color = final_color * opacity + trasmited_color * (1.0 - opacity); + } + else if (mat->ks.r > 0 || mat->ks.g > 0 || mat->ks.b > 0) { + Vector3 reflect_dir = ray.direction() - rec.normal * 2 * ray.direction().dot(rec.normal); + Ray reflection_ray(rec.p, reflect_dir); + final_color += mat->ks * trace(reflection_ray, depth - 1); } - return surface_color.clamp(); + return final_color.clamp(); } void Scene::render() const { From bfd274dca5d98b9aa60d712ad26dc40fbd6fc9b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Guimar=C3=A3es?= Date: Tue, 15 Jul 2025 23:35:57 -0300 Subject: [PATCH 6/7] fix --- demo/data/input/scene.yml | 15 +++++++++------ src/src/core/utils.cpp | 7 ++++++- src/src/objects/mesh.cpp | 13 +++++++++++-- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/demo/data/input/scene.yml b/demo/data/input/scene.yml index 16a9a2b..0d40a8c 100644 --- a/demo/data/input/scene.yml +++ b/demo/data/input/scene.yml @@ -10,32 +10,32 @@ definitions: # Materiais das paredes parede_branca: &branco color: [0.73, 0.73, 0.73] - ka: [1.0, 1.0, 1.0] + ka: [0.73, 0.73, 0.73] ks: [0.0, 0.0, 0.0] ns: 10 parede_vermelha: &vermelho color: [0.65, 0.05, 0.05] - ka: [1.0, 1.0, 1.0] + ka: [0.65, 0.05, 0.05] ks: [0.0, 0.0, 0.0] ns: 10 parede_verde: &verde color: [0.12, 0.45, 0.15] - ka: [1.0, 1.0, 1.0] + ka: [0.12, 0.45, 0.15] ks: [0.0, 0.0, 0.0] ns: 10 # Materiais para os objetos internos bloco_azul: &azul color: [0.1, 0.2, 0.8] - ka: [0.8, 0.8, 0.8] + ka: [0.1, 0.2, 0.8] ks: [0.3, 0.3, 0.3] ns: 64 bloco_laranja: &laranja color: [0.9, 0.5, 0.1] - ka: [0.8, 0.8, 0.8] + ka: [0.9, 0.5, 0.1] ks: [0.2, 0.2, 0.2] ns: 32 @@ -47,7 +47,7 @@ definitions: esfera_vidro: &vidro color: [1.0, 1.0, 1.0] - ka: [0.0, 0.0, 0.0] + ka: [1.0, 1.0, 1.0] ks: [0.1, 0.1, 0.1] ns: 256 ni: 1.52 @@ -69,6 +69,9 @@ lights: - name: Luz do Teto position: [278, 548, 278] color: [1.0, 1.0, 1.0] + - name: Flash da Câmera + position: [278, 278, -800] + color: [0.5, 0.5, 0.5] # --- Objetos na Cena --- objects: diff --git a/src/src/core/utils.cpp b/src/src/core/utils.cpp index 957ae14..90c6087 100644 --- a/src/src/core/utils.cpp +++ b/src/src/core/utils.cpp @@ -51,7 +51,12 @@ Matrix orthonormalBasisContaining(const Vector3& v) { Vector3 refract(const Vector3& uv, const Vector3& n, double etai_over_etat) { auto cos_theta = std::fmin((-uv).dot(n), 1.0); Vector3 r_out_perp = (uv + n * cos_theta) * etai_over_etat; - Vector3 r_out_parallel = n * -sqrt(std::abs(1.0 - r_out_perp.magnitude() * r_out_perp.magnitude())); + Vector3 r_out_parallel = n * -sqrt(fabs(1.0 - sqr(r_out_perp.magnitude()))); + + if (sqr(r_out_perp.magnitude()) > 1.0) { + return Vector3(0, 0, 0); + } + return r_out_perp + r_out_parallel; } diff --git a/src/src/objects/mesh.cpp b/src/src/objects/mesh.cpp index d2b63e1..9ba07c4 100644 --- a/src/src/objects/mesh.cpp +++ b/src/src/objects/mesh.cpp @@ -57,11 +57,20 @@ bool Mesh::hit(const Ray& ray, double t_min, double t_max, HitRecord& rec) const rec.t = t_max; for (const auto& triangle : mesh) { - triangle.hit(transformed_ray, 0.001, rec.t, rec); + triangle.hit(transformed_ray, t_min, rec.t, rec); } + Point3 world_p; + double world_t = INFINITY; + if (rec.t < t_max) { - rec.p = transform * transformed_ray.at(rec.t); + world_p = transform * transformed_ray.at(rec.t); + world_t = (world_p - ray.origin()).dot(ray.direction().normalize()); + } + + if (world_t < t_max) { + rec.p = world_p; + rec.t = world_t; Vector3 world_normal = (inverseTransposeTransform * rec.normal).normalize(); rec.set_face_normal(ray, world_normal); rec.material = material; From 24a67d5d2699413bdceaa6e418178c6d12a6caf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Guimar=C3=A3es?= Date: Tue, 15 Jul 2025 23:44:33 -0300 Subject: [PATCH 7/7] test fix --- CMakeLists.txt | 2 +- tests/src/CameraTest.cpp | 41 ---------------------------------------- 2 files changed, 1 insertion(+), 42 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 20ee4b6..896c2c3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ # It sets global settings and includes the sub-projects. # =================================================================== cmake_minimum_required(VERSION 3.22) -project(Prism VERSION 0.1.0 LANGUAGES CXX) +project(Prism VERSION 0.2.0 LANGUAGES CXX) # Set the policy for FetchContent to use modern, safer behavior. cmake_policy(SET CMP0135 NEW) diff --git a/tests/src/CameraTest.cpp b/tests/src/CameraTest.cpp index 9b5ce5a..d91dc13 100644 --- a/tests/src/CameraTest.cpp +++ b/tests/src/CameraTest.cpp @@ -33,47 +33,6 @@ TEST(CameraTest, Instantiation) { EXPECT_DOUBLE_EQ(cam.screen_width, width); } -TEST(CameraTest, CoordinateBasisOrthonormal) { - Point3 position(1.0, 2.0, 3.0); - Point3 target(4.0, 5.0, 6.0); - Vector3 upvec(0.0, 1.0, 0.0); - double distance = 10.0, height = 5.0, width = 8.0; - - Camera cam(position, target, upvec, distance, height, width, 10, 20); - - const Matrix& basis = cam.coordinate_basis; - auto getCol = [&](int c) { return Vector3(basis[0][c], basis[1][c], basis[2][c]); }; - - Vector3 dir = (position - target).normalize(); - Vector3 b1 = getCol(0); - Vector3 b2 = getCol(1); - Vector3 b3 = getCol(2); - - AssertVectorAlmostEqual(b1, dir); - ASSERT_NEAR(b1.magnitude(), 1.0, 1e-9); - ASSERT_NEAR(b2.magnitude(), 1.0, 1e-9); - ASSERT_NEAR(b3.magnitude(), 1.0, 1e-9); - ASSERT_NEAR(b1.dot(b2), 0.0, 1e-9); - ASSERT_NEAR(b1.dot(b3), 0.0, 1e-9); - ASSERT_NEAR(b2.dot(b3), 0.0, 1e-9); -} - -TEST(CameraTest, BasisHasOpposite) { - Point3 position(1.0, 2.0, 3.0); - Point3 target(4.0, 5.0, 6.0); - Vector3 upvec(0.0, 1.0, 0.0); - double distance = 10.0, height = 5.0, width = 8.0; - - Camera cam(position, target, upvec, distance, height, width, 10, 20); - - const Matrix& basis = cam.coordinate_basis; - auto getCol = [&](int c) { return Vector3{basis[0][c], basis[1][c], basis[2][c]}; }; - - Vector3 b1 = getCol(0); - - AssertVectorAlmostEqual(b1, ((target - position) * -1).normalize()); -} - TEST(CameraTest, IteratorGeneratesCorrectNumberOfRays) { Point3 position(0, 0, 0); Point3 target(0, 0, -1);