void SubdivideParticle(WaveParticle particle) { float angle = particle.dispersionAngle / 3.0f; particles.Add(new WaveParticle { birthPosition = particle.birthPosition, direction = Utils.Rotate(particle.direction, angle), amplitude = particle.amplitude / 3.0f, dispersionAngle = particle.dispersionAngle / 3.0f, birthTime = particle.birthTime, }); particles.Add(new WaveParticle { birthPosition = particle.birthPosition, direction = Utils.Rotate(particle.direction, -angle), amplitude = particle.amplitude / 3.0f, dispersionAngle = particle.dispersionAngle / 3.0f, birthTime = particle.birthTime, }); particle.dispersionAngle /= 3.0f; particle.amplitude /= 3.0f; }
public void calculateSubdivisions(int currentFrame) { int currentIndex = mSubdivisions[currentFrame]; // the max uint value represents a non-existent wave particle while (currentIndex != NO_PARTICLE) { WaveParticle currentParticle = mParticles[currentIndex]; if (Mathf.Abs(currentParticle.amplitude) > _waveParticleKillThreshold) { Vector2 origin = currentParticle.origin; Vector2 middleVelocity = currentParticle.velocity; float newDispersionAngle = currentParticle.dispersionAngle / 3; float newAmplitude = currentParticle.amplitude / 3; Vector2 leftVelocity = Quaternion.AngleAxis(newDispersionAngle * (180f / Mathf.PI), Vector3.forward) * middleVelocity; Vector2 rightVelocity = Quaternion.AngleAxis(newDispersionAngle * (-180f / Mathf.PI), Vector3.forward) * middleVelocity; addParticle(WaveParticle.createWaveParticleUnvalidated(origin, middleVelocity, newAmplitude, newDispersionAngle, currentParticle.startingFrame)); addParticle(WaveParticle.createWaveParticleUnvalidated(origin, leftVelocity, newAmplitude, newDispersionAngle, currentParticle.startingFrame)); addParticle(WaveParticle.createWaveParticleUnvalidated(origin, rightVelocity, newAmplitude, newDispersionAngle, currentParticle.startingFrame)); } int nextIndex = _eventIndices[currentIndex]; mParticles[currentIndex] = WaveParticle.DEAD_PARTICLE; _eventIndices[currentIndex] = NO_PARTICLE; currentIndex = nextIndex; } mSubdivisions[currentFrame] = NO_PARTICLE; }
public void AddParticle(Vector2 position, Vector2 velocity, float amplitude, float dispersionAngle) { if (amplitude > _waveParticleKillThreshold) { WaveParticle wp = WaveParticle.createWaveParticle(position, velocity, amplitude, dispersionAngle, currentFrame); waveParticles.addParticle(wp); } }
//public IEnumerator<WaveParticle> GetEnumerator() //{ // Assert.IsTrue(mCurrentHead < _numParticles); // int startIndex = (mCurrentHead == 0) ? _numParticles - 1 : mCurrentHead - 1; // int index = startIndex; // { // Assert.IsTrue(index != NO_PARTICLE); // if (mParticles[index].amplitude != 0) // { // WaveParticle particle = mParticles[index]; // yield return particle; // } // index = (index == 0) ? _numParticles - 1 : index - 1; // } // while (index != startIndex) // { // Assert.IsTrue(index != NO_PARTICLE); // if (mParticles[index].amplitude != 0) // { // WaveParticle particle = mParticles[index]; // yield return particle; // } // index = (index == 0) ? _numParticles - 1 : index - 1; // } //} public void addParticle(WaveParticle particle) { // TODO: clean up code! float timeToSubdivision = WaveParticle.RADIUS * 0.5f / (WaveParticle.PARTICLE_SPEED * particle.dispersionAngle); bool reflectBeforeSubdivision = false; { // TODO: Calculate Raycast Vector3 origin = new Vector3(particle.origin.x - 2f, 0f, particle.origin.y - 2f); Vector3 direction = new Vector3(particle.velocity.x, 0f, particle.velocity.y); RaycastHit hit; if (Physics.Raycast(origin, direction, out hit)) { float timeToReflection = hit.distance / WaveParticle.PARTICLE_SPEED; if (timeToReflection < timeToSubdivision) { reflectBeforeSubdivision = true; /// reflection /// int reflectionFrame = ((ushort)(Mathf.RoundToInt(timeToReflection / Time.fixedDeltaTime))); reflectionFrame = (particle.startingFrame + reflectionFrame) % WaveParticle.FRAME_CYCLE_LENGTH; int oldParticleIndex = mReflections[reflectionFrame]; int nextIndex = oldParticleIndex; mReflections[reflectionFrame] = mCurrentHead; mParticles[mCurrentHead] = particle; _eventIndices[mCurrentHead] = nextIndex; } Debug.DrawLine(origin, hit.point); } else { Debug.DrawRay(origin, direction, Color.red); } } if (!reflectBeforeSubdivision) { int subdivisionFrame = ((ushort)(Mathf.RoundToInt(timeToSubdivision / Time.fixedDeltaTime))); subdivisionFrame = (particle.startingFrame + subdivisionFrame) % WaveParticle.FRAME_CYCLE_LENGTH; int oldParticleIndex = mSubdivisions[subdivisionFrame]; int nextIndex = oldParticleIndex; mSubdivisions[subdivisionFrame] = mCurrentHead; mParticles[mCurrentHead] = particle; _eventIndices[mCurrentHead] = nextIndex; } mCurrentHead = (mCurrentHead + 1) % _numParticles; }
public void TestSubdivisions() { var pc = new CPUParticleContainer(); pc.Initialise(30000, 0.0001f); for (int i = 0; i < 1000000; i++) { pc.addParticle(WaveParticle.createWaveParticle(new Vector2(0, 0), new Vector2(0.5f, 0.5f), 1f, Mathf.PI / 2, 0)); } }
public void TestParticleAdditions() { var pc = new CPUParticleContainer(); pc.Initialise(30000, 0.0001f); pc.addParticle(WaveParticle.createWaveParticle(new Vector2(0, 0), new Vector2(1, 0), 1f, Mathf.PI / 2, 0)); int count = 0; foreach (var wp in pc) { count++; } Assert.That(count, Is.EqualTo(1)); //Assert.That(count, Is.EqualTo(pc.numActiveParticles)); }
public void addParticle(WaveParticle particle) { /// /// Calculate when WaveParticle is due to subdivide /// int subdivisionFrame; { // if the dispersion angle is 0, the subdivide particle at latest possilbe time if (particle.dispersionAngle == 0f) { subdivisionFrame = particle.startingFrame + WaveParticle.FRAME_CYCLE_LENGTH; } else { float timeToSubdivision = WaveParticle.RADIUS * 0.5f / (WaveParticle.PARTICLE_SPEED * particle.dispersionAngle); int framesToSubdivision = (Mathf.RoundToInt(timeToSubdivision / Time.fixedDeltaTime)); if (framesToSubdivision > WaveParticle.FRAME_CYCLE_LENGTH) { framesToSubdivision = WaveParticle.FRAME_CYCLE_LENGTH; } subdivisionFrame = (framesToSubdivision + particle.startingFrame) % WaveParticle.FRAME_CYCLE_LENGTH; } } /// /// Using the calculated subdivision frame, add the current particle as an event in that frame /// addSubdivisionEvent((_currentHead + _pendingParticlesHead) % _particleContainerSize, subdivisionFrame); /// /// Add the current particle to the to-be-committed buffer /// /// Commit the current buffer if it ends up full /// _pendingParticles[_pendingParticlesHead++] = particle; if (_pendingParticlesHead >= _pendingParticles.Length) { commitParticles(); } }
/// <summary> /// Create new wave particles due to computed object motion. /// </summary> void GenerateWaveParticles() { // TODO: Fix the ripple generator. if (Input.GetKey(KeyCode.Mouse0)) { RaycastHit globalMousePosition; if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out globalMousePosition)) { Vector3 localMousePosition = transform.InverseTransformPoint(globalMousePosition.point); Vector2 clickLocation = new Vector2(localMousePosition.x + extendedHeightField.Width / 2f, localMousePosition.z + extendedHeightField.Height / 2f); // Create a small ripple of particles { WaveParticle wp = WaveParticle.createWaveParticle(clickLocation, new Vector2(0.5f, 0.5f), 0.8f, Mathf.PI * 2, currentFrame); waveParticles.addParticle(wp); } } } }