diff --git a/Makefile b/Makefile index 1096c76..d1d0117 100644 --- a/Makefile +++ b/Makefile @@ -54,7 +54,7 @@ ALL_SRCS := $(IMGUI_SRCS) \ class/Scene.cpp \ class/SceneParser.cpp \ class/ObjParser.cpp \ - CLASS/BVH.cpp \ + class/BVH.cpp \ SRCS := $(ALL_SRCS:%=$(SRCS_DIR)/%) OBJS := $(addprefix $(OBJS_DIR)/, $(SRCS:%.cpp=%.o)) diff --git a/RT b/RT deleted file mode 100644 index a06a478..0000000 Binary files a/RT and /dev/null differ diff --git a/includes/RT/BVH.hpp b/includes/RT/BVH.hpp index 0d5e34f..9a2af8c 100644 --- a/includes/RT/BVH.hpp +++ b/includes/RT/BVH.hpp @@ -15,6 +15,9 @@ # include "RT.hpp" +struct GPUObject; +struct GPUBvh; + struct AABB { glm::vec3 min; @@ -23,7 +26,6 @@ struct AABB AABB(glm::vec3 min, glm::vec3 max) : min(min), max(max) {} }; -struct GPUObject; class BVH { @@ -36,7 +38,13 @@ class BVH void updateBounds(std::vector primitives); void subdivide(std::vector primitives); - const AABB &getAABB() const; + int size(); + + void flatten(std::vector &bvhs, int ¤tIndex); + GPUBvh toGPUBvh(); + + const AABB &getAABB() const; + std::vector getGPUBvhs(); private: diff --git a/includes/RT/Scene.hpp b/includes/RT/Scene.hpp index 45dd7ad..e5abf4e 100644 --- a/includes/RT/Scene.hpp +++ b/includes/RT/Scene.hpp @@ -54,6 +54,20 @@ struct GPUVolume int enabled; }; +struct GPUBvh +{ + alignas(16) glm::vec3 min; + alignas(16) glm::vec3 max; + + int left_index; + int right_index; + + int is_leaf; + + int first_primitive; + int primitive_count; +}; + class Sphere; class Camera; @@ -74,11 +88,14 @@ class Scene const std::vector &getObjectData() const; std::vector &getMaterialData(); GPUVolume &getVolume(); + std::vector &getBVH(); Camera *getCamera(void) const; GPUMaterial getMaterial(int material_index); private: + std::vector _gpu_bvh; + std::vector _gpu_objects; std::vector _gpu_materials; diff --git a/includes/RT/Shader.hpp b/includes/RT/Shader.hpp index 32da445..cd89d6b 100644 --- a/includes/RT/Shader.hpp +++ b/includes/RT/Shader.hpp @@ -25,8 +25,6 @@ class Shader void setupVertexBuffer(const Vertex* vertices, size_t size); void drawTriangles(size_t size); - - // void setBool(const std::string &name, bool value) const; void set_int(const std::string &name, int value) const; void set_float(const std::string &name, float value) const; diff --git a/includes/RT/objects/Triangle.hpp b/includes/RT/objects/Triangle.hpp index d47e0ee..a90b999 100644 --- a/includes/RT/objects/Triangle.hpp +++ b/includes/RT/objects/Triangle.hpp @@ -42,8 +42,8 @@ class Triangle : public Object _vertex2 = glm::vec3(x2, y2, z2); _vertex3 = glm::vec3(x3, y3, z3); - _vertex2 -= _position; //optimization - _vertex3 -= _position; //optimization + // _vertex2 -= _position; //optimization + // _vertex3 -= _position; //optimization _normal = glm::normalize(glm::cross(_vertex2, _vertex3)); //optimization @@ -51,8 +51,8 @@ class Triangle : public Object } Triangle(const glm::vec3& position, const glm::vec3& vertex2, const glm::vec3& vertex3, const int mat_index) : Object(position, mat_index), _vertex2(vertex2), _vertex3(vertex3) { - _vertex2 -= _position; //optimization - _vertex3 -= _position; //optimization + // _vertex2 -= _position; //optimization + // _vertex3 -= _position; //optimization _normal = glm::normalize(glm::cross(_vertex2, _vertex3)); //optimization } diff --git a/scenes/test.rt b/scenes/test.rt index 674db03..7598a7a 100644 --- a/scenes/test.rt +++ b/scenes/test.rt @@ -11,17 +11,18 @@ MAT 255 255 255 5.0 0.0 0.0 //light MAT 255 255 255 0.0 0.0 0.0 TRN // glass +# sp 0 -25 0 50 1 -sp 0 -25 0 50 4 +tr -4 5 0 -3 5 0 -4 5 1 0 +tr 0 7 2 1 4 2 0 5 3 0 +tr 3 7 2 4 5 1 2 6 3 0 -sp 1 1 -0.5 2 0 -sp -0.8 0.8 0 1.5 1 -sp -2.2 0.4 0.25 1 2 -sp -3 0.2 0.50 0.75 3 -sp -3.8 -0.1 0.60 0.5 5 +tr 7 5 0 8 5 0 7 5 1 0 +tr 7 7 2 8 4 2 7 5 3 0 +tr 10 7 2 11 5 1 8 6 3 0 +tr 15 -2 4 11 5 1 8 6 3 0 +tr 15 -2 4 11 5 1 7 5 9 0 +tr 12 4 4 4 3 1 7 5 9 0 -sp -0.071350 13.247917 0.518550 2 5 -cy 0 1 2 0.5 2 -1.5 0 0.75 1 - -OBJ obj/Lowpoly_tree_sample.obj +# OBJ obj/Lowpoly_tree_sample.obj diff --git a/shaders/bvh.glsl b/shaders/bvh.glsl new file mode 100644 index 0000000..c18e5e5 --- /dev/null +++ b/shaders/bvh.glsl @@ -0,0 +1,17 @@ + + +bool intersectRayBVH(Ray ray, GPUBvh node) +{ + vec3 invDir = 1.0 / ray.direction; + + vec3 t1 = (node.min - ray.origin) * invDir; + vec3 t2 = (node.max - ray.origin) * invDir; + + vec3 tMin = min(t1, t2); + vec3 tMax = max(t1, t2); + + float tEnter = max(max(tMin.x, tMin.y), tMin.z); + float tExit = min(min(tMax.x, tMax.y), tMax.z); + + return tEnter <= tExit && tExit >= 0.0; +} \ No newline at end of file diff --git a/shaders/compute.glsl b/shaders/compute.glsl index 4f1bce4..74806f7 100644 --- a/shaders/compute.glsl +++ b/shaders/compute.glsl @@ -161,7 +161,6 @@ hitInfo traceRay(Ray ray) ray = portalRay(ray, hit); } - return (hit); } diff --git a/shaders/debug.glsl b/shaders/debug.glsl new file mode 100644 index 0000000..2d33522 --- /dev/null +++ b/shaders/debug.glsl @@ -0,0 +1,204 @@ +#version 430 core + +layout(local_size_x = 16, local_size_y = 16) in; +layout(binding = 0, rgba32f) uniform image2D output_image; +layout(binding = 1, rgba32f) uniform image2D accumulation_image; + +struct GPUCamera +{ + mat4 view_matrix; + vec3 position; + + float aperture_size; + float focus_distance; + float fov; + + int bounce; +}; +layout(std140, binding = 0) uniform CameraData +{ + GPUCamera camera; +}; + +struct GPUObject { + mat4 rotation; + + vec3 position; // 12 + 4 + + vec3 normal; // 12 + 4 + + vec3 vertex1; // 12 + 4 + vec3 vertex2; // 12 + 4 + + float radius; // 4 + + int mat_index; // 4 + int type; // 4 +}; +layout(std430, binding = 1) buffer ObjectBuffer +{ + GPUObject objects[]; +}; + + +struct GPUBvh +{ + vec3 min; + vec3 max; + + int left_index; + int right_index; + + int is_leaf; + + int first_primitive; + int primitive_count; +}; +layout(std430, binding = 4) buffer BvhBuffer +{ + GPUBvh bvh[]; +}; + +uniform int u_objectsNum; +uniform int u_bvhNum; +uniform vec2 u_resolution; +uniform int u_frameCount; +uniform float u_time; + +struct Ray +{ + vec3 origin; + vec3 direction; +}; + +struct hitInfo +{ + float t; + float last_t; + vec3 normal; + vec3 position; + int obj_index; +}; + +#include "shaders/intersect.glsl" +#include "shaders/bvh.glsl" + +int traceRay(Ray ray) +{ + int num_hit; + + num_hit = 0; + for (int i = 0; i < u_objectsNum; i++) + { + GPUObject obj = objects[i]; + + hitInfo temp_hit; + if (intersect(ray, obj, temp_hit)) + num_hit++; + } + + return (num_hit); +} + + +int traceBVHBad(Ray ray) +{ + int num_hit; + + num_hit = 0; + for (int i = 0; i < u_bvhNum; i++) + { + GPUBvh node = bvh[i]; + + if (intersectRayBVH(ray, node)) + { + // num_hit++; + for (int i = 0; i < node.primitive_count; i++) + { + GPUObject obj = objects[node.first_primitive + i]; + + hitInfo tmp; + if (intersect(ray, obj, tmp)) + num_hit++; + } + } + } + + return (num_hit); +} + +int traceBVH(Ray ray) +{ + int num_hit = 0; + + const int MAX_STACK_SIZE = 64; + int stack[MAX_STACK_SIZE]; + int stack_ptr = 0; + + stack[0] = 0; + + vec3 inv_dir = 1.0 / ray.direction; + + while (stack_ptr >= 0) + { + int current_index = stack[stack_ptr--]; + + GPUBvh node = bvh[current_index]; + + if (intersectRayBVH(ray, node)) + { + num_hit++; + + if (node.is_leaf != 0) + { + for (int i = 0; i < node.primitive_count; i++) + { + GPUObject obj = objects[node.first_primitive + i]; + + hitInfo tmp; + if (intersect(ray, obj, tmp)) + num_hit++; + } + } + + if (node.is_leaf == 0 && stack_ptr < MAX_STACK_SIZE - 2) + { + stack_ptr++; + stack[stack_ptr] = node.left_index; + stack_ptr++; + stack[stack_ptr] = node.right_index; + } + } + } + + return (num_hit); +} + + +Ray initRay(vec2 uv) +{ + float fov = camera.fov; + float focal_length = 1.0 / tan(radians(fov) / 2.0); + + vec3 origin = camera.position; + vec3 view_space_ray = normalize(vec3(uv.x, uv.y, -focal_length)); + vec3 ray_direction = normalize((inverse(camera.view_matrix) * vec4(view_space_ray, 0.0)).xyz); + + return (Ray(origin, ray_direction)); +} + +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(pixel_coords)) / u_resolution) * 2.0 - 1.0;; + uv.x *= u_resolution.x / u_resolution.y; + + Ray ray = initRay(uv); + int hits = traceBVH(ray); + + vec3 color = vec3(float(hits) / float(10)); + imageStore(output_image, pixel_coords, vec4(color, 1.)); +} \ No newline at end of file diff --git a/shaders/intersect.glsl b/shaders/intersect.glsl index ca74177..cfdf23a 100644 --- a/shaders/intersect.glsl +++ b/shaders/intersect.glsl @@ -68,15 +68,18 @@ bool intersectQuad(Ray ray, GPUObject obj, out hitInfo hit) } bool intersectTriangle(Ray ray, GPUObject obj, out hitInfo hit) { - vec3 pvec = cross(ray.direction, obj.vertex2); - float det = dot(obj.vertex1, pvec); + vec3 vertex1 = obj.vertex1 - obj.position; + vec3 vertex2 = obj.vertex2 - obj.position; + + vec3 pvec = cross(ray.direction, vertex2); + float det = dot(vertex1, pvec); vec3 tvec = ray.origin - obj.position; float invDet = 1.0 / det; float u = dot(tvec, pvec) * invDet; - vec3 qvec = cross(tvec, obj.vertex1); + vec3 qvec = cross(tvec, vertex1); float v = dot(ray.direction, qvec) * invDet; - float t = dot(obj.vertex2, qvec) * invDet; + float t = dot(vertex2, qvec) * invDet; bool valid = abs(det) > 1e-8 && u >= 0.0 && u <= 1.0 && diff --git a/srcs/RT.cpp b/srcs/RT.cpp index 62d5e6f..c5891ac 100644 --- a/srcs/RT.cpp +++ b/srcs/RT.cpp @@ -20,7 +20,8 @@ int main(int argc, char **argv) return (1); Window window(&scene, WIDTH, HEIGHT, "RT_GPU", 0); - Shader shader("shaders/vertex.vert", "shaders/frag.frag", "shaders/compute.glsl"); + // Shader shader("shaders/vertex.vert", "shaders/frag.frag", "shaders/compute.glsl"); + Shader shader("shaders/vertex.vert", "shaders/frag.frag", "shaders/debug.glsl"); GLint max_gpu_size; glGetIntegerv(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, &max_gpu_size); @@ -51,6 +52,12 @@ int main(int argc, char **argv) glBufferData(GL_SHADER_STORAGE_BUFFER, scene.getGPULights().size() * sizeof(int), nullptr, GL_STATIC_DRAW); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, lightSSBO); + GLuint bvhSSBO; + glGenBuffers(1, &bvhSSBO); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, bvhSSBO); + glBufferData(GL_SHADER_STORAGE_BUFFER, scene.getBVH().size() * sizeof(GPUBvh), nullptr, GL_STATIC_DRAW); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, bvhSSBO); + GLuint cameraUBO; glGenBuffers(1, &cameraUBO); @@ -86,6 +93,11 @@ int main(int argc, char **argv) glBindBuffer(GL_SHADER_STORAGE_BUFFER, lightSSBO); glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, gpu_lights_array.size() * sizeof(int), gpu_lights_array.data()); + std::vector gpu_bvh = scene.getBVH(); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, bvhSSBO); + glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, gpu_bvh.size() * sizeof(GPUBvh), gpu_bvh.data()); + + GPUCamera camera_data = scene.getCamera()->getGPUData(); glBindBuffer(GL_UNIFORM_BUFFER, cameraUBO); glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(GPUCamera), &camera_data); @@ -96,6 +108,7 @@ int main(int argc, char **argv) shader.set_int("u_frameCount", window.getFrameCount()); shader.set_int("u_objectsNum", object_data.size()); + shader.set_int("u_bvhNum", gpu_bvh.size()); shader.set_int("u_lightsNum", gpu_lights.size()); shader.set_int("u_pixelisation", window.getPixelisation()); shader.set_float("u_time", (float)(glfwGetTime())); diff --git a/srcs/class/BVH.cpp b/srcs/class/BVH.cpp index 99d4c84..160fb3b 100644 --- a/srcs/class/BVH.cpp +++ b/srcs/class/BVH.cpp @@ -34,12 +34,6 @@ void BVH::updateBounds(std::vector primitives) if (leaf_triangle.type != (int)Object::Type::TRIANGLE) continue ; - - if (leaf_triangle.type == (int)Object::Type::TRIANGLE) - { - leaf_triangle.vertex1 += leaf_triangle.position; - leaf_triangle.vertex2 += leaf_triangle.position; - } _aabb.min = glm::min(_aabb.min, leaf_triangle.position); _aabb.min = glm::min(_aabb.min, leaf_triangle.vertex1); @@ -63,7 +57,7 @@ void BVH::subdivide(std::vector primitives) if (extent.y > extent.x) axis = 1; if (extent.z > extent[axis]) axis = 2; - glm::vec3 split_pos = _aabb.min + extent[axis] * 0.5f; + float split_pos = _aabb.min[axis] + extent[axis] * 0.5f; int i = _first_primitive; int j = _first_primitive + _primitive_count - 1; @@ -73,7 +67,7 @@ void BVH::subdivide(std::vector primitives) glm::vec3 centroid = primitives[i].position + primitives[i].vertex1 + primitives[i].vertex2; centroid /= 3.0f; - if (centroid[axis] < split_pos[axis]) + if (centroid[axis] < split_pos) i++; else { @@ -103,7 +97,6 @@ void BVH::showAABB(Scene *scene) { if (_is_leaf) { - scene->addObject(new Sphere(_aabb.min, 0.5f, 6)); scene->addObject(new Sphere(_aabb.max, 0.5f, 6)); scene->addObject(new Sphere(glm::vec3(_aabb.min.x, _aabb.min.y, _aabb.max.z), 0.5f, 6)); @@ -112,7 +105,6 @@ void BVH::showAABB(Scene *scene) scene->addObject(new Sphere(glm::vec3(_aabb.min.x, _aabb.max.y, _aabb.max.z), 0.5f, 6)); scene->addObject(new Sphere(glm::vec3(_aabb.max.x, _aabb.min.y, _aabb.max.z), 0.5f, 6)); scene->addObject(new Sphere(glm::vec3(_aabb.max.x, _aabb.max.y, _aabb.min.z), 0.5f, 6)); - } else { @@ -124,4 +116,60 @@ void BVH::showAABB(Scene *scene) const AABB &BVH::getAABB() const { return (_aabb); +} + +GPUBvh BVH::toGPUBvh() +{ + GPUBvh bvh; + + bvh.is_leaf = _is_leaf; + bvh.first_primitive = _first_primitive; + bvh.primitive_count = _primitive_count; + bvh.max = _aabb.max; + bvh.min = _aabb.min; + + return (bvh); +} + +void BVH::flatten(std::vector &bvhs, int ¤tIndex) +{ + GPUBvh self_bvh = toGPUBvh(); + int self_index = currentIndex++; + + self_bvh.left_index = -1; + self_bvh.right_index = -1; + + if (!_is_leaf) + { + self_bvh.left_index = currentIndex; + _left->flatten(bvhs, currentIndex); + + self_bvh.right_index = currentIndex; + _right->flatten(bvhs, currentIndex); + } + + bvhs[self_index] = self_bvh; +} + +int BVH::size() +{ + int count = 0; + + if (_is_leaf) + return (0); + + count += 1 + _left->size(); + count += 1 + _right->size(); + + return (count); +} + +std::vector BVH::getGPUBvhs() +{ + std::vector bvhs(size() + 1); + + int currentIndex = 0; + flatten(bvhs, currentIndex); + + return (bvhs); } \ No newline at end of file diff --git a/srcs/class/Scene.cpp b/srcs/class/Scene.cpp index 205808e..1b8a099 100644 --- a/srcs/class/Scene.cpp +++ b/srcs/class/Scene.cpp @@ -53,11 +53,11 @@ bool Scene::parseScene(char *name) } file.close(); - //bvh - BVH *bvh = new BVH(_gpu_objects, 0, _gpu_objects.size()); - bvh->showAABB(this); - // addObject(new Cube((bvh->getAABB().max + bvh->getAABB().min) / 2.0f, bvh->getAABB().max - bvh->getAABB().min, 7)); - // + BVH *bvh = new BVH(_gpu_objects, 0, _gpu_objects.size()); + _gpu_bvh = bvh->getGPUBvhs(); + + // bvh->showAABB(this); + return (true); } @@ -162,27 +162,32 @@ void Scene::updateLightAndObjects(int mat_id) } } -std::set Scene::getGPULights() +std::set Scene::getGPULights() { return (_gpu_lights); } -const std::vector& Scene::getObjectData() const +const std::vector &Scene::getObjectData() const { return (_gpu_objects); } -std::vector& Scene::getMaterialData() +std::vector &Scene::getMaterialData() { return (_gpu_materials); } -GPUVolume &Scene::getVolume() +GPUVolume &Scene::getVolume() { return (_gpu_volume); } -Camera *Scene::getCamera(void) const +std::vector &Scene::getBVH() +{ + return (_gpu_bvh); +} + +Camera *Scene::getCamera(void) const { return (_camera); } @@ -192,4 +197,4 @@ GPUMaterial Scene::getMaterial(int material_index) if (material_index < 0 || material_index >= (int)_gpu_materials.size()) throw std::runtime_error("Incorrect material index"); return (_gpu_materials[material_index]); -} \ No newline at end of file +}