Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • vulkan2021/vkcv-framework
1 result
Select Git revision
Show changes
Showing
with 33 additions and 1416 deletions
projects/bloom/resources/Sponza/vase_round.png

132 B

File deleted
#version 450
#extension GL_ARB_separate_shader_objects : enable
layout(set=0, binding=0) uniform texture2D blurImage;
layout(set=0, binding=1) uniform texture2D lensImage;
layout(set=0, binding=2) uniform sampler linearSampler;
layout(set=0, binding=3, r11f_g11f_b10f) uniform image2D colorBuffer;
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
void main()
{
if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(colorBuffer)))){
return;
}
ivec2 pixel_coord = ivec2(gl_GlobalInvocationID.xy);
vec2 pixel_size = vec2(1.0f) / textureSize(sampler2D(blurImage, linearSampler), 0);
vec2 UV = pixel_coord.xy * pixel_size;
vec4 composite_color = vec4(0.0f);
vec3 blur_color = texture(sampler2D(blurImage, linearSampler), UV).rgb;
vec3 lens_color = texture(sampler2D(lensImage, linearSampler), UV).rgb;
vec3 main_color = imageLoad(colorBuffer, pixel_coord).rgb;
// composite blur and lens features
float bloom_weight = 0.25f;
float lens_weight = 0.25f;
float main_weight = 1 - (bloom_weight + lens_weight);
composite_color.rgb = blur_color * bloom_weight +
lens_color * lens_weight +
main_color * main_weight;
imageStore(colorBuffer, pixel_coord, composite_color);
}
\ No newline at end of file
#version 450
#extension GL_ARB_separate_shader_objects : enable
layout(set=0, binding=0) uniform texture2D inBlurImage;
layout(set=0, binding=1) uniform sampler inImageSampler;
layout(set=0, binding=2, r11f_g11f_b10f) uniform writeonly image2D outBlurImage;
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
void main()
{
if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(outBlurImage)))){
return;
}
ivec2 pixel_coord = ivec2(gl_GlobalInvocationID.xy);
vec2 pixel_size = vec2(1.0f) / imageSize(outBlurImage);
vec2 UV = pixel_coord.xy * pixel_size;
vec2 UV_offset = UV + 0.5f * pixel_size;
vec2 color_fetches[13] = {
// center neighbourhood (RED)
vec2(-1, 1), // LT
vec2(-1, -1), // LB
vec2( 1, -1), // RB
vec2( 1, 1), // RT
vec2(-2, 2), // LT
vec2( 0, 2), // CT
vec2( 2, 2), // RT
vec2(0 ,-2), // LC
vec2(0 , 0), // CC
vec2(2, 0), // CR
vec2(-2, -2), // LB
vec2(0 , -2), // CB
vec2(2 , -2) // RB
};
float color_weights[13] = {
// 0.5f
1.f/8.f,
1.f/8.f,
1.f/8.f,
1.f/8.f,
// 0.125f
1.f/32.f,
1.f/16.f,
1.f/32.f,
// 0.25f
1.f/16.f,
1.f/8.f,
1.f/16.f,
// 0.125f
1.f/32.f,
1.f/16.f,
1.f/32.f
};
vec3 sampled_color = vec3(0.0f);
for(uint i = 0; i < 13; i++)
{
vec2 color_fetch = UV_offset + color_fetches[i] * pixel_size;
vec3 color = texture(sampler2D(inBlurImage, inImageSampler), color_fetch).rgb;
color *= color_weights[i];
sampled_color += color;
}
imageStore(outBlurImage, pixel_coord, vec4(sampled_color, 1.f));
}
\ No newline at end of file
#version 440
layout(set=0, binding=0, r11f_g11f_b10f) uniform image2D inImage;
layout(set=0, binding=1, rgba8) uniform image2D outImage;
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
void main(){
if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(inImage)))){
return;
}
ivec2 uv = ivec2(gl_GlobalInvocationID.xy);
vec3 linearColor = imageLoad(inImage, uv).rgb;
// cheap Reinhard tone mapping
linearColor = linearColor/(linearColor + 1.0f);
vec3 gammaCorrected = pow(linearColor, vec3(1.f / 2.2f));
imageStore(outImage, uv, vec4(gammaCorrected, 0.f));
}
\ No newline at end of file
#version 450
#extension GL_ARB_separate_shader_objects : enable
layout(set=0, binding=0) uniform texture2D blurBuffer;
layout(set=0, binding=1) uniform sampler linearSampler;
layout(set=0, binding=2, r11f_g11f_b10f) uniform image2D lensBuffer;
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
vec3 sampleColorChromaticAberration(vec2 _uv)
{
vec2 toCenter = (vec2(0.5) - _uv);
vec3 colorScales = vec3(-1, 0, 1);
float aberrationScale = 0.1;
vec3 scaleFactors = colorScales * aberrationScale;
float r = texture(sampler2D(blurBuffer, linearSampler), _uv + toCenter * scaleFactors.r).r;
float g = texture(sampler2D(blurBuffer, linearSampler), _uv + toCenter * scaleFactors.g).g;
float b = texture(sampler2D(blurBuffer, linearSampler), _uv + toCenter * scaleFactors.b).b;
return vec3(r, g, b);
}
// _uv assumed to be flipped UV coordinates!
vec3 ghost_vectors(vec2 _uv)
{
vec2 ghost_vec = (vec2(0.5f) - _uv);
const uint c_ghost_count = 64;
const float c_ghost_spacing = length(ghost_vec) / c_ghost_count;
ghost_vec *= c_ghost_spacing;
vec3 ret_color = vec3(0.0f);
for (uint i = 0; i < c_ghost_count; ++i)
{
// sample scene color
vec2 s_uv = fract(_uv + ghost_vec * vec2(i));
vec3 s = sampleColorChromaticAberration(s_uv);
// tint/weight
float d = distance(s_uv, vec2(0.5));
float weight = 1.0f - smoothstep(0.0f, 0.75f, d);
s *= weight;
ret_color += s;
}
ret_color /= c_ghost_count;
return ret_color;
}
vec3 halo(vec2 _uv)
{
const float c_aspect_ratio = float(imageSize(lensBuffer).x) / float(imageSize(lensBuffer).y);
const float c_radius = 0.6f;
const float c_halo_thickness = 0.1f;
vec2 halo_vec = vec2(0.5) - _uv;
//halo_vec.x /= c_aspect_ratio;
halo_vec = normalize(halo_vec);
//halo_vec.x *= c_aspect_ratio;
//vec2 w_uv = (_uv - vec2(0.5, 0.0)) * vec2(c_aspect_ratio, 1.0) + vec2(0.5, 0.0);
vec2 w_uv = _uv;
float d = distance(w_uv, vec2(0.5)); // distance to center
float distance_to_halo = abs(d - c_radius);
float halo_weight = 0.0f;
if(abs(d - c_radius) <= c_halo_thickness)
{
float distance_to_border = c_halo_thickness - distance_to_halo;
halo_weight = distance_to_border / c_halo_thickness;
//halo_weight = clamp((halo_weight / 0.4f), 0.0f, 1.0f);
halo_weight = pow(halo_weight, 2.0f);
//halo_weight = 1.0f;
}
return sampleColorChromaticAberration(_uv + halo_vec) * halo_weight;
}
void main()
{
if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(lensBuffer)))){
return;
}
ivec2 pixel_coord = ivec2(gl_GlobalInvocationID.xy);
vec2 pixel_size = vec2(1.0f) / imageSize(lensBuffer);
vec2 UV = pixel_coord.xy * pixel_size;
vec2 flipped_UV = vec2(1.0f) - UV;
vec3 color = vec3(0.0f);
color += ghost_vectors(flipped_UV);
color += halo(UV);
color *= 0.5f;
imageStore(lensBuffer, pixel_coord, vec4(color, 0.0f));
}
\ No newline at end of file
layout(set=1, binding=0) uniform texture2D albedoTexture;
layout(set=1, binding=1) uniform sampler textureSampler;
\ No newline at end of file
#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_GOOGLE_include_directive : enable
#include "perMeshResources.inc"
layout(location = 0) in vec3 passNormal;
layout(location = 1) in vec2 passUV;
layout(location = 2) in vec3 passPos;
layout(location = 0) out vec3 outColor;
layout(set=0, binding=0) uniform sunBuffer {
vec3 L; float padding;
mat4 lightMatrix;
};
layout(set=0, binding=1) uniform texture2D shadowMap;
layout(set=0, binding=2) uniform sampler shadowMapSampler;
float shadowTest(vec3 worldPos){
vec4 lightPos = lightMatrix * vec4(worldPos, 1);
lightPos /= lightPos.w;
lightPos.xy = lightPos.xy * 0.5 + 0.5;
if(any(lessThan(lightPos.xy, vec2(0))) || any(greaterThan(lightPos.xy, vec2(1)))){
return 1;
}
lightPos.z = clamp(lightPos.z, 0, 1);
float shadowMapSample = texture(sampler2D(shadowMap, shadowMapSampler), lightPos.xy).r;
float bias = 0.01f;
shadowMapSample += bias;
return shadowMapSample < lightPos.z ? 0 : 1;
}
void main() {
vec3 N = normalize(passNormal);
vec3 sunColor = vec3(10);
vec3 sun = sunColor * clamp(dot(N, L), 0, 1);
sun *= shadowTest(passPos);
vec3 ambient = vec3(0.05);
vec3 albedo = texture(sampler2D(albedoTexture, textureSampler), passUV).rgb;
outColor = albedo * (sun + ambient);
}
\ 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);
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;
}
#include <iostream>
#include <vkcv/Core.hpp>
#include <GLFW/glfw3.h>
#include <vkcv/camera/CameraManager.hpp>
#include <chrono>
#include <vkcv/asset/asset_loader.hpp>
int main(int argc, const char** argv) {
const char* applicationName = "First Mesh";
uint32_t windowWidth = 800;
uint32_t windowHeight = 600;
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" }
);
vkcv::asset::Scene mesh;
const char* path = argc > 1 ? argv[1] : "resources/cube/cube.gltf";
int result = vkcv::asset::loadScene(path, mesh);
if (result == 1) {
std::cout << "Mesh loading successful!" << std::endl;
}
else {
std::cout << "Mesh loading failed: " << result << std::endl;
return 1;
}
assert(mesh.vertexGroups.size() > 0);
auto vertexBuffer = core.createBuffer<uint8_t>(
vkcv::BufferType::VERTEX,
mesh.vertexGroups[0].vertexBuffer.data.size(),
vkcv::BufferMemoryType::DEVICE_LOCAL
);
vertexBuffer.fill(mesh.vertexGroups[0].vertexBuffer.data);
auto indexBuffer = core.createBuffer<uint8_t>(
vkcv::BufferType::INDEX,
mesh.vertexGroups[0].indexBuffer.data.size(),
vkcv::BufferMemoryType::DEVICE_LOCAL
);
indexBuffer.fill(mesh.vertexGroups[0].indexBuffer.data);
auto& attributes = mesh.vertexGroups[0].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);
});
const std::vector<vkcv::VertexBufferBinding> vertexBufferBindings = {
vkcv::VertexBufferBinding(attributes[0].offset, vertexBuffer.getVulkanHandle()),
vkcv::VertexBufferBinding(attributes[1].offset, vertexBuffer.getVulkanHandle()),
vkcv::VertexBufferBinding(attributes[2].offset, vertexBuffer.getVulkanHandle()) };
const vkcv::Mesh loadedMesh(vertexBufferBindings, indexBuffer.getVulkanHandle(), mesh.vertexGroups[0].numIndices);
// an example attachment for passes that output to the window
const vkcv::AttachmentDescription present_color_attachment(
vkcv::AttachmentOperation::STORE,
vkcv::AttachmentOperation::CLEAR,
core.getSwapchain().getFormat()
);
const vkcv::AttachmentDescription depth_attachment(
vkcv::AttachmentOperation::STORE,
vkcv::AttachmentOperation::CLEAR,
vk::Format::eD32Sfloat
);
vkcv::PassConfig firstMeshPassDefinition({ present_color_attachment, depth_attachment });
vkcv::PassHandle firstMeshPass = core.createPass(firstMeshPassDefinition);
if (!firstMeshPass) {
std::cout << "Error. Could not create renderpass. Exiting." << std::endl;
return EXIT_FAILURE;
}
vkcv::ShaderProgram firstMeshProgram{};
firstMeshProgram.addShader(vkcv::ShaderStage::VERTEX, std::filesystem::path("resources/shaders/vert.spv"));
firstMeshProgram.addShader(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("resources/shaders/frag.spv"));
const std::vector<vkcv::VertexAttachment> vertexAttachments = firstMeshProgram.getVertexAttachments();
std::vector<vkcv::VertexBinding> bindings;
for (size_t i = 0; i < vertexAttachments.size(); i++) {
bindings.push_back(vkcv::VertexBinding(i, { vertexAttachments[i] }));
}
const vkcv::VertexLayout firstMeshLayout (bindings);
std::vector<vkcv::DescriptorBinding> descriptorBindings = { firstMeshProgram.getReflectedDescriptors()[0] };
vkcv::DescriptorSetHandle descriptorSet = core.createDescriptorSet(descriptorBindings);
const vkcv::PipelineConfig firstMeshPipelineConfig {
firstMeshProgram,
windowWidth,
windowHeight,
firstMeshPass,
firstMeshLayout,
{ core.getDescriptorSet(descriptorSet).layout },
true
};
vkcv::PipelineHandle firstMeshPipeline = core.createGraphicsPipeline(firstMeshPipelineConfig);
if (!firstMeshPipeline) {
std::cout << "Error. Could not create graphics pipeline. Exiting." << std::endl;
return EXIT_FAILURE;
}
//vkcv::Image texture = core.createImage(vk::Format::eR8G8B8A8Srgb, mesh.texture_hack.w, mesh.texture_hack.h);
//texture.fill(mesh.texture_hack.img);
vkcv::asset::Texture &tex = mesh.textures[0];
vkcv::Image texture = core.createImage(vk::Format::eR8G8B8A8Srgb, tex.w, tex.h);
texture.fill(tex.data.data());
vkcv::SamplerHandle sampler = core.createSampler(
vkcv::SamplerFilterType::LINEAR,
vkcv::SamplerFilterType::LINEAR,
vkcv::SamplerMipmapMode::LINEAR,
vkcv::SamplerAddressMode::REPEAT
);
vkcv::SamplerHandle shadowSampler = core.createSampler(
vkcv::SamplerFilterType::NEAREST,
vkcv::SamplerFilterType::NEAREST,
vkcv::SamplerMipmapMode::NEAREST,
vkcv::SamplerAddressMode::CLAMP_TO_EDGE
);
vkcv::ImageHandle depthBuffer = core.createImage(vk::Format::eD32Sfloat, windowWidth, windowHeight).getHandle();
const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle();
const vkcv::DescriptorSetUsage descriptorUsage(0, core.getDescriptorSet(descriptorSet).vulkanHandle);
const std::vector<glm::vec3> instancePositions = {
glm::vec3( 0.f, -2.f, 0.f),
glm::vec3( 3.f, 0.f, 0.f),
glm::vec3(-3.f, 0.f, 0.f),
glm::vec3( 0.f, 2.f, 0.f),
glm::vec3( 0.f, -5.f, 0.f)
};
std::vector<glm::mat4> modelMatrices;
std::vector<vkcv::DrawcallInfo> drawcalls;
std::vector<vkcv::DrawcallInfo> shadowDrawcalls;
for (const auto& position : instancePositions) {
modelMatrices.push_back(glm::translate(glm::mat4(1.f), position));
drawcalls.push_back(vkcv::DrawcallInfo(loadedMesh, { descriptorUsage },1));
shadowDrawcalls.push_back(vkcv::DrawcallInfo(loadedMesh, {},1));
}
modelMatrices.back() *= glm::scale(glm::mat4(1.f), glm::vec3(10.f, 1.f, 10.f));
std::vector<std::array<glm::mat4, 2>> mainPassMatrices;
std::vector<glm::mat4> mvpLight;
vkcv::ShaderProgram shadowShader;
shadowShader.addShader(vkcv::ShaderStage::VERTEX, "resources/shaders/shadow_vert.spv");
shadowShader.addShader(vkcv::ShaderStage::FRAGMENT, "resources/shaders/shadow_frag.spv");
const vk::Format shadowMapFormat = vk::Format::eD16Unorm;
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 uint32_t shadowMapResolution = 1024;
const vkcv::Image shadowMap = core.createImage(shadowMapFormat, shadowMapResolution, shadowMapResolution, 1);
const vkcv::PipelineConfig shadowPipeConfig {
shadowShader,
shadowMapResolution,
shadowMapResolution,
shadowPass,
firstMeshLayout,
{},
false
};
const vkcv::PipelineHandle shadowPipe = core.createGraphicsPipeline(shadowPipeConfig);
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::DescriptorWrites setWrites;
setWrites.sampledImageWrites = {
vkcv::SampledImageDescriptorWrite(0, texture.getHandle()),
vkcv::SampledImageDescriptorWrite(3, shadowMap.getHandle()) };
setWrites.samplerWrites = {
vkcv::SamplerDescriptorWrite(1, sampler),
vkcv::SamplerDescriptorWrite(4, shadowSampler) };
setWrites.uniformBufferWrites = { vkcv::UniformBufferDescriptorWrite(2, lightBuffer.getHandle()) };
core.writeDescriptorSet(descriptorSet, setWrites);
auto start = std::chrono::system_clock::now();
const auto appStartTime = start;
while (window.isWindowOpen()) {
window.pollEvents();
uint32_t swapchainWidth, swapchainHeight;
if (!core.beginFrame(swapchainWidth, swapchainHeight)) {
continue;
}
if ((swapchainWidth != windowWidth) || ((swapchainHeight != windowHeight))) {
depthBuffer = core.createImage(vk::Format::eD32Sfloat, swapchainWidth, swapchainHeight).getHandle();
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.001f * static_cast<float>(duration.count());
lightInfo.direction = glm::normalize(glm::vec3(std::cos(sunTheta), 1, std::sin(sunTheta)));
const float shadowProjectionSize = 5.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 = { swapchainInput, depthBuffer };
vkcv::PushConstantData shadowPushConstantData((void*)mvpLight.data(), sizeof(glm::mat4));
auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics);
core.recordDrawcallsToCmdStream(
cmdStream,
shadowPass,
shadowPipe,
shadowPushConstantData,
shadowDrawcalls,
{ shadowMap.getHandle() });
core.prepareImageForSampling(cmdStream, shadowMap.getHandle());
core.recordDrawcallsToCmdStream(
cmdStream,
firstMeshPass,
firstMeshPipeline,
pushConstantData,
drawcalls,
renderTargets);
core.prepareSwapchainImageForPresent(cmdStream);
core.submitCommandStream(cmdStream);
core.endFrame();
}
return 0;
}
......@@ -22,7 +22,7 @@ if(MSVC)
endif()
# including headers of dependencies and the VkCV framework
target_include_directories(first_mesh SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_asset_loader_include} ${vkcv_camera_include})
target_include_directories(first_mesh SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_asset_loader_include} ${vkcv_camera_include} ${vkcv_shader_compiler_include})
# linking with libraries from all dependencies and the VkCV framework
target_link_libraries(first_mesh vkcv ${vkcv_libraries} vkcv_asset_loader ${vkcv_asset_loader_libraries} vkcv_camera)
target_link_libraries(first_mesh vkcv ${vkcv_libraries} vkcv_asset_loader ${vkcv_asset_loader_libraries} vkcv_camera vkcv_shader_compiler)
%VULKAN_SDK%\Bin32\glslc.exe shader.vert -o vert.spv
%VULKAN_SDK%\Bin32\glslc.exe shader.frag -o frag.spv
pause
\ No newline at end of file
File deleted
File deleted
......@@ -4,6 +4,7 @@
#include <vkcv/camera/CameraManager.hpp>
#include <chrono>
#include <vkcv/asset/asset_loader.hpp>
#include <vkcv/shader/GLSLCompiler.hpp>
int main(int argc, const char** argv) {
const char* applicationName = "First Mesh";
......@@ -34,9 +35,8 @@ int main(int argc, const char** argv) {
if (result == 1) {
std::cout << "Mesh loading successful!" << std::endl;
}
else {
std::cout << "Mesh loading failed: " << result << std::endl;
} else {
std::cerr << "Mesh loading failed: " << result << std::endl;
return 1;
}
......@@ -74,14 +74,23 @@ int main(int argc, const char** argv) {
vkcv::PassHandle firstMeshPass = core.createPass(firstMeshPassDefinition);
if (!firstMeshPass) {
std::cout << "Error. Could not create renderpass. Exiting." << std::endl;
std::cerr << "Error. Could not create renderpass. Exiting." << std::endl;
return EXIT_FAILURE;
}
vkcv::ShaderProgram firstMeshProgram{};
firstMeshProgram.addShader(vkcv::ShaderStage::VERTEX, std::filesystem::path("resources/shaders/vert.spv"));
firstMeshProgram.addShader(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("resources/shaders/frag.spv"));
vkcv::ShaderProgram firstMeshProgram;
vkcv::shader::GLSLCompiler compiler;
compiler.compile(vkcv::ShaderStage::VERTEX, std::filesystem::path("resources/shaders/shader.vert"),
[&firstMeshProgram](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
firstMeshProgram.addShader(shaderStage, path);
});
compiler.compile(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("resources/shaders/shader.frag"),
[&firstMeshProgram](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
firstMeshProgram.addShader(shaderStage, path);
});
auto& attributes = mesh.vertexGroups[0].vertexBuffer.attributes;
......@@ -113,12 +122,15 @@ int main(int argc, const char** argv) {
vkcv::PipelineHandle firstMeshPipeline = core.createGraphicsPipeline(firstMeshPipelineConfig);
if (!firstMeshPipeline) {
std::cout << "Error. Could not create graphics pipeline. Exiting." << std::endl;
std::cerr << "Error. Could not create graphics pipeline. Exiting." << std::endl;
return EXIT_FAILURE;
}
if (mesh.textures.empty()) {
std::cerr << "Error. No textures found. Exiting." << std::endl;
return EXIT_FAILURE;
}
// FIXME There should be a test here to make sure there is at least 1
// texture in the mesh.
vkcv::asset::Texture &tex = mesh.textures[0];
vkcv::Image texture = core.createImage(vk::Format::eR8G8B8A8Srgb, tex.w, tex.h);
texture.fill(tex.data.data());
......@@ -154,14 +166,13 @@ int main(int argc, const char** argv) {
vkcv::camera::CameraManager cameraManager(window);
uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT);
uint32_t camIndex1 = cameraManager.addCamera(vkcv::camera::ControllerType::TRACKBALL);
cameraManager.getCamera(camIndex0).setPosition(glm::vec3(0, 0, -3));
auto start = std::chrono::system_clock::now();
while (window.isWindowOpen()) {
window.pollEvents();
vkcv::Window::pollEvents();
if(window.getHeight() == 0 || window.getWidth() == 0)
continue;
......@@ -185,7 +196,8 @@ int main(int argc, const char** argv) {
cameraManager.update(0.000001 * static_cast<double>(deltatime.count()));
glm::mat4 mvp = cameraManager.getActiveCamera().getMVP();
vkcv::PushConstantData pushConstantData((void*)&mvp, sizeof(glm::mat4));
vkcv::PushConstants pushConstants (sizeof(glm::mat4));
pushConstants.appendDrawcall(mvp);
const std::vector<vkcv::ImageHandle> renderTargets = { swapchainInput, depthBuffer };
auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics);
......@@ -194,7 +206,7 @@ int main(int argc, const char** argv) {
cmdStream,
firstMeshPass,
firstMeshPipeline,
pushConstantData,
pushConstants,
{ drawcall },
renderTargets);
core.prepareSwapchainImageForPresent(cmdStream);
......
......@@ -22,7 +22,7 @@ if(MSVC)
endif()
# including headers of dependencies and the VkCV framework
target_include_directories(first_scene SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_asset_loader_include} ${vkcv_camera_include})
target_include_directories(first_scene SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_asset_loader_include} ${vkcv_camera_include} ${vkcv_scene_include} ${vkcv_shader_compiler_include})
# linking with libraries from all dependencies and the VkCV framework
target_link_libraries(first_scene vkcv ${vkcv_libraries} vkcv_asset_loader ${vkcv_asset_loader_libraries} vkcv_camera)
target_link_libraries(first_scene vkcv ${vkcv_libraries} vkcv_asset_loader ${vkcv_asset_loader_libraries} vkcv_camera vkcv_scene vkcv_shader_compiler)