221 lines
8.6 KiB
Text
221 lines
8.6 KiB
Text
// Example of particles with orthogonal occlusion using a viewport depth buffer
|
|
// by Wolfe (https://github.com/Wolfe2x7/)
|
|
// MIT License; main body of shader automatically converted from Godot Engine 3.4.2.stable's ParticlesMaterial.
|
|
|
|
shader_type particles;
|
|
uniform vec3 direction;
|
|
uniform float spread;
|
|
uniform float flatness;
|
|
uniform float initial_linear_velocity;
|
|
uniform float initial_angle;
|
|
uniform float angular_velocity;
|
|
uniform float orbit_velocity;
|
|
uniform float linear_accel;
|
|
uniform float radial_accel;
|
|
uniform float tangent_accel;
|
|
uniform float damping;
|
|
uniform float scale;
|
|
uniform float hue_variation;
|
|
uniform float anim_speed;
|
|
uniform float anim_offset;
|
|
uniform float initial_linear_velocity_random;
|
|
uniform float initial_angle_random;
|
|
uniform float angular_velocity_random;
|
|
uniform float orbit_velocity_random;
|
|
uniform float linear_accel_random;
|
|
uniform float radial_accel_random;
|
|
uniform float tangent_accel_random;
|
|
uniform float damping_random;
|
|
uniform float scale_random;
|
|
uniform float hue_variation_random;
|
|
uniform float anim_speed_random;
|
|
uniform float anim_offset_random;
|
|
uniform float lifetime_randomness;
|
|
uniform vec3 emission_box_extents;
|
|
uniform vec4 color_value : hint_color;
|
|
uniform int trail_divisor;
|
|
uniform vec3 gravity;
|
|
|
|
//
|
|
uniform float occlusion_margin = 0.04;
|
|
uniform float depth_cam_size; // equal to camera size
|
|
uniform sampler2D depth_map : hint_albedo; // link to viewport texture
|
|
|
|
uniform vec3 example_normal;
|
|
//
|
|
|
|
float rand_from_seed(inout uint seed) {
|
|
int k;
|
|
int s = int(seed);
|
|
if (s == 0)
|
|
s = 305420679;
|
|
k = s / 127773;
|
|
s = 16807 * (s - k * 127773) - 2836 * k;
|
|
if (s < 0)
|
|
s += 2147483647;
|
|
seed = uint(s);
|
|
return float(seed % uint(65536)) / 65535.0;
|
|
}
|
|
|
|
float rand_from_seed_m1_p1(inout uint seed) {
|
|
return rand_from_seed(seed) * 2.0 - 1.0;
|
|
}
|
|
|
|
uint hash(uint x) {
|
|
x = ((x >> uint(16)) ^ x) * uint(73244475);
|
|
x = ((x >> uint(16)) ^ x) * uint(73244475);
|
|
x = (x >> uint(16)) ^ x;
|
|
return x;
|
|
}
|
|
|
|
void vertex() {
|
|
uint base_number = NUMBER / uint(trail_divisor);
|
|
uint alt_seed = hash(base_number + uint(1) + RANDOM_SEED);
|
|
float angle_rand = rand_from_seed(alt_seed);
|
|
float scale_rand = rand_from_seed(alt_seed);
|
|
float hue_rot_rand = rand_from_seed(alt_seed);
|
|
float anim_offset_rand = rand_from_seed(alt_seed);
|
|
float pi = 3.14159;
|
|
float degree_to_rad = pi / 180.0;
|
|
|
|
bool restart = false;
|
|
float tv = 0.0;
|
|
if (CUSTOM.y > CUSTOM.w) {
|
|
restart = true;
|
|
tv = 1.0;
|
|
}
|
|
|
|
if (RESTART || restart) {
|
|
uint alt_restart_seed = hash(base_number + uint(301184) + RANDOM_SEED);
|
|
float tex_linear_velocity = 0.0;
|
|
float tex_angle = 0.0;
|
|
float tex_anim_offset = 0.0;
|
|
float spread_rad = spread * degree_to_rad;
|
|
{
|
|
float angle1_rad = rand_from_seed_m1_p1(alt_restart_seed) * spread_rad;
|
|
float angle2_rad = rand_from_seed_m1_p1(alt_restart_seed) * spread_rad * (1.0 - flatness);
|
|
vec3 direction_xz = vec3(sin(angle1_rad), 0.0, cos(angle1_rad));
|
|
vec3 direction_yz = vec3(0.0, sin(angle2_rad), cos(angle2_rad));
|
|
direction_yz.z = direction_yz.z / max(0.0001,sqrt(abs(direction_yz.z))); // better uniform distribution
|
|
vec3 spread_direction = vec3(direction_xz.x * direction_yz.z, direction_yz.y, direction_xz.z * direction_yz.z);
|
|
vec3 direction_nrm = length(direction) > 0.0 ? normalize(direction) : vec3(0.0, 0.0, 1.0);
|
|
// rotate spread to direction
|
|
vec3 binormal = cross(vec3(0.0, 1.0, 0.0), direction_nrm);
|
|
if (length(binormal) < 0.0001) {
|
|
// direction is parallel to Y. Choose Z as the binormal.
|
|
binormal = vec3(0.0, 0.0, 1.0);
|
|
}
|
|
binormal = normalize(binormal);
|
|
vec3 normal = cross(binormal, direction_nrm);
|
|
spread_direction = binormal * spread_direction.x + normal * spread_direction.y + direction_nrm * spread_direction.z;
|
|
VELOCITY = spread_direction * initial_linear_velocity * mix(1.0, rand_from_seed(alt_restart_seed), initial_linear_velocity_random);
|
|
}
|
|
float base_angle = (initial_angle + tex_angle) * mix(1.0, angle_rand, initial_angle_random);
|
|
CUSTOM.x = base_angle * degree_to_rad;
|
|
CUSTOM.y = 0.0;
|
|
CUSTOM.w = (1.0 - lifetime_randomness * rand_from_seed(alt_restart_seed));
|
|
CUSTOM.z = (anim_offset + tex_anim_offset) * mix(1.0, anim_offset_rand, anim_offset_random);
|
|
TRANSFORM[3].xyz = vec3(rand_from_seed(alt_restart_seed) * 2.0 - 1.0, rand_from_seed(alt_restart_seed) * 2.0 - 1.0, rand_from_seed(alt_restart_seed) * 2.0 - 1.0) * emission_box_extents;
|
|
VELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY, 0.0)).xyz;
|
|
TRANSFORM = EMISSION_TRANSFORM * TRANSFORM;
|
|
} else {
|
|
CUSTOM.y += DELTA / LIFETIME;
|
|
tv = CUSTOM.y / CUSTOM.w;
|
|
float tex_linear_velocity = 0.0;
|
|
float tex_angular_velocity = 0.0;
|
|
float tex_linear_accel = 0.0;
|
|
float tex_radial_accel = 0.0;
|
|
float tex_tangent_accel = 0.0;
|
|
float tex_damping = 0.0;
|
|
float tex_angle = 0.0;
|
|
float tex_anim_speed = 0.0;
|
|
float tex_anim_offset = 0.0;
|
|
vec3 force = gravity;
|
|
vec3 pos = TRANSFORM[3].xyz;
|
|
// apply linear acceleration
|
|
force += length(VELOCITY) > 0.0 ? normalize(VELOCITY) * (linear_accel + tex_linear_accel) * mix(1.0, rand_from_seed(alt_seed), linear_accel_random) : vec3(0.0);
|
|
// apply radial acceleration
|
|
vec3 org = EMISSION_TRANSFORM[3].xyz;
|
|
vec3 diff = pos - org;
|
|
force += length(diff) > 0.0 ? normalize(diff) * (radial_accel + tex_radial_accel) * mix(1.0, rand_from_seed(alt_seed), radial_accel_random) : vec3(0.0);
|
|
// apply tangential acceleration;
|
|
vec3 crossDiff = cross(normalize(diff), normalize(gravity));
|
|
force += length(crossDiff) > 0.0 ? normalize(crossDiff) * ((tangent_accel + tex_tangent_accel) * mix(1.0, rand_from_seed(alt_seed), tangent_accel_random)) : vec3(0.0);
|
|
// apply attractor forces
|
|
VELOCITY += force * DELTA;
|
|
// orbit velocity
|
|
if (damping + tex_damping > 0.0) {
|
|
float v = length(VELOCITY);
|
|
float damp = (damping + tex_damping) * mix(1.0, rand_from_seed(alt_seed), damping_random);
|
|
v -= damp * DELTA;
|
|
if (v < 0.0) {
|
|
VELOCITY = vec3(0.0);
|
|
}
|
|
else {
|
|
VELOCITY = normalize(VELOCITY) * v;
|
|
}
|
|
}
|
|
float base_angle = (initial_angle + tex_angle) * mix(1.0, angle_rand, initial_angle_random);
|
|
base_angle += CUSTOM.y * LIFETIME * (angular_velocity + tex_angular_velocity) * mix(1.0, rand_from_seed(alt_seed) * 2.0 - 1.0, angular_velocity_random);
|
|
CUSTOM.x = base_angle * degree_to_rad;
|
|
CUSTOM.z = (anim_offset + tex_anim_offset) * mix(1.0, anim_offset_rand, anim_offset_random) + CUSTOM.y * (anim_speed + tex_anim_speed) * mix(1.0, rand_from_seed(alt_seed), anim_speed_random);
|
|
|
|
//// Particle occlusion ////
|
|
vec3 vector = TRANSFORM[3].xyz - EMISSION_TRANSFORM[3].xyz;
|
|
vec3 x_basis = EMISSION_TRANSFORM[0].xyz;
|
|
vec3 y_basis = EMISSION_TRANSFORM[1].xyz;
|
|
vec3 z_basis = EMISSION_TRANSFORM[2].xyz;
|
|
|
|
// Get UV for depth map from particle's relative XZ position
|
|
float x_diff = vector.x * x_basis.x + vector.y * x_basis.y + vector.z * x_basis.z;
|
|
float z_diff = vector.x * z_basis.x + vector.y * z_basis.y + vector.z * z_basis.z;
|
|
vec2 drop_map = 2.0 * vec2(x_diff, z_diff) / depth_cam_size;
|
|
drop_map = 0.5 * (drop_map + vec2(1.0));
|
|
|
|
// Get nearest surface depth, as well as relative Y position and velocity
|
|
float surface = texture(depth_map, drop_map).x;
|
|
float y_pos = vector.x * y_basis.x + vector.y * y_basis.y + vector.z * y_basis.z;
|
|
float y_velocity = VELOCITY.x * y_basis.x + VELOCITY.y * y_basis.y + VELOCITY.z * y_basis.z;
|
|
|
|
if (y_pos - occlusion_margin + y_velocity * DELTA < surface) {
|
|
//*// insert "collision" logic here //*//
|
|
VELOCITY = 0.9 * reflect(VELOCITY, example_normal); // bounce
|
|
//ACTIVE = false; // or cull particle on contact
|
|
}
|
|
////////
|
|
}
|
|
float tex_scale = 1.0;
|
|
float tex_hue_variation = 0.0;
|
|
float hue_rot_angle = (hue_variation + tex_hue_variation) * pi * 2.0 * mix(1.0, hue_rot_rand * 2.0 - 1.0, hue_variation_random);
|
|
float hue_rot_c = cos(hue_rot_angle);
|
|
float hue_rot_s = sin(hue_rot_angle);
|
|
mat4 hue_rot_mat = mat4(vec4(0.299, 0.587, 0.114, 0.0),
|
|
vec4(0.299, 0.587, 0.114, 0.0),
|
|
vec4(0.299, 0.587, 0.114, 0.0),
|
|
vec4(0.000, 0.000, 0.000, 1.0)) +
|
|
mat4(vec4(0.701, -0.587, -0.114, 0.0),
|
|
vec4(-0.299, 0.413, -0.114, 0.0),
|
|
vec4(-0.300, -0.588, 0.886, 0.0),
|
|
vec4(0.000, 0.000, 0.000, 0.0)) * hue_rot_c +
|
|
mat4(vec4(0.168, 0.330, -0.497, 0.0),
|
|
vec4(-0.328, 0.035, 0.292, 0.0),
|
|
vec4(1.250, -1.050, -0.203, 0.0),
|
|
vec4(0.000, 0.000, 0.000, 0.0)) * hue_rot_s;
|
|
COLOR = hue_rot_mat * color_value;
|
|
|
|
TRANSFORM[0].xyz = normalize(TRANSFORM[0].xyz);
|
|
TRANSFORM[1].xyz = normalize(TRANSFORM[1].xyz);
|
|
TRANSFORM[2].xyz = normalize(TRANSFORM[2].xyz);
|
|
float base_scale = tex_scale * mix(scale, 1.0, scale_random * scale_rand);
|
|
if (base_scale < 0.000001) {
|
|
base_scale = 0.000001;
|
|
}
|
|
TRANSFORM[0].xyz *= base_scale;
|
|
TRANSFORM[1].xyz *= base_scale;
|
|
TRANSFORM[2].xyz *= base_scale;
|
|
if (CUSTOM.y > CUSTOM.w) {
|
|
ACTIVE = false;
|
|
}
|
|
}
|
|
|