Skip to content
Snippets Groups Projects
Commit e74f7413 authored by Alexander Gauggel's avatar Alexander Gauggel
Browse files

Merge branch '77-lens-flares' into 'develop'

Resolve "Lens Flares"

Closes #77

See merge request !62
parents 09fd98e2 87c3435b
Branches
Tags
1 merge request!62Resolve "Lens Flares"
Pipeline #26061 failed
#version 450
#extension GL_ARB_separate_shader_objects : enable
layout(location = 0) in vec3 inPosition;
layout( push_constant ) uniform constants{
mat4 mvp;
};
void main() {
gl_Position = mvp * vec4(inPosition, 1.0);
}
\ No newline at end of file
#version 450
#extension GL_ARB_separate_shader_objects : enable
layout(set=0, binding=0) uniform texture2D inUpsampleImage;
layout(set=0, binding=1) uniform sampler inImageSampler;
layout(set=0, binding=2, r11f_g11f_b10f) uniform image2D outUpsampleImage;
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
void main()
{
if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(outUpsampleImage)))){
return;
}
ivec2 pixel_coord = ivec2(gl_GlobalInvocationID.xy);
vec2 pixel_size = vec2(1.0f) / imageSize(outUpsampleImage);
vec2 UV = pixel_coord.xy * pixel_size;
const float gauss_kernel[3] = {1.f, 2.f, 1.f};
const float gauss_weight = 16.f;
vec3 sampled_color = vec3(0.f);
for(int i = -1; i <= 1; i++)
{
for(int j = -1; j <= 1; j++)
{
vec2 sample_location = UV + vec2(j, i) * pixel_size;
vec3 color = texture(sampler2D(inUpsampleImage, inImageSampler), sample_location).rgb;
color *= gauss_kernel[j+1];
color *= gauss_kernel[i+1];
color /= gauss_weight;
sampled_color += color;
}
}
//vec3 prev_color = imageLoad(outUpsampleImage, pixel_coord).rgb;
//float bloomRimStrength = 0.75f; // adjust this to change strength of bloom
//sampled_color = mix(prev_color, sampled_color, bloomRimStrength);
imageStore(outUpsampleImage, pixel_coord, vec4(sampled_color, 1.f));
}
\ No newline at end of file
#include "BloomAndFlares.hpp"
#include <vkcv/shader/GLSLCompiler.hpp>
BloomAndFlares::BloomAndFlares(
vkcv::Core *p_Core,
vk::Format colorBufferFormat,
uint32_t width,
uint32_t height) :
p_Core(p_Core),
m_ColorBufferFormat(colorBufferFormat),
m_Width(width),
m_Height(height),
m_LinearSampler(p_Core->createSampler(vkcv::SamplerFilterType::LINEAR,
vkcv::SamplerFilterType::LINEAR,
vkcv::SamplerMipmapMode::LINEAR,
vkcv::SamplerAddressMode::CLAMP_TO_EDGE)),
m_Blur(p_Core->createImage(colorBufferFormat, width, height, 1, true, true, false)),
m_LensFeatures(p_Core->createImage(colorBufferFormat, width, height, 1, false, true, false))
{
vkcv::shader::GLSLCompiler compiler;
// DOWNSAMPLE
vkcv::ShaderProgram dsProg;
compiler.compile(vkcv::ShaderStage::COMPUTE,
"resources/shaders/downsample.comp",
[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path)
{
dsProg.addShader(shaderStage, path);
});
for(uint32_t mipLevel = 0; mipLevel < m_Blur.getMipCount(); mipLevel++)
{
m_DownsampleDescSets.push_back(
p_Core->createDescriptorSet(dsProg.getReflectedDescriptors()[0]));
}
m_DownsamplePipe = p_Core->createComputePipeline(
dsProg, { p_Core->getDescriptorSet(m_DownsampleDescSets[0]).layout });
// UPSAMPLE
vkcv::ShaderProgram usProg;
compiler.compile(vkcv::ShaderStage::COMPUTE,
"resources/shaders/upsample.comp",
[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path)
{
usProg.addShader(shaderStage, path);
});
for(uint32_t mipLevel = 0; mipLevel < m_Blur.getMipCount(); mipLevel++)
{
m_UpsampleDescSets.push_back(
p_Core->createDescriptorSet(usProg.getReflectedDescriptors()[0]));
}
m_UpsamplePipe = p_Core->createComputePipeline(
usProg, { p_Core->getDescriptorSet(m_UpsampleDescSets[0]).layout });
// LENS FEATURES
vkcv::ShaderProgram lensProg;
compiler.compile(vkcv::ShaderStage::COMPUTE,
"resources/shaders/lensFlares.comp",
[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path)
{
lensProg.addShader(shaderStage, path);
});
m_LensFlareDescSet = p_Core->createDescriptorSet(lensProg.getReflectedDescriptors()[0]);
m_LensFlarePipe = p_Core->createComputePipeline(
lensProg, { p_Core->getDescriptorSet(m_LensFlareDescSet).layout });
// COMPOSITE
vkcv::ShaderProgram compProg;
compiler.compile(vkcv::ShaderStage::COMPUTE,
"resources/shaders/composite.comp",
[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path)
{
compProg.addShader(shaderStage, path);
});
m_CompositeDescSet = p_Core->createDescriptorSet(compProg.getReflectedDescriptors()[0]);
m_CompositePipe = p_Core->createComputePipeline(
compProg, { p_Core->getDescriptorSet(m_CompositeDescSet).layout });
}
void BloomAndFlares::execDownsamplePipe(const vkcv::CommandStreamHandle &cmdStream,
const vkcv::ImageHandle &colorAttachment)
{
auto dispatchCountX = static_cast<float>(m_Width) / 8.0f;
auto dispatchCountY = static_cast<float>(m_Height) / 8.0f;
// blur dispatch
uint32_t initialDispatchCount[3] = {
static_cast<uint32_t>(glm::ceil(dispatchCountX)),
static_cast<uint32_t>(glm::ceil(dispatchCountY)),
1
};
// downsample dispatch of original color attachment
p_Core->prepareImageForSampling(cmdStream, colorAttachment);
p_Core->prepareImageForStorage(cmdStream, m_Blur.getHandle());
vkcv::DescriptorWrites initialDownsampleWrites;
initialDownsampleWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, colorAttachment)};
initialDownsampleWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(1, m_LinearSampler)};
initialDownsampleWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(2, m_Blur.getHandle(), 0) };
p_Core->writeDescriptorSet(m_DownsampleDescSets[0], initialDownsampleWrites);
p_Core->recordComputeDispatchToCmdStream(
cmdStream,
m_DownsamplePipe,
initialDispatchCount,
{vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_DownsampleDescSets[0]).vulkanHandle)},
vkcv::PushConstantData(nullptr, 0));
// downsample dispatches of blur buffer's mip maps
float mipDispatchCountX = dispatchCountX;
float mipDispatchCountY = dispatchCountY;
for(uint32_t mipLevel = 1; mipLevel < m_DownsampleDescSets.size(); mipLevel++)
{
// mip descriptor writes
vkcv::DescriptorWrites mipDescriptorWrites;
mipDescriptorWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, m_Blur.getHandle(), mipLevel - 1, true)};
mipDescriptorWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(1, m_LinearSampler)};
mipDescriptorWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(2, m_Blur.getHandle(), mipLevel) };
p_Core->writeDescriptorSet(m_DownsampleDescSets[mipLevel], mipDescriptorWrites);
// mip dispatch calculation
mipDispatchCountX /= 2.0f;
mipDispatchCountY /= 2.0f;
uint32_t mipDispatchCount[3] = {
static_cast<uint32_t>(glm::ceil(mipDispatchCountX)),
static_cast<uint32_t>(glm::ceil(mipDispatchCountY)),
1
};
if(mipDispatchCount[0] == 0)
mipDispatchCount[0] = 1;
if(mipDispatchCount[1] == 0)
mipDispatchCount[1] = 1;
// mip blur dispatch
p_Core->recordComputeDispatchToCmdStream(
cmdStream,
m_DownsamplePipe,
mipDispatchCount,
{vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_DownsampleDescSets[mipLevel]).vulkanHandle)},
vkcv::PushConstantData(nullptr, 0));
// image barrier between mips
p_Core->recordImageMemoryBarrier(cmdStream, m_Blur.getHandle());
}
}
void BloomAndFlares::execUpsamplePipe(const vkcv::CommandStreamHandle &cmdStream)
{
// upsample dispatch
p_Core->prepareImageForStorage(cmdStream, m_Blur.getHandle());
const uint32_t upsampleMipLevels = std::min(
static_cast<uint32_t>(m_UpsampleDescSets.size() - 1),
static_cast<uint32_t>(5)
);
// upsample dispatch for each mip map
for(uint32_t mipLevel = upsampleMipLevels; mipLevel > 0; mipLevel--)
{
// mip descriptor writes
vkcv::DescriptorWrites mipUpsampleWrites;
mipUpsampleWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, m_Blur.getHandle(), mipLevel, true)};
mipUpsampleWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(1, m_LinearSampler)};
mipUpsampleWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(2, m_Blur.getHandle(), mipLevel - 1) };
p_Core->writeDescriptorSet(m_UpsampleDescSets[mipLevel], mipUpsampleWrites);
auto mipDivisor = glm::pow(2.0f, static_cast<float>(mipLevel) - 1.0f);
auto upsampleDispatchX = static_cast<float>(m_Width) / mipDivisor;
auto upsampleDispatchY = static_cast<float>(m_Height) / mipDivisor;
upsampleDispatchX /= 8.0f;
upsampleDispatchY /= 8.0f;
const uint32_t upsampleDispatchCount[3] = {
static_cast<uint32_t>(glm::ceil(upsampleDispatchX)),
static_cast<uint32_t>(glm::ceil(upsampleDispatchY)),
1
};
p_Core->recordComputeDispatchToCmdStream(
cmdStream,
m_UpsamplePipe,
upsampleDispatchCount,
{vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_UpsampleDescSets[mipLevel]).vulkanHandle)},
vkcv::PushConstantData(nullptr, 0)
);
// image barrier between mips
p_Core->recordImageMemoryBarrier(cmdStream, m_Blur.getHandle());
}
}
void BloomAndFlares::execLensFeaturePipe(const vkcv::CommandStreamHandle &cmdStream)
{
// lens feature generation descriptor writes
p_Core->prepareImageForSampling(cmdStream, m_Blur.getHandle());
p_Core->prepareImageForStorage(cmdStream, m_LensFeatures.getHandle());
vkcv::DescriptorWrites lensFeatureWrites;
lensFeatureWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, m_Blur.getHandle(), 0)};
lensFeatureWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(1, m_LinearSampler)};
lensFeatureWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(2, m_LensFeatures.getHandle(), 0)};
p_Core->writeDescriptorSet(m_LensFlareDescSet, lensFeatureWrites);
auto dispatchCountX = static_cast<float>(m_Width) / 8.0f;
auto dispatchCountY = static_cast<float>(m_Height) / 8.0f;
// lens feature generation dispatch
uint32_t lensFeatureDispatchCount[3] = {
static_cast<uint32_t>(glm::ceil(dispatchCountX)),
static_cast<uint32_t>(glm::ceil(dispatchCountY)),
1
};
p_Core->recordComputeDispatchToCmdStream(
cmdStream,
m_LensFlarePipe,
lensFeatureDispatchCount,
{vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_LensFlareDescSet).vulkanHandle)},
vkcv::PushConstantData(nullptr, 0));
}
void BloomAndFlares::execCompositePipe(const vkcv::CommandStreamHandle &cmdStream,
const vkcv::ImageHandle &colorAttachment)
{
p_Core->prepareImageForSampling(cmdStream, m_Blur.getHandle());
p_Core->prepareImageForSampling(cmdStream, m_LensFeatures.getHandle());
p_Core->prepareImageForStorage(cmdStream, colorAttachment);
// bloom composite descriptor write
vkcv::DescriptorWrites compositeWrites;
compositeWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, m_Blur.getHandle()),
vkcv::SampledImageDescriptorWrite(1, m_LensFeatures.getHandle())};
compositeWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(2, m_LinearSampler)};
compositeWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(3, colorAttachment)};
p_Core->writeDescriptorSet(m_CompositeDescSet, compositeWrites);
float dispatchCountX = static_cast<float>(m_Width) / 8.0f;
float dispatchCountY = static_cast<float>(m_Height) / 8.0f;
uint32_t compositeDispatchCount[3] = {
static_cast<uint32_t>(glm::ceil(dispatchCountX)),
static_cast<uint32_t>(glm::ceil(dispatchCountY)),
1
};
// bloom composite dispatch
p_Core->recordComputeDispatchToCmdStream(
cmdStream,
m_CompositePipe,
compositeDispatchCount,
{vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_CompositeDescSet).vulkanHandle)},
vkcv::PushConstantData(nullptr, 0));
}
void BloomAndFlares::execWholePipeline(const vkcv::CommandStreamHandle &cmdStream,
const vkcv::ImageHandle &colorAttachment)
{
execDownsamplePipe(cmdStream, colorAttachment);
execUpsamplePipe(cmdStream);
execLensFeaturePipe(cmdStream);
execCompositePipe(cmdStream, colorAttachment);
}
void BloomAndFlares::updateImageDimensions(uint32_t width, uint32_t height)
{
m_Width = width;
m_Height = height;
p_Core->getContext().getDevice().waitIdle();
m_Blur = p_Core->createImage(m_ColorBufferFormat, m_Width, m_Height, 1, true, true, false);
m_LensFeatures = p_Core->createImage(m_ColorBufferFormat, m_Width, m_Height, 1, false, true, false);
}
#pragma once
#include <vkcv/Core.hpp>
#include <glm/glm.hpp>
class BloomAndFlares{
public:
BloomAndFlares(vkcv::Core *p_Core,
vk::Format colorBufferFormat,
uint32_t width,
uint32_t height);
void execWholePipeline(const vkcv::CommandStreamHandle &cmdStream, const vkcv::ImageHandle &colorAttachment);
void updateImageDimensions(uint32_t width, uint32_t height);
private:
vkcv::Core *p_Core;
vk::Format m_ColorBufferFormat;
uint32_t m_Width;
uint32_t m_Height;
vkcv::SamplerHandle m_LinearSampler;
vkcv::Image m_Blur;
vkcv::Image m_LensFeatures;
vkcv::PipelineHandle m_DownsamplePipe;
std::vector<vkcv::DescriptorSetHandle> m_DownsampleDescSets; // per mip desc set
vkcv::PipelineHandle m_UpsamplePipe;
std::vector<vkcv::DescriptorSetHandle> m_UpsampleDescSets; // per mip desc set
vkcv::PipelineHandle m_LensFlarePipe;
vkcv::DescriptorSetHandle m_LensFlareDescSet;
vkcv::PipelineHandle m_CompositePipe;
vkcv::DescriptorSetHandle m_CompositeDescSet;
void execDownsamplePipe(const vkcv::CommandStreamHandle &cmdStream, const vkcv::ImageHandle &colorAttachment);
void execUpsamplePipe(const vkcv::CommandStreamHandle &cmdStream);
void execLensFeaturePipe(const vkcv::CommandStreamHandle &cmdStream);
void execCompositePipe(const vkcv::CommandStreamHandle &cmdStream, const vkcv::ImageHandle &colorAttachment);
};
#include <iostream>
#include <vkcv/Core.hpp>
#include <GLFW/glfw3.h>
#include <vkcv/camera/CameraManager.hpp>
#include <chrono>
#include <vkcv/asset/asset_loader.hpp>
#include <vkcv/shader/GLSLCompiler.hpp>
#include <vkcv/Logger.hpp>
#include "BloomAndFlares.hpp"
#include <glm/glm.hpp>
int main(int argc, const char** argv) {
const char* applicationName = "Bloom";
uint32_t windowWidth = 1920;
uint32_t windowHeight = 1080;
vkcv::Window window = vkcv::Window::create(
applicationName,
windowWidth,
windowHeight,
true
);
vkcv::camera::CameraManager cameraManager(window);
uint32_t camIndex = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT);
uint32_t camIndex2 = cameraManager.addCamera(vkcv::camera::ControllerType::TRACKBALL);
cameraManager.getCamera(camIndex).setPosition(glm::vec3(0.f, 0.f, 3.f));
cameraManager.getCamera(camIndex).setNearFar(0.1f, 30.0f);
cameraManager.getCamera(camIndex).setYaw(180.0f);
cameraManager.getCamera(camIndex2).setNearFar(0.1f, 30.0f);
window.initEvents();
vkcv::Core core = vkcv::Core::create(
window,
applicationName,
VK_MAKE_VERSION(0, 0, 1),
{ vk::QueueFlagBits::eTransfer,vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute },
{},
{ "VK_KHR_swapchain" }
);
const char* path = argc > 1 ? argv[1] : "resources/Sponza/Sponza.gltf";
vkcv::asset::Scene scene;
int result = vkcv::asset::loadScene(path, scene);
if (result == 1) {
std::cout << "Scene loading successful!" << std::endl;
}
else {
std::cout << "Scene loading failed: " << result << std::endl;
return 1;
}
// build index and vertex buffers
assert(!scene.vertexGroups.empty());
std::vector<std::vector<uint8_t>> vBuffers;
std::vector<std::vector<uint8_t>> iBuffers;
std::vector<vkcv::VertexBufferBinding> vBufferBindings;
std::vector<std::vector<vkcv::VertexBufferBinding>> vertexBufferBindings;
std::vector<vkcv::asset::VertexAttribute> vAttributes;
for (int i = 0; i < scene.vertexGroups.size(); i++) {
vBuffers.push_back(scene.vertexGroups[i].vertexBuffer.data);
iBuffers.push_back(scene.vertexGroups[i].indexBuffer.data);
auto& attributes = scene.vertexGroups[i].vertexBuffer.attributes;
std::sort(attributes.begin(), attributes.end(), [](const vkcv::asset::VertexAttribute& x, const vkcv::asset::VertexAttribute& y) {
return static_cast<uint32_t>(x.type) < static_cast<uint32_t>(y.type);
});
}
std::vector<vkcv::Buffer<uint8_t>> vertexBuffers;
for (const vkcv::asset::VertexGroup& group : scene.vertexGroups) {
vertexBuffers.push_back(core.createBuffer<uint8_t>(
vkcv::BufferType::VERTEX,
group.vertexBuffer.data.size()));
vertexBuffers.back().fill(group.vertexBuffer.data);
}
std::vector<vkcv::Buffer<uint8_t>> indexBuffers;
for (const auto& dataBuffer : iBuffers) {
indexBuffers.push_back(core.createBuffer<uint8_t>(
vkcv::BufferType::INDEX,
dataBuffer.size()));
indexBuffers.back().fill(dataBuffer);
}
int vertexBufferIndex = 0;
for (const auto& vertexGroup : scene.vertexGroups) {
for (const auto& attribute : vertexGroup.vertexBuffer.attributes) {
vAttributes.push_back(attribute);
vBufferBindings.push_back(vkcv::VertexBufferBinding(attribute.offset, vertexBuffers[vertexBufferIndex].getVulkanHandle()));
}
vertexBufferBindings.push_back(vBufferBindings);
vBufferBindings.clear();
vertexBufferIndex++;
}
const vk::Format colorBufferFormat = vk::Format::eB10G11R11UfloatPack32;
const vkcv::AttachmentDescription color_attachment(
vkcv::AttachmentOperation::STORE,
vkcv::AttachmentOperation::CLEAR,
colorBufferFormat
);
const vk::Format depthBufferFormat = vk::Format::eD32Sfloat;
const vkcv::AttachmentDescription depth_attachment(
vkcv::AttachmentOperation::STORE,
vkcv::AttachmentOperation::CLEAR,
depthBufferFormat
);
vkcv::PassConfig forwardPassDefinition({ color_attachment, depth_attachment });
vkcv::PassHandle forwardPass = core.createPass(forwardPassDefinition);
vkcv::shader::GLSLCompiler compiler;
vkcv::ShaderProgram forwardProgram;
compiler.compile(vkcv::ShaderStage::VERTEX, std::filesystem::path("resources/shaders/shader.vert"),
[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
forwardProgram.addShader(shaderStage, path);
});
compiler.compile(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("resources/shaders/shader.frag"),
[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
forwardProgram.addShader(shaderStage, path);
});
const std::vector<vkcv::VertexAttachment> vertexAttachments = forwardProgram.getVertexAttachments();
std::vector<vkcv::VertexBinding> vertexBindings;
for (size_t i = 0; i < vertexAttachments.size(); i++) {
vertexBindings.push_back(vkcv::VertexBinding(i, { vertexAttachments[i] }));
}
const vkcv::VertexLayout vertexLayout (vertexBindings);
// shadow map
vkcv::SamplerHandle shadowSampler = core.createSampler(
vkcv::SamplerFilterType::NEAREST,
vkcv::SamplerFilterType::NEAREST,
vkcv::SamplerMipmapMode::NEAREST,
vkcv::SamplerAddressMode::CLAMP_TO_EDGE
);
const vk::Format shadowMapFormat = vk::Format::eD16Unorm;
const uint32_t shadowMapResolution = 1024;
const vkcv::Image shadowMap = core.createImage(shadowMapFormat, shadowMapResolution, shadowMapResolution, 1);
// light info buffer
struct LightInfo {
glm::vec3 direction;
float padding;
glm::mat4 lightMatrix;
};
LightInfo lightInfo;
vkcv::Buffer lightBuffer = core.createBuffer<LightInfo>(vkcv::BufferType::UNIFORM, sizeof(glm::vec3));
vkcv::DescriptorSetHandle forwardShadingDescriptorSet =
core.createDescriptorSet({ forwardProgram.getReflectedDescriptors()[0] });
vkcv::DescriptorWrites forwardDescriptorWrites;
forwardDescriptorWrites.uniformBufferWrites = { vkcv::UniformBufferDescriptorWrite(0, lightBuffer.getHandle()) };
forwardDescriptorWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(1, shadowMap.getHandle()) };
forwardDescriptorWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(2, shadowSampler) };
core.writeDescriptorSet(forwardShadingDescriptorSet, forwardDescriptorWrites);
vkcv::SamplerHandle colorSampler = core.createSampler(
vkcv::SamplerFilterType::LINEAR,
vkcv::SamplerFilterType::LINEAR,
vkcv::SamplerMipmapMode::LINEAR,
vkcv::SamplerAddressMode::REPEAT
);
// prepare per mesh descriptor sets
std::vector<vkcv::DescriptorSetHandle> perMeshDescriptorSets;
std::vector<vkcv::Image> sceneImages;
for (const auto& vertexGroup : scene.vertexGroups) {
perMeshDescriptorSets.push_back(core.createDescriptorSet(forwardProgram.getReflectedDescriptors()[1]));
const auto& material = scene.materials[vertexGroup.materialIndex];
int baseColorIndex = material.baseColor;
if (baseColorIndex < 0) {
vkcv_log(vkcv::LogLevel::WARNING, "Material lacks base color");
baseColorIndex = 0;
}
vkcv::asset::Texture& sceneTexture = scene.textures[baseColorIndex];
sceneImages.push_back(core.createImage(vk::Format::eR8G8B8A8Srgb, sceneTexture.w, sceneTexture.h));
sceneImages.back().fill(sceneTexture.data.data());
vkcv::DescriptorWrites setWrites;
setWrites.sampledImageWrites = {
vkcv::SampledImageDescriptorWrite(0, sceneImages.back().getHandle())
};
setWrites.samplerWrites = {
vkcv::SamplerDescriptorWrite(1, colorSampler),
};
core.writeDescriptorSet(perMeshDescriptorSets.back(), setWrites);
}
const vkcv::PipelineConfig forwardPipelineConfig {
forwardProgram,
windowWidth,
windowHeight,
forwardPass,
vertexLayout,
{ core.getDescriptorSet(forwardShadingDescriptorSet).layout,
core.getDescriptorSet(perMeshDescriptorSets[0]).layout },
true
};
vkcv::PipelineHandle forwardPipeline = core.createGraphicsPipeline(forwardPipelineConfig);
if (!forwardPipeline) {
std::cout << "Error. Could not create graphics pipeline. Exiting." << std::endl;
return EXIT_FAILURE;
}
vkcv::ImageHandle depthBuffer = core.createImage(depthBufferFormat, windowWidth, windowHeight).getHandle();
vkcv::ImageHandle colorBuffer = core.createImage(colorBufferFormat, windowWidth, windowHeight, 1, false, true, true).getHandle();
const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle();
vkcv::ShaderProgram shadowShader;
compiler.compile(vkcv::ShaderStage::VERTEX, "resources/shaders/shadow.vert",
[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
shadowShader.addShader(shaderStage, path);
});
compiler.compile(vkcv::ShaderStage::FRAGMENT, "resources/shaders/shadow.frag",
[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
shadowShader.addShader(shaderStage, path);
});
const std::vector<vkcv::AttachmentDescription> shadowAttachments = {
vkcv::AttachmentDescription(vkcv::AttachmentOperation::STORE, vkcv::AttachmentOperation::CLEAR, shadowMapFormat)
};
const vkcv::PassConfig shadowPassConfig(shadowAttachments);
const vkcv::PassHandle shadowPass = core.createPass(shadowPassConfig);
const vkcv::PipelineConfig shadowPipeConfig{
shadowShader,
shadowMapResolution,
shadowMapResolution,
shadowPass,
vertexLayout,
{},
false
};
const vkcv::PipelineHandle shadowPipe = core.createGraphicsPipeline(shadowPipeConfig);
std::vector<std::array<glm::mat4, 2>> mainPassMatrices;
std::vector<glm::mat4> mvpLight;
// gamma correction compute shader
vkcv::ShaderProgram gammaCorrectionProgram;
compiler.compile(vkcv::ShaderStage::COMPUTE, "resources/shaders/gammaCorrection.comp",
[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
gammaCorrectionProgram.addShader(shaderStage, path);
});
vkcv::DescriptorSetHandle gammaCorrectionDescriptorSet = core.createDescriptorSet(gammaCorrectionProgram.getReflectedDescriptors()[0]);
vkcv::PipelineHandle gammaCorrectionPipeline = core.createComputePipeline(gammaCorrectionProgram,
{ core.getDescriptorSet(gammaCorrectionDescriptorSet).layout });
BloomAndFlares baf(&core, colorBufferFormat, windowWidth, windowHeight);
// model matrices per mesh
std::vector<glm::mat4> modelMatrices;
modelMatrices.resize(scene.vertexGroups.size(), glm::mat4(1.f));
for (const auto& mesh : scene.meshes) {
const glm::mat4 m = *reinterpret_cast<const glm::mat4*>(&mesh.modelMatrix[0]);
for (const auto& vertexGroupIndex : mesh.vertexGroups) {
modelMatrices[vertexGroupIndex] = m;
}
}
// prepare drawcalls
std::vector<vkcv::Mesh> meshes;
for (int i = 0; i < scene.vertexGroups.size(); i++) {
vkcv::Mesh mesh(
vertexBufferBindings[i],
indexBuffers[i].getVulkanHandle(),
scene.vertexGroups[i].numIndices);
meshes.push_back(mesh);
}
std::vector<vkcv::DrawcallInfo> drawcalls;
std::vector<vkcv::DrawcallInfo> shadowDrawcalls;
for (int i = 0; i < meshes.size(); i++) {
drawcalls.push_back(vkcv::DrawcallInfo(meshes[i], {
vkcv::DescriptorSetUsage(0, core.getDescriptorSet(forwardShadingDescriptorSet).vulkanHandle),
vkcv::DescriptorSetUsage(1, core.getDescriptorSet(perMeshDescriptorSets[i]).vulkanHandle) }));
shadowDrawcalls.push_back(vkcv::DrawcallInfo(meshes[i], {}));
}
auto start = std::chrono::system_clock::now();
const auto appStartTime = start;
while (window.isWindowOpen()) {
vkcv::Window::pollEvents();
uint32_t swapchainWidth, swapchainHeight;
if (!core.beginFrame(swapchainWidth, swapchainHeight)) {
continue;
}
if ((swapchainWidth != windowWidth) || ((swapchainHeight != windowHeight))) {
depthBuffer = core.createImage(depthBufferFormat, swapchainWidth, swapchainHeight).getHandle();
colorBuffer = core.createImage(colorBufferFormat, swapchainWidth, swapchainHeight, 1, false, true, true).getHandle();
baf.updateImageDimensions(swapchainWidth, swapchainHeight);
windowWidth = swapchainWidth;
windowHeight = swapchainHeight;
}
auto end = std::chrono::system_clock::now();
auto deltatime = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
start = end;
cameraManager.update(0.000001 * static_cast<double>(deltatime.count()));
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - appStartTime);
const float sunTheta = 0.0001f * static_cast<float>(duration.count());
lightInfo.direction = glm::normalize(glm::vec3(std::cos(sunTheta), 1, std::sin(sunTheta)));
const float shadowProjectionSize = 20.f;
glm::mat4 projectionLight = glm::ortho(
-shadowProjectionSize,
shadowProjectionSize,
-shadowProjectionSize,
shadowProjectionSize,
-shadowProjectionSize,
shadowProjectionSize);
glm::mat4 vulkanCorrectionMatrix(1.f);
vulkanCorrectionMatrix[2][2] = 0.5;
vulkanCorrectionMatrix[3][2] = 0.5;
projectionLight = vulkanCorrectionMatrix * projectionLight;
const glm::mat4 viewLight = glm::lookAt(glm::vec3(0), -lightInfo.direction, glm::vec3(0, -1, 0));
lightInfo.lightMatrix = projectionLight * viewLight;
lightBuffer.fill({ lightInfo });
const glm::mat4 viewProjectionCamera = cameraManager.getActiveCamera().getMVP();
mainPassMatrices.clear();
mvpLight.clear();
for (const auto& m : modelMatrices) {
mainPassMatrices.push_back({ viewProjectionCamera * m, m });
mvpLight.push_back(lightInfo.lightMatrix * m);
}
vkcv::PushConstantData pushConstantData((void*)mainPassMatrices.data(), 2 * sizeof(glm::mat4));
const std::vector<vkcv::ImageHandle> renderTargets = { colorBuffer, depthBuffer };
const vkcv::PushConstantData shadowPushConstantData((void*)mvpLight.data(), sizeof(glm::mat4));
auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics);
// shadow map
core.recordDrawcallsToCmdStream(
cmdStream,
shadowPass,
shadowPipe,
shadowPushConstantData,
shadowDrawcalls,
{ shadowMap.getHandle() });
core.prepareImageForSampling(cmdStream, shadowMap.getHandle());
// main pass
core.recordDrawcallsToCmdStream(
cmdStream,
forwardPass,
forwardPipeline,
pushConstantData,
drawcalls,
renderTargets);
const uint32_t gammaCorrectionLocalGroupSize = 8;
const uint32_t gammaCorrectionDispatchCount[3] = {
static_cast<uint32_t>(glm::ceil(static_cast<float>(windowWidth) / static_cast<float>(gammaCorrectionLocalGroupSize))),
static_cast<uint32_t>(glm::ceil(static_cast<float>(windowHeight) / static_cast<float>(gammaCorrectionLocalGroupSize))),
1
};
baf.execWholePipeline(cmdStream, colorBuffer);
core.prepareImageForStorage(cmdStream, swapchainInput);
// gamma correction descriptor write
vkcv::DescriptorWrites gammaCorrectionDescriptorWrites;
gammaCorrectionDescriptorWrites.storageImageWrites = {
vkcv::StorageImageDescriptorWrite(0, colorBuffer),
vkcv::StorageImageDescriptorWrite(1, swapchainInput) };
core.writeDescriptorSet(gammaCorrectionDescriptorSet, gammaCorrectionDescriptorWrites);
// gamma correction dispatch
core.recordComputeDispatchToCmdStream(
cmdStream,
gammaCorrectionPipeline,
gammaCorrectionDispatchCount,
{ vkcv::DescriptorSetUsage(0, core.getDescriptorSet(gammaCorrectionDescriptorSet).vulkanHandle) },
vkcv::PushConstantData(nullptr, 0));
// present and end
core.prepareSwapchainImageForPresent(cmdStream);
core.submitCommandStream(cmdStream);
core.endFrame();
}
return 0;
}
......@@ -107,10 +107,11 @@ namespace vkcv
std::vector<WriteDescriptorSetInfo> writeInfos;
for (const auto& write : writes.sampledImageWrites) {
vk::ImageLayout layout = write.useGeneralLayout ? vk::ImageLayout::eGeneral : vk::ImageLayout::eShaderReadOnlyOptimal;
const vk::DescriptorImageInfo imageInfo(
nullptr,
imageManager.getVulkanImageView(write.image),
vk::ImageLayout::eShaderReadOnlyOptimal
imageManager.getVulkanImageView(write.image, write.mipLevel),
layout
);
imageInfos.push_back(imageInfo);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment