From 075c2a959a5b4ecf7b51d36c297bdfbbe3a66b59 Mon Sep 17 00:00:00 2001 From: TheRedShip Date: Sat, 8 Mar 2025 20:36:10 +0100 Subject: [PATCH] + | Fog beam laser now in objects --- includes/RT.hpp | 1 + includes/RT/Object.hpp | 4 +- includes/RT/Scene.hpp | 4 +- includes/RT/objects/SpotLight.hpp | 68 +++++++++++++++++++++++ scenes/fog.rt | 24 +++++++++ scenes/window2.rt | 3 +- shaders/intersect.glsl | 2 +- shaders/light.glsl | 89 ++++++++++++++++++------------- srcs/class/Scene.cpp | 15 +++++- srcs/class/SceneParser.cpp | 7 ++- srcs/class/Window.cpp | 6 +-- 11 files changed, 172 insertions(+), 51 deletions(-) create mode 100644 includes/RT/objects/SpotLight.hpp create mode 100644 scenes/fog.rt diff --git a/includes/RT.hpp b/includes/RT.hpp index a1b83cf..cc7af33 100644 --- a/includes/RT.hpp +++ b/includes/RT.hpp @@ -74,6 +74,7 @@ struct GPUDenoise # include "objects/Cube.hpp" # include "objects/Portal.hpp" # include "objects/Cylinder.hpp" +# include "objects/SpotLight.hpp" # include "Buffer.hpp" # include "Arguments.hpp" diff --git a/includes/RT/Object.hpp b/includes/RT/Object.hpp index 95cea16..b57dfaf 100644 --- a/includes/RT/Object.hpp +++ b/includes/RT/Object.hpp @@ -47,7 +47,9 @@ class Object TRIANGLE, CUBE, PORTAL, - CYLINDER + CYLINDER, + SPOTLIGHT, + LASERBEAM }; virtual Type getType() const = 0; diff --git a/includes/RT/Scene.hpp b/includes/RT/Scene.hpp index acbd46a..df32536 100644 --- a/includes/RT/Scene.hpp +++ b/includes/RT/Scene.hpp @@ -6,7 +6,7 @@ /* By: ycontre +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/12/23 18:30:18 by ycontre #+# #+# */ -/* Updated: 2025/03/18 13:37:23 by tomoron ### ########.fr */ +/* Updated: 2025/03/18 16:47:45 by tomoron ### ########.fr */ /* */ /* ************************************************************************** */ @@ -117,7 +117,6 @@ class Scene bool loadTextures(); - void updateLightAndObjects(int mat_id); std::set getGPULights(); void addBvh(std::vector &triangles, glm::vec3 offset, float scale, glm::mat4 transform); @@ -147,6 +146,7 @@ class Scene void changeScene(std::string &name, std::vector &buffers); std::vector createDataOnGPU(void); + void updateLightAndObjects(int mat_id); private: void init(std::string &name); diff --git a/includes/RT/objects/SpotLight.hpp b/includes/RT/objects/SpotLight.hpp new file mode 100644 index 0000000..2ba834f --- /dev/null +++ b/includes/RT/objects/SpotLight.hpp @@ -0,0 +1,68 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* SpotLight.hpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: TheRed +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/03/08 18:50:04 by TheRed #+# #+# */ +/* Updated: 2025/03/08 18:50:04 by TheRed ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef RT_SPOTLIGHT__HPP +# define RT_SPOTLIGHT__HPP + +# include "RT.hpp" + +class SpotLight : public Object +{ + public: + SpotLight(std::stringstream &line) : Object(glm::vec3(0.0f), -1) + { + float x, y, z, radius; + float dir_x, dir_y, dir_z; + float angle; + + int mat_index; + + if (!(line >> x >> y >> z >> radius)) + throw std::runtime_error("Missing position or radius values"); + + if (radius <= 0.0f) + throw std::runtime_error("Radius must be positive"); + + if (!(line >> dir_x >> dir_y >> dir_z)) + throw std::runtime_error("Missing direction values"); + + if (!(line >> angle)) + throw std::runtime_error("Missing angle value"); + + if (!(line >> mat_index)) + throw std::runtime_error("Missing material properties"); + + _position = glm::vec3(x, y, z); + _radius = radius / 2.0; + + _direction = glm::normalize(glm::vec3(dir_x, dir_y, dir_z)); + _angle = angle; + + _mat_index = mat_index; + } + SpotLight(const glm::vec3& position, float radius, const int mat_index) + : Object(position, mat_index), _radius(radius) {} + + float getRadius() const { return (_radius); } + float getAngle() const { return (_angle); } + const glm::vec3 &getDirection() const { return (_direction); } + + Type getType() const override { return Type::SPOTLIGHT; } + + private: + float _radius; + + glm::vec3 _direction; + float _angle; +}; + +#endif \ No newline at end of file diff --git a/scenes/fog.rt b/scenes/fog.rt new file mode 100644 index 0000000..d7e5b27 --- /dev/null +++ b/scenes/fog.rt @@ -0,0 +1,24 @@ +CAM 0. 2.5 10. 5 -90 1.0 14 90 5 + +MAT 150 150 150 0.0 1.0 0.0 // 0 grey +MAT 200 200 200 0.0 1.0 0.0 // 1 white +MAT 255 255 255 0.0 1.0 1.0 // 2 reflective white + +MAT 255 50 50 3.0 2.0 0.0 // 3 red light +MAT 50 255 50 3.0 2.0 0.0 // 4 green light +MAT 50 50 255 3.0 2.0 0.0 // 5 blue light +MAT 255 255 255 3.0 2.0 0.0 // 6 white light + +OBJ obj/Dragon_800K.obj 0 2.2 -2 30 0 0 0 1 +# sp 0 1 -6 2 1 + +sl -10 20 -6 0.25 -0.5 1 0 0.95 3 +sl 0 20 -6 0.25 0 1 0 0.95 4 +sl 10 20 -6 0.25 0.5 1 0 0.95 5 + +qu -5 0.5 2.5 0 1 0 1 0 0.5 0 6 +qu 5 0.5 2.5 0 1 0 -1 0 0.5 0 6 + +pl 0 0 0 0 1 0 0 + + diff --git a/scenes/window2.rt b/scenes/window2.rt index 4e52591..5248bd5 100644 --- a/scenes/window2.rt +++ b/scenes/window2.rt @@ -5,7 +5,8 @@ MAT 150 150 150 0.0 1.0 0.0 //grey MAT 255 255 255 1.0 0.0 0.0 //light -sp -10 7 0 0.1 2 +sp -20 7 0 5 2 +sl -2 6 0 0.25 -0.5 1 0 0.99 2 # qu -5 0 -2.5 0 5 0 0 0 5 0 2 diff --git a/shaders/intersect.glsl b/shaders/intersect.glsl index 23fe42a..9f85371 100644 --- a/shaders/intersect.glsl +++ b/shaders/intersect.glsl @@ -205,7 +205,7 @@ bool intersectCylinder(Ray ray, GPUObject obj, out hitInfo hit) bool intersect(Ray ray, GPUObject obj, out hitInfo hit) { - if (obj.type == 0) + if (obj.type == 0 || obj.type == 7) return (intersectSphere(ray, obj, hit)); if (obj.type == 1) return (intersectPlane(ray, obj, hit)); diff --git a/shaders/light.glsl b/shaders/light.glsl index d094dff..857f884 100644 --- a/shaders/light.glsl +++ b/shaders/light.glsl @@ -20,6 +20,8 @@ vec3 GetEnvironmentLight(Ray ray) return composite; } +#define FOG_BOUNCE 0 + vec3 sampleSphereLight(vec3 position, GPUObject obj, int light_index, GPUMaterial mat, inout uint rng_state) { float theta = 2.0 * M_PI * randomValue(rng_state); @@ -37,46 +39,48 @@ vec3 sampleSphereLight(vec3 position, GPUObject obj, int light_index, GPUMateria Ray shadow_ray = Ray(position + light_dir * 0.001, light_dir, (1.0 / light_dir)); hitInfo shadow_hit = traceRay(shadow_ray); - vec3 dir = normalize(vec3(-0.5, 0.15, 0.)); - if (dot(shadow_ray.direction, dir) < 0.995 || shadow_hit.obj_index != light_index) + float beam_cos_angle = obj.vertex1.x; + vec3 dir = obj.normal; + + if (shadow_hit.obj_index != light_index || dot(shadow_ray.direction, dir) < beam_cos_angle) { - float circleRadius = light_dist * tan(acos(0.995)); + #if FOG_BOUNCE + float circleRadius = light_dist * tan(acos(beam_cos_angle)); - // Uniformly sample a point in a disk. - float r = circleRadius * sqrt(randomValue(rng_state)); - float theta = 2.0 * M_PI * randomValue(rng_state); - vec2 diskSample = vec2(r * cos(theta), r * sin(theta)); + float r = circleRadius * sqrt(randomValue(rng_state)); + float theta = 2.0 * M_PI * randomValue(rng_state); + vec2 diskSample = vec2(r * cos(theta), r * sin(theta)); - // Build an orthonormal basis for the plane perpendicular to 'dir'. - vec3 up = abs(dir.y) < 0.99 ? vec3(0, 1, 0) : vec3(1, 0, 0); - vec3 tangent = normalize(cross(up, dir)); - vec3 bitangent = cross(dir, tangent); + vec3 up = abs(dir.y) < 0.99 ? vec3(0, 1, 0) : vec3(1, 0, 0); + vec3 tangent = normalize(cross(up, dir)); + vec3 bitangent = cross(dir, tangent); - // Determine the center of the projected circle on the wall. - vec3 circleCenter = obj.position + light_dist * dir; + vec3 circleCenter = obj.position + light_dist * dir; - // Compute the final sample point on the projected circle. - vec3 sample_point = circleCenter + diskSample.x * tangent + diskSample.y * bitangent; + vec3 sample_point = circleCenter + diskSample.x * tangent + diskSample.y * bitangent; - Ray light_ray = Ray(sample_point, -dir, (1.0 / -dir)); - hitInfo light_ray_hit = traceRay(light_ray); + Ray light_ray = Ray(sample_point, -dir, (1.0 / -dir)); + hitInfo light_ray_hit = traceRay(light_ray); - if (light_ray_hit.obj_index == -1) - return (vec3(0.0)); + if (light_ray_hit.obj_index == -1) + return (vec3(0.0)); - GPUMaterial light_ray_mat = materials[light_ray_hit.mat_index]; - if (light_ray_mat.metallic == 0.) - return vec3(0.0); + GPUMaterial light_ray_mat = materials[light_ray_hit.mat_index]; + if (light_ray_mat.metallic == 0.) + return vec3(0.0); - Ray reflect_ray = newRay(light_ray_hit, light_ray, rng_state); - reflect_ray.inv_direction = 1.0 / reflect_ray.direction; + Ray reflect_ray = newRay(light_ray_hit, light_ray, rng_state); + reflect_ray.inv_direction = 1.0 / reflect_ray.direction; - vec3 reflect_to_particle = normalize(position - reflect_ray.origin); - - if (dot(reflect_ray.direction, reflect_to_particle) < 0.995) - return vec3(0.0); - mat.color *= light_ray_mat.color; - return mat.emission * mat.color * vec3(10.0); + vec3 reflect_to_particle = normalize(position - reflect_ray.origin); + + if (dot(reflect_ray.direction, reflect_to_particle) < beam_cos_angle) + return vec3(0.0); + + mat.color *= light_ray_mat.color; + #else + return vec3(0.); + #endif } float cos_theta = max(0.0, -dot(light_dir, normalize(sample_point - obj.position))); @@ -98,16 +102,28 @@ vec3 sampleQuadLight(vec3 position, GPUObject obj, int light_index, GPUMaterial if (shadow_hit.obj_index != light_index) return vec3(0.0); - vec3 dir = normalize(vec3(-0.5, 0., 0.)); - if (dot(shadow_ray.direction, dir) < 0.995) - return vec3(0.); + vec3 quad_to_camera = position - obj.position; + float distance_plane = dot(quad_to_camera, obj.normal); + vec3 point_projected = position - distance_plane * obj.normal; + + mat2 A = mat2( + dot(obj.vertex1, obj.vertex1), dot(obj.vertex1, obj.vertex2), + dot(obj.vertex1, obj.vertex2), dot(obj.vertex2, obj.vertex2) + ); + vec2 b = vec2( + dot(point_projected - obj.position, obj.vertex1), + dot(point_projected - obj.position, obj.vertex2) + ); + vec2 alphaBeta = inverse(A) * b; + + if (alphaBeta.x < 0.0f || alphaBeta.x > 1.0f || alphaBeta.y < 0.0f || alphaBeta.y > 1.0f) + return vec3(0.0); vec3 crossQuad = cross(obj.vertex1, obj.vertex2); float area = length(crossQuad); float pdf = 1.0 / area; - vec3 normal = normalize(crossQuad); - float cos_theta = max(0.0, dot(normal, -light_dir)); + float cos_theta = max(0.0, dot(obj.normal, -light_dir)); return mat.emission * mat.color / (light_dist * light_dist) * pdf; } @@ -119,10 +135,11 @@ vec3 sampleLights(in vec3 position, inout uint rng_state) GPUObject light_obj = objects[light_index]; GPUMaterial lightMat = materials[light_obj.mat_index]; - if (light_obj.type == 0) + if (light_obj.type == 7) return float(u_lightsNum) * sampleSphereLight(position, light_obj, light_index, lightMat, rng_state); else if (light_obj.type == 2) return float(u_lightsNum) * sampleQuadLight(position, light_obj, light_index, lightMat, rng_state); + return (vec3(0.)); } vec2 getSphereUV(vec3 surfacePoint) diff --git a/srcs/class/Scene.cpp b/srcs/class/Scene.cpp index f3f0bdb..e42c7ed 100644 --- a/srcs/class/Scene.cpp +++ b/srcs/class/Scene.cpp @@ -6,7 +6,7 @@ /* By: ycontre +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/12/23 18:29:41 by ycontre #+# #+# */ -/* Updated: 2025/03/18 13:37:16 by tomoron ### ########.fr */ +/* Updated: 2025/03/18 16:14:11 by tomoron ### ########.fr */ /* */ /* ************************************************************************** */ @@ -100,6 +100,9 @@ void Scene::addObject(Object *obj) gpu_obj.vertex2 = quad->getRight(); gpu_obj.normal = quad->getNormal(); gpu_obj.radius = quad->getSingleSided(); + + if (_gpu_materials[gpu_obj.mat_index].emission > 0.) + this->_gpu_lights.insert(_gpu_objects.size()); } else if (obj->getType() == Object::Type::CUBE) { @@ -121,6 +124,16 @@ void Scene::addObject(Object *obj) gpu_obj.vertex2 = triangle->getVertex3(); gpu_obj.normal = triangle->getNormal(); } + else if (obj->getType() == Object::Type::SPOTLIGHT) + { + auto spotlight = static_cast(obj); + + gpu_obj.radius = spotlight->getRadius(); + gpu_obj.normal = spotlight->getDirection(); + gpu_obj.vertex1 = glm::vec3(spotlight->getAngle(), 0.0f, 0.0f); + + this->_gpu_lights.insert(_gpu_objects.size()); + } else if (obj->getType() == Object::Type::PORTAL) { auto portal = static_cast(obj); diff --git a/srcs/class/SceneParser.cpp b/srcs/class/SceneParser.cpp index adf5d59..fa330ca 100644 --- a/srcs/class/SceneParser.cpp +++ b/srcs/class/SceneParser.cpp @@ -6,7 +6,7 @@ /* By: ycontre +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/12/26 21:43:51 by TheRed #+# #+# */ -/* Updated: 2025/02/04 01:21:11 by tomoron ### ########.fr */ +/* Updated: 2025/03/18 16:47:59 by tomoron ### ########.fr */ /* */ /* ************************************************************************** */ @@ -21,6 +21,7 @@ SceneParser::SceneParser(Scene *scene, std::string filename) : _scene(scene), _f object_parsers["cu"] = [](std::stringstream &ss) -> Object * { return (new Cube(ss)); }; object_parsers["po"] = [](std::stringstream &ss) -> Object * { return (new Portal(ss)); }; object_parsers["cy"] = [](std::stringstream &ss) -> Object * { return (new Cylinder(ss)); }; + object_parsers["sl"] = [](std::stringstream &ss) -> Object * { return (new SpotLight(ss)); }; } void SceneParser::parseMaterial(std::stringstream &line) @@ -165,14 +166,12 @@ bool SceneParser::parseLine(const std::string &line) Object *obj = it->second(ss); GPUMaterial mat = _scene->getMaterial(obj->getMaterialIndex()); //verify material + (void)mat; if (obj->getType() == Object::Type::PORTAL) _scene->addObject(static_cast(obj)->createSupportQuad()); _scene->addObject(obj); - - if (mat.emission > 0.0) - _scene->updateLightAndObjects(obj->getMaterialIndex()); } if (identifier == "MAT") diff --git a/srcs/class/Window.cpp b/srcs/class/Window.cpp index c0a2a9a..bc7a298 100644 --- a/srcs/class/Window.cpp +++ b/srcs/class/Window.cpp @@ -239,11 +239,7 @@ void Window::imGuiRender(ShaderProgram &raytracing_program) ImGui::Text("Material %d", i); has_changed |= ImGui::ColorEdit3("Color", &mat.color[0]); - if (ImGui::SliderFloat("Emission", &mat.emission, 0.0f, 10.0f)) - { - has_changed = 1; - _scene->updateLightAndObjects(i); - } + has_changed |= ImGui::SliderFloat("Emission", &mat.emission, 0.0f, 10.0f); if (mat.type == 0) {