diff --git a/includes/RT.hpp b/includes/RT.hpp index 3a7c4cf..14501c8 100644 --- a/includes/RT.hpp +++ b/includes/RT.hpp @@ -22,7 +22,6 @@ # include "glad/gl.h" # include "GLFW/glfw3.h" -# include "ShadInclude.hpp" # include # include diff --git a/includes/RT/Shader.hpp b/includes/RT/Shader.hpp index 73d8609..3fe1740 100644 --- a/includes/RT/Shader.hpp +++ b/includes/RT/Shader.hpp @@ -45,7 +45,8 @@ class Shader GLuint _program; GLuint _program_compute; - GLuint _outputTexture; + GLuint _output_texture; + GLuint _accumulation_texture; GLuint _vertex; GLuint _fragment; diff --git a/scenes/test.rt b/scenes/test.rt index df13bcd..7a1cb9c 100644 --- a/scenes/test.rt +++ b/scenes/test.rt @@ -1,10 +1,11 @@ MAT 255 255 255 0.0 1.0 2.0 MAT 255 255 255 1.0 1.0 2.0 +MAT 255 0 0 0.0 1.0 2.0 -sp 0 -1 -6 1.0 0 - -sp 0 5 -6 3.0 1 +sp 0 -50 -6 50.0 0 +sp 50 30 -6 30.0 1 +sp 0 1 -2 1.5 2 R 1.0 -2.0 10 diff --git a/shaders/compute.glsl b/shaders/compute.glsl index 4be4df4..80b171f 100644 --- a/shaders/compute.glsl +++ b/shaders/compute.glsl @@ -1,11 +1,10 @@ #version 430 core -#include "shaders/utils.glsl" -// Work group dimensions +#include "shaders/random.glsl" + layout(local_size_x = 16, local_size_y = 16) in; - -// Output image layout(binding = 0, rgba32f) uniform image2D outputImage; +layout(binding = 1, rgba32f) uniform image2D accumulationImage; struct GPUObject { vec3 position; // 12 + 4 @@ -31,53 +30,100 @@ uniform int u_frameCount; vec3 lightPos = vec3(5.0, 5.0, 5.0); vec3 lightColor = vec3(1.0, 1.0, 1.0); -struct Ray { +struct Ray +{ vec3 origin; vec3 direction; }; -bool intersectSphere(Ray ray, vec3 center, float radius, out float t) +struct hitInfo { - vec3 oc = ray.origin - center; + float t; + vec3 normal; + vec3 position; + 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) - radius * radius; + float c = dot(oc, oc) - obj.radius * obj.radius; float discriminant = b * b - 4.0 * a * c; - if (discriminant < 0.0) { + if (discriminant < 0.0) return false; - } - float t1 = (-b - sqrt(discriminant)) / (2.0 * a); - if (t1 > 0.001) { - t = t1; - return true; - } - 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); } -vec3 pathtrace(Ray ray) +hitInfo trace_ray(Ray ray) { - vec3 color = vec3(0.0); - vec3 light = vec3(0.0); + hitInfo hit; + hit.t = 1e30; + hit.obj_index = -1; - float closest_t = 1e30; for (int i = 0; i < u_objectsNum; i++) { - float t; - if (intersectSphere(ray, objects[i].position, objects[i].radius, t)) - { - if (t < closest_t) - { - closest_t = t; + GPUObject obj = objects[i]; - vec3 hitPoint = ray.origin + t * ray.direction; - vec3 normal = normalize(hitPoint - objects[i].position); - - color = objects[i].color * normal.y; + hitInfo tempHit; + if (intersectSphere(ray, obj, tempHit)) + { + 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; } } } - return (color); + + return (hit); +} + +vec3 pathtrace(Ray ray, vec2 random) +{ + vec3 color = vec3(1.0); + vec3 light = vec3(0.0); + + float closest_t = 1e30; + for (int i = 0; i < 10; i++) + { + hitInfo hit = trace_ray(ray); + if (hit.obj_index == -1) + { + light += vec3(0); //ambient color + break; + } + + GPUObject obj = objects[hit.obj_index]; + + color *= obj.color; + if (obj.emission > 0.0) + { + light += obj.emission * obj.color; + break; + } + + ray.origin = hit.position + hit.normal * 0.001; + //cosine weighted importance sampling + vec3 unit_sphere = normalize(randomVec3Mixed(random, u_frameCount, -1.0, 1.0)); + if (dot(unit_sphere, hit.normal) < 0.0) + unit_sphere = -unit_sphere; + ray.direction = normalize(hit.normal + unit_sphere); + } + return (color * light); } void main() { @@ -97,8 +143,13 @@ void main() { rayDirection = normalize(rayDirection); Ray ray = Ray(u_cameraPosition, rayDirection); - vec3 color = pathtrace(ray); + vec3 color = pathtrace(ray, uv); - imageStore(outputImage, pixelCoords, vec4(randomVec3(uv, u_frameCount), 1.0)); + vec4 accum = imageLoad(accumulationImage, pixelCoords); + accum.rgb = accum.rgb * float(u_frameCount) / float(u_frameCount + 1) + color / float(u_frameCount + 1); + accum.a = 1.0; + + imageStore(accumulationImage, pixelCoords, accum); + imageStore(outputImage, pixelCoords, accum); } diff --git a/shaders/random.glsl b/shaders/random.glsl new file mode 100644 index 0000000..832ce58 --- /dev/null +++ b/shaders/random.glsl @@ -0,0 +1,28 @@ + +float seed = 1.0; +float getRandom(vec2 uv, int frameCount) +{ + float seed = dot(uv, vec2(12.9898, 78.233)) + float(frameCount); + return fract(sin(seed) * 43758.5453); +} +vec3 randomVec3(vec2 uv, int frameCount) +{ + return vec3( + getRandom(uv + vec2(0.1, 0.1), frameCount), + getRandom(uv + vec2(0.2, 0.2), frameCount), + getRandom(uv + vec2(0.3, 0.3), frameCount) + ); +} + +vec3 randomVec3Mixed(vec2 uv, int frameCount, float min_val, float max_val) +{ + float randomX = getRandom(uv + vec2(0.1, 0.1), frameCount); + float randomY = getRandom(uv + vec2(0.2, 0.2), frameCount); + float randomZ = getRandom(uv + vec2(0.3, 0.3), frameCount); + + return vec3( + mix(min_val, max_val, randomX), + mix(min_val, max_val, randomY), + mix(min_val, max_val, randomZ) + ); +} \ No newline at end of file diff --git a/shaders/utils.glsl b/shaders/utils.glsl deleted file mode 100644 index c009a05..0000000 --- a/shaders/utils.glsl +++ /dev/null @@ -1,15 +0,0 @@ - -float seed = 1.0; -float getRandom(vec2 uv, int frameCount) -{ - float seed = dot(uv, vec2(12.9898, 78.233)) + float(frameCount); - return fract(sin(seed) * 43758.5453); -} -vec3 randomVec3(vec2 uv, int frameCount) -{ - return vec3( - getRandom(uv + vec2(0.1, 0.1), frameCount), - getRandom(uv + vec2(0.2, 0.2), frameCount), - getRandom(uv + vec2(0.3, 0.3), frameCount) - ); -} \ No newline at end of file diff --git a/srcs/RT.cpp b/srcs/RT.cpp index 62c72c9..52a2200 100644 --- a/srcs/RT.cpp +++ b/srcs/RT.cpp @@ -21,20 +21,6 @@ int main(int argc, char **argv) Window window(&scene, WIDTH, HEIGHT, "RT_GPU", 1); Shader shader("shaders/vertex.vert", "shaders/frag.frag", "shaders/compute.glsl"); - - // Material redMaterial = {glm::vec3(1.0f, 0.2f, 0.2f), 1.0, 1.0, 0.0}; - // scene.addMaterial(&redMaterial); - - // for (int i = 0; i < 150; i++) - // { - // float angle = (2.0f * M_PI * i) / 150.0f; - // float x = 30.0f * cos(angle); - // float z = 30.0f * sin(angle); - // float y = 2.0f * sin(angle * 3.0f); - // glm::vec3 position(x, y, z); - // float sphereSize = 0.8f + 0.4f * sin(angle * 2.0f); - // scene.addObject(new Sphere(position, sphereSize, 0)); - // } GLuint objectSSBO; glGenBuffers(1, &objectSSBO); diff --git a/srcs/class/Shader.cpp b/srcs/class/Shader.cpp index 7caddf7..5a80c75 100644 --- a/srcs/class/Shader.cpp +++ b/srcs/class/Shader.cpp @@ -54,6 +54,8 @@ Shader::Shader(std::string vertexPath, std::string fragmentPath, std::string com const char *fragmentCode = loadFileWithIncludes(fragmentPath); const char *computeCode = loadFileWithIncludes(computePath); + std::cout << computeCode << std::endl; + _vertex = glCreateShader(GL_VERTEX_SHADER); glShaderSource(_vertex, 1, &vertexCode, NULL); @@ -90,7 +92,6 @@ void Shader::attach(void) _program = glCreateProgram(); _program_compute = glCreateProgram(); - glAttachShader(_program, _vertex); glAttachShader(_program, _fragment); glAttachShader(_program_compute, _compute); @@ -98,14 +99,23 @@ void Shader::attach(void) glLinkProgram(_program); glLinkProgram(_program_compute); - glGenTextures(1, &_outputTexture); - glBindTexture(GL_TEXTURE_2D, _outputTexture); + glGenTextures(1, &_output_texture); + glBindTexture(GL_TEXTURE_2D, _output_texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, WIDTH, HEIGHT, 0, GL_RGBA, GL_FLOAT, NULL); - glBindImageTexture(0, _outputTexture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F); + glBindImageTexture(0, _output_texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F); + + glGenTextures(1, &_accumulation_texture); + glBindTexture(GL_TEXTURE_2D, _accumulation_texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, WIDTH, HEIGHT, 0, GL_RGBA, GL_FLOAT, NULL); + glBindImageTexture(1, _accumulation_texture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F); } void Shader::checkCompileErrors(GLuint shader) @@ -146,7 +156,7 @@ void Shader::setupVertexBuffer(const Vertex* vertices, size_t size) void Shader::drawTriangles(size_t size) { glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, _outputTexture); + glBindTexture(GL_TEXTURE_2D, _output_texture); glUniform1i(glGetUniformLocation(_program, "screenTexture"), 0); glBindVertexArray(_screen_VAO); diff --git a/srcs/class/Window.cpp b/srcs/class/Window.cpp index feee016..8117cf3 100644 --- a/srcs/class/Window.cpp +++ b/srcs/class/Window.cpp @@ -64,6 +64,8 @@ void Window::process_input() bool up = glfwGetKey(_window, GLFW_KEY_SPACE) == GLFW_PRESS; bool down = glfwGetKey(_window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS; + if (forward || backward || left || right || up || down) + _frameCount = 0; _scene->getCamera()->process_keyboard(forward, backward, left, right, up, down); }