diff options
| author | hachem <im@hachem.wtf> | 2025-08-22 12:24:05 +0200 |
|---|---|---|
| committer | hachem <im@hachem.wtf> | 2025-08-22 12:24:05 +0200 |
| commit | 2c8002d30f291cba832a5750212009d48238c308 (patch) | |
| tree | 4aafc468441b3e32c267040830b8e0b5af859faf /src/platform | |
| parent | b9de06951631d9969c52c6ed95de17a6d8aad121 (diff) | |
feat: add HDRI
Diffstat (limited to 'src/platform')
| -rw-r--r-- | src/platform/opengl/opengl_shader.h | 1 | ||||
| -rw-r--r-- | src/platform/opengl/opengl_texture.cpp | 180 | ||||
| -rw-r--r-- | src/platform/opengl/opengl_texture.h | 31 | ||||
| -rw-r--r-- | src/platform/vulkan/vulkan_shader.h | 1 | ||||
| -rw-r--r-- | src/platform/vulkan/vulkan_texture.cpp | 42 | ||||
| -rw-r--r-- | src/platform/vulkan/vulkan_texture.h | 27 |
6 files changed, 282 insertions, 0 deletions
diff --git a/src/platform/opengl/opengl_shader.h b/src/platform/opengl/opengl_shader.h index 6b1ceec..71e20a5 100644 --- a/src/platform/opengl/opengl_shader.h +++ b/src/platform/opengl/opengl_shader.h @@ -32,6 +32,7 @@ namespace Donut virtual void memory_barrier(uint32_t barriers) override; virtual const std::string& get_name() const override { return m_name; } + virtual uint32_t get_renderer_id() const override { return m_renderer_id; } void upload_uniform_int( const std::string& name, int value); void upload_uniform_int_array(const std::string& name, int* values, uint32_t count); diff --git a/src/platform/opengl/opengl_texture.cpp b/src/platform/opengl/opengl_texture.cpp index 5d05fb4..14ae214 100644 --- a/src/platform/opengl/opengl_texture.cpp +++ b/src/platform/opengl/opengl_texture.cpp @@ -1,5 +1,13 @@ #include "opengl_texture.h" +#include "rendering/shader.h" + +#define STB_IMAGE_IMPLEMENTATION +#include "stb_image.h" +#include <glm/glm.hpp> +#include <glm/gtc/matrix_transform.hpp> +#include <glm/gtc/type_ptr.hpp> + namespace Donut { OpenGLTexture2D::OpenGLTexture2D(uint32_t width, uint32_t height) @@ -68,4 +76,176 @@ namespace Donut GLenum access = read_only ? GL_READ_ONLY : GL_WRITE_ONLY; glBindImageTexture(slot, m_renderer_id, 0, GL_FALSE, 0, access, m_internal_format); } + + OpenGLCubemapTexture::OpenGLCubemapTexture(uint32_t width, uint32_t height) + : m_width(width), m_height(height) + { + m_internal_format = GL_RGB16F; + m_data_format = GL_RGB; + + glCreateTextures(GL_TEXTURE_CUBE_MAP, 1, &m_renderer_id); + glTextureStorage2D(m_renderer_id, 1, m_internal_format, m_width, m_height); + + glTextureParameteri(m_renderer_id, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTextureParameteri(m_renderer_id, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTextureParameteri(m_renderer_id, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTextureParameteri(m_renderer_id, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTextureParameteri(m_renderer_id, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + } + + OpenGLCubemapTexture::OpenGLCubemapTexture(const std::string& path) + : m_path(path) + { + m_width = 1024; + m_height = 1024; + m_internal_format = GL_RGB16F; + m_data_format = GL_RGB; + + glCreateTextures(GL_TEXTURE_CUBE_MAP, 1, &m_renderer_id); + glTextureStorage2D(m_renderer_id, 1, m_internal_format, m_width, m_height); + + glTextureParameteri(m_renderer_id, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTextureParameteri(m_renderer_id, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTextureParameteri(m_renderer_id, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTextureParameteri(m_renderer_id, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTextureParameteri(m_renderer_id, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + + load_hdri(path); + } + + OpenGLCubemapTexture::~OpenGLCubemapTexture() + { + glDeleteTextures(1, &m_renderer_id); + } + + void OpenGLCubemapTexture::load_hdri(const std::string& path) + { + stbi_set_flip_vertically_on_load(true); + int width, height, channels; + float* hdr_data = stbi_loadf(path.c_str(), &width, &height, &channels, 3); + + if (!hdr_data) + { + DONUT_ERROR("Failed to load HDRI: {}", path); + float default_sky[6 * 4] = + { + 0.5f, 0.7f, 1.0f, 1.0f, + 0.5f, 0.7f, 1.0f, 1.0f, + 0.5f, 0.7f, 1.0f, 1.0f, + 0.5f, 0.7f, 1.0f, 1.0f, + 0.5f, 0.7f, 1.0f, 1.0f, + 0.5f, 0.7f, 1.0f, 1.0f + }; + + for (int i = 0; i < 6; ++i) + glTextureSubImage3D(m_renderer_id, 0, 0, 0, i, 1, 1, 1, GL_RGBA, GL_FLOAT, &default_sky[i * 4]); + return; + } + + convert_equirectangular_to_cubemap(hdr_data, width, height); + stbi_image_free(hdr_data); + + DONUT_INFO("Successfully loaded HDRI: {} ({}x{})", path, width, height); + } + + void OpenGLCubemapTexture::convert_equirectangular_to_cubemap(float* hdr_data, int width, int height) + { + uint32_t capture_fbo, capture_rbo; + glGenFramebuffers(1, &capture_fbo); + glGenRenderbuffers(1, &capture_rbo); + + glBindFramebuffer(GL_FRAMEBUFFER, capture_fbo); + glBindRenderbuffer(GL_RENDERBUFFER, capture_rbo); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, m_width, m_height); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, capture_rbo); + + uint32_t hdr_texture; + glGenTextures(1, &hdr_texture); + glBindTexture(GL_TEXTURE_2D, hdr_texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGB, GL_FLOAT, hdr_data); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + auto equirect_shader = Shader::create("assets/shaders/equirect_to_cubemap.glsl"); + if (!equirect_shader) + { + DONUT_ERROR("Failed to create equirectangular to cubemap shader"); + return; + } + + uint32_t shader_program = equirect_shader->get_renderer_id(); + + float vertices[] = + { + -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, + -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, + 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, + -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, + -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, + -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f + }; + + uint32_t cube_vao, cube_vbo; + glGenVertexArrays(1, &cube_vao); + glGenBuffers(1, &cube_vbo); + glBindVertexArray(cube_vao); + glBindBuffer(GL_ARRAY_BUFFER, cube_vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); + + glm::mat4 capture_projection = glm::perspective(glm::radians(90.0f), 1.0f, 0.1f, 10.0f); + glm::mat4 capture_views[] = + { + glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3( 1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)), + glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)), + glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3( 0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f)), + glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3( 0.0f, -1.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f)), + glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3( 0.0f, 0.0f, 1.0f), glm::vec3(0.0f, -1.0f, 0.0f)), + glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3( 0.0f, 0.0f, -1.0f), glm::vec3(0.0f, -1.0f, 0.0f)) + }; + + glUseProgram(shader_program); + glUniform1i(glGetUniformLocation(shader_program, "equirectangularMap"), 0); + glUniformMatrix4fv(glGetUniformLocation(shader_program, "projection"), 1, GL_FALSE, &capture_projection[0][0]); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, hdr_texture); + + glViewport(0, 0, m_width, m_height); + glBindFramebuffer(GL_FRAMEBUFFER, capture_fbo); + for (unsigned int i = 0; i < 6; ++i) + { + glUniformMatrix4fv(glGetUniformLocation(shader_program, "view"), 1, GL_FALSE, &capture_views[i][0][0]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, m_renderer_id, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glBindVertexArray(cube_vao); + glDrawArrays(GL_TRIANGLES, 0, 36); + } + glBindVertexArray(0); + + glDeleteVertexArrays(1, &cube_vao); + glDeleteBuffers(1, &cube_vbo); + glDeleteProgram(shader_program); + glDeleteTextures(1, &hdr_texture); + glDeleteFramebuffers(1, &capture_fbo); + glDeleteRenderbuffers(1, &capture_rbo); + } + + void OpenGLCubemapTexture::set_data(void* data, uint32_t size) + { + DONUT_WARN("SetData not implemented for cubemaps"); + } + + void OpenGLCubemapTexture::bind(uint32_t slot) const + { + glBindTextureUnit(slot, m_renderer_id); + } + + void OpenGLCubemapTexture::bind_as_image(uint32_t slot, bool read_only) const + { + GLenum access = read_only ? GL_READ_ONLY : GL_WRITE_ONLY; + glBindImageTexture(slot, m_renderer_id, 0, GL_TRUE, 0, access, m_internal_format); + } }; diff --git a/src/platform/opengl/opengl_texture.h b/src/platform/opengl/opengl_texture.h index 705d770..5e5f6b2 100644 --- a/src/platform/opengl/opengl_texture.h +++ b/src/platform/opengl/opengl_texture.h @@ -34,4 +34,35 @@ namespace Donut uint32_t m_renderer_id; GLenum m_internal_format, m_data_format; }; + + class OpenGLCubemapTexture + : public CubemapTexture + { + public: + OpenGLCubemapTexture(uint32_t width, uint32_t height); + OpenGLCubemapTexture(const std::string& path); + virtual ~OpenGLCubemapTexture(); + + virtual uint32_t get_width() const override { return m_width; } + virtual uint32_t get_height() const override { return m_height; } + virtual uint32_t get_renderer_id() const override { return m_renderer_id; } + + virtual void set_data(void* data, uint32_t size) override; + virtual void bind(uint32_t slot = 0) const override; + virtual void bind_as_image(uint32_t slot = 0, bool read_only = false) const override; + + virtual bool operator==(const Texture& other) const override + { + return m_renderer_id == other.get_renderer_id(); + } + + private: + void load_hdri(const std::string& path); + void convert_equirectangular_to_cubemap(float* hdr_data, int width, int height); + + std::string m_path; + uint32_t m_width, m_height; + uint32_t m_renderer_id; + GLenum m_internal_format, m_data_format; + }; } diff --git a/src/platform/vulkan/vulkan_shader.h b/src/platform/vulkan/vulkan_shader.h index fdf9e65..1619522 100644 --- a/src/platform/vulkan/vulkan_shader.h +++ b/src/platform/vulkan/vulkan_shader.h @@ -32,6 +32,7 @@ namespace Donut virtual void memory_barrier(uint32_t barriers) override; virtual const std::string& get_name() const override { return m_name; } + virtual uint32_t get_renderer_id() const override { return m_renderer_id; } void upload_uniform_int(const std::string& name, int value); void upload_uniform_int_array(const std::string& name, int* values, uint32_t count); diff --git a/src/platform/vulkan/vulkan_texture.cpp b/src/platform/vulkan/vulkan_texture.cpp index e63468d..d2b1e20 100644 --- a/src/platform/vulkan/vulkan_texture.cpp +++ b/src/platform/vulkan/vulkan_texture.cpp @@ -5,11 +5,19 @@ namespace Donut VulkanTexture2D::VulkanTexture2D(uint32_t width, uint32_t height) : m_width(width), m_height(height) { + m_internal_format = 0; + m_data_format = 0; + m_renderer_id = 0; } VulkanTexture2D::VulkanTexture2D(const std::string& path) : m_path(path) { + m_width = 1; + m_height = 1; + m_internal_format = 0; + m_data_format = 0; + m_renderer_id = 0; } VulkanTexture2D::~VulkanTexture2D() @@ -27,4 +35,38 @@ namespace Donut void VulkanTexture2D::bind_as_image(uint32_t slot, bool read_only) const { } + + VulkanCubemapTexture::VulkanCubemapTexture(uint32_t width, uint32_t height) + : m_width(width), m_height(height) + { + m_internal_format = 0; + m_data_format = 0; + m_renderer_id = 0; + } + + VulkanCubemapTexture::VulkanCubemapTexture(const std::string& path) + : m_path(path) + { + m_width = 1024; + m_height = 1024; + m_internal_format = 0; + m_data_format = 0; + m_renderer_id = 0; + } + + VulkanCubemapTexture::~VulkanCubemapTexture() + { + } + + void VulkanCubemapTexture::set_data(void* data, uint32_t size) + { + } + + void VulkanCubemapTexture::bind(uint32_t slot) const + { + } + + void VulkanCubemapTexture::bind_as_image(uint32_t slot, bool read_only) const + { + } }; diff --git a/src/platform/vulkan/vulkan_texture.h b/src/platform/vulkan/vulkan_texture.h index a9ac920..d1b5dc3 100644 --- a/src/platform/vulkan/vulkan_texture.h +++ b/src/platform/vulkan/vulkan_texture.h @@ -30,4 +30,31 @@ namespace Donut uint32_t m_renderer_id; uint32_t m_internal_format, m_data_format; }; + + class VulkanCubemapTexture + : public CubemapTexture + { + public: + VulkanCubemapTexture(uint32_t width, uint32_t height); + VulkanCubemapTexture(const std::string& path); + virtual ~VulkanCubemapTexture(); + + virtual uint32_t get_width() const override { return m_width; } + virtual uint32_t get_height() const override { return m_height; } + virtual uint32_t get_renderer_id() const override { return m_renderer_id; } + + virtual void set_data(void* data, uint32_t size) override; + virtual void bind(uint32_t slot = 0) const override; + virtual void bind_as_image(uint32_t slot = 0, bool read_only = false) const override; + + virtual bool operator==(const Texture& other) const override + { + return m_renderer_id == ((VulkanCubemapTexture&)other).m_renderer_id; + } + private: + std::string m_path; + uint32_t m_width, m_height; + uint32_t m_renderer_id; + uint32_t m_internal_format, m_data_format; + }; }; |
