godot/drivers/gles3/shaders/particles.glsl

261 lines
4.9 KiB
GLSL

[vertex]
layout(location=0) in highp vec4 color;
layout(location=1) in highp vec4 velocity_active;
layout(location=2) in highp vec4 custom;
layout(location=3) in highp vec4 xform_1;
layout(location=4) in highp vec4 xform_2;
layout(location=5) in highp vec4 xform_3;
struct Attractor {
vec3 pos;
vec3 dir;
float radius;
float eat_radius;
float strength;
float attenuation;
};
#define MAX_ATTRACTORS 64
uniform bool emitting;
uniform float system_phase;
uniform float prev_system_phase;
uniform int total_particles;
uniform float explosiveness;
uniform float randomness;
uniform float time;
uniform float delta;
uniform int attractor_count;
uniform Attractor attractors[MAX_ATTRACTORS];
uniform bool clear;
uniform uint cycle;
uniform float lifetime;
uniform mat4 emission_transform;
uniform uint random_seed;
out highp vec4 out_color; //tfb:
out highp vec4 out_velocity_active; //tfb:
out highp vec4 out_custom; //tfb:
out highp vec4 out_xform_1; //tfb:
out highp vec4 out_xform_2; //tfb:
out highp vec4 out_xform_3; //tfb:
#if defined(USE_MATERIAL)
layout(std140) uniform UniformData { //ubo:0
MATERIAL_UNIFORMS
};
#endif
VERTEX_SHADER_GLOBALS
uint hash(uint x) {
x = ((x >> uint(16)) ^ x) * uint(0x45d9f3b);
x = ((x >> uint(16)) ^ x) * uint(0x45d9f3b);
x = (x >> uint(16)) ^ x;
return x;
}
void main() {
#ifdef PARTICLES_COPY
out_color=color;
out_velocity_active=velocity_active;
out_custom = custom;
out_xform_1 = xform_1;
out_xform_2 = xform_2;
out_xform_3 = xform_3;
#else
bool apply_forces=true;
bool apply_velocity=true;
float local_delta=delta;
float mass = 1.0;
float restart_phase = float(gl_VertexID)/float(total_particles);
if (randomness>0.0) {
uint seed = cycle;
if (restart_phase >= system_phase) {
seed-=uint(1);
}
seed*=uint(total_particles);
seed+=uint(gl_VertexID);
float random = float(hash(seed) % uint(65536)) / 65536.0;
restart_phase+=randomness * random * 1.0 / float(total_particles);
}
restart_phase*= (1.0-explosiveness);
bool restart=false;
bool shader_active = velocity_active.a > 0.5;
if (system_phase > prev_system_phase) {
// restart_phase >= prev_system_phase is used so particles emit in the first frame they are processed
if (restart_phase >= prev_system_phase && restart_phase < system_phase ) {
restart=true;
#ifdef USE_FRACTIONAL_DELTA
local_delta = (system_phase - restart_phase) * lifetime;
#endif
}
} else {
if (restart_phase >= prev_system_phase) {
restart=true;
#ifdef USE_FRACTIONAL_DELTA
local_delta = (1.0 - restart_phase + system_phase) * lifetime;
#endif
} else if (restart_phase < system_phase ) {
restart=true;
#ifdef USE_FRACTIONAL_DELTA
local_delta = (system_phase - restart_phase) * lifetime;
#endif
}
}
uint current_cycle = cycle;
if (system_phase < restart_phase) {
current_cycle-=uint(1);
}
uint particle_number = current_cycle * uint(total_particles) + uint(gl_VertexID);
int index = int(gl_VertexID);
if (restart) {
shader_active=emitting;
}
mat4 xform;
#if defined(ENABLE_KEEP_DATA)
if (clear) {
#else
if (clear || restart) {
#endif
out_color=vec4(1.0);
out_velocity_active=vec4(0.0);
out_custom=vec4(0.0);
if (!restart)
shader_active=false;
xform = mat4(
vec4(1.0,0.0,0.0,0.0),
vec4(0.0,1.0,0.0,0.0),
vec4(0.0,0.0,1.0,0.0),
vec4(0.0,0.0,0.0,1.0)
);
} else {
out_color=color;
out_velocity_active=velocity_active;
out_custom=custom;
xform = transpose(mat4(xform_1,xform_2,xform_3,vec4(vec3(0.0),1.0)));
}
if (shader_active) {
//execute shader
{
VERTEX_SHADER_CODE
}
#if !defined(DISABLE_FORCE)
if (true) {
vec3 force = vec3(0.0);
for(int i=0;i<attractor_count;i++) {
vec3 rel_vec = xform[3].xyz - attractors[i].pos;
float dist = length(rel_vec);
if (attractors[i].radius < dist)
continue;
if (attractors[i].eat_radius>0 && attractors[i].eat_radius > dist) {
out_velocity_active.a=0.0;
}
rel_vec = normalize(rel_vec);
float attenuation = pow(dist / attractors[i].radius,attractors[i].attenuation);
if (attractors[i].dir==vec3(0.0)) {
//towards center
force+=attractors[i].strength * rel_vec * attenuation * mass;
} else {
force+=attractors[i].strength * attractors[i].dir * attenuation *mass;
}
}
out_velocity_active.xyz += force * local_delta;
}
#endif
#if !defined(DISABLE_VELOCITY)
if (true) {
xform[3].xyz += out_velocity_active.xyz * local_delta;
}
#endif
} else {
xform=mat4(0.0);
}
xform = transpose(xform);
out_velocity_active.a = mix(0.0,1.0,shader_active);
out_xform_1 = xform[0];
out_xform_2 = xform[1];
out_xform_3 = xform[2];
#endif //PARTICLES_COPY
}
[fragment]
//any code here is never executed, stuff is filled just so it works
#if defined(USE_MATERIAL)
layout(std140) uniform UniformData {
MATERIAL_UNIFORMS
};
#endif
FRAGMENT_SHADER_GLOBALS
void main() {
{
LIGHT_SHADER_CODE
}
{
FRAGMENT_SHADER_CODE
}
}