Example #1
0
        private void Awake()
        {
            GetComponent <MeshRenderer>().material = GraphicsE.diffuseVertexColor;

            var template = MeshE.TetrahedronFlat(0.3f);

            templateVertices        = template.vertices;
            templateVerticesLength  = template.vertices.Length;
            templateTriangles       = template.triangles;
            templateTrianglesLength = template.triangles.Length;
            swarmCount = Mathf.Min(65000 / templateVerticesLength, swarmCount);

            vertices  = new Vector3[swarmCount * templateVerticesLength];
            triangles = new int[swarmCount * templateTrianglesLength];
            colors32  = new Color32[swarmCount * templateVerticesLength];
            for (var i = 0; i < swarmCount; i++)
            {
                var boid = new Boid
                {
                    position = Random.insideUnitSphere * spawnSphere,
                    rotation = Random.rotation,
                    velocity = Random.onUnitSphere * maxSpeed
                };
                boids.Add(boid);

                SetBoidVertices(boid, i);
                SetBoidTriangles(i);
                SetBoidColors(boid, i);
            }

            mesh = new Mesh
            {
                name      = "Boids",
                vertices  = vertices,
                triangles = triangles,
                colors32  = colors32
            };
            mesh.RecalculateNormals();
            mesh.MarkDynamic();
            GetComponent <MeshFilter>().mesh = mesh;

            StartCoroutine(SimulateCoroutine());
        }
        /// <summary>
        /// Generate new colors and positions for boids
        /// </summary>
        public Mesh Generate(Config config)
        {
            this.config = config;

            // Avoid vertex count overflow
            config.swarmCount = Mathf.Min(65000 / config.template.vertexCount, config.swarmCount);
            // Optimization trick: in each frame we simulate only small percent of all boids
            maxSimulationSteps = Mathf.RoundToInt(config.swarmCount * config.simulationPercent);
            int vertexCount = config.swarmCount * config.template.vertexCount;

            draft = new MeshDraft
            {
                name      = "Boids",
                vertices  = new List <Vector3>(vertexCount),
                triangles = new List <int>(vertexCount),
                normals   = new List <Vector3>(vertexCount),
                uv        = new List <Vector2>(vertexCount),
                colors    = new List <Color>(vertexCount)
            };

            for (var i = 0; i < config.swarmCount; i++)
            {
                // Assign random starting values for each boid
                var boid = new Boid
                {
                    position = Random.insideUnitSphere * config.spawnSphere,
                    rotation = Random.rotation,
                    velocity = Random.onUnitSphere * config.maxSpeed
                };
                boids.Add(boid);

                draft.Add(config.template);
            }

            mesh = draft.ToMesh();
            mesh.MarkDynamic();
            // Set bounds manually for correct culling
            mesh.bounds = new Bounds(Vector3.zero, Vector3.one * config.worldSphere * 2);
            return(mesh);
        }
Example #3
0
        /// <summary>
        /// Run simulation
        /// </summary>
        public IEnumerator CalculateVelocities()
        {
            int simulationStep = 0;

            for (int currentIndex = 0; currentIndex < boids.Count; currentIndex++)
            {
                // Optimization trick: in each frame we simulate only small percent of all boids
                simulationStep++;
                if (simulationStep > maxSimulationSteps)
                {
                    simulationStep = 0;
                    yield return(null);
                }

                var boid = boids[currentIndex];
                // Search for nearest neighbours
                neighbours.Clear();
                for (int i = 0; i < boids.Count; i++)
                {
                    Boid neighbour = boids[i];

                    Vector3 toNeighbour = neighbour.position - boid.position;
                    if (toNeighbour.sqrMagnitude < interactionRadius)
                    {
                        neighbours.Add(neighbour);
                        if (neighbours.Count == maxBoids)
                        {
                            break;
                        }
                    }
                }

                if (neighbours.Count < 2)
                {
                    continue;
                }

                boid.velocity   = Vector3.zero;
                boid.cohesion   = Vector3.zero;
                boid.separation = Vector3.zero;
                boid.alignment  = Vector3.zero;

                // Calculate boid parameters
                int separationCount = 0;
                for (int i = 0; i < neighbours.Count && i < maxBoids; i++)
                {
                    Boid neighbour = neighbours[i];

                    boid.cohesion  += neighbour.position;
                    boid.alignment += neighbour.velocity;

                    Vector3 toNeighbour = neighbour.position - boid.position;
                    if (toNeighbour.sqrMagnitude > 0 &&
                        toNeighbour.sqrMagnitude < separationDistance * separationDistance)
                    {
                        boid.separation += toNeighbour / toNeighbour.sqrMagnitude;
                        separationCount++;
                    }
                }

                // Clamp all parameters to safe values
                boid.cohesion /= Mathf.Min(neighbours.Count, maxBoids);
                boid.cohesion  = Vector3.ClampMagnitude(boid.cohesion - boid.position, maxSpeed);
                boid.cohesion *= cohesionCoefficient;

                if (separationCount > 0)
                {
                    boid.separation /= separationCount;
                    boid.separation  = Vector3.ClampMagnitude(boid.separation, maxSpeed);
                    boid.separation *= separationCoefficient;
                }

                boid.alignment /= Mathf.Min(neighbours.Count, maxBoids);
                boid.alignment  = Vector3.ClampMagnitude(boid.alignment, maxSpeed);
                boid.alignment *= alignmentCoefficient;

                // Calculate resulting velocity
                Vector3 velocity = boid.cohesion + boid.separation + boid.alignment;
                boid.velocity = Vector3.ClampMagnitude(velocity, maxSpeed);
                if (boid.velocity == Vector3.zero)
                {
                    // Prevent boids from stopping
                    boid.velocity = Random.onUnitSphere * maxSpeed;
                }
            }
        }
 private void SetBoidVertices(Boid boid, int index)
 {
     for (int i = 0; i < template.vertices.Count; i++)
     {
         draft.vertices[index*template.vertices.Count + i] = boid.rotation*template.vertices[i] + boid.position;
     }
 }
        /// <summary>
        /// Generate new colors and positions for boids
        /// </summary>
        public Mesh Generate()
        {
            template = MeshDraft.Tetrahedron(0.3f);

            // Avoid vertex count overflow
            swarmCount = Mathf.Min(65000/template.vertices.Count, swarmCount);
            // Optimization trick: in each frame we simulate only small percent of all boids
            maxSimulationSteps = Mathf.RoundToInt(swarmCount*simulationPercent);
            int vertexCount = swarmCount*template.vertices.Count;

            // Paint template in random color
            template.colors.Clear();
            var color = RandomE.colorHSV;
            // Assuming that we are dealing with tetrahedron, first vertex should be boid's "nose"
            template.colors.Add(color.Inverted());
            for (int i = 1; i < template.vertices.Count; i++)
            {
                template.colors.Add(color);
            }

            draft = new MeshDraft
            {
                name = "Boids",
                vertices = new List<Vector3>(vertexCount),
                triangles = new List<int>(vertexCount),
                normals = new List<Vector3>(vertexCount),
                uv = new List<Vector2>(vertexCount),
                colors = new List<Color>(vertexCount)
            };

            for (var i = 0; i < swarmCount; i++)
            {
                // Assign random starting values for each boid
                var boid = new Boid
                {
                    position = Random.insideUnitSphere*spawnSphere,
                    rotation = Random.rotation,
                    velocity = Random.onUnitSphere*maxSpeed
                };
                boids.Add(boid);

                draft.Add(template);
            }

            mesh = draft.ToMesh();
            mesh.MarkDynamic();
            return mesh;
        }
Example #6
0
        void AvoidTerrain(Boid boid)
        {
            if (transform == null)
            {
                return;
            }
            float s         = 0.75f;
            int   hits      = 0;
            bool  directHit = false;

            for (float x = -s; x <= s; x = x + s)
            {
                for (float y = -s; y <= s; y = y + s)
                {
                    for (float z = -s; z <= s; z = z + s)
                    {
                        Vector3 p        = new Vector3(boid.position.x + x, boid.position.y + y, boid.position.z + z);
                        Vector3 pos      = p + boid.velocity * Time.deltaTime * 2f;
                        World3  worldPos = new World3(transform.TransformPoint(pos));
                        ushort  block    = World.GetBlock(worldPos);
                        if ((block != Block.Air && block != Block.Null && worldPos.y < 16) || worldPos.y < -48)
                        {
                            hits++;
                            if (x == 0 && y == 0 && z == 0)
                            {
                                directHit = true;
                            }
                        }
                    }
                }
            }
            for (float x = -s; x <= s; x = x + s)
            {
                for (float y = -s; y <= s; y = y + s)
                {
                    for (float z = -s; z <= s; z = z + s)
                    {
                        Vector3 p        = new Vector3(boid.position.x + x, boid.position.y + y, boid.position.z + z);
                        Vector3 pos      = p + boid.velocity;
                        World3  worldPos = new World3(transform.TransformPoint(pos));
                        ushort  block    = World.GetBlock(worldPos);
                        if ((block != Block.Air && block != Block.Null && worldPos.y < 16) || worldPos.y < -48)
                        {
                            hits++;
                            if (x == 0 && y == 0 && z == 0)
                            {
                                directHit = true;
                            }
                        }
                    }
                }
            }

            if (hits == 0)
            {
                boid.rotation = Quaternion.FromToRotation(Vector3.up, boid.velocity);
            }
            else
            {
                boid.rotation = Quaternion.FromToRotation(Vector3.up, Vector3.RotateTowards(boid.velocity, -boid.velocity, Time.deltaTime * hits, 0f));
            }
            if (directHit)
            {
                boid.velocity -= Vector3.up * 100f;
                boid.velocity  = Vector3.ClampMagnitude(boid.velocity, maxSpeed);
            }
            if (hits > 0)
            {
                boid.velocity  = Vector3.RotateTowards(boid.velocity, -boid.velocity, Time.deltaTime * hits * 5f, 0f);
                boid.velocity *= flutterBoost;
                boid.velocity += Vector3.up;
                boid.velocity  = Vector3.ClampMagnitude(boid.velocity, maxSpeed);
            }
        }
Example #7
0
        /// <summary>
        /// Run simulation
        /// </summary>
        public IEnumerator Simulate()
        {
            simulationCount = 0;
            while (true)
            {
                for (int i = 0; i < boids.Count; i++)
                {
                    // Optimization trick: in each frame we simulate only small percent of all boids
                    simulationCount++;
                    if (simulationCount > simulationUpdate)
                    {
                        simulationCount = 0;
                        yield return null;
                    }

                    var boid = boids[i];
                    // Search for nearest neighbours
                    neighbours.Clear();
                    for (int j = 0; j < boids.Count; j++)
                    {
                        var b = boids[j];
                        if ((b.position - boid.position).sqrMagnitude < interactionRadius)
                        {
                            neighbours.Add(b);
                            if (neighbours.Count == maxBoids)
                            {
                                break;
                            }
                        }
                    }

                    if (neighbours.Count < 2) continue;

                    boid.velocity = Vector3.zero;
                    boid.cohesion = Vector3.zero;
                    boid.separation = Vector3.zero;
                    boid.alignment = Vector3.zero;

                    // Calculate boid parameters
                    separationCount = 0;
                    for (var j = 0; j < neighbours.Count && j < maxBoids; j++)
                    {
                        other = neighbours[j];
                        boid.cohesion += other.position;
                        boid.alignment += other.velocity;
                        toOther = other.position - boid.position;
                        if (toOther.sqrMagnitude > 0 && toOther.sqrMagnitude < separationDistance*separationDistance)
                        {
                            boid.separation += toOther/toOther.sqrMagnitude;
                            separationCount++;
                        }
                    }

                    // Clamp all parameters to safe values
                    boid.cohesion /= Mathf.Min(neighbours.Count, maxBoids);
                    boid.cohesion = Vector3.ClampMagnitude(boid.cohesion - boid.position, maxSpeed);
                    boid.cohesion *= cohesionCoefficient;
                    if (separationCount > 0)
                    {
                        boid.separation /= separationCount;
                        boid.separation = Vector3.ClampMagnitude(boid.separation, maxSpeed);
                        boid.separation *= separationCoefficient;
                    }
                    boid.alignment /= Mathf.Min(neighbours.Count, maxBoids);
                    boid.alignment = Vector3.ClampMagnitude(boid.alignment, maxSpeed);
                    boid.alignment *= alignmentCoefficient;

                    // Calculate resulting velocity
                    boid.velocity = Vector3.ClampMagnitude(boid.cohesion + boid.separation + boid.alignment, maxSpeed);
                    if (boid.velocity == Vector3.zero)
                    {
                        // Prevent boids from stopping
                        boid.velocity = Random.onUnitSphere*maxSpeed;
                    }
                }
            }
        }
Example #8
0
        private IEnumerator Simulate()
        {
            simulationCount = 0;
            while (true)
            {
                for (int i = 0; i < swarmCount; i++)
                {
                    simulationCount++;
                    if (simulationCount > simulationUpdate)
                    {
                        simulationCount = 0;
                        yield return(null);
                    }
                    var boid = boids[i];
                    neighbours.Clear();
                    for (int j = 0; j < swarmCount; j++)
                    {
                        var b = boids[j];
                        if ((b.position - boid.position).sqrMagnitude < cohesionRadius)
                        {
                            neighbours.Add(b);
                            if (neighbours.Count == maxBoids)
                            {
                                break;
                            }
                        }
                    }

                    if (neighbours.Count < 2)
                    {
                        continue;
                    }

                    boid.velocity   = Vector3.zero;
                    boid.cohesion   = Vector3.zero;
                    boid.separation = Vector3.zero;

                    separationCount = 0;
                    alignment       = Vector3.zero;

                    for (var j = 0; j < neighbours.Count && j < maxBoids; j++)
                    {
                        other          = neighbours[j];
                        boid.cohesion += other.position;
                        alignment     += other.velocity;
                        toOther        = other.position - boid.position;
                        if (toOther.sqrMagnitude > 0 && toOther.sqrMagnitude < separationDistance * separationDistance)
                        {
                            boid.separation += toOther / toOther.sqrMagnitude;
                            separationCount++;
                        }
                    }

                    boid.cohesion /= Mathf.Min(neighbours.Count, maxBoids);
                    boid.cohesion  = Vector3.ClampMagnitude(boid.cohesion - boid.position, maxSpeed);
                    boid.cohesion *= cohesionCoefficient;
                    if (separationCount > 0)
                    {
                        boid.separation /= separationCount;
                        boid.separation  = Vector3.ClampMagnitude(boid.separation, maxSpeed);
                        boid.separation *= separationCoefficient;
                    }
                    alignment /= Mathf.Min(neighbours.Count, maxBoids);
                    alignment  = Vector3.ClampMagnitude(alignment, maxSpeed);
                    alignment *= alignmentCoefficient;

                    boid.velocity = Vector3.ClampMagnitude(boid.cohesion + boid.separation + alignment, maxSpeed);
                    if (boid.velocity == Vector3.zero)
                    {
                        boid.velocity = Random.onUnitSphere * maxSpeed;
                    }
                }
            }
        }
Example #9
0
        private IEnumerator Simulate()
        {
            simulationCount = 0;
            while (true)
            {
                for (int i = 0; i < swarmCount; i++)
                {
                    simulationCount++;
                    if (simulationCount > simulationUpdate)
                    {
                        simulationCount = 0;
                        yield return null;
                    }
                    var boid = boids[i];
                    neighbours.Clear();
                    for (int j = 0; j < swarmCount; j++)
                    {
                        var b = boids[j];
                        if ((b.position - boid.position).sqrMagnitude < cohesionRadius)
                        {
                            neighbours.Add(b);
                            if (neighbours.Count == maxBoids)
                            {
                                break;
                            }
                        }
                    }

                    if (neighbours.Count < 2) continue;

                    boid.velocity = Vector3.zero;
                    boid.cohesion = Vector3.zero;
                    boid.separation = Vector3.zero;

                    separationCount = 0;
                    alignment = Vector3.zero;

                    for (var j = 0; j < neighbours.Count && j < maxBoids; j++)
                    {
                        other = neighbours[j];
                        boid.cohesion += other.position;
                        alignment += other.velocity;
                        toOther = other.position - boid.position;
                        if (toOther.sqrMagnitude > 0 && toOther.sqrMagnitude < separationDistance*separationDistance)
                        {
                            boid.separation += toOther/toOther.sqrMagnitude;
                            separationCount++;
                        }
                    }

                    boid.cohesion /= Mathf.Min(neighbours.Count, maxBoids);
                    boid.cohesion = Vector3.ClampMagnitude(boid.cohesion - boid.position, maxSpeed);
                    boid.cohesion *= cohesionCoefficient;
                    if (separationCount > 0)
                    {
                        boid.separation /= separationCount;
                        boid.separation = Vector3.ClampMagnitude(boid.separation, maxSpeed);
                        boid.separation *= separationCoefficient;
                    }
                    alignment /= Mathf.Min(neighbours.Count, maxBoids);
                    alignment = Vector3.ClampMagnitude(alignment, maxSpeed);
                    alignment *= alignmentCoefficient;

                    boid.velocity = Vector3.ClampMagnitude(boid.cohesion + boid.separation + alignment, maxSpeed);
                    if (boid.velocity == Vector3.zero)
                    {
                        boid.velocity = Random.onUnitSphere*maxSpeed;
                    }
                }
            }
        }
Example #10
0
        /// <summary>
        /// Run simulation
        /// </summary>
        public IEnumerator Simulate()
        {
            simulationCount = 0;
            while (true)
            {
                for (int i = 0; i < boids.Count; i++)
                {
                    // Optimization trick: in each frame we simulate only small percent of all boids
                    simulationCount++;
                    if (simulationCount > simulationUpdate)
                    {
                        simulationCount = 0;
                        yield return(null);
                    }

                    var boid = boids[i];
                    // Search for nearest neighbours
                    neighbours.Clear();
                    for (int j = 0; j < boids.Count; j++)
                    {
                        var b = boids[j];
                        if ((b.position - boid.position).sqrMagnitude < interactionRadius)
                        {
                            neighbours.Add(b);
                            if (neighbours.Count == maxBoids)
                            {
                                break;
                            }
                        }
                    }

                    if (neighbours.Count < 2)
                    {
                        continue;
                    }

                    boid.velocity   = Vector3.zero;
                    boid.cohesion   = Vector3.zero;
                    boid.separation = Vector3.zero;
                    boid.alignment  = Vector3.zero;

                    // Calculate boid parameters
                    separationCount = 0;
                    for (var j = 0; j < neighbours.Count && j < maxBoids; j++)
                    {
                        other           = neighbours[j];
                        boid.cohesion  += other.position;
                        boid.alignment += other.velocity;
                        toOther         = other.position - boid.position;
                        if (toOther.sqrMagnitude > 0 && toOther.sqrMagnitude < separationDistance * separationDistance)
                        {
                            boid.separation += toOther / toOther.sqrMagnitude;
                            separationCount++;
                        }
                    }

                    // Clamp all parameters to safe values
                    boid.cohesion /= Mathf.Min(neighbours.Count, maxBoids);
                    boid.cohesion  = Vector3.ClampMagnitude(boid.cohesion - boid.position, maxSpeed);
                    boid.cohesion *= cohesionCoefficient;
                    if (separationCount > 0)
                    {
                        boid.separation /= separationCount;
                        boid.separation  = Vector3.ClampMagnitude(boid.separation, maxSpeed);
                        boid.separation *= separationCoefficient;
                    }
                    boid.alignment /= Mathf.Min(neighbours.Count, maxBoids);
                    boid.alignment  = Vector3.ClampMagnitude(boid.alignment, maxSpeed);
                    boid.alignment *= alignmentCoefficient;

                    // Calculate resulting velocity
                    boid.velocity = Vector3.ClampMagnitude(boid.cohesion + boid.separation + boid.alignment, maxSpeed);
                    if (boid.velocity == Vector3.zero)
                    {
                        // Prevent boids from stopping
                        boid.velocity = Random.onUnitSphere * maxSpeed;
                    }
                }
            }
        }