Commit 7b80919d authored by Florian Oetke's avatar Florian Oetke
Browse files

fixed particle update, rotation and billboard rendering

parent ba3aae40
......@@ -8,7 +8,7 @@
"ttl": {"mean": 4, "stddev": 0.5},
"velocity": {"mean": 1, "stddev": 0.5},
"velocity": {"mean": 1, "stddev": 0.0},
"emit_script_id": "comp_shader:particle_spawn_sphere",
......
......@@ -3,21 +3,27 @@
{
"time": 0,
"color": {"mean":{"hue":0}, "stddev":{"hue":0.5}},
"size": {"mean": {"x": 0.08, "y":0.08, "z":0.08}, "stddev":{"x": 0.04, "y":0.04, "z":0.04}},
"size": {"mean": {"x": 0.04, "y":0.15, "z":0.04}, "stddev":{"x": 0.02, "y":0.02, "z":0.02}},
"rotation": {"mean":{"angle":0}, "stddev":{"elevation":1, "azimuth":1, "angle": 1}},
"drag": 0.1
},
{
"time": 3,
"time": 4,
"color": {"mean":{"hue":0}, "stddev":{"hue":0}},
"size": {"mean": {"x": 0.01, "y":0.01, "z":0.01}},
"size": {"mean": {"x": 0.01, "y":0.1, "z":0.01}},
"rotation": {"mean":{"angle":1}, "stddev":{"elevation":1, "azimuth":1, "angle": 1}},
"drag": 1.0
}
],
"symmetric_scaling": true,
"symmetric_scaling": false,
"rotate_with_velocity": false,
"blend": "solid",
/*
"geometry": "billboard",
"material_id": "mat:billboard_material.msf",
*/
"geometry": "mesh",
"model_id": "model:cube",
"update_script_id": "comp_shader:particle_update_simple"
......
Subproject commit aa0e9f5b67c0a66ffd3064e933be3c8980c6a331
Subproject commit fb58fbf3f6a0258d519b21e0ae52a1639854b759
......@@ -173,6 +173,7 @@ namespace mirrage {
case "pause"_strid:
LOG(plog::debug) << "Pause/Unpause playback";
_meta_system.nims().toggle_pause();
_paused = !_paused;
break;
case "toggle_ui"_strid: _show_ui = !_show_ui; break;
......@@ -295,7 +296,7 @@ namespace mirrage {
});
_look = {0.f, 0.f};
_meta_system.update(dt);
_meta_system.update(_paused ? util::Time(0.001f) : dt);
_performance_log.process([&](auto& log) {
_performance_log_delay_left -= dt;
......
......@@ -56,6 +56,8 @@ namespace mirrage {
glm::vec3 _move{};
bool _mouse_look = false;
bool _paused = false;
float _cam_yaw = 0;
float _cam_pitch = 0;
......
......@@ -20,9 +20,10 @@
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, keyframe, keyframe_interpolation_factor
glm::vec4 position; // xyz + ttl_left
glm::vec4 velocity; // xyz + ttl_initial
glm::uvec4
ttl; // last_feedback_buffer_index, seed, keyframe, floatBitsToUint(keyframe_interpolation_factor)
};
class Particle_script {
......@@ -49,6 +50,16 @@ namespace mirrage::renderer {
};
sf2_structDef(Particle_color, hue, saturation, value, alpha);
/// angle + axis rotation with the axis expressed in spherical coordinates
/// elevation=0 and azimuth=0 is (0,0,1)
struct Particle_rotation {
float elevation = 0.f; //< 0=0°, 1= 90°
float azimuth = 0.f; //< 0=0°, 1=360°
float angle = 0.f; //< 0=0°, 1=360°
float padding;
};
sf2_structDef(Particle_rotation, elevation, azimuth, angle);
template <typename T>
struct Random_value {
T mean{};
......@@ -56,7 +67,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_rotation>, mean, stddev);
sf2_structDef(Random_value<Particle_color>, mean, stddev);
......@@ -87,9 +98,9 @@ namespace mirrage::renderer {
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}};
Random_value<Particle_color> color = {{1, 1, 1, 1}};
Random_value<Particle_rotation> 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;
......
......@@ -13,13 +13,13 @@ layout(location = 2) in vec2 tex_coords;
layout(location = 3) in vec4 particle_position;
layout(location = 4) in vec4 particle_velocity;
layout(location = 5) in vec4 particle_ttl;
layout(location = 5) in uvec4 particle_data;
layout(location = 0) out vec3 out_view_pos;
layout(location = 1) out vec3 out_normal;
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(location = 4) out uvec4 out_particle_data;
layout(location = 5) out vec4 out_particle_color;
layout(std140, set=2, binding = 0) readonly buffer Particle_type_config {
......@@ -41,6 +41,11 @@ vec3 calc_size(uint keyframe_a, uint keyframe_b, float t, vec3 rand) {
rand_xyz(particle_config.keyframes[keyframe_b].size, rand),
t);
}
vec4 calc_rotation(uint keyframe_a, uint keyframe_b, float t, vec3 rand) {
return normalize(mix(rand_quat(particle_config.keyframes[keyframe_a].rotation, rand),
rand_quat(particle_config.keyframes[keyframe_b].rotation, rand),
t));
}
vec4 calc_color(uint keyframe_a, uint keyframe_b, float t, vec4 rand) {
return mix(rand_vec4(particle_config.keyframes[keyframe_a].color, rand),
rand_vec4(particle_config.keyframes[keyframe_b].color, rand),
......@@ -84,7 +89,7 @@ void calc_random(uint seed, out vec3 rotation, out vec3 size, out vec4 color) {
}
void main() {
uint seed = floatBitsToUint(particle_velocity.w);
uint seed = particle_data.y;
vec3 rand_rotation;
vec3 rand_size;
......@@ -92,24 +97,66 @@ void main() {
calc_random(seed, rand_rotation, rand_size, rand_color);
uint keyframe_a = floatBitsToUint(particle_ttl[2]);
uint keyframe_a = particle_data.z;
uint keyframe_b = min(keyframe_a+1, particle_config.keyframe_count-1);
float keyframe_t = particle_ttl[3];
float keyframe_t = uintBitsToFloat(particle_data.w);
vec3 size = max(vec3(0,0,0), calc_size(keyframe_a, keyframe_b, keyframe_t, rand_size));
if(particle_config.symmetric_scaling!=0)
size.y = size.z = size.x;
vec3 p = position * size;
// TODO: rotation
vec4 view_pos = model_uniforms.model_to_view * vec4(p + particle_position.xyz, 1.0);
vec4 p = vec4(position * size, 1.0);
vec4 n = vec4(normal, 0.0);
vec4 rotation = calc_rotation(keyframe_a, keyframe_b, keyframe_t, rand_rotation);
p.xyz = quaternion_rotate(p.xyz, rotation);
n.xyz = quaternion_rotate(n.xyz, rotation);
if(particle_config.rotate_with_velocity==2) {
vec4 view_vel = (global_uniforms.view_mat * vec4(particle_velocity.xyz, 0.0));
float len_2d = length(view_vel.xy);
if(len_2d >= 0.001) {
view_vel.xy = view_vel.xy / len_2d;
float angle = (view_vel.y<0? -1.0 : 1.0) * acos(view_vel.x);
angle -= 3.1415926*0.5;
float sa = sin(angle);
float ca = cos(angle);
p.xy = vec2(p.x*ca - p.y*sa, p.x*sa + p.y*ca);
n.xy = vec2(n.x*ca - n.y*sa, n.x*sa + n.y*ca);
}
} else if(particle_config.rotate_with_velocity==1) {
vec3 dir = particle_velocity.xyz;
float dir_len = length(dir);
if(dir_len > 0) {
dir /= dir_len;
if(dir.y <= -1.0) {
p.xyz = vec3(-p.x, -p.y, p.z);
n.xyz = vec3(-n.x, -n.y, n.z);
} else if(dir.y < 1.0) {
vec3 my = normalize(dir);
vec3 mz = normalize(cross(my, vec3(0,1,0)));
vec3 mx = normalize(cross(my, mz));
p.xyz = mat3(mx,my,mz) * p.xyz;
n.xyz = mat3(mx,my,mz) * n.xyz;
}
}
}
p = model_uniforms.model_to_view * p;
n = model_uniforms.model_to_view * n;
vec4 view_pos = global_uniforms.view_mat * vec4(p.xyz + particle_position.xyz, 1.0);
out_view_pos = view_pos.xyz / view_pos.w;
out_normal = (model_uniforms.model_to_view * vec4(normal, 0.0)).xyz;
out_normal = (global_uniforms.view_mat * n).xyz;
out_tex_coords = tex_coords;
out_particle_velocity = particle_velocity;
out_particle_ttl = particle_ttl;
out_particle_data = particle_data;
vec4 color = calc_color(keyframe_a, keyframe_b, keyframe_t, rand_color);;
out_particle_color = vec4(hsv2rgb(color.xyz), color.a);
......
......@@ -30,7 +30,6 @@ float rand_float(Random_float range, float rand) {
return range.mean + range.stddev*rand;
}
vec4 rand_vec4(Random_vec4 range, vec4 rand) {
// vec4 rand = vec4(normal_rand(seed, range_begin, range_begin+1), normal_rand(seed, range_begin+2, range_begin+4));
return range.mean + range.stddev*rand;
}
vec3 rand_xyz(Random_vec4 range, vec3 rand) {
......@@ -42,6 +41,17 @@ vec3 rand_dir(vec2 mean_angles, vec2 stddev_angles, vec2 rand) {
sin(angles.x)*sin(angles.y),
cos(angles.x));
}
vec4 rand_quat(Random_vec4 range, vec3 rand) {
range.mean *= vec4(0.5, 1, 1, 1) * 3.14159265359;
range.stddev *= vec4(0.5, 1, 1, 1) * 3.14159265359;
vec3 axis = rand_dir(range.mean.xy, range.stddev.xy, rand.xy);
float angle = range.mean.z + range.stddev.z * rand.z;
float half_angle = angle/2.0;
float sha = sin(half_angle);
return vec4(axis * sha, cos(half_angle));
}
struct Effector {
......@@ -55,9 +65,9 @@ struct Effector {
};
struct Particle {
vec4 position; // xyz + uintBitsToFloat(last_feedback_buffer_index)
vec4 velocity; // xyz + seed
vec4 ttl; // ttl_left, ttl_initial, keyframe, keyframe_interpolation_factor
vec4 position; // xyz + ttl_left
vec4 velocity; // xyz + ttl_initial
uvec4 data; // last_feedback_buffer_index, seed, keyframe, floatBitsToUint(keyframe_interpolation_factor)
// seed: 0=ttl, 1=velocity, 2+3=direction, 4+5=vel_direction, 6...=position
// 10-13=color
// 20-22=rotation, 23-25=size
......@@ -70,7 +80,7 @@ struct Emitter_particle_range {
struct Particle_keyframe {
Random_vec4 color; // hsv + alpha
Random_vec4 rotation; // pitch, yaw, roll
Random_vec4 rotation; // elevation, azimuth, angle
Random_vec4 size; // xyz
float time;
......@@ -100,6 +110,6 @@ struct Particle_keyframe {
uint keyframe_count; \
Particle_keyframe[] keyframes;
vec3 quaternion_rotate(vec3 dir, vec4 q) {
return dir + 2.0 * cross(q.xyz, cross(q.xyz, dir) + q.w * dir);
vec3 quaternion_rotate(vec3 v, vec4 q) {
return v + 2.0 * cross(cross(v, q.xyz ) + q.w*v, q.xyz);
}
......@@ -37,9 +37,9 @@ void main() {
float rand_ttl = rand_float(emitter_cfg.ttl, r01[0]);
float rand_vel = rand_float(emitter_cfg.velocity, r01[1]);
pout.particles[index].position.w = uintBitsToFloat(emitter_cfg.feedback_buffer_id);
pout.particles[index].velocity.w = uintBitsToFloat(seed);
pout.particles[index].ttl = vec4(rand_ttl, rand_ttl, 0, 0);
pout.particles[index].position.w = rand_ttl;
pout.particles[index].velocity.w = rand_ttl;
pout.particles[index].data = uvec4(emitter_cfg.feedback_buffer_id, seed, 0, floatBitsToUint(0));
bool dir_normal_distr = (emitter_cfg.direction_flags & 2) != 0;
vec2 r23 = dir_normal_distr ? normal_rand(seed, 2, 3) : uniform_rand(seed, 2,3)*2-1;
......
......@@ -26,7 +26,7 @@ void main() {
if(offset < update_cfg.particle_read_count) {
uint index = offset + update_cfg.particle_read_offset;
vec2 ttl = pin.particles[index].ttl.xy;
vec2 ttl = vec2(pin.particles[index].position.w, pin.particles[index].velocity.w);
ttl[0] -= update_cfg.timestep;
if(ttl[0] <= 0) {
......@@ -35,36 +35,43 @@ void main() {
const float dt = update_cfg.timestep;
// incr count and get output index
uint old_feedback_index = floatBitsToUint(pin.particles[index].position.w);
uint old_feedback_index = pin.particles[index].data.x;
uint feedback_index = feedback_mapping.new_feedback_index[old_feedback_index];
uint out_offset = atomicAdd(feedback.ranges[feedback_index].count, 1);
uint out_index = out_offset + feedback.ranges[feedback_index].offset;
// update keyframe
float age = ttl[1] - ttl[0];
uint keyframe = 0;
for(; keyframe+1<particle_config.keyframe_count-1; keyframe++) {
if(particle_config.keyframes[keyframe].time >= age) {
keyframe--;
uint keyframe = pin.particles[index].data.z;
for(uint i=keyframe+1; i<particle_config.keyframe_count-1; i++) {
if(particle_config.keyframes[i].time > age) {
keyframe = i - 1;
break;
}
}
uint keyframe_b = min(keyframe+1, particle_config.keyframe_count-1);
float time_a = particle_config.keyframes[keyframe].time;
float time_b = particle_config.keyframes[min(keyframe+1, particle_config.keyframe_count-1)].time;
float keyframe_t = clamp(0, 1, time_b <= time_a ? 0.0 : (age - time_a) / (time_b - time_a));
float time_b = particle_config.keyframes[keyframe_b].time;
float time_diff = time_b - time_a;
float keyframe_t = time_diff>0.0 ? clamp((age - time_a) / time_diff, 0.0, 1.0) : 0.0;
// update position / velocity
vec3 velocity = pin.particles[index].velocity.xyz;
// TODO: velocity *= (1.0 - config.drag*dt);
velocity *= (1.0 - dt*mix(particle_config.keyframes[keyframe].drag,
particle_config.keyframes[keyframe_b].drag,
keyframe_t));
// TODO: apply global and local effectors
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);
pout.particles[out_index].velocity.w = pin.particles[index].velocity.w;
pout.particles[out_index].ttl = vec4(ttl.x, ttl.y, uintBitsToFloat(keyframe), keyframe_t);
pout.particles[out_index].position.w = ttl.x;
pout.particles[out_index].velocity.w = ttl.y;
pout.particles[out_index].data = uvec4(feedback_index, pin.particles[index].data.y,
keyframe, floatBitsToUint(keyframe_t));
}
}
}
......@@ -12,7 +12,7 @@ layout(location = 0) in vec3 view_pos;
layout(location = 1) in vec3 normal;
layout(location = 2) in vec2 tex_coords;
layout(location = 3) in vec4 out_particle_velocity;
layout(location = 4) in vec4 out_particle_ttl;
layout(location = 4) in flat uvec4 out_particle_data;
layout(location = 5) in vec4 out_particle_color;
......
......@@ -28,10 +28,10 @@ namespace mirrage::renderer {
auto create_billboard_model(Deferred_renderer& r)
{
const auto vertices = std::array<Model_vertex, 4>{
Model_vertex{glm::vec3(0, 0, 0), glm::vec3(0, 0, 1), glm::vec2(0, 1)},
Model_vertex{glm::vec3(1, 0, 0), glm::vec3(0, 0, 1), glm::vec2(1, 1)},
Model_vertex{glm::vec3(0, 1, 0), glm::vec3(0, 0, 1), glm::vec2(0, 0)},
Model_vertex{glm::vec3(1, 1, 0), glm::vec3(0, 0, 1), glm::vec2(1, 0)}};
Model_vertex{glm::vec3(-0.5f, -0.5f, 0), glm::vec3(0, 0, 1), glm::vec2(0, 1)},
Model_vertex{glm::vec3(0.5f, -0.5f, 0), glm::vec3(0, 0, 1), glm::vec2(1, 1)},
Model_vertex{glm::vec3(-0.5f, 0.5f, 0), glm::vec3(0, 0, 1), glm::vec2(0, 0)},
Model_vertex{glm::vec3(0.5f, 0.5f, 0), glm::vec3(0, 0, 1), glm::vec2(1, 0)}};
const auto indices = std::array<std::uint32_t, 6>{0, 1, 2, 2, 1, 3};
return Model{graphic::Mesh{r.device(), r.queue_family(), vertices, indices},
......@@ -396,7 +396,11 @@ namespace mirrage::renderer {
{particle.emitter->particle_buffer()},
{std::uint32_t(particle.emitter->particle_offset())});
dpc.model = _renderer.global_uniforms().view_mat;
dpc.model = glm::mat4(1);
if(particle.type_cfg->geometry == Particle_geometry::billboard) {
dpc.model = glm::inverse(_renderer.global_uniforms().view_mat);
dpc.model[3] = glm::vec4(0, 0, 0, 1);
}
render_pass.push_constant("dpc"_strid, dpc);
// draw instanced
......
......@@ -503,9 +503,10 @@ namespace mirrage::renderer {
auto& uniforms = *reinterpret_cast<Type_uniforms*>(uniforms_ptr);
auto keyframes = reinterpret_cast<char*>(uniforms_ptr + sizeof(Type_uniforms));
uniforms.keyframe_count = gsl::narrow<std::uint32_t>(cfg.keyframes.size());
uniforms.rotate_with_velocity = cfg.rotate_with_velocity ? 1 : 0;
uniforms.symmetric_scaling = cfg.symmetric_scaling ? 1 : 0;
uniforms.keyframe_count = gsl::narrow<std::uint32_t>(cfg.keyframes.size());
uniforms.rotate_with_velocity =
cfg.rotate_with_velocity ? (cfg.geometry == Particle_geometry::billboard ? 2 : 1) : 0;
uniforms.symmetric_scaling = cfg.symmetric_scaling ? 1 : 0;
auto ndf = std::uint32_t(0);
auto i = std::uint32_t(0);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment