I’m trying to follow learnOpenGL IBL diffuse irradiance tutorial using vulkan. The tutorial basically uses a equirectangular image to render to six different cubes passing a different view matrix , looking at each cube’s face.
Since i’m getting a very weird result, I’m not sure if it’s done correctly.
is this process correct?
std::vector<float> vertices = {
// back face
-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,
// front face
-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,
// left face
-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,
// right face
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,
// bottom face
-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,
// top face
-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,
};
//HDR image
VkImage hdrText;
VkDeviceMemory hdrMemory;
VkImageView hdrImgView;
createtextureImage("C:\\Users\\Icaro\\source\\repos\\VulkanRender\\model\\scene\\models\\Old_Industrial_Hall\\\Old_Industrial_Hall\\fin4_Env.hdr", &hdrText, &hdrMemory);
hdrImgView = createImageView(hdrText, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT);
//cube vertexBuffer
VkDeviceSize bufferSize = sizeof(CubeVertex) * vertices.size();
VkBuffer stagingBuffer;
VkDeviceMemory stagingBufferMemory;
createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory);
void* data;
vkMapMemory(device, stagingBufferMemory, 0, bufferSize, 0, &data);
memcpy(data, vertices.data(), (size_t)bufferSize);
vkUnmapMemory(device, stagingBufferMemory);
createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, cube.vertexBuffer, cube.vertexBufferMemory);
copyBuffer(stagingBuffer, cube.vertexBuffer, bufferSize);
vkDestroyBuffer(device, stagingBuffer, nullptr);
vkFreeMemory(device, stagingBufferMemory, nullptr);
//View Matricex
glm::mat4 captureProjection = glm::perspective(glm::radians(90.0f), 1.0f, 0.1f, 1.0f);
glm::mat4 captureViews[] =
{
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))
};
//Generate CubeMap target;
const VkFormat format = VK_FORMAT_R32G32B32A32_SFLOAT;
const int32_t width = 800;
const int32_t height = 800;
// Sampler
VkSamplerCreateInfo samplerCI = initializeVulkanStructure::samplerCreateInfo();
samplerCI.magFilter = VK_FILTER_LINEAR;
samplerCI.minFilter = VK_FILTER_LINEAR;
samplerCI.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
samplerCI.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerCI.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerCI.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerCI.minLod = 0.0f;
samplerCI.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
vkCreateSampler(device, &samplerCI, nullptr, &cube.texture.sampler);
// FB, Att, RP, Pipe, etc.
VkAttachmentDescription attDesc = {};
// Color attachment
attDesc.format = format;
attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attDesc.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
VkAttachmentReference colorReference = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
VkSubpassDescription subpassDescription = {};
subpassDescription.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpassDescription.colorAttachmentCount = 1;
subpassDescription.pColorAttachments = &colorReference;
// Use subpass dependencies for layout transitions
std::array<VkSubpassDependency, 2> dependencies;
dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
dependencies[0].dstSubpass = 0;
dependencies[0].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
dependencies[1].srcSubpass = 0;
dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL;
dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[1].dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
// Renderpass
VkRenderPassCreateInfo renderPassCI = initializeVulkanStructure::renderPassCreateInfo();
renderPassCI.attachmentCount = 1;
renderPassCI.pAttachments = &attDesc;
renderPassCI.subpassCount = 1;
renderPassCI.pSubpasses = &subpassDescription;
renderPassCI.dependencyCount = 2;
renderPassCI.pDependencies = dependencies.data();
VkRenderPass rdpass;
vkCreateRenderPass(device, &renderPassCI, nullptr, &rdpass);
const int32_t dim = 800;
const uint32_t numMips = static_cast<uint32_t>(floor(log2(dim))) + 1;
{
// Color attachment
VkImageCreateInfo imageCreateInfo = initializeVulkanStructure::imageCreateInfo();
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
imageCreateInfo.format = format;
imageCreateInfo.extent.width = width;
imageCreateInfo.extent.height = height;
imageCreateInfo.extent.depth = 1;
imageCreateInfo.mipLevels = 1;
imageCreateInfo.arrayLayers = 6;
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageCreateInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |VK_IMAGE_USAGE_SAMPLED_BIT;
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageCreateInfo.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
vkCreateImage(device, &imageCreateInfo, nullptr, &offscreen.image);
VkMemoryAllocateInfo memAlloc = initializeVulkanStructure::memoryAllocateInfo();
VkMemoryRequirements memReqs;
vkGetImageMemoryRequirements(device, offscreen.image, &memReqs);
memAlloc.allocationSize = memReqs.size;
memAlloc.memoryTypeIndex = findMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
vkAllocateMemory(device, &memAlloc, nullptr, &offscreen.memory);
vkBindImageMemory(device, offscreen.image, offscreen.memory, 0);
VkImageViewCreateInfo colorImageView = initializeVulkanStructure::imageViewCreateInfo();
colorImageView.viewType = VK_IMAGE_VIEW_TYPE_CUBE;
colorImageView.format = format;
colorImageView.subresourceRange = {};
colorImageView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
colorImageView.subresourceRange.baseMipLevel = 0;
colorImageView.subresourceRange.levelCount = 1;
colorImageView.subresourceRange.baseArrayLayer = 0;
colorImageView.subresourceRange.layerCount = 6;
colorImageView.image = offscreen.image;
vkCreateImageView(device, &colorImageView, nullptr, &offscreen.view);
VkFramebufferCreateInfo fbufCreateInfo = initializeVulkanStructure::framebufferCreateInfo();
fbufCreateInfo.renderPass = rdpass;
fbufCreateInfo.attachmentCount = 1;
fbufCreateInfo.pAttachments = &offscreen.view;
fbufCreateInfo.width = width;
fbufCreateInfo.height = height;
fbufCreateInfo.layers = 6;
vkCreateFramebuffer(device, &fbufCreateInfo, nullptr, &offscreen.framebuffer);
}
//Descriptors
std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings = {
initializeVulkanStructure::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 0),
};
VkDescriptorSetLayoutCreateInfo descriptorsetlayoutCI = initializeVulkanStructure::descriptorSetLayoutCreateInfo(setLayoutBindings);
vkCreateDescriptorSetLayout(device, &descriptorsetlayoutCI, nullptr, &cube.descriptorsetLayout);
std::vector<VkDescriptorPoolSize> poolSizes = { initializeVulkanStructure::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1) };
VkDescriptorPoolCreateInfo descriptorPoolCI = initializeVulkanStructure::descriptorPoolCreateInfo(poolSizes, 2);
VkDescriptorPool descriptorpool;
vkCreateDescriptorPool(device, &descriptorPoolCI, nullptr, &descriptorpool);
VkDescriptorSetAllocateInfo allocInfo =initializeVulkanStructure::descriptorSetAllocateInfo(descriptorpool, &cube.descriptorsetLayout, 1);
(vkAllocateDescriptorSets(device, &allocInfo, &cube.descritproset));
VkDescriptorImageInfo hdrTexture = {};
hdrTexture.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
hdrTexture.imageView = hdrImgView;
hdrTexture.sampler = cube.texture.sampler;
//AQUIIIII
VkWriteDescriptorSet writeDescriptorSet = initializeVulkanStructure::writeDescriptorSet(cube.descritproset, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 0, &hdrTexture);
vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr);
VkPipelineLayoutCreateInfo pipelineLayoutCI = initializeVulkanStructure::pipelineLayoutCreateInfo(&cube.descriptorsetLayout, 1);
std::vector<VkPushConstantRange> pushConstantRanges = {
initializeVulkanStructure::pushConstantRange( VK_SHADER_STAGE_VERTEX_BIT, sizeof(PushBlock), 0),
};
pipelineLayoutCI.pushConstantRangeCount = 1;
pipelineLayoutCI.pPushConstantRanges = pushConstantRanges.data();
(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &cube.pipelineLayout));
// Pipeline
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = initializeVulkanStructure::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0, VK_FALSE);
VkPipelineRasterizationStateCreateInfo rasterizationState = initializeVulkanStructure::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, VK_CULL_MODE_NONE, VK_FRONT_FACE_COUNTER_CLOCKWISE);
VkPipelineColorBlendAttachmentState blendAttachmentState = initializeVulkanStructure::pipelineColorBlendAttachmentState(0xf, VK_FALSE);
VkPipelineColorBlendStateCreateInfo colorBlendState = initializeVulkanStructure::pipelineColorBlendStateCreateInfo(1, &blendAttachmentState);
VkPipelineDepthStencilStateCreateInfo depthStencilState = initializeVulkanStructure::pipelineDepthStencilStateCreateInfo(VK_FALSE, VK_FALSE, VK_COMPARE_OP_LESS_OR_EQUAL);
VkPipelineViewportStateCreateInfo viewportState = initializeVulkanStructure::pipelineViewportStateCreateInfo(1, 1, VK_DYNAMIC_STATE_VIEWPORT);
VkPipelineMultisampleStateCreateInfo multisampleState = initializeVulkanStructure::pipelineMultisampleStateCreateInfo(VK_SAMPLE_COUNT_1_BIT);
std::vector<VkDynamicState> dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
VkPipelineDynamicStateCreateInfo dynamicState = initializeVulkanStructure::pipelineDynamicStateCreateInfo(dynamicStateEnables);
// Vertex input state
std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages;
VkPipelineVertexInputStateCreateInfo vertexInputState = {};
vertexInputState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
auto bindingDescription = CubeVertex::getBindingDescription();
auto attributeDescriptions = CubeVertex::getAttributeDescriptions();
vertexInputState.vertexBindingDescriptionCount = 1;
vertexInputState.vertexAttributeDescriptionCount = static_cast<uint32_t>(attributeDescriptions.size());
vertexInputState.pVertexBindingDescriptions = &bindingDescription;
vertexInputState.pVertexAttributeDescriptions = attributeDescriptions.data();
auto vertShaderCode = readFile("C:\\Users\\Icaro\\source\\repos\\VulkanRender\\shaders\\spir-v\\postvert.spv");
auto fragShaderCode = readFile("C:\\Users\\Icaro\\source\\repos\\VulkanRender\\shaders\\spir-v\\postfrag.spv");
auto vert = createShaderModule(vertShaderCode);
auto frag = createShaderModule(fragShaderCode);
VkPipelineShaderStageCreateInfo vertShader = {};
vertShader.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
vertShader.stage = VK_SHADER_STAGE_VERTEX_BIT;
vertShader.module = vert;
vertShader.pName = "main";
VkPipelineShaderStageCreateInfo fragShader = {};
fragShader.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
fragShader.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
fragShader.module = frag;
fragShader.pName = "main";
shaderStages = { vertShader,fragShader };
VkGraphicsPipelineCreateInfo pipelineCI = initializeVulkanStructure::pipelineCreateInfo(cube.pipelineLayout, rdpass);
pipelineCI.pInputAssemblyState = &inputAssemblyState;
pipelineCI.pRasterizationState = &rasterizationState;
pipelineCI.pColorBlendState = &colorBlendState;
pipelineCI.pMultisampleState = &multisampleState;
pipelineCI.pViewportState = &viewportState;
pipelineCI.pDepthStencilState = &depthStencilState;
pipelineCI.pDynamicState = &dynamicState;
pipelineCI.stageCount = 2;
pipelineCI.pStages = shaderStages.data();
pipelineCI.pVertexInputState = &vertexInputState;
pipelineCI.renderPass = rdpass;
vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &cube.pipeline);
PushBlock p;
p.projection = captureProjection;
//Render
VkClearValue clearValues[1];
clearValues[0].color = { { 0.3f, 1.0f, 0.2f, 0.0f } };
VkRenderPassBeginInfo renderPassBeginInfo = initializeVulkanStructure::renderPassBeginInfo();
// Reuse render pass from example pass
renderPassBeginInfo.renderPass = rdpass;
renderPassBeginInfo.framebuffer = offscreen.framebuffer;
renderPassBeginInfo.renderArea.extent.width = width;
renderPassBeginInfo.renderArea.extent.height = height;
renderPassBeginInfo.clearValueCount = 1;
renderPassBeginInfo.pClearValues = clearValues;
VkViewport viewport;
viewport.height = height;
viewport.width = width;
viewport.minDepth = 0;
viewport.maxDepth = 1;
VkDescriptorSet descriptorset1;
VkCommandBuffer cmd = beginSingleTimeCommands();
vkCmdBeginRenderPass(cmd, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
for (unsigned int i = 0; i < 6; i++) {
VkDeviceSize offsets[1] = { 0 };
vkCmdSetViewport(cmd, 0, 1, &viewport);
p.projection = captureProjection;
p.view = captureViews[i];
VkRect2D rect = {};
rect.extent.width = width;
rect.extent.height = height;
rect.offset = { 0,0 };
vkCmdSetScissor(cmd, 0, 1, &rect);
descriptorset1 = cube.descritproset;
vkCmdBindVertexBuffers(cmd, 0, 1, &cube.vertexBuffer, offsets);
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, cube.pipelineLayout, 0, 1, &descriptorset1, 0, NULL);
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, cube.pipeline);
vkCmdPushConstants(
cmd,
cube.pipelineLayout,
VK_SHADER_STAGE_VERTEX_BIT,
0,
sizeof(PushBlock),
&p);
vkCmdDraw(cmd,36, 1, 0, 0);
}
vkCmdEndRenderPass(cmd);
endSingleTimeCommands(cmd);
I know there are many function specific to my project (or sascha willems repo) the overall process, is it done correctly?
When I try to render a cube using this offscreen.image texture.
I see that the texture is aplied only to one face, always the same face. When changing the view it just the change de “part” of the image to be loaded, but it always load to the same face
the other 5 faces are just setted to the clean value…