123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679 |
- #[compute]
- #version 450
- #VERSION_DEFINES
- layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
- #define SDF_MAX_LENGTH 16384.0
- /* SET 0: GLOBAL DATA */
- #include "samplers_inc.glsl"
- layout(set = 0, binding = 2, std430) restrict readonly buffer GlobalShaderUniformData {
- vec4 data[];
- }
- global_shader_uniforms;
- /* Set 1: FRAME AND PARTICLE DATA */
- // a frame history is kept for trail deterministic behavior
- #define MAX_ATTRACTORS 32
- #define ATTRACTOR_TYPE_SPHERE 0
- #define ATTRACTOR_TYPE_BOX 1
- #define ATTRACTOR_TYPE_VECTOR_FIELD 2
- struct Attractor {
- mat4 transform;
- vec3 extents; //exents or radius
- uint type;
- uint texture_index; //texture index for vector field
- float strength;
- float attenuation;
- float directionality;
- };
- #define MAX_COLLIDERS 32
- #define COLLIDER_TYPE_SPHERE 0
- #define COLLIDER_TYPE_BOX 1
- #define COLLIDER_TYPE_SDF 2
- #define COLLIDER_TYPE_HEIGHT_FIELD 3
- #define COLLIDER_TYPE_2D_SDF 4
- struct Collider {
- mat4 transform;
- vec3 extents; //exents or radius
- uint type;
- uint texture_index; //texture index for vector field
- float scale;
- uint pad[2];
- };
- struct FrameParams {
- bool emitting;
- float system_phase;
- float prev_system_phase;
- uint cycle;
- float explosiveness;
- float randomness;
- float time;
- float delta;
- uint frame;
- float amount_ratio;
- uint pad1;
- uint pad2;
- uint random_seed;
- uint attractor_count;
- uint collider_count;
- float particle_size;
- mat4 emission_transform;
- vec3 emitter_velocity;
- float interp_to_end;
- Attractor attractors[MAX_ATTRACTORS];
- Collider colliders[MAX_COLLIDERS];
- };
- layout(set = 1, binding = 0, std430) restrict buffer FrameHistory {
- FrameParams data[];
- }
- frame_history;
- #define PARTICLE_FLAG_ACTIVE uint(1)
- #define PARTICLE_FLAG_STARTED uint(2)
- #define PARTICLE_FLAG_TRAILED uint(4)
- #define PARTICLE_FRAME_MASK uint(0xFFFF)
- #define PARTICLE_FRAME_SHIFT uint(16)
- struct ParticleData {
- mat4 xform;
- vec3 velocity;
- uint flags;
- vec4 color;
- vec4 custom;
- #ifdef USERDATA1_USED
- vec4 userdata1;
- #endif
- #ifdef USERDATA2_USED
- vec4 userdata2;
- #endif
- #ifdef USERDATA3_USED
- vec4 userdata3;
- #endif
- #ifdef USERDATA4_USED
- vec4 userdata4;
- #endif
- #ifdef USERDATA5_USED
- vec4 userdata5;
- #endif
- #ifdef USERDATA6_USED
- vec4 userdata6;
- #endif
- };
- layout(set = 1, binding = 1, std430) restrict buffer Particles {
- ParticleData data[];
- }
- particles;
- #define EMISSION_FLAG_HAS_POSITION 1
- #define EMISSION_FLAG_HAS_ROTATION_SCALE 2
- #define EMISSION_FLAG_HAS_VELOCITY 4
- #define EMISSION_FLAG_HAS_COLOR 8
- #define EMISSION_FLAG_HAS_CUSTOM 16
- struct ParticleEmission {
- mat4 xform;
- vec3 velocity;
- uint flags;
- vec4 color;
- vec4 custom;
- };
- layout(set = 1, binding = 2, std430) restrict buffer SourceEmission {
- int particle_count;
- uint pad0;
- uint pad1;
- uint pad2;
- ParticleEmission data[];
- }
- src_particles;
- layout(set = 1, binding = 3, std430) restrict buffer DestEmission {
- int particle_count;
- int particle_max;
- uint pad1;
- uint pad2;
- ParticleEmission data[];
- }
- dst_particles;
- /* SET 2: COLLIDER/ATTRACTOR TEXTURES */
- #define MAX_3D_TEXTURES 7
- layout(set = 2, binding = 0) uniform texture3D sdf_vec_textures[MAX_3D_TEXTURES];
- layout(set = 2, binding = 1) uniform texture2D height_field_texture;
- /* SET 3: MATERIAL */
- #ifdef MATERIAL_UNIFORMS_USED
- layout(set = 3, binding = 0, std140) uniform MaterialUniforms{
- #MATERIAL_UNIFORMS
- } material;
- #endif
- layout(push_constant, std430) uniform Params {
- float lifetime;
- bool clear;
- uint total_particles;
- uint trail_size;
- bool use_fractional_delta;
- bool sub_emitter_mode;
- bool can_emit;
- bool trail_pass;
- }
- params;
- 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;
- }
- bool emit_subparticle(mat4 p_xform, vec3 p_velocity, vec4 p_color, vec4 p_custom, uint p_flags) {
- if (!params.can_emit) {
- return false;
- }
- bool valid = false;
- int dst_index = atomicAdd(dst_particles.particle_count, 1);
- if (dst_index >= dst_particles.particle_max) {
- atomicAdd(dst_particles.particle_count, -1);
- return false;
- }
- dst_particles.data[dst_index].xform = p_xform;
- dst_particles.data[dst_index].velocity = p_velocity;
- dst_particles.data[dst_index].color = p_color;
- dst_particles.data[dst_index].custom = p_custom;
- dst_particles.data[dst_index].flags = p_flags;
- return true;
- }
- vec3 safe_normalize(vec3 direction) {
- const float EPSILON = 0.001;
- if (length(direction) < EPSILON) {
- return vec3(0.0);
- }
- return normalize(direction);
- }
- #GLOBALS
- void main() {
- uint particle = gl_GlobalInvocationID.x;
- if (params.trail_size > 1) {
- if (params.trail_pass) {
- if (particle >= params.total_particles * (params.trail_size - 1)) {
- return;
- }
- particle += (particle / (params.trail_size - 1)) + 1;
- } else {
- if (particle >= params.total_particles) {
- return;
- }
- particle *= params.trail_size;
- }
- }
- if (particle >= params.total_particles * params.trail_size) {
- return; //discard
- }
- uint index = particle / params.trail_size;
- uint frame = (particle % params.trail_size);
- #define FRAME frame_history.data[frame]
- #define PARTICLE particles.data[particle]
- bool apply_forces = true;
- bool apply_velocity = true;
- float local_delta = FRAME.delta;
- float mass = 1.0;
- bool restart = false;
- bool restart_position = false;
- bool restart_rotation_scale = false;
- bool restart_velocity = false;
- bool restart_color = false;
- bool restart_custom = false;
- if (params.clear) {
- PARTICLE.color = vec4(1.0);
- PARTICLE.custom = vec4(0.0);
- PARTICLE.velocity = vec3(0.0);
- PARTICLE.flags = 0;
- PARTICLE.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));
- }
- //clear started flag if set
- if (params.trail_pass) {
- //trail started
- uint src_idx = index * params.trail_size;
- if (bool(particles.data[src_idx].flags & PARTICLE_FLAG_STARTED)) {
- //save start conditions for trails
- PARTICLE.color = particles.data[src_idx].color;
- PARTICLE.custom = particles.data[src_idx].custom;
- PARTICLE.velocity = particles.data[src_idx].velocity;
- PARTICLE.flags = PARTICLE_FLAG_TRAILED | ((frame_history.data[0].frame & PARTICLE_FRAME_MASK) << PARTICLE_FRAME_SHIFT); //mark it as trailed, save in which frame it will start
- PARTICLE.xform = particles.data[src_idx].xform;
- #ifdef USERDATA1_USED
- PARTICLE.userdata1 = particles.data[src_idx].userdata1;
- #endif
- #ifdef USERDATA2_USED
- PARTICLE.userdata2 = particles.data[src_idx].userdata2;
- #endif
- #ifdef USERDATA3_USED
- PARTICLE.userdata3 = particles.data[src_idx].userdata3;
- #endif
- #ifdef USERDATA4_USED
- PARTICLE.userdata4 = particles.data[src_idx].userdata4;
- #endif
- #ifdef USERDATA5_USED
- PARTICLE.userdata5 = particles.data[src_idx].userdata5;
- #endif
- #ifdef USERDATA6_USED
- PARTICLE.userdata6 = particles.data[src_idx].userdata6;
- #endif
- }
- if (!bool(particles.data[src_idx].flags & PARTICLE_FLAG_ACTIVE)) {
- // Disable the entire trail if the parent is no longer active.
- PARTICLE.flags = 0;
- return;
- }
- if (bool(PARTICLE.flags & PARTICLE_FLAG_TRAILED) && ((PARTICLE.flags >> PARTICLE_FRAME_SHIFT) == (FRAME.frame & PARTICLE_FRAME_MASK))) { //check this is trailed and see if it should start now
- // we just assume that this is the first frame of the particle, the rest is deterministic
- PARTICLE.flags = PARTICLE_FLAG_ACTIVE | (particles.data[src_idx].flags & (PARTICLE_FRAME_MASK << PARTICLE_FRAME_SHIFT));
- return; //- this appears like it should be correct, but it seems not to be.. wonder why.
- }
- } else {
- PARTICLE.flags &= ~PARTICLE_FLAG_STARTED;
- }
- bool collided = false;
- vec3 collision_normal = vec3(0.0);
- float collision_depth = 0.0;
- vec3 attractor_force = vec3(0.0);
- #if !defined(DISABLE_VELOCITY)
- if (bool(PARTICLE.flags & PARTICLE_FLAG_ACTIVE)) {
- PARTICLE.xform[3].xyz += PARTICLE.velocity * local_delta;
- }
- #endif
- if (!params.trail_pass && params.sub_emitter_mode) {
- if (!bool(PARTICLE.flags & PARTICLE_FLAG_ACTIVE)) {
- int src_index = atomicAdd(src_particles.particle_count, -1) - 1;
- if (src_index >= 0) {
- PARTICLE.flags = (PARTICLE_FLAG_ACTIVE | PARTICLE_FLAG_STARTED | (FRAME.cycle << PARTICLE_FRAME_SHIFT));
- restart = true;
- if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_POSITION)) {
- PARTICLE.xform[3] = src_particles.data[src_index].xform[3];
- } else {
- PARTICLE.xform[3] = vec4(0, 0, 0, 1);
- restart_position = true;
- }
- if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_ROTATION_SCALE)) {
- PARTICLE.xform[0] = src_particles.data[src_index].xform[0];
- PARTICLE.xform[1] = src_particles.data[src_index].xform[1];
- PARTICLE.xform[2] = src_particles.data[src_index].xform[2];
- } else {
- PARTICLE.xform[0] = vec4(1, 0, 0, 0);
- PARTICLE.xform[1] = vec4(0, 1, 0, 0);
- PARTICLE.xform[2] = vec4(0, 0, 1, 0);
- restart_rotation_scale = true;
- }
- if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_VELOCITY)) {
- PARTICLE.velocity = src_particles.data[src_index].velocity;
- } else {
- PARTICLE.velocity = vec3(0);
- restart_velocity = true;
- }
- if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_COLOR)) {
- PARTICLE.color = src_particles.data[src_index].color;
- } else {
- PARTICLE.color = vec4(1);
- restart_color = true;
- }
- if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_CUSTOM)) {
- PARTICLE.custom = src_particles.data[src_index].custom;
- } else {
- PARTICLE.custom = vec4(0);
- restart_custom = true;
- }
- }
- }
- } else if (FRAME.emitting) {
- float restart_phase = float(index) / float(params.total_particles);
- if (FRAME.randomness > 0.0) {
- uint seed = FRAME.cycle;
- if (restart_phase >= FRAME.system_phase) {
- seed -= uint(1);
- }
- seed *= uint(params.total_particles);
- seed += uint(index);
- float random = float(hash(seed) % uint(65536)) / 65536.0;
- restart_phase += FRAME.randomness * random * 1.0 / float(params.total_particles);
- }
- restart_phase *= (1.0 - FRAME.explosiveness);
- if (FRAME.system_phase > FRAME.prev_system_phase) {
- // restart_phase >= prev_system_phase is used so particles emit in the first frame they are processed
- if (restart_phase >= FRAME.prev_system_phase && restart_phase < FRAME.system_phase) {
- restart = true;
- if (params.use_fractional_delta) {
- local_delta = (FRAME.system_phase - restart_phase) * params.lifetime;
- }
- }
- } else if (FRAME.delta > 0.0) {
- if (restart_phase >= FRAME.prev_system_phase) {
- restart = true;
- if (params.use_fractional_delta) {
- local_delta = (1.0 - restart_phase + FRAME.system_phase) * params.lifetime;
- }
- } else if (restart_phase < FRAME.system_phase) {
- restart = true;
- if (params.use_fractional_delta) {
- local_delta = (FRAME.system_phase - restart_phase) * params.lifetime;
- }
- }
- }
- if (params.trail_pass) {
- restart = false;
- }
- if (restart) {
- PARTICLE.flags = FRAME.emitting ? (PARTICLE_FLAG_ACTIVE | PARTICLE_FLAG_STARTED | (FRAME.cycle << PARTICLE_FRAME_SHIFT)) : 0;
- restart_position = true;
- restart_rotation_scale = true;
- restart_velocity = true;
- restart_color = true;
- restart_custom = true;
- }
- }
- bool particle_active = bool(PARTICLE.flags & PARTICLE_FLAG_ACTIVE);
- uint particle_number = (PARTICLE.flags >> PARTICLE_FRAME_SHIFT) * uint(params.total_particles) + index;
- if (restart && particle_active) {
- #CODE : START
- }
- if (particle_active) {
- for (uint i = 0; i < FRAME.attractor_count; i++) {
- vec3 dir;
- float amount;
- vec3 rel_vec = PARTICLE.xform[3].xyz - FRAME.attractors[i].transform[3].xyz;
- vec3 local_pos = rel_vec * mat3(FRAME.attractors[i].transform);
- switch (FRAME.attractors[i].type) {
- case ATTRACTOR_TYPE_SPHERE: {
- dir = safe_normalize(rel_vec);
- float d = length(local_pos) / FRAME.attractors[i].extents.x;
- if (d > 1.0) {
- continue;
- }
- amount = max(0.0, 1.0 - d);
- } break;
- case ATTRACTOR_TYPE_BOX: {
- dir = safe_normalize(rel_vec);
- vec3 abs_pos = abs(local_pos / FRAME.attractors[i].extents);
- float d = max(abs_pos.x, max(abs_pos.y, abs_pos.z));
- if (d > 1.0) {
- continue;
- }
- amount = max(0.0, 1.0 - d);
- } break;
- case ATTRACTOR_TYPE_VECTOR_FIELD: {
- vec3 uvw_pos = (local_pos / FRAME.attractors[i].extents + 1.0) * 0.5;
- if (any(lessThan(uvw_pos, vec3(0.0))) || any(greaterThan(uvw_pos, vec3(1.0)))) {
- continue;
- }
- vec3 s = texture(sampler3D(sdf_vec_textures[FRAME.attractors[i].texture_index], SAMPLER_LINEAR_CLAMP), uvw_pos).xyz * -2.0 + 1.0;
- dir = mat3(FRAME.attractors[i].transform) * safe_normalize(s); //revert direction
- amount = length(s);
- } break;
- }
- amount = pow(amount, FRAME.attractors[i].attenuation);
- dir = safe_normalize(mix(dir, FRAME.attractors[i].transform[2].xyz, FRAME.attractors[i].directionality));
- attractor_force -= amount * dir * FRAME.attractors[i].strength;
- }
- float particle_size = FRAME.particle_size;
- #ifdef USE_COLLISION_SCALE
- particle_size *= dot(vec3(length(PARTICLE.xform[0].xyz), length(PARTICLE.xform[1].xyz), length(PARTICLE.xform[2].xyz)), vec3(0.33333333333));
- #endif
- if (FRAME.collider_count == 1 && FRAME.colliders[0].type == COLLIDER_TYPE_2D_SDF) {
- //2D collision
- vec2 pos = PARTICLE.xform[3].xy;
- vec4 to_sdf_x = FRAME.colliders[0].transform[0];
- vec4 to_sdf_y = FRAME.colliders[0].transform[1];
- vec2 sdf_pos = vec2(dot(vec4(pos, 0, 1), to_sdf_x), dot(vec4(pos, 0, 1), to_sdf_y));
- vec4 sdf_to_screen = vec4(FRAME.colliders[0].extents, FRAME.colliders[0].scale);
- vec2 uv_pos = sdf_pos * sdf_to_screen.xy + sdf_to_screen.zw;
- if (all(greaterThan(uv_pos, vec2(0.0))) && all(lessThan(uv_pos, vec2(1.0)))) {
- vec2 pos2 = pos + vec2(0, particle_size);
- vec2 sdf_pos2 = vec2(dot(vec4(pos2, 0, 1), to_sdf_x), dot(vec4(pos2, 0, 1), to_sdf_y));
- float sdf_particle_size = distance(sdf_pos, sdf_pos2);
- float d = texture(sampler2D(height_field_texture, SAMPLER_LINEAR_CLAMP), uv_pos).r * SDF_MAX_LENGTH;
- d -= sdf_particle_size;
- if (d < 0.0) {
- const float EPSILON = 0.001;
- vec2 n = normalize(vec2(
- texture(sampler2D(height_field_texture, SAMPLER_LINEAR_CLAMP), uv_pos + vec2(EPSILON, 0.0)).r - texture(sampler2D(height_field_texture, SAMPLER_LINEAR_CLAMP), uv_pos - vec2(EPSILON, 0.0)).r,
- texture(sampler2D(height_field_texture, SAMPLER_LINEAR_CLAMP), uv_pos + vec2(0.0, EPSILON)).r - texture(sampler2D(height_field_texture, SAMPLER_LINEAR_CLAMP), uv_pos - vec2(0.0, EPSILON)).r));
- collided = true;
- sdf_pos2 = sdf_pos + n * d;
- pos2 = vec2(dot(vec4(sdf_pos2, 0, 1), FRAME.colliders[0].transform[2]), dot(vec4(sdf_pos2, 0, 1), FRAME.colliders[0].transform[3]));
- n = pos - pos2;
- collision_normal = normalize(vec3(n, 0.0));
- collision_depth = length(n);
- }
- }
- } else {
- for (uint i = 0; i < FRAME.collider_count; i++) {
- vec3 normal;
- float depth;
- bool col = false;
- vec3 rel_vec = PARTICLE.xform[3].xyz - FRAME.colliders[i].transform[3].xyz;
- vec3 local_pos = rel_vec * mat3(FRAME.colliders[i].transform);
- // Allowing for a small epsilon to allow particle just touching colliders to count as collided
- const float EPSILON = 0.001;
- switch (FRAME.colliders[i].type) {
- case COLLIDER_TYPE_SPHERE: {
- float d = length(rel_vec) - (particle_size + FRAME.colliders[i].extents.x);
- if (d <= EPSILON) {
- col = true;
- depth = -d;
- normal = normalize(rel_vec);
- }
- } break;
- case COLLIDER_TYPE_BOX: {
- vec3 abs_pos = abs(local_pos);
- vec3 sgn_pos = sign(local_pos);
- if (any(greaterThan(abs_pos, FRAME.colliders[i].extents))) {
- //point outside box
- vec3 closest = min(abs_pos, FRAME.colliders[i].extents);
- vec3 rel = abs_pos - closest;
- depth = length(rel) - particle_size;
- if (depth <= EPSILON) {
- col = true;
- normal = mat3(FRAME.colliders[i].transform) * (normalize(rel) * sgn_pos);
- depth = -depth;
- }
- } else {
- //point inside box
- vec3 axis_len = FRAME.colliders[i].extents - abs_pos;
- // there has to be a faster way to do this?
- if (all(lessThan(axis_len.xx, axis_len.yz))) {
- normal = vec3(1, 0, 0);
- } else if (all(lessThan(axis_len.yy, axis_len.xz))) {
- normal = vec3(0, 1, 0);
- } else {
- normal = vec3(0, 0, 1);
- }
- col = true;
- depth = dot(normal * axis_len, vec3(1)) + particle_size;
- normal = mat3(FRAME.colliders[i].transform) * (normal * sgn_pos);
- }
- } break;
- case COLLIDER_TYPE_SDF: {
- vec3 apos = abs(local_pos);
- float extra_dist = 0.0;
- if (any(greaterThan(apos, FRAME.colliders[i].extents))) { //outside
- vec3 mpos = min(apos, FRAME.colliders[i].extents);
- extra_dist = distance(mpos, apos);
- }
- if (extra_dist > particle_size) {
- continue;
- }
- vec3 uvw_pos = (local_pos / FRAME.colliders[i].extents) * 0.5 + 0.5;
- float s = texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], SAMPLER_LINEAR_CLAMP), uvw_pos).r;
- s *= FRAME.colliders[i].scale;
- s += extra_dist;
- if (s <= particle_size + EPSILON) {
- col = true;
- depth = particle_size - s;
- normal = mat3(FRAME.colliders[i].transform) *
- normalize(
- vec3(
- texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], SAMPLER_LINEAR_CLAMP), uvw_pos + vec3(EPSILON, 0.0, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], SAMPLER_LINEAR_CLAMP), uvw_pos - vec3(EPSILON, 0.0, 0.0)).r,
- texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], SAMPLER_LINEAR_CLAMP), uvw_pos + vec3(0.0, EPSILON, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], SAMPLER_LINEAR_CLAMP), uvw_pos - vec3(0.0, EPSILON, 0.0)).r,
- texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], SAMPLER_LINEAR_CLAMP), uvw_pos + vec3(0.0, 0.0, EPSILON)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], SAMPLER_LINEAR_CLAMP), uvw_pos - vec3(0.0, 0.0, EPSILON)).r));
- }
- } break;
- case COLLIDER_TYPE_HEIGHT_FIELD: {
- vec3 local_pos_bottom = local_pos;
- local_pos_bottom.y -= particle_size;
- if (any(greaterThan(abs(local_pos_bottom), FRAME.colliders[i].extents))) {
- continue;
- }
- const float DELTA = 1.0 / 8192.0;
- vec3 uvw_pos = vec3(local_pos_bottom / FRAME.colliders[i].extents) * 0.5 + 0.5;
- float y = texture(sampler2D(height_field_texture, SAMPLER_LINEAR_CLAMP), uvw_pos.xz).r;
- if (y + EPSILON >= uvw_pos.y) {
- //inside heightfield
- vec3 pos1 = (vec3(uvw_pos.x, y, uvw_pos.z) * 2.0 - 1.0) * FRAME.colliders[i].extents;
- vec3 pos2 = (vec3(uvw_pos.x + DELTA, texture(sampler2D(height_field_texture, SAMPLER_LINEAR_CLAMP), uvw_pos.xz + vec2(DELTA, 0)).r, uvw_pos.z) * 2.0 - 1.0) * FRAME.colliders[i].extents;
- vec3 pos3 = (vec3(uvw_pos.x, texture(sampler2D(height_field_texture, SAMPLER_LINEAR_CLAMP), uvw_pos.xz + vec2(0, DELTA)).r, uvw_pos.z + DELTA) * 2.0 - 1.0) * FRAME.colliders[i].extents;
- normal = normalize(cross(pos1 - pos2, pos1 - pos3));
- float local_y = (vec3(local_pos / FRAME.colliders[i].extents) * 0.5 + 0.5).y;
- col = true;
- depth = dot(normal, pos1) - dot(normal, local_pos_bottom);
- }
- } break;
- }
- if (col) {
- if (!collided) {
- collided = true;
- collision_normal = normal;
- collision_depth = depth;
- } else {
- vec3 c = collision_normal * collision_depth;
- c += normal * max(0.0, depth - dot(normal, c));
- collision_normal = normalize(c);
- collision_depth = length(c);
- }
- }
- }
- }
- }
- if (particle_active) {
- #CODE : PROCESS
- }
- PARTICLE.flags &= ~PARTICLE_FLAG_ACTIVE;
- if (particle_active) {
- PARTICLE.flags |= PARTICLE_FLAG_ACTIVE;
- }
- }
|