private void CheckResources() { if (waterWavesParticlesMaterial == null) { waterWavesParticlesMaterial = new Material(waterWavesParticlesShader); waterWavesParticlesMaterial.hideFlags = HideFlags.DontSave; } if (particles == null) { particles = new WaveParticlesQuadtree(new Rect(-1000.0f, -1000.0f, 2000.0f, 2000.0f), maxParticlesPerTile, maxParticles); } }
protected override void SpawnChildNodes() { mesh.Destroy(); mesh = null; float halfWidth = rect.width * 0.5f; float halfHeight = rect.height * 0.5f; base.a = a = new WaveParticlesQuadtree(root, new Rect(rect.xMin, center.y, halfWidth, halfHeight), elements.Length); base.b = b = new WaveParticlesQuadtree(root, new Rect(center.x, center.y, halfWidth, halfHeight), elements.Length); base.c = c = new WaveParticlesQuadtree(root, new Rect(rect.xMin, rect.yMin, halfWidth, halfHeight), elements.Length); base.d = d = new WaveParticlesQuadtree(root, new Rect(center.x, rect.yMin, halfWidth, halfHeight), elements.Length); vertices = null; tangentsPack = null; particleGroups = null; numParticleGroups = 0; }
private void Subdivide(WaveParticlesQuadtree quadtree, WaveParticle left, WaveParticle right, ref int numSubdivisions) { Vector2 diff = left.position - right.position; float distance = diff.magnitude; if (distance * frequency > 1.0f && distance > 1.0f && quadtree.FreeSpace != 0) // don't subdivide below 1m on CPU { var newParticle = Create(right.position + diff * 0.5f, (left.direction + right.direction) * 0.5f, (left.baseFrequency + right.baseFrequency) * 0.5f, (left.baseAmplitude + right.baseAmplitude) * 0.5f, (left.lifetime + right.lifetime) * 0.5f, left.isShoreWave); if (newParticle != null) { newParticle.group = left.group; newParticle.amplitude = (left.amplitude + right.amplitude) * 0.5f; newParticle.frequency = (left.frequency + right.frequency) * 0.5f; newParticle.speed = (left.speed + right.speed) * 0.5f; newParticle.targetSpeed = (left.targetSpeed + right.targetSpeed) * 0.5f; newParticle.energyBalance = (left.energyBalance + right.energyBalance) * 0.5f; newParticle.shoaling = (left.shoaling + right.shoaling) * 0.5f; if (quadtree.AddElement(newParticle)) { /*const float subdivideEnergyLoss = 0.94f; * * left.baseAmplitude *= subdivideEnergyLoss; * left.amplitude *= subdivideEnergyLoss; * right.baseAmplitude *= subdivideEnergyLoss; * right.amplitude *= subdivideEnergyLoss; * newParticle.baseAmplitude *= subdivideEnergyLoss; * newParticle.amplitude *= subdivideEnergyLoss;*/ newParticle.leftNeighbour = left; newParticle.rightNeighbour = right; left.rightNeighbour = newParticle; right.leftNeighbour = newParticle; } ++numSubdivisions; } } }
public int CostlyUpdate(WaveParticlesQuadtree quadtree, float deltaTime) { float depth; if (frequency < 0.025f) // in case of big waves, sample center and front of the particle to get a better result { float posx = position.x + direction.x / frequency; float posy = position.y + direction.y / frequency; depth = Mathf.Max(StaticWaterInteraction.GetTotalDepthAt(position.x, position.y), StaticWaterInteraction.GetTotalDepthAt(posx, posy)); } else { depth = StaticWaterInteraction.GetTotalDepthAt(position.x, position.y); } if (depth <= 0.001f) { Destroy(); return(0); } UpdateWaveParameters(deltaTime, depth); int numSubdivisions = 0; if (quadtree != null && !disallowSubdivision) { if (leftNeighbour != null) { Subdivide(quadtree, leftNeighbour, this, ref numSubdivisions); } if (rightNeighbour != null) { Subdivide(quadtree, this, rightNeighbour, ref numSubdivisions); } } return(numSubdivisions); }
public void CostlyUpdate(WaveParticlesQuadtree quadtree, float time) { WaveParticle particle = leftParticle; float deltaTime = time - lastCostlyUpdateTime; lastCostlyUpdateTime = time; int numSubdivisions = 0; do { var p = particle; particle = particle.rightNeighbour; numSubdivisions += p.CostlyUpdate(numSubdivisions < 30 ? quadtree : null, deltaTime); }while(particle != null); particle = leftParticle; WaveParticle firstParticleInWave = particle; int waveLength = 0; do { var p = particle; particle = particle.rightNeighbour; ++waveLength; if (p != firstParticleInWave && (p.disallowSubdivision || particle == null)) { if (waveLength > 3) { FilterRefractedDirections(firstParticleInWave, p, waveLength); } firstParticleInWave = particle; waveLength = 0; } }while(particle != null); }
private WaveParticlesQuadtree(WaveParticlesQuadtree root, Rect rect, int maxElementsPerNode) : this(rect, maxElementsPerNode, 0) { this.root = root; }
public WaveParticlesQuadtree(Rect rect, int maxElementsPerNode, int maxTotalElements) : base(rect, maxElementsPerNode, maxTotalElements) { root = this; particleGroups = new WaveParticlesGroup[maxElementsPerNode >> 3]; CreateMesh(); }
private void UpdateParticles(float time) { var enabledWaterCameras = WaterCamera.EnabledWaterCameras; int numEnabledWaterCameras = enabledWaterCameras.Count; bool isVisible = false; for (int i = 0; i < numEnabledWaterCameras; ++i) { if (rect.Overlaps(enabledWaterCameras[i].LocalMapsRect)) { isVisible = true; break; } } int startIndex, endIndex, vertexIndex; if (!isVisible) { startIndex = lastUpdateIndex; endIndex = lastUpdateIndex + 8; vertexIndex = startIndex << 2; if (endIndex >= elements.Length) { endIndex = elements.Length; lastUpdateIndex = 0; } else { lastUpdateIndex = endIndex; } } else { startIndex = 0; endIndex = elements.Length; vertexIndex = 0; } WaveParticlesQuadtree rootQuadtree = isVisible ? root : null; float updateDelay = isVisible ? 0.01f : 1.5f; float costlyUpdateDelay = isVisible ? 0.4f : 8.0f; bool didCostlyUpdate = false; updateDelay *= root.stress; costlyUpdateDelay *= root.stress; for (int i = 0; particleGroups != null && i < particleGroups.Length; ++i) { var group = particleGroups[i]; if (group != null) { if (!group.leftParticle.isAlive) { --numParticleGroups; particleGroups[i] = null; continue; } if (time >= group.lastUpdateTime + updateDelay) { if (time >= group.lastCostlyUpdateTime + costlyUpdateDelay && !didCostlyUpdate) { if (!RectContainsParticleGroup(group)) { --numParticleGroups; particleGroups[i] = null; continue; } group.CostlyUpdate(rootQuadtree, time); didCostlyUpdate = true; } group.Update(time); } } } if (elements != null) { for (int i = startIndex; i < endIndex; ++i) { var particle = elements[i]; if (particle != null) { if (particle.isAlive) { if (marginRect.Contains(particle.position)) { var vertexData = particle.VertexData; var particleData = particle.PackedParticleData; vertices[vertexIndex] = vertexData; tangentsPack[vertexIndex++] = particleData; vertices[vertexIndex] = vertexData; tangentsPack[vertexIndex++] = particleData; vertices[vertexIndex] = vertexData; tangentsPack[vertexIndex++] = particleData; vertices[vertexIndex] = vertexData; tangentsPack[vertexIndex++] = particleData; tangentsPackChanged = true; } else { // re-add particle base.RemoveElementAt(i); vertices[vertexIndex++].x = float.NaN; vertices[vertexIndex++].x = float.NaN; vertices[vertexIndex++].x = float.NaN; vertices[vertexIndex++].x = float.NaN; root.AddElement(particle); } } else { // remove particle base.RemoveElementAt(i); vertices[vertexIndex++].x = float.NaN; vertices[vertexIndex++].x = float.NaN; vertices[vertexIndex++].x = float.NaN; vertices[vertexIndex++].x = float.NaN; particle.AddToCache(); } } else { vertexIndex += 4; } } } }