Commit 4220906a authored by Florian Oetke's avatar Florian Oetke
Browse files

basic structures for particle system

parent f280d110
......@@ -5,4 +5,4 @@ blueprint:sun = blueprints/sun.json
blueprint:cube = blueprints/cube.json
blueprint:billboard = blueprints/billboard.json
blueprint:decal = blueprints/decal.json
blueprint:test_particle_emitter = blueprints/test_particle_emitter.json
particle: = particles/
particle_def:test_particles = particles/test_particles.json
particle_sys:test_particles = particles/test_particle_system.json
{
"Transform":{
"scale": {"x": 0.1, "y": 0.1, "z": 0.1}
},
"Model": {
"aid": "model:cube"
},
"Particle_system": {
"cfg": "particle_sys:test_particles"
}
}
{
"emitters": [{
"spawn": [
{"particles_per_second": 100, "time": 1},
{"particles_per_second": 0, "time": 2}
],
"spawn_loop": true,
"ttl": {"mean": 10, "stddev": 1},
"velocity": {"mean": 2, "stddev": 0.5},
"emit_script_id": "comp_shader:particle_spawn_sphere",
"type_id": "particle_def:test_particles"
}]
}
{
"size": {"mean": {"x": 0.2, "y":0.2, "z":0.2}},
"drag": 0.1,
"blend": "solid",
"geometry": "mesh",
"model_id": "model:cube",
"update_script_id": "comp_shader:particle_update_simple"
}
......@@ -12,6 +12,7 @@
#include <mirrage/renderer/pass/gen_mipmap_pass.hpp>
#include <mirrage/renderer/pass/gi_pass.hpp>
#include <mirrage/renderer/pass/gui_pass.hpp>
#include <mirrage/renderer/pass/particle_pass.hpp>
#include <mirrage/renderer/pass/shadowmapping_pass.hpp>
#include <mirrage/renderer/pass/ssao_pass.hpp>
#include <mirrage/renderer/pass/taa_pass.hpp>
......@@ -35,6 +36,7 @@ namespace mirrage {
*this,
window(),
util::make_vector(renderer::make_pass_factory<renderer::Frustum_culling_pass_factory>(),
renderer::make_pass_factory<renderer::Particle_pass_factory>(),
renderer::make_pass_factory<renderer::Animation_pass_factory>(),
renderer::make_pass_factory<renderer::Shadowmapping_pass_factory>(),
renderer::make_pass_factory<renderer::Deferred_pass_factory>(),
......
......@@ -97,6 +97,10 @@ namespace mirrage {
_meta_system.entities().emplace("sponza");
_meta_system.entities().emplace("test_particle_emitter").process<Transform_comp>([&](auto& transform) {
transform.position = {-6, 2, 1};
});
auto billboard = _meta_system.entities().emplace("billboard");
billboard.get<Transform_comp>().process([](auto& transform) {
transform.position = {-8, 1, 0.5f};
......
......@@ -156,11 +156,15 @@ namespace mirrage::asset {
template <typename T>
auto Asset_manager::load(const AID& id, bool cache) -> Ptr<T>
{
auto a = load_maybe<T>(id, cache);
if(a.is_nothing())
auto path = resolve(id);
if(path.is_nothing())
throw std::system_error(Asset_error::resolve_failed, id.str());
return a.get_or_throw();
auto&& container = _find_container<T>();
if(container.is_nothing())
throw std::system_error(Asset_error::stateful_loader_not_initialized, util::type_name<T>());
return container.get_or_throw().load(id, path.get_or_throw(), cache);
}
template <typename T>
......
......@@ -416,6 +416,10 @@ namespace mirrage::asset {
return id.name();
}
LOG(plog::warning) << "Couldn't resove AID '" << id.str()
<< "'. Dispatcher: " << (res != _dispatchers.end() ? res->second : "!NO-MATCH")
<< "; Base: " << baseDir.get_or("!NO-MATCH");
return util::nothing;
}
auto Asset_manager::resolve_reverse(std::string_view path) -> util::maybe<AID>
......@@ -441,8 +445,7 @@ namespace mirrage::asset {
if(dir == _dispatchers.end())
return util::nothing;
std::string bdir = dir->second;
return bdir;
return dir->second;
}
void Asset_manager::_reload_dispatchers()
......
......@@ -78,7 +78,7 @@ namespace mirrage {
std::vector<const char*> _enabled_layers;
vk::UniqueInstance _instance;
vk::UniqueDebugReportCallbackEXT _debug_callback;
vk::UniqueDebugUtilsMessengerEXT _debug_callback;
std::unordered_map<std::string, Window_ptr> _windows;
......
......@@ -129,6 +129,11 @@ namespace mirrage::graphic {
auto memory() -> auto& { return _memory; }
operator bool() const noexcept { return valid(); }
auto valid() const noexcept { return _instance.operator bool(); }
private:
UniqueHandleType _instance;
Device_memory _memory;
......
......@@ -20,28 +20,28 @@
extern "C" {
VkResult vkCreateDebugReportCallbackEXT(VkInstance instance,
const VkDebugReportCallbackCreateInfoEXT* pCreateInfo,
VkResult vkCreateDebugUtilsMessengerEXT(VkInstance instance,
const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkDebugReportCallbackEXT* pCallback)
VkDebugUtilsMessengerEXT* pMessenger)
{
auto func = reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>(
vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT"));
auto func = reinterpret_cast<PFN_vkCreateDebugUtilsMessengerEXT>(
vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT"));
if(func != nullptr) {
return func(instance, pCreateInfo, pAllocator, pCallback);
return func(instance, pCreateInfo, pAllocator, pMessenger);
} else {
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
}
void vkDestroyDebugReportCallbackEXT(VkInstance instance,
VkDebugReportCallbackEXT callback,
void vkDestroyDebugUtilsMessengerEXT(VkInstance instance,
VkDebugUtilsMessengerEXT messenger,
const VkAllocationCallbacks* pAllocator)
{
auto func = reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>(
vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT"));
auto func = reinterpret_cast<PFN_vkDestroyDebugUtilsMessengerEXT>(
vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT"));
if(func != nullptr) {
func(instance, callback, pAllocator);
func(instance, messenger, pAllocator);
}
}
}
......@@ -181,35 +181,45 @@ namespace mirrage::graphic {
return validation_layers;
}
VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugReportFlagsEXT flags,
VkDebugReportObjectTypeEXT objType,
uint64_t obj,
size_t location,
int32_t code,
const char* layerPrefix,
const char* msg,
void* userData)
VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageType,
const VkDebugUtilsMessengerCallbackDataEXT* data,
void*)
{
(void) obj;
(void) location;
(void) code;
(void) userData;
// silences: DescriptorSet 0x3f previously bound as set #1 is incompatible with set
// 0x1cc99c0 newly bound as set #1 so set #2 and any subsequent sets were
// disturbed by newly bound pipelineLayout (0x4f)
if(objType == VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT)
return VK_FALSE;
if(flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
LOG(plog::error) << "[VK | " << layerPrefix << "] " << msg;
} else if(flags & VK_DEBUG_REPORT_WARNING_BIT_EXT
|| flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) {
LOG(plog::warning) << "[VK | " << layerPrefix << "] " << msg;
} else {
LOG(plog::info) << "[VK | " << layerPrefix << "] " << msg;
auto level = [&] {
if(messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) {
return plog::verbose;
} else if(messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) {
return plog::info;
} else if(messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) {
return plog::warning;
} else {
return plog::error;
}
}();
auto type = [&] {
if(messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) {
return " GENERAL";
} else if(messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT) {
return " SPEC";
} else if(messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) {
return " PERF";
} else {
return "";
}
}();
auto details = std::stringstream();
if(data->objectCount > 0) {
// TODO
}
if(data->cmdBufLabelCount > 0) {
// TODO
}
LOG(level) << "[VK" << type << "|" << data->pMessageIdName << "] " << data->pMessage
<< details.str();
return VK_FALSE;
}
......@@ -258,7 +268,6 @@ namespace mirrage::graphic {
add_present_extensions(required_extensions, _windows);
auto optional_extensions = std::vector<const char*>{};
required_extensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
required_extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
if(debug) {
......@@ -296,11 +305,16 @@ namespace mirrage::graphic {
_instance = vk::createInstanceUnique(instanceCreateInfo);
if(debug) {
_debug_callback = _instance->createDebugReportCallbackEXTUnique(
{/* vk::DebugReportFlagBitsEXT::eDebug | vk::DebugReportFlagBitsEXT::eInformation | */
vk::DebugReportFlagBitsEXT::eError | vk::DebugReportFlagBitsEXT::ePerformanceWarning
| vk::DebugReportFlagBitsEXT::eWarning,
debugCallback});
auto create_info = vk::DebugUtilsMessengerCreateInfoEXT{
vk::DebugUtilsMessengerCreateFlagsEXT{},
vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo
| vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning
| vk::DebugUtilsMessageSeverityFlagBitsEXT::eError,
vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral
| vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation
| vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance,
&debugCallback};
_debug_callback = _instance->createDebugUtilsMessengerEXTUnique(create_info);
}
_vkCmdBeginDebugUtilsLabelEXT = reinterpret_cast<PFN_vkCmdBeginDebugUtilsLabelEXT>(
......
......@@ -22,14 +22,16 @@ add_custom_target(mirrage_renderer_shaders SOURCES ${ALL_SHADERS})
set(MIRRAGE_GLSL_COMPILER "glslc" CACHE STRING "Path to glslc compiler")
foreach(GLSL ${GLSL_SOURCE_FILES})
get_filename_component(FILE_NAME ${GLSL} NAME)
set(SPIRV "${CMAKE_CURRENT_BINARY_DIR}/shader/${FILE_NAME}.spv")
add_custom_command(
OUTPUT ${SPIRV}
COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/shader/"
COMMAND ${MIRRAGE_GLSL_COMPILER} -o ${SPIRV} -c ${GLSL}
DEPENDS ${ALL_SHADERS})
list(APPEND SPIRV_BINARY_FILES ${SPIRV})
get_filename_component(FILE_DIR ${GLSL} DIRECTORY)
string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}" "" FILE_DIR ${FILE_DIR})
get_filename_component(FILE_NAME ${GLSL} NAME)
set(SPIRV "${CMAKE_CURRENT_BINARY_DIR}/${FILE_DIR}/${FILE_NAME}.spv")
add_custom_command(
OUTPUT ${SPIRV}
COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/${FILE_DIR}/"
COMMAND ${CMAKE_GLSL_COMPILER} -o ${SPIRV} -c ${GLSL}
DEPENDS ${ALL_SHADERS})
list(APPEND SPIRV_BINARY_FILES ${SPIRV})
endforeach(GLSL)
......
shader: = shader/
comp_shader:particle_spawn_sphere = shader/particle/spawn_sphere.comp.spv
comp_shader:particle_update_simple = shader/particle/update_simple.comp.spv
vert_shader:billboard = shader/billboard.vert.spv
frag_shader:billboard_lit = shader/billboard.frag.spv
frag_shader:billboard_unlit = shader/billboard_unlit.frag.spv
......
......@@ -141,6 +141,11 @@ namespace mirrage::renderer {
void settings(const Renderer_settings& s, bool apply = true);
void save_settings();
auto global_uniforms_layout() const noexcept { return *_global_uniform_descriptor_set_layout; }
auto compute_storage_buffer_layout() const { return *_compute_storage_buffer_layout; }
auto compute_uniform_buffer_layout() const { return *_compute_uniform_buffer_layout; }
private:
friend class Deferred_renderer;
struct Asset_loaders;
......@@ -168,6 +173,9 @@ namespace mirrage::renderer {
bool _recreation_pending = false;
vk::UniqueSampler _model_material_sampler;
vk::UniqueDescriptorSetLayout _model_desc_set_layout;
vk::UniqueDescriptorSetLayout _global_uniform_descriptor_set_layout;
vk::UniqueDescriptorSetLayout _compute_storage_buffer_layout;
vk::UniqueDescriptorSetLayout _compute_uniform_buffer_layout;
std::unique_ptr<Asset_loaders> _asset_loaders;
Render_pass_mask _all_passes_mask;
......@@ -205,7 +213,6 @@ namespace mirrage::renderer {
auto gbuffer() noexcept -> auto& { return *_gbuffer; }
auto gbuffer() const noexcept -> auto& { return *_gbuffer; }
auto global_uniforms() const noexcept -> auto& { return _global_uniforms; }
auto global_uniforms_layout() const noexcept { return *_global_uniform_descriptor_set_layout; }
auto asset_manager() noexcept -> auto& { return _factory->_assets; }
auto device() noexcept -> auto& { return *_factory->_device; }
......@@ -226,6 +233,10 @@ namespace mirrage::renderer {
auto model_material_sampler() const noexcept { return _factory->model_material_sampler(); }
auto model_descriptor_set_layout() const noexcept { return _factory->model_descriptor_set_layout(); }
auto global_uniforms_layout() const noexcept { return _factory->global_uniforms_layout(); }
auto compute_storage_buffer_layout() const { return _factory->compute_storage_buffer_layout(); }
auto compute_uniform_buffer_layout() const { return _factory->compute_uniform_buffer_layout(); }
auto active_camera() noexcept -> util::maybe<Camera_state&>;
auto settings() const -> auto& { return _factory->settings(); }
......@@ -267,9 +278,8 @@ namespace mirrage::renderer {
float _delta_time = 0.f;
std::uint32_t _frame_counter = 0;
vk::UniqueDescriptorSetLayout _global_uniform_descriptor_set_layout;
graphic::DescriptorSet _global_uniform_descriptor_set;
graphic::Dynamic_buffer _global_uniform_buffer;
graphic::DescriptorSet _global_uniform_descriptor_set;
graphic::Dynamic_buffer _global_uniform_buffer;
graphic::Texture_ptr _blue_noise;
vk::UniqueSampler _noise_sampler;
......
......@@ -43,270 +43,200 @@ namespace mirrage::renderer {
enum class Particle_geometry { billboard, ribbon, mesh };
sf2_enumDef(Particle_geometry, billboard, ribbon, mesh);
template <typename T = std::uint8_t>
struct Particle_color {
T hue;
T saturation;
T value;
T alpha;
float hue = 0.f;
float saturation = 0.f;
float value = 0.f;
float alpha = 0.f;
};
sf2_structDef(Particle_color<float>, hue, saturation, value, alpha);
sf2_structDef(Particle_color<std::uint8_t>, hue, saturation, value, alpha);
sf2_structDef(Particle_color, hue, saturation, value, alpha);
struct Particle_emitter_spawn {
float spawn_rate_mean = 10.f;
float spawn_rate_variance = 1.f;
float time = -1.f;
template <typename T>
struct Random_value {
T mean{};
T stddev{};
};
sf2_structDef(Particle_emitter_spawn, spawn_rate_mean, spawn_rate_variance, time);
sf2_structDef(Random_value<float>, mean, stddev);
sf2_structDef(Random_value<glm::vec4>, mean, stddev);
sf2_structDef(Random_value<Particle_color>, mean, stddev);
struct Particle_emitter_config {
float time = 0;
util::small_vector<Particle_emitter_spawn, 4> spawn;
/// modify velocities of living particles
/// e.g.
/// gravity: {..., force=10, dir={0,-1,0}, decay=0, fixed_dir=true}
/// point: {position=? dir={0,0,0}, decay=2}
/// flow: {position=? dir={1,0,0}, decay=2}
struct Particle_effector_config {
glm::vec3 position{0, 0, 0};
glm::quat rotation{1, 0, 0, 0};
Particle_color<float> color_mean = {1, 1, 1, 1};
Particle_color<float> color_variance = {0, 0, 0, 0};
Particle_color<float> color_change_mean = {0, 0, 0, 0};
Particle_color<float> color_change_variance = {0, 0, 0, 0};
float force = 0.f;
glm::vec3 force_dir{0, 0, 0};
float distance_decay = 2.f;
bool fixed_dir = false;
bool scale_with_mass = true;
};
sf2_structDef(Particle_effector_config,
position,
rotation,
force,
force_dir,
distance_decay,
fixed_dir,
scale_with_mass);
float size_mean = 0.1f;
float size_variance = 0.f;
float size_change_mean = 0.f;
float size_change_variance = 0.f;
/// describes how living particles are updated and drawn
struct Particle_type_config {
Random_value<Particle_color> color = {{1, 1, 1, 1}};
Random_value<Particle_color> color_change = {{0, 0, 0, 0}};
float rotation_mean = 0.1f;
float rotation_variance = 0.1f;
float rotation_change_mean = 0.f;
float rotation_change_variance = 0.f;
Random_value<glm::vec4> size = {{1.f, 1.f, 1.f, 0.f}};
Random_value<glm::vec4> size_change = {{0.f, 0.f, 0.f, 0.f}};
float ttl_mean = 1.f;
float ttl_variance = 0.f;
float base_mass = 1.f;
float density = 0.f;
float velocity_mean = 1.f;
float velocity_variance = 0.f;
Random_value<float> sprite_rotation = {0.0f};
Random_value<float> sprite_rotation_change = {0.0f};
Particle_blend_mode blend = Particle_blend_mode::transparent;
Particle_geometry geometry = Particle_geometry::billboard;
float update_range = -1.f;
float draw_range = -1.f;
bool shadowcaster = false;
std::string material_id;
renderer::Material_ptr material;
std::string model_id;
asset::Ptr<renderer::Model> model;
float drag = 0.f;
float parent_velocity = 0.f;
glm::vec3 offset{0, 0, 0};
glm::quat rotation{1, 0, 0, 0};
std::string emit_script_id;
std::string update_script_id;
float drag = 0.f;
asset::Ptr<Particle_script> emit_script;
std::string update_script_id;
asset::Ptr<Particle_script> update_script;
};
sf2_structDef(Particle_emitter_config,
time,
spawn,
color_mean,
color_variance,
color_change_mean,
color_change_variance,
size_mean,
size_variance,
size_change_mean,
size_change_variance,
rotation_mean,
rotation_variance,
rotation_change_mean,
rotation_change_variance,
ttl_mean,
ttl_variance,
velocity_mean,
velocity_variance,
sf2_structDef(Particle_type_config,
color,
color_change,
size,
size_change,
base_mass,
density,
sprite_rotation,
sprite_rotation_change,
blend,
geometry,
update_range,
draw_range,
shadowcaster,
material_id,
model_id,
drag,
parent_velocity,
emit_script_id,
update_script_id);
struct Particle_effector_config {
glm::vec3 position{0, 0, 0};
struct Particle_emitter_spawn {
float particles_per_second = 10.f;
float variance = 0.f;
float time = -1.f;
};
sf2_structDef(Particle_emitter_spawn, particles_per_second, variance, time);
// describes how new particles are created
struct Particle_emitter_config {
util::small_vector<Particle_emitter_spawn, 4> spawn;
bool spawn_loop = true;
Random_value<float> ttl = {1.f};
Random_value<float> velocity = {1.f};
float parent_velocity = 0.f;
glm::vec3 offset{0, 0, 0};
glm::quat rotation{1, 0, 0, 0};
float force = 0.f;
glm::vec3 force_dir{0, 0, 0};
float distance_decay = 2.f;
std::string emit_script_id;
asset::Ptr<Particle_script> emit_script;
std::string type_id;
asset::Ptr<Particle_type_config> type;
};
sf2_structDef(Particle_effector_config, position, rotation, force, force_dir, distance_decay);
sf2_structDef(Particle_emitter_config,
spawn,
spawn_loop,
ttl,
velocity,
parent_velocity,