+ | Optimization + reflection

This commit is contained in:
TheRedShip
2025-01-02 16:33:21 +01:00
parent 21f2e84b61
commit 5d92a82b66
14 changed files with 204 additions and 101 deletions

View File

@ -37,6 +37,7 @@ struct Vertex {
# include "Object.hpp"
# include "objects/Sphere.hpp"
# include "objects/Plane.hpp"
# include "Camera.hpp"
# include "Window.hpp"

View File

@ -38,6 +38,7 @@ class Object
enum class Type {
SPHERE,
PLANE,
};
virtual Type getType() const = 0;

View File

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

View File

@ -41,8 +41,9 @@ class Window
GLFWwindow *_window;
Scene *_scene;
int _frameCount;
float _fps;
float _delta;
int _frameCount;
};

View File

@ -0,0 +1,54 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Plane.hpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: ycontre <ycontre@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* 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

View File

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

View File

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

39
shaders/intersect.glsl Normal file
View File

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

View File

@ -38,22 +38,18 @@ void Camera::update_camera_vectors()
void Camera::update(float delta_time)
{
_velocity += _acceleration * delta_time;
// std::cout << _acceleration.x << " " << _acceleration.y << " " << _acceleration.z << " " << std::endl;
delta_time = 0.016;
_velocity += _acceleration * delta_time;
// 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);
}

View File

@ -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<int>(obj->getType());
if (obj->getType() == Object::Type::SPHERE)
{
auto sphere = static_cast<const Sphere*>(obj);
auto sphere = static_cast<const Sphere *>(obj);
gpu_obj.radius = sphere->getRadius();
}
else if (obj->getType() == Object::Type::PLANE)
{
auto plane = static_cast<const Plane *>(obj);
gpu_obj.normal = plane->getNormal();
}
_gpu_objects.push_back(gpu_obj);
}

View File

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

View File

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

View File

@ -1,12 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* parsing.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: ycontre <ycontre@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/12/23 18:28:59 by ycontre #+# #+# */
/* Updated: 2024/12/23 18:29:00 by ycontre ### ########.fr */
/* */
/* ************************************************************************** */