diff --git a/TODO b/TODO index 5906ae5..ad1f543 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,3 @@ -[ ] The main thread is constantly polling for changes in the render texture, consider using a notification mechanism instead. For example, you could use a callback function that the renderer registers with the render texture, which is called whenever the texture is updated. +[x] The main thread is constantly polling for changes in the render texture, consider using a notification mechanism instead. For example, you could use a callback function that the renderer registers with the render texture, which is called whenever the texture is updated. [ ] diff --git a/libhart/scene/camera.hpp b/libhart/scene/camera.hpp index 1e3f004..8a1cf9b 100644 --- a/libhart/scene/camera.hpp +++ b/libhart/scene/camera.hpp @@ -15,7 +15,7 @@ typedef struct _CameraImpl { typedef struct Viewport { glm::ivec2 Raster = {1920, 1080}; - glm::ivec2 Ray = {1920, 1080}; + glm::ivec2 Ray = {50, 50}; } Viewports; typedef struct Camera { diff --git a/libhart/tracing/ray.hpp b/libhart/tracing/ray.hpp deleted file mode 100644 index c186b94..0000000 --- a/libhart/tracing/ray.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include - -namespace inferno { - -struct Ray -{ - glm::vec3 Origin; - glm::vec3 Direction; - uint32_t Reference; -}; - -} diff --git a/src/graphics.hpp b/src/graphics.hpp index 1cba674..60f9b44 100644 --- a/src/graphics.hpp +++ b/src/graphics.hpp @@ -21,6 +21,8 @@ extern "C" #include namespace inferno { +namespace graphics::rays { class Ray; -using RayField = std::vector; +} +using RayField = std::vector; } diff --git a/src/inferno.cpp b/src/inferno.cpp index 5f51cf7..61d2ba5 100644 --- a/src/inferno.cpp +++ b/src/inferno.cpp @@ -94,22 +94,28 @@ InfernoApp* inferno_create() graphics::shader_link(basicShader); basicMaterial->setGlShader(basicShader); - scene::Mesh* mesh = new scene::Mesh; - mesh->loadOBJ("res/lucy.obj"); - mesh->ready(); - mesh->setMaterial(basicMaterial); + // scene::Mesh* mesh = new scene::Mesh; + // mesh->loadOBJ("res/dragon-cornell-size.obj"); + // mesh->ready(); + // mesh->setMaterial(basicMaterial); + // scene::SceneObject* object = scene::scene_object_create(); + // scene::scene_object_add_mesh(object, mesh); + // scene::scene_add_object(app->Scene, object); - scene::SceneObject* object = scene::scene_object_create(); - scene::scene_object_add_mesh(object, mesh); + scene::Mesh* box = new scene::Mesh; + box->loadOBJ("res/cornell-box.obj"); + box->ready(); + box->setMaterial(basicMaterial); + scene::SceneObject* box_object = scene::scene_object_create(); + scene::scene_object_add_mesh(box_object, box); + scene::scene_add_object(app->Scene, box_object); - scene::scene_add_object(app->Scene, object); app->PreviewRenderer = graphics::preview_create(); graphics::preview_set_viewport(app->PreviewRenderer, app->Scene->Camera); app->RayRenderer = graphics::rayr_create(app->Scene); graphics::rayr_set_viewport(app->RayRenderer, app->Scene->Camera); - return app; } diff --git a/src/renderer/globalillumination.cpp b/src/renderer/global_illumination.cpp similarity index 100% rename from src/renderer/globalillumination.cpp rename to src/renderer/global_illumination.cpp diff --git a/src/renderer/globalillumination.hpp b/src/renderer/global_illumination.hpp similarity index 100% rename from src/renderer/globalillumination.hpp rename to src/renderer/global_illumination.hpp diff --git a/libhart/tracing/hit.hpp b/src/renderer/hit.hpp similarity index 67% rename from libhart/tracing/hit.hpp rename to src/renderer/hit.hpp index b990987..b186dff 100644 --- a/libhart/tracing/hit.hpp +++ b/src/renderer/hit.hpp @@ -2,15 +2,14 @@ #include -namespace inferno { +namespace inferno::graphics::rays { class Ray; struct HitInfo { Ray* Caller; - // indicie of hit ^ mesh idx of hit - int Identifier; + bool Did; glm::vec2 UV; glm::vec3 SurfaceNormal; float Distance; diff --git a/src/renderer/object_tracer.cpp b/src/renderer/object_tracer.cpp new file mode 100644 index 0000000..dd1ada1 --- /dev/null +++ b/src/renderer/object_tracer.cpp @@ -0,0 +1,71 @@ +#include "object_tracer.hpp" +#include "scene/object.hpp" + +#include +#include +#include + +namespace inferno::graphics::rays { + +bool triangle_ray_collide(Ray* ray, float* t, glm::vec3 vertex0, glm::vec3 vertex1, glm::vec3 vertex2) +{ + glm::vec3 edge1, edge2, h, s, q; + float a, f, u, v; + edge1 = vertex1 - vertex0; + edge2 = vertex2 - vertex0; + h = glm::cross(ray->Direction, edge2); + a = glm::dot(edge1, h); + if (a > -helpers::EPSILON && a < helpers::EPSILON) + return false; // This ray is parallel to this triangle. + f = 1.0 / a; + s = ray->Origin - vertex0; + u = f * glm::dot(s, h); + if (u < 0.0 || u > 1.0) + return false; + q = glm::cross(s, edge1); + v = f * glm::dot(ray->Direction, q); + if (v < 0.0 || u + v > 1.0) + return false; + // At this stage we can compute t to find out where the intersection point is on the line. + *t = f * glm::dot(edge2, q); + if (*t > helpers::EPSILON) // ray intersection + return true; + else // This means that there is a line intersection but not a ray intersection. + return false; +} + +HitInfo* object_ray_collide(scene::SceneObject* object, Ray* ray) +{ + HitInfo* info = new HitInfo; + info->Distance = INFINITY; + info->Did = false; + for (auto* mesh : scene::scene_object_get_meshs(object)) { + // extract triangles and loop over them, if there is a hit - we return + const uint32_t* ind; + const float* verts; + const float* norms; + mesh->getIndicies(&ind); + mesh->getVerticies(&verts, &norms); + + float t = INFINITY; + for (int i = 0; i < mesh->getIndexCount(); i++) { + uint32_t index = ind[i]; + glm::vec3 a = { verts[3 * index + 0], verts[3 * index + 1], verts[3 * index + 2] }; + glm::vec3 b = { verts[3 * index + 3], verts[3 * index + 4], verts[3 * index + 5] }; + glm::vec3 c = { verts[3 * index + 6], verts[3 * index + 7], verts[3 * index + 8] }; + + float temp_t; + if (!triangle_ray_collide(ray, &temp_t, a, b, c)) + continue; + + info->Did = true; + if (temp_t < t) { + t = temp_t; + info->Distance = t; + } + } + } + return info; +} + +} diff --git a/src/renderer/object_tracer.hpp b/src/renderer/object_tracer.hpp new file mode 100644 index 0000000..cdf2a96 --- /dev/null +++ b/src/renderer/object_tracer.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include +#include +#include +#include + +namespace inferno::graphics::rays { + +HitInfo* object_ray_collide(scene::SceneObject* object, Ray* ray); + +} + diff --git a/src/renderer/ray.cpp b/src/renderer/ray.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/src/renderer/ray.hpp b/src/renderer/ray.hpp index e69de29..cc06c66 100644 --- a/src/renderer/ray.hpp +++ b/src/renderer/ray.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include + +namespace inferno::graphics::rays { + +struct Ray +{ + glm::vec3 Origin; + glm::vec3 Direction; + uint32_t Reference; +}; + +} diff --git a/src/renderer/ray_source.cpp b/src/renderer/ray_source.cpp index 62393e2..e6239ad 100644 --- a/src/renderer/ray_source.cpp +++ b/src/renderer/ray_source.cpp @@ -1,70 +1,50 @@ -// #include "ray_source.hpp" -// -// #include -// -// #include -// -// #include -// -// #include -// -// using namespace inferno; -// -// RaySource::RaySource(Camera* camera) -// : mReferenceCamera(camera) -// { -// this->generate(); -// } -// -// RaySource::~RaySource() -// { -// -// } -// -// void RaySource::generate() -// { -// // const float aspect = mReferenceCamera->getRayViewport().x / mReferenceCamera->getRayViewport().y; -// // float scale = tan(mReferenceCamera->FOV / 2.0f * helpers::PI / 180.0f); -// } -// -// ReferencedRayField RaySource::getInitialRays(bool MSAA) -// { -// if (mReferenceCamera->didUpdate()) -// { -// this->generate(); -// } -// -// RayField field; -// field.reserve(mReferenceCamera->getRayViewport().x * mReferenceCamera->getRayViewport().y); -// -// const float aspect = mReferenceCamera->getRayViewport().x / mReferenceCamera->getRayViewport().y; -// float scale = tan(mReferenceCamera->FOV / 2.0f * helpers::PI / 180.0f); -// -// glm::mat4 cameraToWorld = mReferenceCamera->getCameraLook(); -// glm::vec3 origin = mReferenceCamera->Position; -// -// std::unordered_map reference; -// -// uint32_t i = 0; -// for (int x = 0; x < mReferenceCamera->getRayViewport().x; x++) -// for (int y = 0; y < mReferenceCamera->getRayViewport().y; y++) -// { -// float Px = (2.0f * ((x + 0.5f) / mReferenceCamera->getRayViewport().x) - 1.0f) * scale * aspect; -// float Py = (2.0f * ((y + 0.5f) / mReferenceCamera->getRayViewport().y) - 1.0f) * scale; -// -// Ray* ray = new Ray{}; -// -// glm::vec4 dir4 = glm::vec4(Px, Py, -1.0f, 1.0f) * cameraToWorld; -// glm::vec3 dir3 = glm::vec3(dir4) / dir4.w; -// ray->Direction = glm::normalize(dir3); -// -// ray->Origin = origin; -// ray->Reference = i; -// reference[i] = {x, y}; -// -// field.push_back(ray); -// i++; -// } -// -// return { field, reference }; -// } +#include "ray_source.hpp" + +#include + +#include + +#include +#include + +namespace inferno::graphics::rays { + +ReferencedRayField generate_initial_rays(graphics::Camera* camera, bool MSAA) +{ + auto viewport = graphics::camera_ray_get_viewport(camera); + + RayField field; + field.reserve(viewport.x * viewport.y); + + const float aspect = static_cast(viewport.x) / static_cast(viewport.y); + float scale = tan(camera->FOV / 2.0f * helpers::PI / 180.0f); + + glm::mat4 cameraToWorld = graphics::camera_get_look(camera); + glm::vec3 origin = camera->Position; + + std::unordered_map reference; + + uint32_t i = 0; + for (int x = 0; x < viewport.x; x++) + for (int y = 0; y < viewport.y; y++) { + float Px = (2.0f * ((x + 0.5f) / viewport.x) - 1.0f) * scale * aspect; + float Py = (2.0f * ((y + 0.5f) / viewport.y) - 1.0f) * scale; + + Ray* ray = new Ray {}; + + glm::vec4 dir4 = glm::vec4(Px, Py, -1.0f, 1.0f) * cameraToWorld; + glm::vec3 dir3 = glm::vec3(dir4) / dir4.w; + ray->Direction = glm::normalize(dir3); + + ray->Origin = origin; + ray->Reference = i; + reference[i] = { x, y }; + + field.push_back(ray); + i++; + } + + return { field, reference }; +} + +} // namespace inferno::graphics::rays diff --git a/src/renderer/ray_source.hpp b/src/renderer/ray_source.hpp index 9ccce94..243e5f5 100644 --- a/src/renderer/ray_source.hpp +++ b/src/renderer/ray_source.hpp @@ -1,33 +1,23 @@ -// #pragma once -// -// #include -// #include -// -// #include -// -// #include -// -// namespace inferno { -// -// class Camera; -// -// struct ReferencedRayField { -// RayField Field; -// std::unordered_map Reference; -// }; -// -// -// class RaySource -// { -// public: -// RaySource(Camera* camera); -// ~RaySource(); -// -// void generate(); -// ReferencedRayField getInitialRays(bool MSAA); -// -// private: -// Camera* mReferenceCamera; -// }; -// -// } +#pragma once + +#include +#include + +#include + +#include + +namespace inferno::graphics { + class Camera; +} + +namespace inferno::graphics::rays { + +struct ReferencedRayField { + RayField Field; + std::unordered_map Reference; +}; + +ReferencedRayField generate_initial_rays(Camera* camera, bool MSAA); + +} diff --git a/src/renderer/renderer.cpp b/src/renderer/renderer.cpp index 96fbb34..7c060f2 100644 --- a/src/renderer/renderer.cpp +++ b/src/renderer/renderer.cpp @@ -2,11 +2,12 @@ #include +#include +#include +#include #include #include #include -#include -#include #include "ray_source.hpp" @@ -15,6 +16,7 @@ #include #include +#include namespace inferno::graphics { @@ -30,6 +32,7 @@ RayRenderer* rayr_create(scene::Scene* scene) yolo::debug("Raytracing Rendering {}x{} viewport", renderer->Viewport.x, renderer->Viewport.y); renderer->RenderData = new glm::fvec4[renderer->Viewport.x * renderer->Viewport.y]; + memset(renderer->RenderData, 0, renderer->Viewport.x * renderer->Viewport.y * sizeof(glm::fvec4)); glGenTextures(1, &renderer->RenderTargetTexture); glBindTexture(GL_TEXTURE_2D, renderer->RenderTargetTexture); @@ -93,6 +96,9 @@ glm::fvec4* rayr_get_render_data(RayRenderer* renderer) void rayr_prepare(RayRenderer* renderer) { + // TODO: This is TEMP + memset(renderer->RenderData, 0, renderer->Viewport.x * renderer->Viewport.y * sizeof(glm::fvec4)); + assert(renderer->Scene != nullptr); if (scene::scene_did_update(renderer->Scene)) { yolo::debug("Scene updated, rebuilding acceleration structure"); @@ -102,14 +108,27 @@ void rayr_prepare(RayRenderer* renderer) void rayr_draw(RayRenderer* renderer) { + rayr_prepare(renderer); + scene::scene_frame_tick(renderer->Scene); // TODO: Rays should definately be bump allocated if possible, this is KBs of // ray data and nothing else being reallocated every frame for no reason - // ReferencedRayField startRays = mRaySource->getInitialRays(true); + rays::ReferencedRayField startRays = rays::generate_initial_rays(scene::scene_get_camera(renderer->Scene), true); for (int x = 0; x < renderer->Viewport.x; x++) { for (int y = 0; y < renderer->Viewport.y; y++) { - renderer->RenderData[y * renderer->Viewport.x + x] = { 0.1f, 1.0f, 0.1f, 1.0f }; + rays::Ray* ray = startRays.Field[x * renderer->Viewport.y + y]; + + // we want to iterate over every object in the scene and then ask that object for an intersection + for (auto& obj : scene::scene_get_renderables(renderer->Scene)) { + rays::HitInfo* hit = rays::object_ray_collide(obj, ray); + if (hit->Did) { + glm::vec3 hit_distance = glm::vec3{ hit->Distance }; + hit_distance /= 10; + renderer->RenderData[y * renderer->Viewport.x + x] = { hit_distance, 1.0 }; + } + delete hit; + } } } } diff --git a/src/renderer/scenetracer.cpp b/src/renderer/scenetracer.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/src/renderer/scenetracer.hpp b/src/renderer/scenetracer.hpp deleted file mode 100644 index e69de29..0000000 diff --git a/src/renderer/triangle.cpp b/src/renderer/triangle.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/src/renderer/triangle.hpp b/src/renderer/triangle.hpp index e69de29..e0b96ff 100644 --- a/src/renderer/triangle.hpp +++ b/src/renderer/triangle.hpp @@ -0,0 +1,8 @@ +#pragma once + +namespace inferno::graphics::rays { + + +} + + diff --git a/src/scene/mesh.cpp b/src/scene/mesh.cpp index b81da20..b26234d 100644 --- a/src/scene/mesh.cpp +++ b/src/scene/mesh.cpp @@ -74,16 +74,16 @@ void Mesh::ready() yolo::debug("Mesh for preview ready..."); } -int Mesh::getVerticies(void** v, void** n) +int Mesh::getVerticies(const float** v, const float** n) { - *v = (void*)&mObjLoader->getPositions()[0]; - *n = (void*)&mObjLoader->getNormals()[0]; + *v = &mObjLoader->getPositions()[0]; + *n = &mObjLoader->getNormals()[0]; return mObjLoader->getVertCount(); } -int Mesh::getIndicies(void** i) +int Mesh::getIndicies(const uint32_t** i) { - *i = (void*)&mObjLoader->getFaces()[0]; + *i = &mObjLoader->getFaces()[0]; return mObjLoader->getIndexCount(); } diff --git a/src/scene/mesh.hpp b/src/scene/mesh.hpp index fc585b2..b686f63 100644 --- a/src/scene/mesh.hpp +++ b/src/scene/mesh.hpp @@ -26,8 +26,8 @@ public: void loadOBJ(std::filesystem::path file); void ready(); - int getVerticies(void** v, void** n); - int getIndicies(void** i); + int getVerticies(const float** v, const float** n); + int getIndicies(const uint32_t** i); int getIndexCount();