We got a skybox
This commit is contained in:
@@ -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
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <destrum/Graphics/Pipelines/MeshPipeline.h>
|
||||
#include <destrum/FS/AssetFS.h>
|
||||
|
||||
MeshPipeline::MeshPipeline() {
|
||||
MeshPipeline::MeshPipeline(): m_pipelineLayout{nullptr} {
|
||||
}
|
||||
|
||||
MeshPipeline::~MeshPipeline() {
|
||||
|
||||
90
destrum/src/Graphics/Pipelines/SkyboxPipeline.cpp
Normal file
90
destrum/src/Graphics/Pipelines/SkyboxPipeline.cpp
Normal 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;
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
286
destrum/src/Graphics/Resources/Cubemap.cpp
Normal file
286
destrum/src/Graphics/Resources/Cubemap.cpp
Normal 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
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user