diff --git a/includes/RT.hpp b/includes/RT.hpp index 14501c8..d6976a9 100644 --- a/includes/RT.hpp +++ b/includes/RT.hpp @@ -37,6 +37,7 @@ struct Vertex { # include "Object.hpp" # include "objects/Sphere.hpp" +# include "objects/Plane.hpp" # include "Camera.hpp" # include "Window.hpp" diff --git a/includes/RT/Object.hpp b/includes/RT/Object.hpp index 07f7e75..1014e0f 100644 --- a/includes/RT/Object.hpp +++ b/includes/RT/Object.hpp @@ -38,6 +38,7 @@ class Object enum class Type { SPHERE, + PLANE, }; virtual Type getType() const = 0; diff --git a/includes/RT/Scene.hpp b/includes/RT/Scene.hpp index b86ccc5..df3e57f 100644 --- a/includes/RT/Scene.hpp +++ b/includes/RT/Scene.hpp @@ -18,12 +18,16 @@ struct GPUObject { alignas(16) glm::vec3 position; + alignas(16) glm::vec3 color; - float emission; - float roughness; - float specular; - float radius; - int type; + float emission; + float roughness; + float specular; + + float radius; // sphere + alignas(16) glm::vec3 normal; // plane + + int type; }; class Sphere; diff --git a/includes/RT/Window.hpp b/includes/RT/Window.hpp index 2fe220d..ea1891c 100644 --- a/includes/RT/Window.hpp +++ b/includes/RT/Window.hpp @@ -41,8 +41,9 @@ class Window GLFWwindow *_window; Scene *_scene; - int _frameCount; float _fps; + float _delta; + int _frameCount; }; diff --git a/includes/RT/objects/Plane.hpp b/includes/RT/objects/Plane.hpp new file mode 100644 index 0000000..b0f03f1 --- /dev/null +++ b/includes/RT/objects/Plane.hpp @@ -0,0 +1,54 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* Plane.hpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: ycontre +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/12/23 19:12:51 by ycontre #+# #+# */ +/* Updated: 2024/12/23 19:47:09 by ycontre ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef RT_Plane__HPP +# define RT_Plane__HPP + +# include "RT.hpp" + +class Plane : public Object +{ + public: + Plane(std::stringstream &line) : Object(glm::vec3(0.0f), -1) + { + try { + float x, y, z; + float nx, ny, nz; + int mat_index; + + if (!(line >> x >> y >> z)) + throw std::runtime_error("Missing position"); + + if (!(line >> nx >> ny >> nz)) + throw std::runtime_error("Missing plane's normal"); + + if (!(line >> mat_index)) + throw std::runtime_error("Missing material properties"); + + _position = glm::vec3(x, y, z); + _normal = glm::vec3(nx, ny, nz); + + _mat_index = mat_index; + } + catch (const std::exception &e) { throw; } + } + Plane(const glm::vec3 &position, const glm::vec3 &normal, const int mat_index) + : Object(position, mat_index), _normal(normal) {} + + glm::vec3 getNormal() const { return (_normal); } + Type getType() const override { return Type::PLANE; } + + private: + glm::vec3 _normal; +}; + +#endif \ No newline at end of file diff --git a/scenes/test.rt b/scenes/test.rt index 4c95ed8..3279231 100644 --- a/scenes/test.rt +++ b/scenes/test.rt @@ -1,14 +1,29 @@ -MAT 255 255 255 0.0 1.0 2.0 -MAT 255 255 255 3.0 1.0 2.0 -MAT 255 0 0 0.0 1.0 2.0 +MAT 255 255 255 0.0 0.0 0.0 +MAT 255 255 255 2.0 0.0 0.0 -sp 0 -50 -6 50.0 0 -sp 50 30 -6 30.0 1 +MAT 255 0 0 0.0 0.0 0.0 +MAT 0 150 255 0.0 0.0 0.0 +MAT 150 255 150 0.0 0.0 0.0 + +MAT 255 255 255 0.0 1.0 0.0 + +sp 0 7.5 0 5 1 + +sp 0 1 0 0.5 5 + +sp 0 -2 -1 1 2 +sp -1 -2 0.8 1 3 +sp 1 -2 0.8 1 4 + + +pl 0 -3 0 0 1 0 0 +pl 3 0 0 -1 0 0 0 +pl -3 0 0 1 0 0 0 +pl 0 3 0 0 -1 0 0 +pl 0 0 -3 0 0 1 0 +pl 0 0 3 0 0 -1 0 -sp 0 1 -2 1.5 0 -sp 0 2 -5 1.5 2 -sp 0 4 -1 1.5 2 R 1.0 -2.0 10 diff --git a/shaders/compute.glsl b/shaders/compute.glsl index 4d8069a..0756a4b 100644 --- a/shaders/compute.glsl +++ b/shaders/compute.glsl @@ -1,19 +1,21 @@ #version 430 core -#include "shaders/random.glsl" - layout(local_size_x = 16, local_size_y = 16) in; -layout(binding = 0, rgba32f) uniform image2D outputImage; -layout(binding = 1, rgba32f) uniform image2D accumulationImage; +layout(binding = 0, rgba32f) uniform image2D output_image; +layout(binding = 1, rgba32f) uniform image2D accumulation_image; struct GPUObject { vec3 position; // 12 + 4 + vec3 color; // 12 + 4 float emission; // 4 float roughness; // 4 float specular; // 4 + float radius; // 4 - int type; // 4 + 12 + vec3 normal; // 12 + 4 + + int type; // 4 }; layout(std430, binding = 1) buffer ObjectBuffer @@ -28,9 +30,6 @@ uniform mat4 u_viewMatrix; uniform int u_frameCount; uniform float u_time; -vec3 lightPos = vec3(5.0, 5.0, 5.0); -vec3 lightColor = vec3(1.0, 1.0, 1.0); - struct Ray { vec3 origin; @@ -45,29 +44,10 @@ struct hitInfo int obj_index; }; -bool intersectSphere(Ray ray, GPUObject obj, out hitInfo hit) -{ - vec3 oc = ray.origin - obj.position; - float a = dot(ray.direction, ray.direction); - float b = 2.0 * dot(oc, ray.direction); - float c = dot(oc, oc) - obj.radius * obj.radius; - float discriminant = b * b - 4.0 * a * c; +#include "shaders/random.glsl" +#include "shaders/intersect.glsl" - if (discriminant < 0.0) - return false; - - float t = (-b - sqrt(discriminant)) / (2.0 * a); - if (t < 0.0) - t = (-b + sqrt(discriminant)) / (2.0 * a); - - hit.t = t; - hit.position = ray.origin + ray.direction * t; - hit.normal = normalize(hit.position - obj.position); - - return (true); -} - -hitInfo trace_ray(Ray ray) +hitInfo traceRay(Ray ray) { hitInfo hit; hit.t = 1e30; @@ -77,31 +57,46 @@ hitInfo trace_ray(Ray ray) { GPUObject obj = objects[i]; - hitInfo tempHit; - if (intersectSphere(ray, obj, tempHit)) + hitInfo temp_hit; + if (intersect(ray, obj, temp_hit) && temp_hit.t > 0.0f && temp_hit.t < hit.t) { - if (tempHit.t > 0.0f && tempHit.t < hit.t) - { - hit.t = tempHit.t; - hit.obj_index = i; - hit.position = tempHit.position; - hit.normal = tempHit.normal; - } + hit.t = temp_hit.t; + hit.obj_index = i; + hit.position = temp_hit.position; + hit.normal = temp_hit.normal; } } return (hit); } -vec3 pathtrace(Ray ray, vec2 random) +Ray newRay(hitInfo hit, Ray ray, vec2 uv) +{ + Ray new_ray; + vec3 in_unit_sphere; + + in_unit_sphere = normalize(randomVec3(uv, u_time)); + in_unit_sphere *= sign(dot(in_unit_sphere, hit.normal)); + + vec3 diffuse_dir = normalize(hit.normal + in_unit_sphere); + vec3 specular_dir = reflect(ray.direction, hit.normal); + + new_ray.origin = hit.position + hit.normal * 0.001; + new_ray.direction = mix(diffuse_dir, specular_dir, objects[hit.obj_index].roughness); + + return (new_ray); +} + +vec3 pathtrace(Ray ray, vec2 uv) { vec3 color = vec3(1.0); vec3 light = vec3(0.0); float closest_t = 1e30; - for (int i = 0; i < 10; i++) + + for (int i = 0; i < 3; i++) { - hitInfo hit = trace_ray(ray); + hitInfo hit = traceRay(ray); if (hit.obj_index == -1) { light += vec3(0); //ambient color @@ -117,40 +112,35 @@ vec3 pathtrace(Ray ray, vec2 random) break; } - ray.origin = hit.position + hit.normal * 0.001; - //cosine weighted importance sampling - vec3 unit_sphere = normalize(randomVec3(random, u_time)); - if (dot(unit_sphere, hit.normal) < 0.0) - unit_sphere = -unit_sphere; - ray.direction = normalize(hit.normal + unit_sphere); + ray = newRay(hit, ray, uv); } return (color * light); } -void main() { - ivec2 pixelCoords = ivec2(gl_GlobalInvocationID.xy); - if (pixelCoords.x >= int(u_resolution.x) || pixelCoords.y >= int(u_resolution.y)) +void main() +{ + ivec2 pixel_coords = ivec2(gl_GlobalInvocationID.xy); + if (pixel_coords.x >= int(u_resolution.x) || pixel_coords.y >= int(u_resolution.y)) return; - vec2 uv = vec2(pixelCoords) / u_resolution; - uv = uv * 2.0 - 1.0; + vec2 uv = (vec2(pixel_coords) / u_resolution) * 2.0 - 1.0;; uv.x *= u_resolution.x / u_resolution.y; float fov = 90.0; float focal_length = 1.0 / tan(radians(fov) / 2.0); - vec3 viewSpaceRay = normalize(vec3(uv.x, uv.y, -focal_length)); + vec3 view_space_ray = normalize(vec3(uv.x, uv.y, -focal_length)); - vec3 rayDirection = (inverse(u_viewMatrix) * vec4(viewSpaceRay, 0.0)).xyz; - rayDirection = normalize(rayDirection); - Ray ray = Ray(u_cameraPosition, rayDirection); + vec3 ray_direction = normalize((inverse(u_viewMatrix) * vec4(view_space_ray, 0.0)).xyz); + Ray ray = Ray(u_cameraPosition, ray_direction); vec3 color = pathtrace(ray, uv); - vec4 accum = imageLoad(accumulationImage, pixelCoords); - accum.rgb = accum.rgb * float(u_frameCount) / float(u_frameCount + 1) + color / float(u_frameCount + 1); + float blend = 1.0 / float(u_frameCount + 1); + vec4 accum = imageLoad(accumulation_image, pixel_coords); + accum.rgb = mix(accum.rgb, color, blend); accum.a = 1.0; - imageStore(accumulationImage, pixelCoords, accum); - imageStore(outputImage, pixelCoords, accum); + imageStore(accumulation_image, pixel_coords, accum); + imageStore(output_image, pixel_coords, accum); } diff --git a/shaders/intersect.glsl b/shaders/intersect.glsl new file mode 100644 index 0000000..ab623d6 --- /dev/null +++ b/shaders/intersect.glsl @@ -0,0 +1,39 @@ +bool intersectSphere(Ray ray, GPUObject obj, out hitInfo hit) +{ + vec3 oc = ray.origin - obj.position; + + float b = dot(oc, ray.direction); + float c = dot(oc, oc) - obj.radius * obj.radius; + float h = b * b - c; + + float t = -b - sqrt(h); + t = mix(t, -b + sqrt(h), step(t, 0.0)); + + hit.t = t; + hit.position = ray.origin + ray.direction * t; + hit.normal = normalize(hit.position - obj.position); + + return (h >= 0.0 && t > 0.0); +} + +bool intersectPlane(Ray ray, GPUObject obj, out hitInfo hit) +{ + float d = dot(obj.normal, ray.direction); + float t = dot(obj.position - ray.origin, obj.normal) / d; + bool valid = t >= 0.0 && d != 0.0; + + hit.t = t; + hit.position = ray.origin + ray.direction * t; + hit.normal = d < 0.0 ? obj.normal : -obj.normal; + + return (valid); +} + +bool intersect(Ray ray, GPUObject obj, out hitInfo hit) +{ + if (obj.type == 0) + return (intersectSphere(ray, obj, hit)); + if (obj.type == 1) + return (intersectPlane(ray, obj, hit)); + return (false); +} \ No newline at end of file diff --git a/srcs/RT.cpp b/srcs/RT.cpp index e610949..329d1db 100644 --- a/srcs/RT.cpp +++ b/srcs/RT.cpp @@ -58,7 +58,7 @@ int main(int argc, char **argv) shader.drawTriangles(size); std::cout << "\rFrame: " << window.getFrameCount() << " Fps: " << int(window.getFps()) << " " << std::flush; - + window.display(); window.pollEvents(); } diff --git a/srcs/class/Camera.cpp b/srcs/class/Camera.cpp index 79c0a38..533085a 100644 --- a/srcs/class/Camera.cpp +++ b/srcs/class/Camera.cpp @@ -38,22 +38,18 @@ void Camera::update_camera_vectors() void Camera::update(float delta_time) { + delta_time = 0.016; + _velocity += _acceleration * delta_time; - // std::cout << _acceleration.x << " " << _acceleration.y << " " << _acceleration.z << " " << std::endl; - // Apply deceleration when no acceleration if (glm::length(_acceleration) < 0.1f) _velocity *= (1.0f - _deceleration_rate * delta_time); - // Clamp velocity to maximum speed float speed = glm::length(_velocity); if (speed > _maxSpeed) _velocity = (_velocity / speed) * _maxSpeed; - // Update position _position += _velocity * delta_time; - - // Reset acceleration _acceleration = glm::vec3(0.0f); } diff --git a/srcs/class/Scene.cpp b/srcs/class/Scene.cpp index 0f5bdb6..c954699 100644 --- a/srcs/class/Scene.cpp +++ b/srcs/class/Scene.cpp @@ -72,17 +72,24 @@ void Scene::updateGPUData() mat = getMaterial(obj->getMaterialIndex()); gpu_obj.position = obj->getPosition(); + gpu_obj.color = mat->color; gpu_obj.emission = mat->emission; gpu_obj.roughness = mat->roughness; gpu_obj.specular = mat->specular; + gpu_obj.type = static_cast(obj->getType()); if (obj->getType() == Object::Type::SPHERE) { - auto sphere = static_cast(obj); + auto sphere = static_cast(obj); gpu_obj.radius = sphere->getRadius(); } + else if (obj->getType() == Object::Type::PLANE) + { + auto plane = static_cast(obj); + gpu_obj.normal = plane->getNormal(); + } _gpu_objects.push_back(gpu_obj); } diff --git a/srcs/class/SceneParser.cpp b/srcs/class/SceneParser.cpp index 3217fb7..4ba762d 100644 --- a/srcs/class/SceneParser.cpp +++ b/srcs/class/SceneParser.cpp @@ -14,10 +14,16 @@ SceneParser::SceneParser(Scene *scene) : _scene(scene) { - object_parsers["sp"] = [](std::stringstream& ss) -> Object* + object_parsers["sp"] = [](std::stringstream &ss) -> Object * { try { return (new Sphere(ss)); } - catch (const std::exception& e) { throw; } + catch (const std::exception &e) { throw; } + }; + + object_parsers["pl"] = [](std::stringstream &ss) -> Object * + { + try { return (new Plane(ss)); } + catch (const std::exception &e) { throw; } }; } diff --git a/srcs/class/Window.cpp b/srcs/class/Window.cpp index 6c5e366..3e4cd18 100644 --- a/srcs/class/Window.cpp +++ b/srcs/class/Window.cpp @@ -66,6 +66,7 @@ void Window::process_input() if (forward || backward || left || right || up || down) _frameCount = 0; + _scene->getCamera()->process_keyboard(forward, backward, left, right, up, down); } @@ -89,7 +90,6 @@ void Window::mouseMoveCallback(GLFWwindow* window, double xpos, double ypos) if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS) { win->_scene->getCamera()->process_mouse(xoffset, yoffset, true); - win->_frameCount = 0; } @@ -116,10 +116,11 @@ void Window::display() { static double lastTime = glfwGetTime(); double currentTime = glfwGetTime(); - double delta = currentTime - lastTime; + + _delta = currentTime - lastTime; lastTime = currentTime; - _fps = 1.0f / delta; + _fps = 1.0f / _delta; _frameCount++; @@ -128,7 +129,7 @@ void Window::display() void Window::pollEvents() { this->process_input(); - _scene->getCamera()->update(1.0f / _fps); + _scene->getCamera()->update(_delta); glfwPollEvents(); } diff --git a/srcs/parsing/parsing.cpp b/srcs/parsing/parsing.cpp deleted file mode 100644 index a7092de..0000000 --- a/srcs/parsing/parsing.cpp +++ /dev/null @@ -1,12 +0,0 @@ -/* ************************************************************************** */ -/* */ -/* ::: :::::::: */ -/* parsing.cpp :+: :+: :+: */ -/* +:+ +:+ +:+ */ -/* By: ycontre +#+ +:+ +#+ */ -/* +#+#+#+#+#+ +#+ */ -/* Created: 2024/12/23 18:28:59 by ycontre #+# #+# */ -/* Updated: 2024/12/23 18:29:00 by ycontre ### ########.fr */ -/* */ -/* ************************************************************************** */ -