overte-thingvellir/interface/resources/shaders/proceduralParticleSwarmUpdate.frag
2024-04-17 15:43:20 -07:00

73 lines
2.9 KiB
GLSL

uniform float lifespan = 1.0; // seconds
uniform float speed = 0.1; // m/s
uniform float speedSpread = 0.25;
uniform float mass = 1.0;
const float G = 6.67e-11;
// prop0: xyz: position, w: age
// prop1: xyz: velocity, w: prevUpdateTime
// prop2: xyz: prevVelocity
vec3 initPosition(const int particleID) {
return 0.5 * (vec3(hifi_hash(particleID + iGlobalTime),
hifi_hash(particleID + iGlobalTime + 1.0),
hifi_hash(particleID + iGlobalTime + 2.0)) - 0.5);
}
mat3 rotationMatrix(vec3 axis, float angle) {
float s = sin(angle);
float c = cos(angle);
float oc = 1.0 - c;
return mat3(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s,
oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s,
oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c);
}
vec3 initVelocity(const int particleID, const vec3 position) {
const float particleSpeed = speed * ((1.0 - speedSpread) + speedSpread * hifi_hash(particleID + iGlobalTime + 3.0));
vec3 r = normalize(iWorldPosition - position);
float angle = 2.0 * 3.14159 * hifi_hash(particleID + iGlobalTime + 4.0);
return particleSpeed * rotationMatrix(r, angle) * cross(r, vec3(0, 1, 0));
}
void updateParticleProps(const int particleID, inout ParticleUpdateProps particleProps) {
// First draw
if (particleProps.prop1.w < 0.00001) {
particleProps.prop0.xyz = iWorldOrientation * (initPosition(particleID) * iWorldScale) + iWorldPosition;
particleProps.prop0.w = -lifespan * hifi_hash(particleID + iGlobalTime + 3.0);
particleProps.prop1.xyz = initVelocity(particleID, particleProps.prop0.xyz);
particleProps.prop1.w = iGlobalTime;
particleProps.prop2.xyz = particleProps.prop1.xyz;
return;
}
// Particle expired
if (particleProps.prop0.w >= lifespan) {
particleProps.prop0.xyz = iWorldOrientation * (initPosition(particleID) * iWorldScale) + iWorldPosition;
particleProps.prop0.w = 0.0;
particleProps.prop1.xyz = initVelocity(particleID, particleProps.prop0.xyz);
particleProps.prop1.w = iGlobalTime;
particleProps.prop2.xyz = particleProps.prop1.xyz;
return;
}
float dt = 0.01666666666;//max(0.0, iGlobalTime - particleProps.prop1.w);
particleProps.prop2.xyz = particleProps.prop1.xyz;
if (particleProps.prop0.w >= 0.0) {
// gravitational acceleration
vec3 r = iWorldPosition - particleProps.prop0.xyz;
vec3 g = (G * mass / max(0.01, dot(r, r))) * r;
// position
particleProps.prop0.xyz += particleProps.prop1.xyz * dt + (0.5 * dt * dt) * g;
// velocity
particleProps.prop1.xyz += g * dt;
}
// age
particleProps.prop0.w += dt;
// prevUpdateTime
particleProps.prop1.w = iGlobalTime;
}