We got a skybox

This commit is contained in:
2026-01-21 06:05:35 +01:00
parent b9878f2a06
commit a5b26f3bdd
27 changed files with 843 additions and 42 deletions

View File

@@ -21,6 +21,7 @@ public:
void Randomize(uint32_t seed);
void Update() override;
void Start() override;
// optional setters
void SetRadius(float r) { m_Radius = r; }
@@ -37,12 +38,18 @@ private:
float m_OrbitSpeed = 1.0f; // rad/sec
float m_OrbitAngle = 0.0f; // current angle
float m_OrbitPhase = 0.0f; // starting offset
float m_GrowPhase = 0.0f;
glm::vec3 m_U{1,0,0}; // orbit basis axis 1
glm::vec3 m_V{0,0,1}; // orbit basis axis 2
glm::vec3 m_BaseScale{1.0f};
float m_GrowSpeed = 1.0f; // rad/sec
// self spin
glm::vec3 m_SpinAxis{0,1,0};
float m_SpinSpeed = 2.0f; // rad/sec
MaterialID m_MaterialID{0};
};
#endif //ORBITANDSPIN_H

View File

@@ -46,6 +46,7 @@ public:
VkCommandBuffer beginFrame();
[[nodiscard]] bool needsSwapchainRecreate() const { return swapchain.isDirty(); }
VulkanImmediateExecutor& GetImmediateExecuter();
struct EndFrameProps {
@@ -126,6 +127,19 @@ private:
ImageCache imageCache;
static uint32_t BytesPerTexel(VkFormat fmt) {
switch (fmt) {
case VK_FORMAT_R8_UNORM: return 1;
case VK_FORMAT_R8G8B8A8_UNORM: return 4;
case VK_FORMAT_B8G8R8A8_SRGB: return 4;
case VK_FORMAT_R16G16B16A16_SFLOAT: return 8;
case VK_FORMAT_R32G32B32A32_SFLOAT: return 16;
case VK_FORMAT_R8G8B8A8_SRGB: return 4;
default:
throw std::runtime_error("BytesPerTexel: unsupported format");
}
}
};

View File

@@ -39,6 +39,16 @@ public:
void setErrorImageId(ImageID id) { errorImageId = id; }
static uint32_t BytesPerTexel(VkFormat fmt) {
switch (fmt) {
case VK_FORMAT_R32G32B32A32_SFLOAT: return 16;
case VK_FORMAT_R16G16B16A16_SFLOAT: return 8;
case VK_FORMAT_R8G8B8A8_UNORM: return 4;
// add formats you use
default: throw std::runtime_error("BytesPerTexel: unsupported format");
}
}
private:
std::vector<GPUImage> images;
GfxDevice& gfxDevice;

View File

@@ -26,6 +26,10 @@ public:
const GPUBuffer& getMaterialDataBuffer() const { return materialDataBuffer; }
VkDeviceAddress getMaterialDataBufferAddress() const { return materialDataBuffer.address; }
Material& getMaterialMutable(MaterialID id);
void updateMaterialGPU(GfxDevice& gfxDevice, MaterialID id);
private:
std::vector<Material> materials;

View File

@@ -0,0 +1,43 @@
#ifndef SKYBOXPIPELINE_H
#define SKYBOXPIPELINE_H
#include <memory>
#include <vulkan/vulkan.h>
#include <glm/mat4x4.hpp>
#include <glm/vec4.hpp>
#include <destrum/Graphics/ids.h>
#include <destrum/Graphics/Pipeline.h>
#include <destrum/Graphics/Camera.h>
class SkyboxPipeline final {
public:
SkyboxPipeline();
~SkyboxPipeline();
void init(
GfxDevice& gfxDevice,
VkFormat drawImageFormat,
VkFormat depthImageFormat
);
void cleanup(VkDevice device);
void draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera& camera);
void setSkyboxImage(const ImageID skyboxId);
private:
VkPipelineLayout pipelineLayout;
std::unique_ptr<Pipeline> pipeline;
ImageID skyboxTextureId{NULL_IMAGE_ID};
struct SkyboxPushConstants {
glm::mat4 invViewProj;
glm::vec4 cameraPos;
std::uint32_t skyboxTextureId;
};
};
#endif //SKYBOXPIPELINE_H

View File

@@ -13,6 +13,8 @@
#include <memory>
#include "Pipelines/SkyboxPipeline.h"
class GameRenderer {
public:
struct SceneData {
@@ -39,6 +41,12 @@ public:
createDrawImage(gfxDevice, newSize, false);
}
Material& getMaterialMutable(MaterialID id);
void updateMaterialGPU(MaterialID id);
void setSkyboxTexture(ImageID skyboxImageId);
private:
void createDrawImage(GfxDevice& gfxDevice, const glm::ivec2& drawImageSize, bool firstCreate);
@@ -79,6 +87,7 @@ private:
std::unique_ptr<MeshPipeline> meshPipeline;
std::unique_ptr<SkyboxPipeline> skyboxPipeline;
};
#endif //RENDERER_H

View File

@@ -0,0 +1,66 @@
#ifndef CUBEMAP_H
#define CUBEMAP_H
#include <array>
#include <filesystem>
#include <glm/glm.hpp>
#include <glm/ext/matrix_transform.hpp>
#include <vulkan/vulkan.h>
#include <destrum/Graphics/ids.h>
#include "destrum/Graphics/Pipeline.h"
class CubeMap {
public:
explicit CubeMap();
~CubeMap();
void LoadCubeMap(const std::filesystem::path &directoryPath);
void RenderToCubemap(ImageID inputImage, VkImage outputImage, std::array<VkImageView, 6> faceViews, uint32_t size);
void InitCubemapPipeline(const std::string& vertPath, const std::string& fragPath);
void CreateCubeMap();
ImageID GetCubeMapImageID();
private:
const std::array<glm::mat4, 6> viewMatrices = {
// POSITIVE_X
glm::lookAt(glm::vec3(0.0f), glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)),
// NEGATIVE_X
glm::lookAt(glm::vec3(0.0f), glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)),
// POSITIVE_Y
glm::lookAt(glm::vec3(0.0f), glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f)),
// NEGATIVE_Y
glm::lookAt(glm::vec3(0.0f), glm::vec3(0.0f, -1.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f)),
// POSITIVE_Z
glm::lookAt(glm::vec3(0.0f), glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(0.0f, -1.0f, 0.0f)),
// NEGATIVE_Z
glm::lookAt(glm::vec3(0.0f), glm::vec3(0.0f, 0.0f, -1.0f), glm::vec3(0.0f, -1.0f, 0.0f))
};
struct alignas(16) PC {
glm::mat4 viewMtx; // 64
glm::mat4 projMtx; // 64
std::uint32_t inputImageId; // 4
};
glm::mat4 m_projection{};
ImageID m_hdrImage{};
uint32_t m_cubeMapSize = 1024; // Default size for cube map
VkImageView m_skyboxView;
VkPipelineLayout m_cubemapPipelineLayout = VK_NULL_HANDLE;
std::unique_ptr<Pipeline> m_cubemapPipeline;
std::string m_cubemapVert;
std::string m_cubemapFrag;
ImageID m_cubemapImageID;
};
#endif //CUBEMAP_H

View File

@@ -0,0 +1,40 @@
#ifndef GAMESTATE_H
#define GAMESTATE_H
#include <cassert>
#include <destrum/Singleton.h>
class GfxDevice;
class GameRenderer;
class GameState final: public Singleton<GameState> {
public:
friend class Singleton<GameState>;
void SetGfxDevice(GfxDevice* device) { m_gfxDevice = device; }
GfxDevice& Gfx() {
assert(m_gfxDevice && "GfxDevice not registered yet!");
return *m_gfxDevice;
}
const GfxDevice& Gfx() const {
assert(m_gfxDevice && "GfxDevice not registered yet!");
return *m_gfxDevice;
}
void SetRenderer(GameRenderer* renderer) { m_renderer = renderer; }
GameRenderer& Renderer() {
assert(m_renderer && "Renderer not registered yet!");
return *m_renderer;
}
const GameRenderer& Renderer() const {
assert(m_renderer && "Renderer not registered yet!");
return *m_renderer;
}
private:
GfxDevice* m_gfxDevice{nullptr};
GameRenderer* m_renderer{nullptr};
};
#endif //GAMESTATE_H