Example #1
0
        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);
            }
        }
Example #2
0
        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;
        }
Example #3
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;
                }
            }
        }
Example #4
0
        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);
        }
Example #5
0
        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);
        }
Example #6
0
 private WaveParticlesQuadtree(WaveParticlesQuadtree root, Rect rect, int maxElementsPerNode) : this(rect, maxElementsPerNode, 0)
 {
     this.root = root;
 }
Example #7
0
 public WaveParticlesQuadtree(Rect rect, int maxElementsPerNode, int maxTotalElements) : base(rect, maxElementsPerNode, maxTotalElements)
 {
     root           = this;
     particleGroups = new WaveParticlesGroup[maxElementsPerNode >> 3];
     CreateMesh();
 }
Example #8
0
        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;
                    }
                }
            }
        }