diff --git a/includes/RT.hpp b/includes/RT.hpp index 2a88240..c1016e9 100644 --- a/includes/RT.hpp +++ b/includes/RT.hpp @@ -16,6 +16,7 @@ # define WIDTH 1920 # define HEIGHT 1080 + # include "glm/glm.hpp" # include "glm/gtc/matrix_transform.hpp" # include "glm/gtc/type_ptr.hpp" @@ -23,8 +24,14 @@ # include "glad/gl.h" # include "GLFW/glfw3.h" + # include +struct Vertex { + glm::vec2 position; + glm::vec2 texCoord; +}; + # include "Camera.hpp" # include "Window.hpp" # include "Shader.hpp" diff --git a/includes/RT/Object.hpp b/includes/RT/Object.hpp index b13ae92..204d9c4 100644 --- a/includes/RT/Object.hpp +++ b/includes/RT/Object.hpp @@ -13,6 +13,8 @@ #ifndef RT_OBJECT__HPP # define RT_OBJECT__HPP +#include "RT.hpp" + class Object { public: diff --git a/includes/RT/Shader.hpp b/includes/RT/Shader.hpp index 723306f..dc8759c 100644 --- a/includes/RT/Shader.hpp +++ b/includes/RT/Shader.hpp @@ -18,15 +18,12 @@ class Shader { public: - Shader(std::string vertexPath, std::string fragmentPath); - Shader(Shader const &src); + Shader(std::string vertexPath, std::string fragmentPath, std::string computePath); ~Shader(void); - Shader &operator=(Shader const &rhs); - // void compile(const char *vertexSource, const char *fragmentSource); void attach(void); - void setupVertexBuffer(const glm::vec2* vertices, size_t size); + void setupVertexBuffer(const Vertex* vertices, size_t size); void drawTriangles(size_t size); @@ -40,15 +37,20 @@ class Shader void set_mat4(const std::string &name, const glm::mat4 &value) const; GLuint getProgram(void) const; + GLuint getProgramCompute(void) const; private: GLuint _screen_VAO, _screen_VBO; GLuint _program; + GLuint _program_compute; + + GLuint _outputTexture; GLuint _vertex; GLuint _fragment; + GLuint _compute; void checkCompileErrors(unsigned int shader); }; diff --git a/shaders/compute.glsl b/shaders/compute.glsl new file mode 100644 index 0000000..b624d33 --- /dev/null +++ b/shaders/compute.glsl @@ -0,0 +1,79 @@ +#version 430 core + +// Work group dimensions +layout(local_size_x = 16, local_size_y = 16) in; + +// Output image +layout(binding = 0, rgba32f) uniform image2D outputImage; + +// Uniforms for camera and scene +uniform vec2 u_resolution; +uniform vec3 u_cameraPosition; +uniform mat4 u_viewMatrix; +vec3 lightPos = vec3(5.0, 5.0, 5.0); +vec3 lightColor = vec3(1.0, 1.0, 1.0); + +// Scene definition +vec3 sphereCenter = vec3(0.0, 0.0, -5.0); +float sphereRadius = 1.0; +vec3 objectColor = vec3(0.4, 0.7, 0.9); + +struct Ray { + vec3 origin; + vec3 direction; +}; + +bool intersectSphere(Ray ray, vec3 center, float radius, out float t) { + vec3 oc = ray.origin - center; + float a = dot(ray.direction, ray.direction); + float b = 2.0 * dot(oc, ray.direction); + float c = dot(oc, oc) - radius * radius; + float discriminant = b * b - 4.0 * a * c; + + if (discriminant < 0.0) { + return false; + } else { + t = (-b - sqrt(discriminant)) / (2.0 * a); + return true; + } +} + +vec3 computeLighting(vec3 point, vec3 normal, vec3 viewDir) { + vec3 lightDir = normalize(lightPos - point); + float diff = max(dot(normal, lightDir), 0.0); + vec3 diffuse = diff * lightColor; + return objectColor * diffuse; +} + +void main() { + // Compute pixel coordinates + ivec2 pixelCoords = ivec2(gl_GlobalInvocationID.xy); + if (pixelCoords.x >= int(u_resolution.x) || pixelCoords.y >= int(u_resolution.y)) { + return; + } + + vec2 uv = vec2(pixelCoords) / u_resolution; + uv = uv * 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 rayDirection = (inverse(u_viewMatrix) * vec4(viewSpaceRay, 0.0)).xyz; + rayDirection = normalize(rayDirection); + Ray ray = Ray(u_cameraPosition, rayDirection); + + float t; + vec4 color = vec4(0.0, 0.0, 0.0, 1.0); + if (intersectSphere(ray, sphereCenter, sphereRadius, t)) { + vec3 hitPoint = ray.origin + t * ray.direction; + vec3 normal = normalize(hitPoint - sphereCenter); + vec3 viewDir = normalize(-ray.direction); + vec3 lighting = computeLighting(hitPoint, normal, viewDir); + color = vec4(lighting, 1.0); + } + + // Write to the output image + imageStore(outputImage, pixelCoords, color); +} \ No newline at end of file diff --git a/shaders/frag.frag b/shaders/frag.frag index 71afa8f..017073a 100644 --- a/shaders/frag.frag +++ b/shaders/frag.frag @@ -1,85 +1,9 @@ #version 430 core -out vec4 FragColor; +in vec2 TexCoords; +out vec4 FragColor; -uniform vec2 u_resolution; -uniform vec3 u_cameraPosition; -uniform mat4 u_viewMatrix; -uniform mat4 u_projectionMatrix; +uniform sampler2D screenTexture; -uniform vec3 u_cameraDir; - -vec3 sphereCenter = vec3(0.0, 0.0, -5.0); -float sphereRadius = 1.0; - - -vec3 lightPos = vec3(5.0, 5.0, 5.0); -vec3 lightColor = vec3(1.0, 1.0, 1.0); -vec3 objectColor = vec3(0.4, 0.7, 0.9); - - -struct Ray { - vec3 origin; - vec3 direction; -}; - - -bool intersectSphere(Ray ray, vec3 center, float radius, out float t) { - vec3 oc = ray.origin - center; - float a = dot(ray.direction, ray.direction); - float b = 2.0 * dot(oc, ray.direction); - float c = dot(oc, oc) - radius * radius; - float discriminant = b * b - 4.0 * a * c; - - if (discriminant < 0.0) { - return false; - } else { - t = (-b - sqrt(discriminant)) / (2.0 * a); - return true; - } -} - - -vec3 computeLighting(vec3 point, vec3 normal, vec3 viewDir) { - vec3 lightDir = normalize(lightPos - point); - float diff = max(dot(normal, lightDir), 0.0); - - - vec3 diffuse = diff * lightColor; - - - return objectColor * diffuse; -} - - -void main() -{ - vec2 uv; - vec4 color; - - uv = gl_FragCoord.xy / u_resolution.xy; - uv = uv * 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 rayDirection = (inverse(u_viewMatrix) * vec4(viewSpaceRay, 0.0)).xyz; - rayDirection = normalize(rayDirection); - Ray ray = Ray(u_cameraPosition, rayDirection); - - float t; - if (intersectSphere(ray, sphereCenter, sphereRadius, t)) - { - vec3 hitPoint = ray.origin + t * ray.direction; - vec3 normal = normalize(hitPoint - sphereCenter); - - vec3 viewDir = normalize(-ray.direction); - - vec3 color = computeLighting(hitPoint, normal, viewDir); - FragColor = vec4(color, 1.0); - } else { - FragColor = vec4(0., 0.0, 0.0, 1.0); - } +void main() { + FragColor = texture(screenTexture, TexCoords); } \ No newline at end of file diff --git a/shaders/vertex.vert b/shaders/vertex.vert index da5678f..4c038e7 100644 --- a/shaders/vertex.vert +++ b/shaders/vertex.vert @@ -1,6 +1,10 @@ -#version 330 core -layout(location = 0) in vec2 vPos; -void main() -{ - gl_Position = vec4(vPos, 0.0, 1.0); -}; \ No newline at end of file +#version 430 core +layout(location = 0) in vec2 aPos; +layout(location = 1) in vec2 aTexCoord; + +out vec2 TexCoords; + +void main() { + TexCoords = aTexCoord; + gl_Position = vec4(aPos, 0.0, 1.0); +} \ No newline at end of file diff --git a/srcs/RT.cpp b/srcs/RT.cpp index 99441df..c49ed7a 100644 --- a/srcs/RT.cpp +++ b/srcs/RT.cpp @@ -12,29 +12,40 @@ #include "RT.hpp" + + int main(void) { Window window(WIDTH, HEIGHT, "RT_GPU", 0); - Shader shader("shaders/vertex.vert", "shaders/frag.frag"); + Shader shader("shaders/vertex.vert", "shaders/frag.frag", "shaders/compute.glsl"); + Vertex vertices[3] = { + {{-1.0f, -1.0f}, {0.0f, 0.0f}}, + {{3.0f, -1.0f}, {2.0f, 0.0f}}, + {{-1.0f, 3.0f}, {0.0f, 2.0f}} + }; + shader.attach(); - glm::vec2 vertices[3] = { - {-1.0f, -1.0f}, {3.0f, -1.0f}, {-1.0f, 3.0f} - }; - size_t size = sizeof(vertices) / sizeof(glm::vec2) / 3; + size_t size = sizeof(vertices) / sizeof(Vertex) / 3; shader.setupVertexBuffer(vertices, size); while (!window.shouldClose()) { - glClear(GL_COLOR_BUFFER_BIT); - + glUseProgram(shader.getProgramCompute()); + shader.set_vec2("u_resolution", glm::vec2(WIDTH, HEIGHT)); shader.set_vec3("u_cameraPosition", window.getScene()->getCamera()->get_position()); shader.set_mat4("u_viewMatrix", window.getScene()->getCamera()->get_view_matrix()); + + glDispatchCompute((WIDTH + 15) / 16, (HEIGHT + 15) / 16, 1); + glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); + + glClear(GL_COLOR_BUFFER_BIT); glUseProgram(shader.getProgram()); + shader.drawTriangles(size); std::cout << "\rFPS: " << int(window.getFps()) << " " << std::flush; diff --git a/srcs/class/Shader.cpp b/srcs/class/Shader.cpp index 328613c..e0074fe 100644 --- a/srcs/class/Shader.cpp +++ b/srcs/class/Shader.cpp @@ -37,10 +37,11 @@ char* load_file(char const* path) return buffer; } -Shader::Shader(std::string vertexPath, std::string fragmentPath) +Shader::Shader(std::string vertexPath, std::string fragmentPath, std::string computePath) { const char *vertexCode = load_file(vertexPath.c_str()); const char *fragmentCode = load_file(fragmentPath.c_str()); + const char *computeCode = load_file(computePath.c_str()); _vertex = glCreateShader(GL_VERTEX_SHADER); @@ -55,38 +56,45 @@ Shader::Shader(std::string vertexPath, std::string fragmentPath) glCompileShader(_fragment); checkCompileErrors(_fragment); -} -Shader::Shader(Shader const &src) -{ - *this = src; -} + _compute = glCreateShader(GL_COMPUTE_SHADER); -Shader &Shader::operator=(Shader const &rhs) -{ - if (this != &rhs) - { - _program = rhs._program; - _vertex = rhs._vertex; - _fragment = rhs._fragment; - } - return (*this); + glShaderSource(_compute, 1, &computeCode, NULL); + glCompileShader(_compute); + + checkCompileErrors(_compute); } Shader::~Shader(void) { glDeleteShader(_vertex); glDeleteShader(_fragment); + glDeleteShader(_compute); glDeleteProgram(_program); + glDeleteProgram(_program_compute); } void Shader::attach(void) { _program = glCreateProgram(); + _program_compute = glCreateProgram(); + glAttachShader(_program, _vertex); glAttachShader(_program, _fragment); + glAttachShader(_program_compute, _compute); + glLinkProgram(_program); + glLinkProgram(_program_compute); + + glGenTextures(1, &_outputTexture); + glBindTexture(GL_TEXTURE_2D, _outputTexture); + 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); } void Shader::checkCompileErrors(GLuint shader) @@ -102,25 +110,34 @@ void Shader::checkCompileErrors(GLuint shader) } } -void Shader::setupVertexBuffer(const glm::vec2* vertices, size_t size) +void Shader::setupVertexBuffer(const Vertex* vertices, size_t size) { - glGenVertexArrays(1, &_screen_VAO); + glGenVertexArrays(1, &_screen_VAO); glGenBuffers(1, &_screen_VBO); - + glBindVertexArray(_screen_VAO); glBindBuffer(GL_ARRAY_BUFFER, _screen_VBO); - glBufferData(GL_ARRAY_BUFFER, size * 3 * sizeof(glm::vec2), vertices, GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, size * 3 * sizeof(Vertex), vertices, GL_STATIC_DRAW); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0); + // Position attribute + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0); glEnableVertexAttribArray(0); + // Texture coordinate attribute + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, texCoord)); + glEnableVertexAttribArray(1); + glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); } void Shader::drawTriangles(size_t size) { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, _outputTexture); + glUniform1i(glGetUniformLocation(_program, "screenTexture"), 0); + glBindVertexArray(_screen_VAO); glDrawArrays(GL_TRIANGLES, 0, size * 3); } @@ -128,20 +145,25 @@ void Shader::drawTriangles(size_t size) void Shader::set_vec2(const std::string &name, const glm::vec2 &value) const { - glUniform2fv(glGetUniformLocation(_program, name.c_str()), 1, glm::value_ptr(value)); + glUniform2fv(glGetUniformLocation(_program_compute, name.c_str()), 1, glm::value_ptr(value)); } void Shader::set_vec3(const std::string &name, const glm::vec3 &value) const { - glUniform3fv(glGetUniformLocation(_program, name.c_str()), 1, glm::value_ptr(value)); + glUniform3fv(glGetUniformLocation(_program_compute, name.c_str()), 1, glm::value_ptr(value)); } void Shader::set_mat4(const std::string &name, const glm::mat4 &value) const { - glUniformMatrix4fv(glGetUniformLocation(_program, name.c_str()), 1, GL_FALSE, glm::value_ptr(value)); + glUniformMatrix4fv(glGetUniformLocation(_program_compute, name.c_str()), 1, GL_FALSE, glm::value_ptr(value)); } GLuint Shader::getProgram(void) const { return (_program); +} + +GLuint Shader::getProgramCompute(void) const +{ + return (_program_compute); } \ No newline at end of file