Merge branch 'Fog-laser-beam'

This commit is contained in:
TheRedShip
2025-03-08 20:36:43 +01:00
13 changed files with 189 additions and 39 deletions

View File

@ -58,6 +58,7 @@ struct Vertex {
# include "objects/Cube.hpp"
# include "objects/Portal.hpp"
# include "objects/Cylinder.hpp"
# include "objects/SpotLight.hpp"
# include "Buffer.hpp"
# include "Arguments.hpp"

View File

@ -47,7 +47,9 @@ class Object
TRIANGLE,
CUBE,
PORTAL,
CYLINDER
CYLINDER,
SPOTLIGHT,
LASERBEAM
};
virtual Type getType() const = 0;

View File

@ -127,7 +127,6 @@ class Scene
bool loadTextures();
void updateLightAndObjects(int mat_id);
std::set<int> getGPULights();
void addBvh(std::vector<Triangle> &triangles, glm::vec3 offset, float scale, glm::mat4 transform);

View File

@ -0,0 +1,68 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* SpotLight.hpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: TheRed <TheRed@students.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* 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

24
scenes/fog.rt Normal file
View File

@ -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

View File

@ -7,5 +7,5 @@ MAT 255 255 255 1.0 0.0 0.0 LAM 0 // 1
# sp 0 2 0 150 1
# pl 0 0 0 0 1 0 0
OBJ obj/lambo2.obj 0 0 0 0.25
OBJ obj/castle.obj 0 0 0 1

View File

@ -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 -5 5 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
@ -17,6 +18,7 @@ qu -2.5 0 -2.5 0 5 0 5 0 0 0 0
qu -2.5 0 2.5 0 5 0 5 0 0 0 0
qu -2.5 5 -2.5 0 0 5 5 0 0 0 0
qu -2.5 0 -2.5 0 2.5 0 0 0 5 0 0
qu -2.5 3.5 -2.5 0 1.5 0 0 0 5 0 0

View File

@ -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));

View File

@ -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);
@ -36,9 +38,50 @@ 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);
float beam_cos_angle = obj.vertex1.x;
vec3 dir = obj.normal;
if (shadow_hit.obj_index != light_index)
return vec3(0.0);
if (shadow_hit.obj_index != light_index || dot(shadow_ray.direction, dir) < beam_cos_angle)
{
#if FOG_BOUNCE
float circleRadius = light_dist * tan(acos(beam_cos_angle));
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));
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 circleCenter = obj.position + light_dist * dir;
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);
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);
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) < 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)));
return mat.emission * mat.color / (light_dist * light_dist) * cos_theta / (4.0 * M_PI * (obj.radius / 2.0) * (obj.radius / 2.0));
@ -59,12 +102,28 @@ vec3 sampleQuadLight(vec3 position, GPUObject obj, int light_index, GPUMaterial
if (shadow_hit.obj_index != light_index)
return vec3(0.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;
}
@ -76,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)
@ -143,8 +203,10 @@ void calculateLightColor(GPUMaterial mat, hitInfo hit, inout vec3 color, inou
else
{
vec3 mat_color = (mat.type == 3) ? getCheckerboardColor(mat, hit) : mat.color;
color *= mat_color;
light += mat.emission * mat_color;
// if (mat.emission == 0.0)
// light += sampleLights(hit.position, rng_state);
}

View File

@ -44,11 +44,14 @@ void calculateVolumetricLight(float t_scatter, inout Ray ray, inout vec3 color,
transmittance *= exp(-volume.sigma_t * t_scatter);
color *= volume.sigma_s / volume.sigma_t;
light += transmittance * color * sampleLights(scatter_pos, rng_state);
vec3 direct_light = sampleLights(scatter_pos, rng_state);
float cos_theta = sampleHG(volume.g, rng_state);
vec3 new_dir = sampleDirection(ray.direction, cos_theta, rng_state);
ray.origin = scatter_pos;
ray.direction = new_dir;
ray.inv_direction = 1.0 / new_dir;
light += transmittance * color * direct_light;
}

View File

@ -94,6 +94,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)
{
@ -115,6 +118,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<SpotLight *>(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<Portal *>(obj);
@ -293,25 +306,9 @@ bool Scene::loadTextures()
return (true);
}
void Scene::updateLightAndObjects(int mat_id)
{
for (unsigned int i = 0; i < _gpu_objects.size(); i++)
{
if (_gpu_objects[i].mat_index == mat_id)
_gpu_lights.insert(i);
}
for (auto it = _gpu_lights.begin(); it != _gpu_lights.end(); )
{
if (_gpu_materials[_gpu_objects[*it].mat_index].emission <= 0.0)
it = _gpu_lights.erase(it);
else
++it;
}
}
bool Scene::fail(void) const
{
return(_fail);
return (_fail);
}
std::set<int> Scene::getGPULights()

View File

@ -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)
@ -170,9 +171,6 @@ bool SceneParser::parseLine(const std::string &line)
_scene->addObject(static_cast<Portal *>(obj)->createSupportQuad());
_scene->addObject(obj);
if (mat.emission > 0.0)
_scene->updateLightAndObjects(obj->getMaterialIndex());
}
if (identifier == "MAT")

View File

@ -231,11 +231,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)
{
@ -318,7 +314,6 @@ void Window::imGuiRender(ShaderProgram &raytracing_program)
has_changed |= ImGui::SliderInt("Triangle treshold", &_scene->getDebug().triangle_treshold, 1, 2000);
}
_renderer->renderImgui();
ImGui::End();
@ -326,7 +321,6 @@ void Window::imGuiRender(ShaderProgram &raytracing_program)
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
if (has_changed)
_frameCount = (accumulate == 0) - 1;
}