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

@@ -4,7 +4,10 @@
#include <random>
#include <cmath>
#include "destrum/ObjectModel/GameObject.h"
#include "destrum/ObjectModel/Transform.h"
#include "destrum/Components/MeshRendererComponent.h"
#include "destrum/Util/GameState.h"
static glm::vec3 RandomUnitVector(std::mt19937& rng)
{
@@ -48,11 +51,6 @@ void OrbitAndSpin::BuildOrbitBasis()
void OrbitAndSpin::Update()
{
// If your engine provides dt via a global/time service, use that instead.
// Since your Spinner takes dt indirectly, I'm assuming Component::Update()
// is called once per frame and you can access dt somewhere globally.
//
// If you CAN pass dt into Update, change signature to Update(float dt).
float dt = 1.0f / 60.0f;
// orbit
@@ -60,10 +58,37 @@ void OrbitAndSpin::Update()
float a = m_OrbitAngle + m_OrbitPhase;
glm::vec3 offset = (m_U * std::cos(a) + m_V * std::sin(a)) * m_Radius;
// IMPORTANT: if SetWorldPosition resets TRS in your engine, this will wipe scale unless you set it again after.
GetTransform().SetWorldPosition(m_Center + offset);
// self spin (local rotation)
// spin
glm::quat dq = glm::angleAxis(m_SpinSpeed * dt, glm::normalize(m_SpinAxis));
auto current = GetTransform().GetLocalRotation(); // adapt to your API
auto current = GetTransform().GetLocalRotation();
GetTransform().SetLocalRotation(glm::normalize(dq * current));
// grow (always positive)
m_GrowPhase += m_GrowSpeed * dt;
float t = 0.5f * (std::sin(m_GrowPhase) + 1.0f); // 0..1
float s = 1.50 + t * 0.70f; // 0.05..0.15 (pick what you want)
GetTransform().SetLocalScale(glm::vec3(std::sin(m_GrowPhase)));
// material color
// auto& mat = GameState::GetInstance().Renderer().getMaterialMutable(m_MaterialID);
// mat.baseColor = glm::vec3(
// 0.5f + 0.5f * std::sin(m_OrbitAngle * 2.0f),
// 0.5f + 0.5f * std::sin(m_OrbitAngle * 3.0f + 2.0f),
// 0.5f + 0.5f * std::sin(m_OrbitAngle * 4.0f + 4.0f)
// );
// GameState::GetInstance().Renderer().updateMaterialGPU(m_MaterialID);
}
void OrbitAndSpin::Start() {
auto meshComp = this->GetGameObject()->GetComponent<MeshRendererComponent>();
m_MaterialID = meshComp->GetMaterialID();
m_BaseScale = GetTransform().GetLocalScale(); // <-- important
}

View File

@@ -70,8 +70,8 @@ void Camera::Update(float deltaTime) {
if (input.IsKeyDown(SDL_SCANCODE_S)) move -= m_forward;
if (input.IsKeyDown(SDL_SCANCODE_D)) move += m_right;
if (input.IsKeyDown(SDL_SCANCODE_A)) move -= m_right;
if (input.IsKeyDown(SDL_SCANCODE_Q)) move += glm::vec3(0, 1, 0); // Absolute Up
if (input.IsKeyDown(SDL_SCANCODE_E)) move -= glm::vec3(0, 1, 0); // Absolute Down
if (input.IsKeyDown(SDL_SCANCODE_E)) move += glm::vec3(0, 1, 0); // Absolute Up
if (input.IsKeyDown(SDL_SCANCODE_Q)) move -= glm::vec3(0, 1, 0); // Absolute Down
if (glm::length2(move) > 0.0f) {
m_position += glm::normalize(move) * (moveSpeed * deltaTime);

View File

@@ -15,6 +15,7 @@
#include <destrum/Graphics/Init.h>
#include "destrum/Graphics/imageLoader.h"
#include "destrum/Util/GameState.h"
#include "spdlog/spdlog.h"
GfxDevice::GfxDevice(): imageCache(*this) {
@@ -141,7 +142,7 @@ void GfxDevice::init(SDL_Window* window, const std::string& appName, bool vSync)
// "white texture",
// &pixel);
// }
GameState::GetInstance().SetGfxDevice(this);
}
void GfxDevice::recreateSwapchain(int width, int height) {
@@ -164,6 +165,10 @@ VkCommandBuffer GfxDevice::beginFrame() {
return cmd;
}
VulkanImmediateExecutor& GfxDevice::GetImmediateExecuter() {
return executor;
}
void GfxDevice::endFrame(VkCommandBuffer cmd, const GPUImage& drawImage, const EndFrameProps& props) {
// get swapchain image
const auto [swapchainImage, swapchainImageIndex] = swapchain.acquireNextImage(getCurrentFrameIndex());
@@ -426,7 +431,7 @@ GPUImage GfxDevice::createImageRaw(
if (createInfo.isCubemap) {
assert(createInfo.numLayers % 6 == 0);
assert(!createInfo.mipMap);
// assert(!createInfo.mipMap);
assert((createInfo.flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) != 0);
}
@@ -503,16 +508,14 @@ GPUImage GfxDevice::createImageRaw(
void GfxDevice::uploadImageData(const GPUImage& image, void* pixelData, std::uint32_t layer) const
{
int numChannels = 4;
if (image.format == VK_FORMAT_R8_UNORM) {
// FIXME: support more types
numChannels = 1;
}
const auto dataSize =
image.extent.depth * image.extent.width * image.extent.height * numChannels;
VkDeviceSize dataSize =
VkDeviceSize(image.extent.depth) *
image.extent.width *
image.extent.height *
BytesPerTexel(image.format);
const auto uploadBuffer = createBuffer(dataSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
memcpy(uploadBuffer.info.pMappedData, pixelData, dataSize);
auto uploadBuffer = createBuffer(dataSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
memcpy(uploadBuffer.info.pMappedData, pixelData, size_t(dataSize));
executor.immediateSubmit([&](VkCommandBuffer cmd) {
assert(

View File

@@ -75,3 +75,33 @@ MaterialID MaterialCache::getPlaceholderMaterialId() const
assert(placeholderMaterialId != NULL_MATERIAL_ID && "MaterialCache::init not called");
return placeholderMaterialId;
}
Material& MaterialCache::getMaterialMutable(MaterialID id) {
assert(id < materials.size());
return materials.at(id);
}
void MaterialCache::updateMaterialGPU(GfxDevice& gfxDevice, MaterialID id)
{
assert(id < materials.size());
assert(materialDataBuffer.info.pMappedData && "materialDataBuffer must be mapped");
const auto getTextureOrElse = [](ImageID imageId, ImageID placeholder) {
return imageId != NULL_IMAGE_ID ? imageId : placeholder;
};
Material& material = materials[id];
MaterialData* data = reinterpret_cast<MaterialData*>(materialDataBuffer.info.pMappedData);
const ImageID whiteTextureID = gfxDevice.getWhiteTextureID();
data[id] = MaterialData{
.baseColor = glm::vec4(material.baseColor, 1.0f),
.metalRoughnessEmissive = glm::vec4(material.metallicFactor, material.roughnessFactor, material.emissiveFactor, 0.f),
.diffuseTex = getTextureOrElse(material.diffuseTexture, whiteTextureID),
.normalTex = whiteTextureID, // if you have this field
.metallicRoughnessTex = whiteTextureID,
.emissiveTex = whiteTextureID,
};
}

View File

@@ -1,7 +1,7 @@
#include <destrum/Graphics/Pipelines/MeshPipeline.h>
#include <destrum/FS/AssetFS.h>
MeshPipeline::MeshPipeline() {
MeshPipeline::MeshPipeline(): m_pipelineLayout{nullptr} {
}
MeshPipeline::~MeshPipeline() {

View File

@@ -0,0 +1,90 @@
#include <destrum/Graphics/Pipelines/SkyboxPipeline.h>
#include <destrum/FS/AssetFS.h>
#include "spdlog/spdlog.h"
SkyboxPipeline::SkyboxPipeline(): pipelineLayout{nullptr} {
}
SkyboxPipeline::~SkyboxPipeline() {
}
void SkyboxPipeline::init(GfxDevice& gfxDevice, VkFormat drawImageFormat, VkFormat depthImageFormat) {
const auto vertexShader = AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/fullscreen_triangle.vert");
const auto fragShader = AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/skybox.frag");
constexpr auto bufferRange = VkPushConstantRange{
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
.offset = 0,
.size = sizeof(SkyboxPushConstants),
};
constexpr auto pushConstantRanges = std::array{bufferRange};
const auto layouts = std::array{gfxDevice.getBindlessDescSetLayout()};
VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutInfo.setLayoutCount = static_cast<uint32_t>(layouts.size());
pipelineLayoutInfo.pSetLayouts = layouts.data();
pipelineLayoutInfo.pushConstantRangeCount = static_cast<uint32_t>(pushConstantRanges.size());
pipelineLayoutInfo.pPushConstantRanges = pushConstantRanges.data();
if (vkCreatePipelineLayout(gfxDevice.getDevice().device, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) {
throw std::runtime_error("Could not make pipleine layout");
}
PipelineConfigInfo pipelineConfig{};
Pipeline::DefaultPipelineConfigInfo(pipelineConfig);
pipelineConfig.name = "skybox pipeline";
pipelineConfig.pipelineLayout = pipelineLayout;
pipelineConfig.vertexAttributeDescriptions = {};
pipelineConfig.vertexBindingDescriptions = {};
pipelineConfig.colorAttachments = { drawImageFormat };
pipelineConfig.depthAttachment = depthImageFormat;
pipelineConfig.rasterizationInfo.cullMode = VK_CULL_MODE_NONE;
pipelineConfig.depthStencilInfo.depthTestEnable = VK_TRUE;
pipelineConfig.depthStencilInfo.depthWriteEnable = VK_FALSE;
pipelineConfig.depthStencilInfo.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
pipelineConfig.rasterizationInfo.cullMode = VK_CULL_MODE_NONE;
pipeline = std::make_unique<Pipeline>(
gfxDevice,
vertexShader.string(),
fragShader.string(),
pipelineConfig
);
}
void SkyboxPipeline::cleanup(VkDevice device) {
pipeline.reset();
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
}
void SkyboxPipeline::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera& camera) {
if (skyboxTextureId == NULL_IMAGE_ID) {
return;
}
pipeline->bind(cmd);
gfxDevice.bindBindlessDescSet(cmd, pipelineLayout);
const auto pcs = SkyboxPushConstants{
.invViewProj = glm::inverse(camera.GetViewProjectionMatrix()),
.cameraPos = glm::vec4{camera.GetPosition(), 1.f},
.skyboxTextureId = static_cast<std::uint32_t>(skyboxTextureId),
};
vkCmdPushConstants(cmd, pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(SkyboxPushConstants), &pcs);
vkCmdDraw(cmd, 3, 1, 0, 0);
}
void SkyboxPipeline::setSkyboxImage(const ImageID skyboxId) {
skyboxTextureId = skyboxId;
}

View File

@@ -2,6 +2,7 @@
#include <destrum/Graphics/Util.h>
#include "destrum/Util/GameState.h"
#include "spdlog/spdlog.h"
GameRenderer::GameRenderer(MeshCache& meshCache, MaterialCache& matCache): meshCache{meshCache}, materialCache{matCache} {
@@ -19,6 +20,11 @@ void GameRenderer::init(GfxDevice& gfxDevice, const glm::ivec2& drawImageSize) {
meshPipeline = std::make_unique<MeshPipeline>();
meshPipeline->init(gfxDevice, drawImageFormat, depthImageFormat);
skyboxPipeline = std::make_unique<SkyboxPipeline>();
skyboxPipeline->init(gfxDevice, drawImageFormat, depthImageFormat);
GameState::GetInstance().SetRenderer(this);
}
void GameRenderer::beginDrawing(GfxDevice& gfxDevice) {
@@ -80,6 +86,9 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
meshDrawCommands,
sortedMeshDrawCommands);
skyboxPipeline->draw(cmd, gfxDevice, camera);
vkCmdEndRendering(cmd);
// vkutil::cmdEndLabel(cmd);
@@ -106,6 +115,21 @@ const GPUImage& GameRenderer::getDrawImage(const GfxDevice& gfx_device) const {
return gfx_device.getImage(drawImageId);
}
Material& GameRenderer::getMaterialMutable(MaterialID id) {
assert(id != NULL_MATERIAL_ID);
return materialCache.getMaterialMutable(id);
}
void GameRenderer::updateMaterialGPU(MaterialID id) {
assert(id != NULL_MATERIAL_ID);
materialCache.updateMaterialGPU(GameState::GetInstance().Gfx(), id);
}
void GameRenderer::setSkyboxTexture(ImageID skyboxImageId) {
spdlog::debug("Set skybox texture to image id {}", skyboxImageId);
skyboxPipeline->setSkyboxImage(skyboxImageId);
}
void GameRenderer::createDrawImage(GfxDevice& gfxDevice,
const glm::ivec2& drawImageSize,
bool firstCreate)

View File

@@ -0,0 +1,286 @@
#include <destrum/Graphics/Resources/Cubemap.h>
#include "destrum/FS/AssetFS.h"
#include "destrum/Graphics/GfxDevice.h"
#include "destrum/Graphics/Pipeline.h"
#include "destrum/Util/GameState.h"
#include <destrum/Graphics/Util.h>
#include "glm/ext/matrix_clip_space.hpp"
#include "spdlog/spdlog.h"
CubeMap::CubeMap() {
m_projection = glm::perspective(glm::radians(90.0f), 1.0f, 0.1f, 10.0f);;
}
CubeMap::~CubeMap() {
auto& gfx = GameState::GetInstance().Gfx();
VkDevice device = gfx.getDevice();
if (m_skyboxView) {
vkDestroyImageView(device, m_skyboxView, nullptr);
m_skyboxView = VK_NULL_HANDLE;
}
if (m_cubemapPipelineLayout) {
vkDestroyPipelineLayout(device, m_cubemapPipelineLayout, nullptr);
m_cubemapPipelineLayout = VK_NULL_HANDLE;
}
}
void CubeMap::LoadCubeMap(const std::filesystem::path& directoryPath) {
m_hdrImage = GameState::GetInstance().Gfx().loadImageFromFile(directoryPath, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, false);
}
void CubeMap::RenderToCubemap(ImageID inputImage,
VkImage outputImage,
std::array<VkImageView, 6> faceViews,
uint32_t size)
{
// Ensure pipeline exists
if (!m_cubemapPipeline || m_cubemapPipelineLayout == VK_NULL_HANDLE) {
throw std::runtime_error("Cubemap pipeline not initialized. Call InitCubemapPipeline first.");
}
auto& gfx = GameState::GetInstance().Gfx();
gfx.GetImmediateExecuter().immediateSubmit([&](VkCommandBuffer cmd) {
VkImageMemoryBarrier barrier{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = outputImage;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 6;
barrier.srcAccessMask = 0;
barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
vkCmdPipelineBarrier(
cmd,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
0,
0, nullptr,
0, nullptr,
1, &barrier
);
VkViewport viewport{};
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = static_cast<float>(size);
viewport.height = static_cast<float>(size);
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
VkRect2D scissor{};
scissor.offset = {0, 0};
scissor.extent = {size, size};
for (uint32_t face = 0; face < 6; ++face) {
PC pc{};
pc.viewMtx = viewMatrices[face];
pc.projMtx = m_projection;
pc.inputImageId = m_hdrImage;
VkRenderingAttachmentInfoKHR colorAttachment{ VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR };
colorAttachment.imageView = faceViews[face];
colorAttachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorAttachment.clearValue.color = {0.f, 0.f, 0.f, 1.f};
VkRenderingInfoKHR renderingInfo{ VK_STRUCTURE_TYPE_RENDERING_INFO_KHR };
renderingInfo.renderArea.offset = {0, 0};
renderingInfo.renderArea.extent = {size, size};
renderingInfo.layerCount = 1;
renderingInfo.colorAttachmentCount = 1;
renderingInfo.pColorAttachments = &colorAttachment;
vkCmdBeginRendering(cmd, &renderingInfo);
vkCmdSetViewport(cmd, 0, 1, &viewport);
vkCmdSetScissor(cmd, 0, 1, &scissor);
m_cubemapPipeline->bind(cmd);
gfx.bindBindlessDescSet(cmd, m_cubemapPipelineLayout);
vkCmdPushConstants(
cmd,
m_cubemapPipelineLayout,
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
0,
sizeof(PC),
&pc
);
vkCmdDraw(cmd, 36, 1, 0, 0);
vkCmdEndRendering(cmd);
}
// Transition to shader read
barrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
vkCmdPipelineBarrier(
cmd,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
0,
0, nullptr,
0, nullptr,
1, &barrier
);
});
}
void CubeMap::CreateCubeMap() {
const uint32_t mipLevels = static_cast<uint32_t>(std::floor(std::log2(m_cubeMapSize))) + 1;
VkImageCreateInfo imageInfo{};
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageInfo.imageType = VK_IMAGE_TYPE_2D;
imageInfo.extent.height = m_cubeMapSize;
imageInfo.extent.width = m_cubeMapSize;
imageInfo.extent.depth = 1;
imageInfo.mipLevels = mipLevels;
imageInfo.arrayLayers = 6; // 6 faces for cubemap
imageInfo.format = VK_FORMAT_R32G32B32A32_SFLOAT;
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageInfo.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; // Create a cubemap
VmaAllocationCreateInfo allocInfo{};
allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
auto& device = GameState::GetInstance().Gfx();
GPUImage cubeMapID = device.createImageRaw({
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT,
.extent =
VkExtent3D{
.width = m_cubeMapSize,
.height = m_cubeMapSize,
.depth = 1,
},
.numLayers = 6,
.mipMap = true,
.isCubemap = true
});
// if (vmaCreateImage(device.getAllocator(), &imageInfo, &allocInfo, &cubeMapID.image, &cubeMapID.allocation, nullptr) != VK_SUCCESS) {
// throw std::runtime_error("Failed to create image with VMA!");
// }
std::array<VkImageView, 6> faceViews{};
for (uint32_t face = 0; face < 6; ++face) {
VkImageViewCreateInfo viewInfo{};
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewInfo.image = cubeMapID.image;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.format = VK_FORMAT_R32G32B32A32_SFLOAT;
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
viewInfo.subresourceRange.baseMipLevel = 0;
viewInfo.subresourceRange.levelCount = 1;
viewInfo.subresourceRange.baseArrayLayer = face;
viewInfo.subresourceRange.layerCount = 1;
if (vkCreateImageView(device.getDevice(), &viewInfo, nullptr, &faceViews[face]) != VK_SUCCESS) {
throw std::runtime_error("Failed to create image view!");
}
}
VkImageViewCreateInfo viewInfo{};
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewInfo.image = cubeMapID.image;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_CUBE;
viewInfo.format = VK_FORMAT_R32G32B32A32_SFLOAT;
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
viewInfo.subresourceRange.baseMipLevel = 0;
viewInfo.subresourceRange.levelCount = 1;
viewInfo.subresourceRange.baseArrayLayer = 0;
viewInfo.subresourceRange.layerCount = 6;
if (vkCreateImageView(device.getDevice(), &viewInfo, nullptr, &m_skyboxView) != VK_SUCCESS) {
throw std::runtime_error("Failed to create image view!");
}
const auto vertPath = AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/cubemap.vert");
const auto fragPath = AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/cubemap.frag");
spdlog::info("hdriImage id = {}", m_hdrImage);
RenderToCubemap(m_hdrImage, cubeMapID.image, faceViews, m_cubeMapSize);
m_cubemapImageID = GameState::GetInstance().Gfx().addImageToCache(cubeMapID);
for (auto v : faceViews) {
vkDestroyImageView(device.getDevice(), v, nullptr);
}
}
ImageID CubeMap::GetCubeMapImageID() {
return m_cubemapImageID;
}
void CubeMap::InitCubemapPipeline(const std::string& vertPath, const std::string& fragPath)
{
auto& gfx = GameState::GetInstance().Gfx();
VkDevice device = gfx.getDevice();
if (m_cubemapPipeline) return; // already created
// Save paths if you want
m_cubemapVert = vertPath;
m_cubemapFrag = fragPath;
VkPushConstantRange pushConstantRange{};
pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
pushConstantRange.offset = 0;
pushConstantRange.size = sizeof(PC);
const auto layouts = std::array{ gfx.getBindlessDescSetLayout() };
VkPipelineLayoutCreateInfo pipelineLayoutInfo{ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
pipelineLayoutInfo.setLayoutCount = static_cast<uint32_t>(layouts.size());
pipelineLayoutInfo.pSetLayouts = layouts.data();
pipelineLayoutInfo.pushConstantRangeCount = 1;
pipelineLayoutInfo.pPushConstantRanges = &pushConstantRange;
if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &m_cubemapPipelineLayout) != VK_SUCCESS) {
throw std::runtime_error("Failed to create cubemap pipeline layout!");
}
PipelineConfigInfo pipelineConfig{};
Pipeline::DefaultPipelineConfigInfo(pipelineConfig);
pipelineConfig.vertexAttributeDescriptions = {};
pipelineConfig.vertexBindingDescriptions = {};
pipelineConfig.pipelineLayout = m_cubemapPipelineLayout;
pipelineConfig.colorAttachments = { VK_FORMAT_R32G32B32A32_SFLOAT }; // must match cubemap image view format
pipelineConfig.depthAttachment = VK_FORMAT_UNDEFINED;
pipelineConfig.depthStencilInfo.depthTestEnable = VK_FALSE;
pipelineConfig.depthStencilInfo.depthWriteEnable = VK_FALSE;
pipelineConfig.rasterizationInfo.cullMode = VK_CULL_MODE_NONE;
m_cubemapPipeline = std::make_unique<Pipeline>(
gfx,
vertPath,
fragPath,
pipelineConfig
);
}