public Vector3 ApplyField(Vector3 position, ref ParticleCustomData cdata, float influence, int particleIdx) { var acc = force(position); var xn_1 = cdata.Xn_1[customDataIdx]; var xn = cdata.Xn[customDataIdx]; var dt = Time.deltaTime; var dt2 = dt * dt; Vector3 newPos; if (cdata.NumTimestep == 0) { newPos = xn + (velocity(xn) * dt) + (influence * 0.5f * dt2 * force(xn)); } else { newPos = (2 * xn) - xn_1 + (influence * dt2 * force(xn)); } cdata.Xn[customDataIdx] = newPos; cdata.Xn_1[customDataIdx] = xn; return(newPos); }
void FixedUpdate() { int particleCount = ps.particleCount; if (!ps.isPlaying || particleCount == 0) { return; } dt = Time.deltaTime; dt2 = dt * dt; ParticleSystem.Particle[] particles = new ParticleSystem.Particle[particleCount]; ps.GetParticles(particles); ps.GetCustomParticleData(customData, ParticleSystemCustomData.Custom1); DateTime curTime = DateTime.Now; for (int i = 0; i < particles.Length; ++i) { int particleIdx = Mathf.RoundToInt(customData[i].x); // Init custom data for new particle if (particleIdx <= 0) { particleIdx = ++uniqueID; customData[i] = new Vector4(particleIdx, 0, 0, 0); cdata[particleIdx] = new ParticleCustomData(forceFields.Count); } var temp = cdata[particleIdx]; AdvectParticleDirect(ref particles[i], ref temp, particleIdx); temp.NumTimestep++; temp.LastTime = curTime; cdata[particleIdx] = temp; var lifetime = cdata[particleIdx].NumTimestep * dt + cdata[particleIdx].ParamPhase; particles[i].remainingLifetime = MaxParticleLifetime - lifetime - dt; } ps.SetCustomParticleData(customData, ParticleSystemCustomData.Custom1); ps.SetParticles(particles); }
private void AdvectParticleDirect(ref ParticleSystem.Particle p, ref ParticleCustomData data, int idx) { p.velocity = Vector3.zero; float time, normalizedTime; Vector3 T, N, B; Tuple <int, float> splineParam; float theta; // compute pseudo-random parameters if (data.NumTimestep == 0) { data.ParamPhase = dt * UnityEngine.Random.value; data.PositionNoiseSeed[0] = UnityEngine.Random.value * 50; data.PositionNoiseSeed[1] = UnityEngine.Random.value * 50; data.RotationNoiseSeed[0] = UnityEngine.Random.value * 50; data.RotationNoiseSeed[1] = UnityEngine.Random.value * 50; } // find Bishop frame time = data.NumTimestep * dt + data.ParamPhase; splineParam = emissionCurve.GetSplineParamFromTime(time); T = emissionCurve.Tangent(splineParam.Item1, splineParam.Item2); N = emissionCurve.Normal(splineParam.Item1, splineParam.Item2); B = Vector3.Cross(T, N); normalizedTime = time / MaxParticleLifetime; // compute other init parameters if (data.NumTimestep == 0) { var pos = p.position - Vector3.Dot(p.position, T) * T; data.Delta = pos.magnitude / emitterShape.radius; if (data.Delta > float.Epsilon) { data.Theta0 = Mathf.Atan2(Vector3.Dot(pos, B), Vector3.Dot(pos, N)); } else { data.Theta0 = 0; } } theta = data.Theta0 + 2 * Mathf.PI * SpiralFrequency * time; var emissionData = GetInterpolatedEmissionData(time); p.position = emissionCurve.Evaluate(splineParam.Item1, splineParam.Item2) + data.Delta * emissionData.Radius * (N * Mathf.Cos(theta) + B * Mathf.Sin(theta)); Vector3 externalForceInfluence = Vector3.zero; foreach (var force in forceFields) { switch (force.EffectType) { case ParticleCustomForceField.FieldEffectType.Gravity: externalForceInfluence += transform.InverseTransformVector(force.ApplyField(p.position, ref data, GravityInfluence, idx)); break; case ParticleCustomForceField.FieldEffectType.Wind: externalForceInfluence += transform.InverseTransformVector(force.ApplyField(p.position, ref data, WindInfluence, idx)); break; } } p.position += externalForceInfluence; data.Xn_1[0] = data.Xn[0]; data.Xn[0] = p.position; data.Nn_1 = N; Vector2 positionNoise = new Vector2( -1 + 2 * Mathf.PerlinNoise(data.PositionNoiseSeed[0], PositionNoiseFrequency * time), -1 + 2 * Mathf.PerlinNoise(data.PositionNoiseSeed[1], PositionNoiseFrequency * time) ) * MaxPositionNoise * normalizedTime; Vector2 rotationNoise = new Vector2( -1 + 2 * Mathf.PerlinNoise(data.RotationNoiseSeed[0], RotationNoiseFrequency * time), -1 + 2 * Mathf.PerlinNoise(data.RotationNoiseSeed[1], RotationNoiseFrequency * time) ) * MaxRotationNoise * normalizedTime; p.position += N * positionNoise.x + B * positionNoise.y; Quaternion rot = Quaternion.LookRotation(T, B); rot *= (Quaternion.AngleAxis(rotationNoise.x, N) * Quaternion.AngleAxis(rotationNoise.y, B)); p.rotation3D = (rot * InitialParticleRotation).eulerAngles; }