역시 바쁠 때 가장 먼저 놓게 되는게 블로그인거같다..
지금까지 한 일은 메모리 누수와 여러 잡다한 에러의 처리와
skybox 개선, collider를 그리는 렌더패스를 추가했다.
우선 skybox개선
전전 블로그의 그 이슈이다.
예상했던 문제가 맞았고 hdr이미지를 본래 이미지 받아오는 것처럼 VK_FORMAT_R8G8B8A8_UNORM 형식이 아닌
VK_FORMAT_R32G32B32A32_SFLOAT로 32비트로 받아와서 저장을 하니깐 말끔하게 해결되었다.
받아오는 코드
bool ImageBuffer::initHDRImageBuffer(std::string path)
{
auto &context = VulkanContext::getContext();
m_device = context.getDevice();
m_physicalDevice = context.getPhysicalDevice();
m_commandPool = context.getCommandPool();
m_graphicsQueue = context.getGraphicsQueue();
int texWidth, texHeight, texChannels;
float *pixels = stbi_loadf(path.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
if (!pixels)
return false;
VkDeviceSize imageSize = texWidth * texHeight * 4 * sizeof(float);
mipLevels = static_cast<uint32_t>(std::floor(std::log2(std::max(texWidth, texHeight)))) + 1;
VkBuffer stagingBuffer;
VkDeviceMemory stagingBufferMemory;
createBuffer(imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer,
stagingBufferMemory);
void *data;
vkMapMemory(m_device, stagingBufferMemory, 0, imageSize, 0, &data);
memcpy(data, pixels, static_cast<size_t>(imageSize));
vkUnmapMemory(m_device, stagingBufferMemory);
stbi_image_free(pixels);
VulkanUtil::createImage(
texWidth, texHeight, mipLevels, VK_SAMPLE_COUNT_1_BIT, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_TILING_OPTIMAL,
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, textureImage, textureImageMemory);
transitionImageLayout(textureImage, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, mipLevels);
copyBufferToImage(stagingBuffer, textureImage, static_cast<uint32_t>(texWidth), static_cast<uint32_t>(texHeight));
vkDestroyBuffer(m_device, stagingBuffer, nullptr);
vkFreeMemory(m_device, stagingBufferMemory, nullptr);
generateMipmaps(textureImage, VK_FORMAT_R32G32B32A32_SFLOAT, texWidth, texHeight, mipLevels);
return true;
}
포맷을 처음에는 16비트로 바꿔봤었는데 계속 초록색 화면만 나와서 당황했었는데
32비트로 바꾸니깐 바로 되더라..
여기서 하나 배운 점이 있다면 hdr파일의 톤매핑 기법인데
vec3 ACESFilm(vec3 x) {
float a = 2.51;
float b = 0.03;
float c = 2.43;
float d = 0.59;
float e = 0.14;
return clamp((x * (a * x + b)) / (x * (c * x + d) + e), 0.0, 1.0);
}
요거요거 용하다.
hdr톤 매핑 기법 중 하나라고 해서 써봤는데
정말 뚜렷하게 나와서 놀랐다.
기록해뒀다가 두고두고 써먹어야지..
결과는
완전 밝은 부분이 확연하게 줄었고 전체적으로 색감이 좋아져서 아주 만족이다.
그리고 콜라이더를 그렸다.
이건 물리엔진 친구의 요청이었는데 디버깅 할 때 너무 힘들다해서 만들어 달란 요청이 있었다.
깊이까지 적용되면 생각보다 복잡해질 거 같아 골아팠는데
콜라이더는 그냥 항상 보이게 해도 된다그래서
기존 렌더패스에서 생성한 이미지 위에다가 덧대 그렸다.
너무 간단한 방법이라 손쉽게 추가했고
여기서 다른 파이프라인과 차별점은
VkPipelineRasterizationStateCreateInfo rasterizer{};
rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizer.depthClampEnable = VK_FALSE;
rasterizer.rasterizerDiscardEnable = VK_FALSE;
rasterizer.polygonMode = VK_POLYGON_MODE_LINE;
rasterizer.lineWidth = 2.0f;
rasterizer.cullMode = VK_CULL_MODE_NONE;
rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
rasterizer.depthBiasEnable = VK_FALSE;
polygonmode를 라인으로 바꾸고
VkPipelineDepthStencilStateCreateInfo depthStencil{};
depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
depthStencil.depthTestEnable = VK_FALSE;
depthStencil.depthWriteEnable = VK_FALSE;
depthStencil.depthCompareOp = VK_COMPARE_OP_ALWAYS;
depthStencil.depthBoundsTestEnable = VK_FALSE;
depthStencil.stencilTestEnable = VK_FALSE;
뎁스는 신경쓰지 않는다.
요런식으로 파이프라인을 설정해준다음
콜라이더 그릴 메쉬만 그려주면 끝!
기존의 저장되어있던 메쉬들로 그려주면 됐는데
박스만 중간에 사선이 있는게 별로여서
새로 메쉬를 콜라이더용 박스메쉬로 인덱스를 바꿔 저장했다.
생각보다 이쁘게 나와 기분이 아주 좋다.
'Computer Graphics > Vulkan' 카테고리의 다른 글
Vulkan Game Engine - 21. 엔진 문제와 해결 방안 고민 (최적화) (0) | 2025.03.12 |
---|---|
Vulkan Game Engine - 20. point light PCF 그림자 수정 (0) | 2025.03.10 |
Vulkan Game Engine - 18. 그림자 퀄리티 개선, PCF (0) | 2025.02.17 |
Vulkan Game Engine - 17. Skybox 적용 (0) | 2025.02.17 |
Vulkan Game Engine - 16. 중간 정검 (0) | 2025.02.17 |