Commit c66aca6b authored by Florian Oetke's avatar Florian Oetke
Browse files

changed particle data structure to keyframe-based

parent 138249c5
......@@ -5,6 +5,8 @@
"source_radius": 0.8,
"intensity": 130000.0,
"temperature": 4500,
"shadow_intensity": 2.0,
"shadow_temperature": 4000,
"shadow_size": 24,
"near_plane": 1.0,
"far_plane": 80,
......
{
"size": {"mean": {"x": 0.2, "y":0.2, "z":0.2}},
"drag": 0.1,
"keyframes": [
{
"size": {"mean": {"x": 0.2, "y":0.2, "z":0.2}},
"drag": 0.1
}
],
"blend": "solid",
"geometry": "mesh",
......
......@@ -50,11 +50,14 @@ namespace mirrage::renderer {
float scotopic_sim_weight = 1.f;
float min_display_luminance = 2.f;
float max_display_luminance = 150.0f;
float amient_light_intensity = 0.1f;
bool taa = true;
bool ssao = true;
bool bloom = true;
bool depth_of_field = true;
bool taa = true;
bool ssao = true;
bool bloom = true;
bool depth_of_field = true;
bool particles = true;
std::int32_t max_particles = 1'000'000;
float background_intensity = 0.f;
......@@ -75,10 +78,13 @@ namespace mirrage::renderer {
gi_low_quality_mip_levels,
min_display_luminance,
max_display_luminance,
amient_light_intensity,
taa,
ssao,
bloom,
depth_of_field,
particles,
max_particles,
shadows,
dynamic_lighting,
debug_geometry);
......
......@@ -16,10 +16,13 @@ namespace mirrage::renderer {
using Component::Component;
void temperature(float kelvin);
void shadow_temperature(float kelvin);
auto shadowcaster(bool b) noexcept { _shadowcaster = b; }
void source_radius(util::Distance v) noexcept { _source_radius = v; }
void intensity(float v) noexcept { _intensity = v; }
void shadow_intensity(float v) noexcept { _shadow_intensity = v; }
void color(util::Rgb v) noexcept { _color = v; }
void shadow_color(util::Rgb v) noexcept { _shadow_color = v; }
void shadowmap_id(int id) noexcept { _shadowmap_id = id; }
void shadow_size(float v) noexcept { _shadow_size = v; }
void shadow_near_plane(float v) noexcept { _shadow_near_plane = v; }
......@@ -28,7 +31,9 @@ namespace mirrage::renderer {
auto shadowcaster() const noexcept { return _shadowcaster; }
auto source_radius() const noexcept { return _source_radius; }
auto intensity() const noexcept { return _intensity; }
auto shadow_intensity() const noexcept { return _shadow_intensity; }
auto color() const noexcept { return _color; }
auto shadow_color() const noexcept { return _shadow_color; }
auto shadowmap_id() const noexcept { return _shadowmap_id; }
auto calc_shadowmap_view_proj(ecs::components::Transform_comp& transform) const -> glm::mat4;
......@@ -49,6 +54,8 @@ namespace mirrage::renderer {
util::Distance _source_radius;
float _intensity; // in lux
util::Rgb _color;
float _shadow_intensity = 0; // in lux
util::Rgb _shadow_color = {0, 0, 0};
bool _shadowcaster = true;
int _shadowmap_id = -1;
float _shadow_size = 128;
......
......@@ -22,7 +22,7 @@ namespace mirrage::renderer {
struct Particle {
glm::vec4 position; // xyz + uintBitsToFloat(last_feedback_buffer_index)
glm::vec4 velocity; // xyz + seed
glm::vec4 ttl; // ttl_left, ttl_initial, <empty>, <empty>
glm::vec4 ttl; // ttl_left, ttl_initial, keyframe, keyframe_interpolation_factor
};
class Particle_script {
......@@ -56,6 +56,7 @@ namespace mirrage::renderer {
};
sf2_structDef(Random_value<float>, mean, stddev);
sf2_structDef(Random_value<glm::vec4>, mean, stddev);
sf2_structDef(Random_value<glm::quat>, mean, stddev);
sf2_structDef(Random_value<Particle_color>, mean, stddev);
......@@ -85,20 +86,34 @@ namespace mirrage::renderer {
fixed_dir,
scale_with_mass);
struct Particle_keyframe {
Random_value<Particle_color> color = {{1, 1, 1, 1}};
Random_value<glm::vec4> rotation = {{0.f, 0.f, 0.f, 0.f}};
Random_value<glm::vec4> size = {{1.f, 1.f, 1.f, 0.f}};
float time = 0;
float base_mass = 1;
float density = 0;
float drag = 0.f;
};
sf2_structDef(Particle_keyframe, color, rotation, size, time, base_mass, density, drag);
/// 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}};
util::small_vector<Particle_keyframe, 3> keyframes;
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}};
bool color_normal_distribution_h = true;
bool color_normal_distribution_s = true;
bool color_normal_distribution_v = true;
bool color_normal_distribution_a = true;
bool rotation_normal_distribution_x = true;
bool rotation_normal_distribution_y = true;
bool rotation_normal_distribution_z = true;
bool size_normal_distribution_x = true;
bool size_normal_distribution_y = true;
bool size_normal_distribution_z = true;
Random_value<float> sprite_rotation = {0.0f};
Random_value<float> sprite_rotation_change = {0.0f};
float base_mass = 1.f;
float density = 0.f;
float drag = 0.f;
bool rotate_with_velocity = false;
Particle_blend_mode blend = Particle_blend_mode::transparent;
Particle_geometry geometry = Particle_geometry::billboard;
......@@ -117,14 +132,18 @@ namespace mirrage::renderer {
asset::Ptr<Particle_script> update_script;
};
sf2_structDef(Particle_type_config,
color,
color_change,
size,
size_change,
base_mass,
density,
sprite_rotation,
sprite_rotation_change,
keyframes,
color_normal_distribution_h,
color_normal_distribution_s,
color_normal_distribution_v,
color_normal_distribution_a,
rotation_normal_distribution_x,
rotation_normal_distribution_y,
rotation_normal_distribution_z,
size_normal_distribution_x,
size_normal_distribution_y,
size_normal_distribution_z,
rotate_with_velocity,
blend,
geometry,
update_range,
......@@ -132,7 +151,6 @@ namespace mirrage::renderer {
shadowcaster,
material_id,
model_id,
drag,
update_script_id);
......@@ -194,6 +212,9 @@ namespace mirrage::renderer {
void next_uniforms(vk::DescriptorSet s) { _next_uniforms = s; }
auto next_uniforms() const noexcept { return _next_uniforms; }
auto batch_able() const noexcept { return _batch_able; }
void batch_able(bool b) noexcept { _batch_able = b; }
private:
vk::Buffer _buffer;
vk::DescriptorSet _uniforms;
......@@ -203,6 +224,7 @@ namespace mirrage::renderer {
std::int32_t _offset = 0;
std::int32_t _count = 0;
std::uint32_t _feedback_idx = 0;
bool _batch_able = true;
friend class Particle_emitter;
};
......@@ -225,6 +247,7 @@ namespace mirrage::renderer {
void incr_time(float dt);
auto spawn(util::default_rand&) -> std::int32_t;
void override_spawn(std::int32_t spawn) { _particles_to_spawn = spawn; }
auto drawable() const noexcept { return _gpu_data && _gpu_data->valid(); }
auto particle_offset() const noexcept { return drawable() ? _gpu_data->_offset : 0; }
......
......@@ -15,7 +15,7 @@ namespace mirrage::renderer {
glm::vec4 light_color; //< for light-subpass; A=intensity
glm::vec4 light_data; //< for light-subpass; R=src_radius, GBA=direction
glm::vec4 light_data2; //< for light-subpass; R=shadowmapID
glm::vec4 placeholder;
glm::vec4 shadow_color;
};
static_assert(sizeof(Deferred_push_constants) <= 4096, "Too large for push constants!");
......
......@@ -84,8 +84,9 @@ namespace mirrage::renderer {
auto _alloc_feedback_buffer(Frame_data&)
-> std::tuple<gsl::span<Emitter_range>, gsl::span<std::uint32_t>>;
void _update_descriptor_set(Per_frame_data&, util::maybe<Per_frame_data&>);
void _update_type_uniforms(Frame_data&, Per_frame_data&);
void _dispatch_emits(Frame_data&, vk::CommandBuffer);
void _dispatch_updates(Frame_data&, vk::CommandBuffer, Per_frame_data&);
void _dispatch_updates(Frame_data&, vk::CommandBuffer);
};
class Particle_pass_factory : public Render_pass_factory {
......
......@@ -37,7 +37,7 @@ vec3 fresnelSchlick(float cosTheta, vec3 F0) {
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
}
vec3 brdf(vec3 albedo, vec3 F0, float roughness, vec3 N, vec3 V, vec3 L, vec3 radiance, out vec3 diffuse) {
vec3 brdf_without_NdotL(vec3 albedo, vec3 F0, float roughness, vec3 N, vec3 V, vec3 L, vec3 radiance, out vec3 diffuse) {
const float PI = 3.14159265359;
vec3 H = normalize(V+L);
......@@ -53,9 +53,12 @@ vec3 brdf(vec3 albedo, vec3 F0, float roughness, vec3 N, vec3 V, vec3 L, vec3 ra
float denominator = 4 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0) + 0.001;
vec3 brdf = nominator / denominator;
// add to outgoing radiance Lo
float NdotL = max(dot(N, L), 0.0);
diffuse = kD * albedo / PI * radiance;
return (kD * albedo / PI + brdf) * radiance;
}
diffuse = kD * albedo / PI * radiance * NdotL;
return (kD * albedo / PI + brdf) * radiance * NdotL;
vec3 brdf(vec3 albedo, vec3 F0, float roughness, vec3 N, vec3 V, vec3 L, vec3 radiance, out vec3 diffuse) {
float NdotL = max(dot(N, L), 0.0);
radiance *= NdotL;
return brdf_without_NdotL(albedo, F0, roughness, N, V, L, radiance, diffuse);
}
......@@ -32,6 +32,7 @@ layout(push_constant) uniform Per_model_uniforms {
vec4 light_color;
vec4 light_data; // R=src_radius, GBA=direction
vec4 light_data2; // R=shadowmapID
vec4 shadow_color;
} model_uniforms;
......@@ -47,6 +48,7 @@ void main() {
vec3 position = position_from_ldepth(vertex_out.tex_coords, depth);
vec3 V = -normalize(position);
vec3 L = model_uniforms.light_data.gba;
vec3 albedo = albedo_mat_id.rgb;
int material = int(albedo_mat_id.a*255);
......@@ -56,21 +58,26 @@ void main() {
vec3 F0 = mix(vec3(0.04), albedo.rgb, metallic);
albedo.rgb *= 1.0 - metallic;
vec3 radiance = model_uniforms.light_color.rgb * model_uniforms.light_color.a;
vec3 radiance = model_uniforms.light_color.rgb * model_uniforms.light_color.a;
float shadow = sample_shadowmap(position + N*0.06);
float NdotL = max(dot(N, L), 0.0);
vec3 shadow_radiance = model_uniforms.shadow_color.rgb * model_uniforms.shadow_color.a;
out_color = vec4(0,0,0,0);
out_color_diff = vec4(0,0,0,0);
out_color = vec4(0,0,0,1.0);
out_color_diff = vec4(0,0,0,1.0);
if(shadow>0.0) {
vec3 L = model_uniforms.light_data.gba;
shadow *= NdotL;
if(shadow>0.0) {
vec3 diffuse;
out_color = vec4(brdf(albedo, F0, roughness, N, V, L, radiance, diffuse) * shadow, 1.0);
out_color_diff = vec4(diffuse * shadow, 1.0);
}
out_color.rgb += shadow_radiance * albedo / PI * (1.0 - shadow);
out_color_diff.rgb += shadow_radiance * albedo / PI * (1.0 - shadow);
}
......
......@@ -20,28 +20,9 @@ layout(location = 2) out vec2 out_tex_coords;
layout(location = 3) out vec4 out_particle_velocity;
layout(location = 4) out vec4 out_particle_ttl;
layout(std140, set=2, binding = 0) uniform Particle_config {
Random_vec4 color; // hsva
Random_vec4 color_change;
Random_vec4 size;
Random_vec4 size_change;
Random_float sprite_rotation;
Random_float sprite_rotation_change;
float base_mass;
float density;
float drag;
float timestep;
uint particle_offset;
uint particle_count;
int padding;
int effector_count;
Effector effectors[];
} particle_config;
layout(std140, set=2, binding = 0) uniform Particle_type_config_dummy {
Particle_type_config particle_config;
};
layout(push_constant) uniform Per_model_uniforms {
mat4 model_to_view;
......@@ -58,7 +39,7 @@ void main() {
float age = particle_ttl.y - particle_ttl.x;
vec3 p = position;
p *= rand_vec4(particle_config.size, seed,20).xyz + age*rand_vec4(particle_config.size_change, seed,24).xyz;
// p *= rand_vec4(particle_config.size, seed,20).xyz + age*rand_vec4(particle_config.size_change, seed,24).xyz;
// TODO: rotation
vec4 view_pos = model_uniforms.model_to_view * vec4(p + particle_position.xyz, 1.0);
......
#include "data_structures.glsl"
layout(std140, set=0, binding = 0) uniform Shared_uniforms {
// TODO ?
int effector_count;
int global_effector_count;
int padding1;
int padding2;
int padding3;
Effector effectors[];
} shared_uniforms;
//layout(set=1, binding = 0) uniform sampler2D color_sampler;
layout(std430, set=0, binding = 1) readonly buffer Particles_old {
Particle particles[];
} pin;
......@@ -28,3 +25,5 @@ layout(std430, set=0, binding = 3) buffer Feedback_buffer {
layout(std430, set=0, binding = 4) buffer Feedback_mapping {
uint new_feedback_index[];
} feedback_mapping;
//layout(set=5, binding = 0) uniform sampler2D color_sampler;
......@@ -37,7 +37,7 @@ struct Effector {
struct Particle {
vec4 position; // xyz + uintBitsToFloat(last_feedback_buffer_index)
vec4 velocity; // xyz + seed
vec4 ttl; // ttl_left, ttl_initial, <empty>, <empty>
vec4 ttl; // ttl_left, ttl_initial, keyframe, keyframe_interpolation_factor
// seed: 0=ttl, 1=velocity, 2+3=direction, TODO: position?
// 10-13=color, 14-17=color_change
// 20-23=size, 24-27=size_change
......@@ -49,6 +49,37 @@ struct Emitter_particle_range {
int count;
};
struct Particle_keyframe {
Random_vec4 color; // hsv + alpha
Random_vec4 rotation; // pitch, yaw, roll
Random_vec4 size; // xyz
float time;
float base_mass;
float density;
float drag;
};
struct Particle_type_config {
uint normal_distribution_flags;
// 1 << 0 : color[0] normal/uniform
// 1 << 1 : color[1] normal/uniform
// 1 << 2 : color[2] normal/uniform
// 1 << 3 : color[3] normal/uniform
// 1 << 4 : rotation[0] normal/uniform
// 1 << 5 : rotation[1] normal/uniform
// 1 << 6 : rotation[2] normal/uniform
// 1 << 7 : size[0] normal/uniform
// 1 << 8 : size[1] normal/uniform
// 1 << 9 : size[2] normal/uniform
uint rotate_with_velocity; // bool
uint keyframe_count;
uint padding;
Particle_keyframe keyframes;
};
vec3 quaternion_rotate(vec3 dir, vec4 q) {
return dir + 2.0 * cross(q.xyz, cross(q.xyz, dir) + q.w * dir);
......
......@@ -44,9 +44,6 @@ void main() {
pos += velocity * emitter_cfg.timestep*(float(invId)/float(emitter_cfg.to_spawn));
// TODO: take euler step of timestep*(float(invId)/float(emitter_cfg.to_spawn))
// might distribute particles more evenly => test it first
pout.particles[index].position.xyz = pos;
pout.particles[index].velocity.xyz = velocity;
......
......@@ -5,44 +5,35 @@
layout (local_size_x = 32, local_size_y = 1, local_size_z = 1) in;
layout(std140, set=1, binding = 0) uniform Config {
Random_vec4 color; // hsva
Random_vec4 color_change;
layout(std140, set=1, binding = 0) uniform Particle_type_config_dummy {
Particle_type_config config;
};
Random_vec4 size;
Random_vec4 size_change;
Random_float sprite_rotation;
Random_float sprite_rotation_change;
float base_mass;
float density;
float drag;
layout(push_constant) uniform Push_constants {
float timestep;
uint particle_read_offset;
uint particle_read_count;
int padding;
int effector_count;
Effector effectors[];
} config;
#include "../global_uniforms.glsl"
uint effector_count;
uint effector_offset;
} update_cfg;
void main() {
uint offset = gl_GlobalInvocationID.x;
if(offset < config.particle_read_count) {
uint index = offset + config.particle_read_offset;
if(offset < update_cfg.particle_read_count) {
uint index = offset + update_cfg.particle_read_offset;
vec2 ttl = pin.particles[index].ttl.xy;
ttl[0] -= config.timestep;
ttl[0] -= update_cfg.timestep;
if(ttl[0] <= 0) {
// dead => drop data
} else {
const float dt = update_cfg.timestep;
// incr count and get output index
uint old_feedback_index = floatBitsToUint(pin.particles[index].position.w);
uint feedback_index = feedback_mapping.new_feedback_index[old_feedback_index];
......@@ -51,10 +42,10 @@ void main() {
// update position / velocity
vec3 velocity = pin.particles[index].velocity.xyz;
velocity *= (1.0 - config.drag*config.timestep);
// TODO: velocity *= (1.0 - config.drag*dt);
// TODO: apply global and local effectors
pout.particles[out_index].position.xyz = pin.particles[index].position.xyz + velocity * config.timestep;
pout.particles[out_index].position.xyz = pin.particles[index].position.xyz + velocity * dt;
pout.particles[out_index].velocity.xyz = velocity;
pout.particles[out_index].position.w = uintBitsToFloat(feedback_index);
......
......@@ -26,28 +26,9 @@ layout(set=1, binding = 1) uniform sampler2D normal_sampler;
layout(set=1, binding = 2) uniform sampler2D brdf_sampler;
layout(set=1, binding = 3) uniform sampler2D emission_sampler;
layout(std140, set=2, binding = 0) uniform Particle_config {
Random_vec4 color; // hsva
Random_vec4 color_change;
Random_vec4 size;
Random_vec4 size_change;
Random_float sprite_rotation;
Random_float sprite_rotation_change;
float base_mass;
float density;
float drag;
float timestep;
uint particle_offset;
uint particle_count;
int padding;
int effector_count;
Effector effectors[];
} particle_config;
layout(std140, set=2, binding = 0) uniform Particle_type_config_dummy {
Particle_type_config particle_config;
};
layout(push_constant) uniform Per_model_uniforms {
mat4 model;
......
......@@ -54,7 +54,7 @@ namespace mirrage::renderer {
factory._window.width(),
factory._window.height())
: std::unique_ptr<GBuffer>())
, _profiler(device(), 64)
, _profiler(device(), 128)
, _global_uniform_descriptor_set(
_descriptor_set_pool.create_descriptor(*factory._global_uniform_descriptor_set_layout, 1))
......
......@@ -11,13 +11,17 @@ namespace mirrage::renderer {
void load_component(ecs::Deserializer& state, Directional_light_comp& comp)
{
auto src_radius = comp._source_radius / 1_m;
auto temperature = -1.f;
auto src_radius = comp._source_radius / 1_m;
auto temperature = -1.f;
auto shadow_temperature = -1.f;
state.read_virtual(sf2::vmember("source_radius", src_radius),
sf2::vmember("intensity", comp._intensity),
sf2::vmember("color", comp._color),
sf2::vmember("temperature", temperature),
sf2::vmember("shadow_intensity", comp._shadow_intensity),
sf2::vmember("shadow_color", comp._shadow_color),
sf2::vmember("shadow_temperature", shadow_temperature),
sf2::vmember("shadow_size", comp._shadow_size),
sf2::vmember("near_plane", comp._shadow_near_plane),
sf2::vmember("far_plane", comp._shadow_far_plane),
......@@ -27,6 +31,9 @@ namespace mirrage::renderer {
if(temperature >= 0.f) {
comp.temperature(temperature);
}
if(shadow_temperature >= 0.f) {
comp.shadow_temperature(shadow_temperature);
}
}
void save_component(ecs::Serializer& state, const Directional_light_comp& comp)
......@@ -34,6 +41,8 @@ namespace mirrage::renderer {
state.write_virtual(sf2::vmember("source_radius", comp._source_radius / 1_m),
sf2::vmember("intensity", comp._intensity),
sf2::vmember("color", comp._color),
sf2::vmember("shadow_intensity", comp._shadow_intensity),
sf2::vmember("shadow_color", comp._shadow_color),
sf2::vmember("shadow_size", comp._shadow_size),
sf2::vmember("near_plane", comp._shadow_near_plane),
sf2::vmember("far_plane", comp._shadow_far_plane),
......@@ -41,6 +50,10 @@ namespace mirrage::renderer {
}
void Directional_light_comp::temperature(float kelvin) { _color = temperature_to_color(kelvin); }
void Directional_light_comp::shadow_temperature(float kelvin)
{
_shadow_color = temperature_to_color(kelvin);
}