private void GenerateObject(MyProceduralCell cell, MyObjectSeed objectSeed, ref int index, MyRandom random, IMyModule densityFunction)
        {
            cell.AddObject(objectSeed);
            switch (objectSeed.Type)
            {
                case MyObjectSeedType.Asteroid:
                    m_asteroidSeedCount++;
                    break;
                case MyObjectSeedType.AsteroidCluster:
                    objectSeed.Type = MyObjectSeedType.Asteroid;
                    m_asteroidSeedCount++;

                    m_tmpClusterBoxes.Add(objectSeed.BoundingVolume);

                    for (int j = 0; j < OBJECT_MAX_IN_CLUSTER; ++j)
                    {
                        var direction = GetRandomDirection(random);
                        var size = GetClusterObjectSize(random.NextDouble());
                        var distance = MathHelper.Lerp(OBJECT_MIN_DISTANCE_CLUSTER, OBJECT_MAX_DISTANCE_CLUSTER, random.NextDouble());
                        var clusterObjectPosition = objectSeed.BoundingVolume.Center + direction * (size + objectSeed.BoundingVolume.HalfExtents.Length() * 2 + distance);

                        ProfilerShort.Begin("GetValue");
                        var value = densityFunction.GetValue(clusterObjectPosition.X, clusterObjectPosition.Y, clusterObjectPosition.Z);
                        ProfilerShort.End();

                        if (value < OBJECT_DENSITY_CLUSTER) // -1..+1
                        {
                            var clusterObjectSeed = new MyObjectSeed(cell, clusterObjectPosition, size);
                            clusterObjectSeed.Seed = random.Next();
                            clusterObjectSeed.Index = index++;
                            clusterObjectSeed.Type = GetClusterSeedType(random.NextDouble());

                            bool overlaps = false;
                            foreach (var box in m_tmpClusterBoxes)
                            {
                                if (overlaps |= clusterObjectSeed.BoundingVolume.Intersects(box))
                                {
                                    break;
                                }
                            }

                            if (!overlaps)
                            {
                                m_tmpClusterBoxes.Add(clusterObjectSeed.BoundingVolume);
                                GenerateObject(cell, clusterObjectSeed, ref index, random, densityFunction);
                            }
                        }
                    }
                    m_tmpClusterBoxes.Clear();
                    break;
                case MyObjectSeedType.EncounterAlone:
                case MyObjectSeedType.EncounterSingle:
                case MyObjectSeedType.EncounterMulti:
                    m_encounterSeedCount++;
                    break;
                default:
                    throw new InvalidBranchException();
                    break;
            }
        }
        private Vector3D GetRandomDirection(MyRandom random)
        {
            double phi = random.NextDouble() * 2.0 * Math.PI;
            double z = random.NextDouble() * 2.0 - 1.0;
            double root = Math.Sqrt(1.0 - z * z);

            return new Vector3D(root * Math.Cos(phi), root * Math.Sin(phi), z);
        }
        private void GenerateObject(MyProceduralCell cell, MyObjectSeed objectSeed, ref int index, MyRandom random, IMyModule densityFunctionFilled, IMyModule densityFunctionRemoved)
        {
            cell.AddObject(objectSeed);

            IMyAsteroidFieldDensityFunction func = objectSeed.UserData as IMyAsteroidFieldDensityFunction;
            if (func != null)
            {
                ChildrenAddDensityFunctionRemoved(func);
            }

            switch (objectSeed.Type)
            {
                case MyObjectSeedType.Moon:
                    break;
                case MyObjectSeedType.Planet:
                    m_tmpClusterBoxes.Add(objectSeed.BoundingVolume);

                    for (int i = 0; i < MOONS_MAX; ++i)
                    {
                        var direction = GetRandomDirection(random);
                        var size = MathHelper.Lerp(MOON_SIZE_MIN, MOON_SIZE_MAX, random.NextDouble());
                        var distance = MathHelper.Lerp(MOON_DISTANCE_MIN, MOON_DISTANCE_MAX, random.NextDouble());
                        var position = objectSeed.BoundingVolume.Center + direction * (size + objectSeed.BoundingVolume.HalfExtents.Length() * 2 + distance);

                        ProfilerShort.Begin("GetValue");
                        var value = densityFunctionFilled.GetValue(position.X, position.Y, position.Z);
                        ProfilerShort.End();

                        if (value < MOON_DENSITY) // -1..+1
                        {
                            var clusterObjectSeed = new MyObjectSeed(cell, position, size);
                            clusterObjectSeed.Seed = random.Next();
                            clusterObjectSeed.Type = MyObjectSeedType.Moon;
                            clusterObjectSeed.Index = index++;
                            clusterObjectSeed.UserData = new MySphereDensityFunction(position, OBJECT_SEED_RADIUS, OBJECT_SEED_RADIUS);

                            bool overlaps = false;
                            foreach (var box in m_tmpClusterBoxes)
                            {
                                if (overlaps |= clusterObjectSeed.BoundingVolume.Intersects(box))
                                {
                                    break;
                                }
                            }

                            if (!overlaps)
                            {
                                m_tmpClusterBoxes.Add(clusterObjectSeed.BoundingVolume);
                                GenerateObject(cell, clusterObjectSeed, ref index, random, densityFunctionFilled, densityFunctionRemoved);
                            }
                        }
                    }
                    m_tmpClusterBoxes.Clear();
                    break;
                case MyObjectSeedType.Empty:
                    break;
                default:
                    throw new InvalidBranchException();
                    break;
            }
        }