playcanvas
Version:
PlayCanvas WebGL game engine
84 lines (82 loc) • 3.65 kB
JavaScript
var particleUpdaterStartPS = `
fn saturate(x: f32) -> f32 {
return clamp(x, 0.0, 1.0);
}
fn unpack3NFloats(src: f32) -> vec3f {
let r = fract(src);
let g = fract(src * 256.0);
let b = fract(src * 65536.0);
return vec3f(r, g, b);
}
struct TexLerpUnpackResult {
result: vec3f,
unpacked: vec3f
}
fn tex1Dlod_lerp(tex: texture_2d<f32>, texSampler: sampler, tc: vec2f) -> TexLerpUnpackResult {
let tc_next = tc + vec2f(uniform.graphSampleSize);
let a = textureSampleLevel(tex, texSampler, tc, 0.0);
let b = textureSampleLevel(tex, texSampler, tc_next, 0.0);
let c = fract(tc.x * uniform.graphNumSamples);
let unpackedA = unpack3NFloats(a.w);
let unpackedB = unpack3NFloats(b.w);
let w_out = mix(unpackedA, unpackedB, c);
return TexLerpUnpackResult(mix(a.xyz, b.xyz, c), w_out);
}
const HASHSCALE4: vec4f = vec4f(1031.0, 0.1030, 0.0973, 0.1099);
fn hash41(p: f32) -> vec4f {
var p4 = fract(vec4f(p) * HASHSCALE4);
p4 = p4 + dot(p4, p4.wzxy + 19.19);
return fract(vec4f((p4.x + p4.y)*p4.z, (p4.x + p4.z)*p4.y, (p4.y + p4.z)*p4.w, (p4.z + p4.w)*p4.x));
}
@fragment
fn fragmentMain(input : FragmentInput) -> FragmentOutput {
var output: FragmentOutput;
if (pcPosition.x > uniform.numParticles) {
discard;
return output;
}
readInput(input.vUv0.x);
visMode = select(-1.0, 1.0, inShow);
let rndFactor = hash41(pcPosition.x + uniform.seed);
let particleRate = uniform.rate + uniform.rateDiv * rndFactor.x;
outLife = inLife + uniform.delta;
let nlife = clamp(outLife / uniform.lifetime, 0.0, 1.0);
let lerpResult0 = tex1Dlod_lerp(internalTex0, internalTex0Sampler, vec2f(nlife, 0.0));
var localVelocity = lerpResult0.result;
let localVelocityDiv = lerpResult0.unpacked;
let lerpResult1 = tex1Dlod_lerp(internalTex1, internalTex1Sampler, vec2f(nlife, 0.0));
var velocity = lerpResult1.result;
let velocityDiv = lerpResult1.unpacked;
let lerpResult2 = tex1Dlod_lerp(internalTex2, internalTex2Sampler, vec2f(nlife, 0.0));
let params = lerpResult2.result;
let paramDiv = lerpResult2.unpacked;
var rotSpeed = params.x;
let rotSpeedDiv = paramDiv.y;
let lerpResult3 = tex1Dlod_lerp(internalTex3, internalTex3Sampler, vec2f(nlife, 0.0));
let radialParams = lerpResult3.result;
let radialParamDiv = lerpResult3.unpacked;
let radialSpeed = radialParams.x;
let radialSpeedDiv = radialParamDiv.y;
let respawn = inLife <= 0.0 || outLife >= uniform.lifetime;
inPos = select(inPos, calcSpawnPosition(rndFactor.xyz, rndFactor.x), respawn);
inAngle = select(inAngle, mix(uniform.startAngle, uniform.startAngle2, rndFactor.x), respawn);
#ifndef LOCAL_SPACE
var radialVel: vec3f = inPos - uniform.emitterPos;
#else
var radialVel: vec3f = inPos;
#endif
radialVel = select(vec3f(0.0), radialSpeed * normalize(radialVel), dot(radialVel, radialVel) > 1.0E-8);
radialVel = radialVel + (radialSpeedDiv * vec3f(2.0) - vec3f(1.0)) * uniform.radialSpeedDivMult * rndFactor.xyz;
localVelocity = localVelocity + (localVelocityDiv * vec3f(2.0) - vec3f(1.0)) * uniform.localVelocityDivMult * rndFactor.xyz;
velocity = velocity + (velocityDiv * vec3f(2.0) - vec3f(1.0)) * uniform.velocityDivMult * rndFactor.xyz;
rotSpeed = rotSpeed + (rotSpeedDiv * 2.0 - 1.0) * uniform.rotSpeedDivMult * rndFactor.y;
addInitialVelocity(&localVelocity, rndFactor.xyz);
#ifndef LOCAL_SPACE
outVel = uniform.emitterMatrix * localVelocity + (radialVel + velocity) * uniform.emitterScale;
#else
outVel = (localVelocity + radialVel) / uniform.emitterScale + uniform.emitterMatrixInv * velocity;
#endif
outPos = inPos + outVel * uniform.delta;
outAngle = inAngle + rotSpeed * uniform.delta;
`;
export { particleUpdaterStartPS as default };