Skip to content
Snippets Groups Projects
Commit 36182a67 authored by Sebastian Gaida's avatar Sebastian Gaida
Browse files

[#111] add sph project and flipflop buffer

parent 66ad5638
Branches
Tags
1 merge request!95Resolve "Wassersimulation mit Interaktion"
Showing
with 1186 additions and 0 deletions
......@@ -4,6 +4,7 @@ add_subdirectory(first_triangle)
add_subdirectory(first_mesh)
add_subdirectory(first_scene)
add_subdirectory(particle_simulation)
add_subdirectory(sph)
add_subdirectory(voxelization)
add_subdirectory(mesh_shader)
add_subdirectory(indirect_dispatch)
particle_simulation
\ No newline at end of file
cmake_minimum_required(VERSION 3.16)
project(sph)
# setting c++ standard for the project
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# this should fix the execution path to load local files from the project
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
# adding source files to the project
add_executable(sph
src/main.cpp
src/ParticleSystem.hpp
src/ParticleSystem.cpp
src/Particle.hpp
src/Particle.cpp
src/BloomAndFlares.hpp
src/BloomAndFlares.cpp)
# this should fix the execution path to load local files from the project (for MSVC)
if(MSVC)
set_target_properties(sph PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
set_target_properties(sph PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
# in addition to setting the output directory, the working directory has to be set
# by default visual studio sets the working directory to the build directory, when using the debugger
set_target_properties(sph PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
endif()
# including headers of dependencies and the VkCV framework
target_include_directories(sph SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_testing_include} ${vkcv_camera_include} ${vkcv_shader_compiler_include})
# linking with libraries from all dependencies and the VkCV framework
target_link_libraries(sph vkcv vkcv_testing vkcv_camera vkcv_shader_compiler)
#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.01f;
float lens_weight = 0.f;
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 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
#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
float circleFactor(vec2 triangleCoordinates){
// percentage of distance from center to circle edge
float p = clamp((0.4 - length(triangleCoordinates)) / 0.4, 0, 1);
// remapping for nice falloff
return sqrt(p);
}
\ No newline at end of file
#version 460 core
#extension GL_ARB_separate_shader_objects : enable
layout(location = 0) in vec3 particle;
struct Particle
{
vec3 position;
float lifeTime;
vec3 velocity;
float padding_2;
vec3 reset_velocity;
float padding_3;
};
layout(std430, binding = 2) readonly buffer buffer_inParticle1
{
Particle inParticle1[];
};
layout(std430, binding = 3) readonly buffer buffer_inParticle2
{
Particle inParticle2[];
};
layout( push_constant ) uniform constants{
mat4 view;
mat4 projection;
};
layout(location = 0) out vec2 passTriangleCoordinates;
layout(location = 1) out vec3 passVelocity;
layout(location = 2) out float passlifeTime;
void main()
{
int id = gl_InstanceIndex;
passVelocity = inParticle1[id].velocity;
passlifeTime = inParticle1[id].lifeTime;
// particle position in view space
vec4 positionView = view * vec4(inParticle1[id].position, 1);
// by adding the triangle position in view space the mesh is always camera facing
positionView.xyz += particle;
// multiply with projection matrix for final position
gl_Position = projection * positionView;
// 0.01 corresponds to vertex position size in main
float normalizationDivider = 0.012;
passTriangleCoordinates = particle.xy / normalizationDivider;
}
\ No newline at end of file
#version 450 core
#extension GL_ARB_separate_shader_objects : enable
layout(local_size_x = 256) in;
struct Particle
{
vec3 position;
float lifeTime;
vec3 velocity;
float mass;
vec3 reset_velocity;
float _padding;
};
layout(std430, binding = 0) coherent buffer buffer_inParticle
{
Particle inParticle[];
};
layout( push_constant ) uniform constants{
float deltaTime;
float rand;
};
const int n = 4;
vec4 gravityPoint[n] = vec4[n](
vec4(-0.8, -0.5, 0.0, 3),
vec4(-0.4, 0.5, 0.8, 2),
vec4( 0.8, 0.8, -0.3, 4),
vec4( 0.5, -0.7, -0.5, 1)
);
const float G = 6.6743015e-11;
const float sim_d_factor = 10e11;
const float sim_g_factor = 10e30;
const float sim_t_factor = 5;
const float c = 299792458;
void main() {
uint id = gl_GlobalInvocationID.x;
inParticle[id].lifeTime -= deltaTime;
vec3 pos = inParticle[id].position;
vec3 vel = inParticle[id].velocity;
float mass = inParticle[id].mass;
if(inParticle[id].lifeTime < 0.f)
{
inParticle[id].lifeTime = 5.f * rand;
inParticle[id].mass *= rand;
pos = vec3(0);
vel *= rand;
}
for(int i = 0; i < n; i++)
{
vec3 d = (gravityPoint[i].xyz - pos) * sim_d_factor;
float r = length(d);
float g = G * (gravityPoint[i].w * sim_g_factor) / (r * r);
if (r > 0) {
vec3 dvel = (deltaTime * sim_t_factor) * g * (d / r);
vel = (vel + dvel) / (1.0 + dot(vel, dvel) / (c*c));
}
}
pos += vel * (deltaTime * sim_t_factor);
vec3 a_pos = abs(pos);
if ((a_pos.x > 2.0) || (a_pos.y > 2.0) || (a_pos.z > 2.0))
{
inParticle[id].lifeTime *= 0.9;
}
inParticle[id].position = pos;
inParticle[id].velocity = vel;
}
#version 450 core
#extension GL_ARB_separate_shader_objects : enable
layout(local_size_x = 256) in;
struct Particle
{
vec3 position;
float lifeTime;
vec3 velocity;
float padding_2;
vec3 reset_velocity;
float padding_3;
};
layout(std430, binding = 0) coherent buffer buffer_inParticle
{
Particle inParticle[];
};
layout( push_constant ) uniform constants{
float deltaTime;
float rand;
};
vec3 attraction(vec3 pos, vec3 attractPos)
{
vec3 delta = attractPos - pos;
const float damp = 0.5;
float dDampedDot = dot(delta, delta) + damp;
float invDist = 1.0f / sqrt(dDampedDot);
float invDistCubed = invDist*invDist*invDist;
return delta * invDistCubed * 0.0035;
}
vec3 repulsion(vec3 pos, vec3 attractPos)
{
vec3 delta = attractPos - pos;
float targetDistance = sqrt(dot(delta, delta));
return delta * (1.0 / (targetDistance * targetDistance * targetDistance)) * -0.000035;
}
const int n = 4;
vec3 gravity = vec3(0,-9.8,0);
vec3 gravityPoint[n] = vec3[n](vec3(-0.3, .5, -0.6),vec3(-0.2, 0.6, -0.3),vec3(.4, -0.4, 0.6),vec3(-.4, -0.4, -0.6));
//vec3 gravityPoint[n] = vec3[n](vec3(-0.5, 0.5, 0));
void main() {
uint id = gl_GlobalInvocationID.x;
inParticle[id].lifeTime -= deltaTime;
vec3 pos = inParticle[id].position;
vec3 vel = inParticle[id].velocity;
if(inParticle[id].lifeTime < 0.f)
{
inParticle[id].lifeTime = 5.f;
pos = vec3(0);
}
// inParticle[id].position += deltaTime * -normalize(max(2 - distance(inParticle[id].position,respawnPos),0.0) * respawnPos - inParticle[id].position);
for(int i = 0; i < n; i++)
{
vel += deltaTime * deltaTime * normalize(max(2 - distance(pos,gravityPoint[i]),0.1) * gravityPoint[i] - pos);
}
if((pos.x <= -2.0) || (pos.x > 2.0) || (pos.y <= -2.0) || (pos.y > 2.0)|| (pos.z <= -2.0) || (pos.z > 2.0)){
vel = (-vel * 0.1);
}
pos += normalize(vel) * deltaTime;
inParticle[id].position = pos;
float rand1 = rand;
inParticle[id].velocity = vel;
}
#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_GOOGLE_include_directive : enable
#include "particleShading.inc"
layout(location = 0) in vec2 passTriangleCoordinates;
layout(location = 1) in vec3 passVelocity;
layout(location = 2) in float passlifeTime;
layout(location = 0) out vec3 outColor;
layout(set=0, binding=0) uniform uColor {
vec4 color;
} Color;
layout(set=0,binding=1) uniform uPosition{
vec2 position;
} Position;
void main()
{
vec2 mouse = vec2(Position.position.x, Position.position.y);
vec3 c0 = vec3(1, 1, 0.05);
vec3 c1 = vec3(1, passlifeTime * 0.5, 0.05);
vec3 c2 = vec3(passlifeTime * 0.5,passlifeTime * 0.5,0.05);
vec3 c3 = vec3(1, 0.05, 0.05);
if(passlifeTime < 1){
outColor = mix(c0, c1, passlifeTime );
}
else if(passlifeTime < 2){
outColor = mix(c1, c2, passlifeTime - 1);
}
else{
outColor = mix(c2, c3, clamp((passlifeTime - 2) * 0.5, 0, 1));
}
// make the triangle look like a circle
outColor *= circleFactor(passTriangleCoordinates);
// fade out particle shortly before it dies
outColor *= clamp(passlifeTime * 2, 0, 1);
}
\ No newline at end of file
#version 450 core
#extension GL_ARB_separate_shader_objects : enable
layout(local_size_x = 256) in;
struct Particle
{
vec3 position;
float lifeTime;
vec3 velocity;
float padding_2;
vec3 reset_velocity;
float padding_3;
};
layout(std430, binding = 0) readonly buffer buffer_inParticle
{
Particle inParticle[];
};
layout(std430, binding = 1) writeonly buffer buffer_outParticle
{
Particle outParticle[];
};
layout( push_constant ) uniform constants{
float deltaTime;
float rand;
};
vec3 attraction(vec3 pos, vec3 attractPos)
{
vec3 delta = attractPos - pos;
const float damp = 0.5;
float dDampedDot = dot(delta, delta) + damp;
float invDist = 1.0f / sqrt(dDampedDot);
float invDistCubed = invDist*invDist*invDist;
return delta * invDistCubed * 0.0035;
}
vec3 repulsion(vec3 pos, vec3 attractPos)
{
vec3 delta = attractPos - pos;
float targetDistance = sqrt(dot(delta, delta));
return delta * (1.0 / (targetDistance * targetDistance * targetDistance)) * -0.000035;
}
const int n = 3;
vec3 gravity = vec3(0,-9.8,0);
vec3 gravityPoint[n] = vec3[n](vec3(-0.5, 0.5, 0),vec3(0.5, 0.5, 0),vec3(0, -0.5, 0));
//vec3 gravityPoint[n] = vec3[n](vec3(-0.5, 0.5, 0));
void main() {
uint id = gl_GlobalInvocationID.x;
outParticle[id].lifeTime = inParticle[id].lifeTime - deltaTime;
vec3 pos = inParticle[id].position;
vec3 vel = inParticle[id].velocity;
if(inParticle[id].lifeTime < 0.f)
{
outParticle[id].lifeTime = 7.f;
pos = vec3(0);
vel = inParticle[id].reset_velocity;
outParticle[id].velocity = inParticle[id].reset_velocity;
}
// inParticle[id].position += deltaTime * -normalize(max(2 - distance(inParticle[id].position,respawnPos),0.0) * respawnPos - inParticle[id].position);
for(int i = 0; i < n; i++)
{
vel += deltaTime * deltaTime * deltaTime * normalize(max(2 - distance(pos,gravityPoint[i]),0.1) * gravityPoint[i] - pos);
}
//vec3 delta = respawnPos - pos;
//float targetDistane = sqrt(dot(delta,delta));
//vel += repulsion(pos, respawnPos);
//if((pos.x <= -1.0) || (pos.x > 1.0) || (pos.y <= -1.0) || (pos.y > 1.0)|| (pos.z <= -1.0) || (pos.z > 1.0))
vel = (-vel * 0.01);
if((pos.y <= -1.0) || (pos.y > 1.0)){
vel = reflect(vel, vec3(0,1,0));
}
pos += normalize(vel) * deltaTime;
outParticle[id].position = pos;
float weight = 1.0;
float rand1 = rand;
outParticle[id].velocity = vel;
}
#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_GOOGLE_include_directive : enable
#include "particleShading.inc"
layout(location = 0) in vec2 passTriangleCoordinates;
layout(location = 1) in vec3 passVelocity;
layout(location = 2) in float passlifeTime;
layout(location = 0) out vec3 outColor;
layout(set=0, binding=0) uniform uColor {
vec4 color;
} Color;
layout(set=0,binding=1) uniform uPosition{
vec2 position;
} Position;
void main()
{
float normlt = 1-normalize(passlifeTime);
vec2 mouse = vec2(Position.position.x, Position.position.y);
vec3 c0 = vec3(0.2,0.5,1);
vec3 c1 = vec3(0.3, 0.7,1);
vec3 c2 = vec3(0.5,0.9,1);
vec3 c3 = vec3(0.9,1,1);
if(passlifeTime < 1){
outColor = mix(c0, c1, passlifeTime );
}
else if(passlifeTime < 2){
outColor = mix(c1, c2, passlifeTime - 1);
}
else{
outColor = mix(c2, c3, clamp((passlifeTime - 2) * 0.5, 0, 1));
}
// make the triangle look like a circle
outColor *= circleFactor(passTriangleCoordinates);
// fade out particle shortly before it dies
outColor *= clamp(passlifeTime * 2, 0, 1);
}
#version 440
layout(set=0, binding=0, rgba16f) 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;
vec3 tonemapped = linearColor / (dot(linearColor, vec3(0.21, 0.71, 0.08)) + 1); // reinhard tonemapping
vec3 gammaCorrected = pow(tonemapped, vec3(1.f / 2.2f));
imageStore(outImage, uv, vec4(gammaCorrected, 0.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,
"shaders/bloom/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_DownsampleDescSetLayouts.push_back(
p_Core->createDescriptorSetLayout(dsProg.getReflectedDescriptors().at(0)));
m_DownsampleDescSets.push_back(
p_Core->createDescriptorSet(m_DownsampleDescSetLayouts.back()));
}
m_DownsamplePipe = p_Core->createComputePipeline(
dsProg, { p_Core->getDescriptorSetLayout(m_DownsampleDescSetLayouts[0]).vulkanHandle });
// UPSAMPLE
vkcv::ShaderProgram usProg;
compiler.compile(vkcv::ShaderStage::COMPUTE,
"shaders/bloom/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_UpsampleDescSetLayouts.push_back(
p_Core->createDescriptorSetLayout(usProg.getReflectedDescriptors().at(0)));
m_UpsampleDescSets.push_back(
p_Core->createDescriptorSet(m_UpsampleDescSetLayouts.back()));
}
m_UpsamplePipe = p_Core->createComputePipeline(
usProg, { p_Core->getDescriptorSetLayout(m_UpsampleDescSetLayouts[0]).vulkanHandle });
// LENS FEATURES
vkcv::ShaderProgram lensProg;
compiler.compile(vkcv::ShaderStage::COMPUTE,
"shaders/bloom/lensFlares.comp",
[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path)
{
lensProg.addShader(shaderStage, path);
});
m_LensFlareDescSetLayout = p_Core->createDescriptorSetLayout(lensProg.getReflectedDescriptors().at(0));
m_LensFlareDescSet = p_Core->createDescriptorSet(m_LensFlareDescSetLayout);
m_LensFlarePipe = p_Core->createComputePipeline(
lensProg, { p_Core->getDescriptorSetLayout(m_LensFlareDescSetLayout).vulkanHandle });
// COMPOSITE
vkcv::ShaderProgram compProg;
compiler.compile(vkcv::ShaderStage::COMPUTE,
"shaders/bloom/composite.comp",
[&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path)
{
compProg.addShader(shaderStage, path);
});
m_CompositeDescSetLayout = p_Core->createDescriptorSetLayout(compProg.getReflectedDescriptors().at(0));
m_CompositeDescSet = p_Core->createDescriptorSet(m_CompositeDescSetLayout);
m_CompositePipe = p_Core->createComputePipeline(
compProg, { p_Core->getDescriptorSetLayout(m_CompositeDescSetLayout).vulkanHandle });
}
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::PushConstants(0));
// downsample dispatches of blur buffer's mip maps
float mipDispatchCountX = dispatchCountX;
float mipDispatchCountY = dispatchCountY;
for(uint32_t mipLevel = 1; mipLevel < std::min((uint32_t)m_DownsampleDescSets.size(), m_Blur.getMipCount()); 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::PushConstants(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>(3)
);
// 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::PushConstants(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::PushConstants(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::PushConstants(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)
{
if ((width == m_Width) && (height == m_Height)) {
return;
}
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::DescriptorSetLayoutHandle> m_DownsampleDescSetLayouts;
std::vector<vkcv::DescriptorSetHandle> m_DownsampleDescSets; // per mip desc set
vkcv::PipelineHandle m_UpsamplePipe;
std::vector<vkcv::DescriptorSetLayoutHandle> m_UpsampleDescSetLayouts;
std::vector<vkcv::DescriptorSetHandle> m_UpsampleDescSets; // per mip desc set
vkcv::PipelineHandle m_LensFlarePipe;
vkcv::DescriptorSetLayoutHandle m_LensFlareDescSetLayout;
vkcv::DescriptorSetHandle m_LensFlareDescSet;
vkcv::PipelineHandle m_CompositePipe;
vkcv::DescriptorSetLayoutHandle m_CompositeDescSetLayout;
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 "Particle.hpp"
Particle::Particle(glm::vec3 position, glm::vec3 velocity, float lifeTime)
: m_position(position),
m_lifeTime(lifeTime),
m_velocity(velocity),
m_mass(1.0f),
m_reset_velocity(velocity)
{}
const glm::vec3& Particle::getPosition()const{
return m_position;
}
bool Particle::isAlive()const{
return m_lifeTime > 0.f;
}
void Particle::setPosition( const glm::vec3 pos ){
m_position = pos;
}
const glm::vec3& Particle::getVelocity()const{
return m_velocity;
}
void Particle::setVelocity( const glm::vec3 vel ){
m_velocity = vel;
}
void Particle::update( const float delta ){
m_position += m_velocity * delta;
}
void Particle::setLifeTime( const float lifeTime ){
m_lifeTime = lifeTime;
}
const float& Particle::getLifeTime()const{
return m_lifeTime;
}
\ No newline at end of file
#pragma once
#include <glm/glm.hpp>
class Particle {
public:
Particle(glm::vec3 position, glm::vec3 velocity, float lifeTime = 1.f);
const glm::vec3& getPosition()const;
void setPosition( const glm::vec3 pos );
const glm::vec3& getVelocity()const;
void setVelocity( const glm::vec3 vel );
void update( const float delta );
bool isAlive()const;
void setLifeTime( const float lifeTime );
const float& getLifeTime()const;
private:
// all properties of the Particle
glm::vec3 m_position;
float m_lifeTime;
glm::vec3 m_velocity;
float m_mass;
glm::vec3 m_reset_velocity;
float padding_3;
};
#include "ParticleSystem.hpp"
ParticleSystem::ParticleSystem(uint32_t particleCount ,glm::vec3 minVelocity , glm::vec3 maxVelocity , glm::vec2 lifeTime )
{
m_rdmVel.resize(3);
m_rdmVel[0] = std::uniform_real_distribution<float>(minVelocity.x, maxVelocity.x);
m_rdmVel[1] = std::uniform_real_distribution<float>(minVelocity.y, maxVelocity.y);
m_rdmVel[2] = std::uniform_real_distribution<float>(minVelocity.z, maxVelocity.z);
m_rdmLifeTime = std::uniform_real_distribution<float>(lifeTime.x, lifeTime.y);
for(uint32_t i = 0; i < particleCount ;i++ ){
addParticle(Particle(m_respawnPos, getRandomVelocity(), getRandomLifeTime()));
}
}
const std::vector<Particle>& ParticleSystem::getParticles() const{
return m_particles;
}
void ParticleSystem::addParticle( const Particle particle ){
m_particles.push_back(particle);
}
void ParticleSystem::addParticles( const std::vector<Particle> particles ){
m_particles.insert(m_particles.end(), particles.begin(), particles.end());
}
void ParticleSystem::updateParticles( const float deltaTime ){
for(Particle& particle :m_particles){
bool alive = particle.isAlive();
particle.setPosition( particle.getPosition() * static_cast<float>(alive) + static_cast<float>(!alive) * m_respawnPos );
particle.setVelocity( particle.getVelocity() * static_cast<float>(alive) + static_cast<float>(!alive) * getRandomVelocity());
particle.setLifeTime( (particle.getLifeTime() * alive + !alive * getRandomLifeTime() ) - deltaTime );
particle.update(deltaTime);
}
}
glm::vec3 ParticleSystem::getRandomVelocity(){
return glm::vec3(m_rdmVel[0](m_rdmEngine), m_rdmVel[1](m_rdmEngine),m_rdmVel[2](m_rdmEngine));
}
float ParticleSystem::getRandomLifeTime(){
return m_rdmLifeTime(m_rdmEngine);
}
void ParticleSystem::setRespawnPos( const glm::vec3 respawnPos){
m_respawnPos = respawnPos;
}
void ParticleSystem::setRdmLifeTime( const glm::vec2 lifeTime ){
m_rdmLifeTime = std::uniform_real_distribution<float> (lifeTime.x,lifeTime.y);
}
void ParticleSystem::setRdmVelocity( glm::vec3 minVelocity, glm::vec3 maxVelocity ){
m_rdmVel[0] = std::uniform_real_distribution<float> (minVelocity.x,maxVelocity.x);
m_rdmVel[1] = std::uniform_real_distribution<float> (minVelocity.y,maxVelocity.y);
m_rdmVel[2] = std::uniform_real_distribution<float> (minVelocity.z,maxVelocity.z);
}
const glm::vec3 ParticleSystem::getRespawnPos() const{
return m_respawnPos;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment