예제 #1
0
        public static void Process(MapMagic.CoordRect rect, Chunk.Results results, GeneratorsAsset gens, Chunk.Size terrainSize, Func <float, bool> stop = null)
        {
            if (stop != null && stop(0))
            {
                return;
            }

            Noise noise = new Noise(12345, permutationCount: 128);            //to pick objects based on biome

            List <TreeInstance>  instancesList  = new List <TreeInstance>();
            List <TreePrototype> prototypesList = new List <TreePrototype>();

            //find all of the biome masks - they will be used to determine object probability
            List <TupleSet <MadMapsTreeOutput, Matrix> > allGensMasks = new List <TupleSet <MadMapsTreeOutput, Matrix> >();

            foreach (MadMapsTreeOutput gen in gens.GeneratorsOfType <MadMapsTreeOutput>(onlyEnabled: true, checkBiomes: true))
            {
                Matrix biomeMask = null;
                if (gen.biome != null)
                {
                    object biomeMaskObj = gen.biome.mask.GetObject(results);
                    if (biomeMaskObj == null)
                    {
                        continue;                                           //adding nothing if biome has no mask
                    }
                    biomeMask = (Matrix)biomeMaskObj;
                    if (biomeMask == null)
                    {
                        continue;
                    }
                    if (biomeMask.IsEmpty())
                    {
                        continue;                                          //optimizing empty biomes
                    }
                }

                allGensMasks.Add(new TupleSet <MadMapsTreeOutput, Matrix>(gen, biomeMask));
            }
            int allGensMasksCount = allGensMasks.Count;

            //biome rect to find array pos faster
            MapMagic.CoordRect biomeRect = new MapMagic.CoordRect();
            for (int g = 0; g < allGensMasksCount; g++)
            {
                if (allGensMasks[g].item2 != null)
                {
                    biomeRect = allGensMasks[g].item2.rect; break;
                }
            }

            //prepare biome mask values stack to re-use it to find per-coord biome
            float[] biomeVals = new float[allGensMasksCount];             //+1 for not using any object at all

            //iterating all gens
            for (int g = 0; g < allGensMasksCount; g++)
            {
                MadMapsTreeOutput gen = allGensMasks[g].item1;

                //iterating in layers
                for (int b = 0; b < gen.baseLayers.Length; b++)
                {
                    if (stop != null && stop(0))
                    {
                        return;                                            //checking stop before reading output
                    }
                    Layer layer = gen.baseLayers[b];
//					if (layer.prefab == null) continue;

                    //loading objects from input
                    SpatialHash hash = (SpatialHash)gen.baseLayers[b].input.GetObject(results);
                    if (hash == null)
                    {
                        continue;
                    }

                    //adding prototype
//					if (layer.prefab == null) continue;
                    TreePrototype prototype = new TreePrototype()
                    {
                        prefab = layer.prefab, bendFactor = layer.bendFactor
                    };
                    prototypesList.Add(prototype);
                    int prototypeNum = prototypesList.Count - 1;

                    //filling instances (no need to check/add key in multidict)
                    foreach (SpatialObject obj in hash.AllObjs())
                    {
                        //blend biomes - calling continue if improper biome
                        if (biomeBlendType == BiomeBlendType.Sharp)
                        {
                            float biomeVal = 1;
                            if (allGensMasks[g].item2 != null)
                            {
                                biomeVal = allGensMasks[g].item2[obj.pos];
                            }
                            if (biomeVal < 0.5f)
                            {
                                continue;
                            }
                        }
                        else if (biomeBlendType == BiomeBlendType.AdditiveRandom)
                        {
                            float biomeVal = 1;
                            if (allGensMasks[g].item2 != null)
                            {
                                biomeVal = allGensMasks[g].item2[obj.pos];
                            }

                            float rnd = noise.Random((int)obj.pos.x, (int)obj.pos.y);

                            if (biomeVal > 0.5f)
                            {
                                rnd = 1 - rnd;
                            }

                            if (biomeVal < rnd)
                            {
                                continue;
                            }
                        }
                        else if (biomeBlendType == BiomeBlendType.NormalizedRandom)
                        {
                            //filling biome masks values
                            int pos = biomeRect.GetPos(obj.pos);

                            for (int i = 0; i < allGensMasksCount; i++)
                            {
                                if (allGensMasks[i].item2 != null)
                                {
                                    biomeVals[i] = allGensMasks[i].item2.array[pos];
                                }
                                else
                                {
                                    biomeVals[i] = 1;
                                }
                            }

                            //calculate normalized sum
                            float sum = 0;
                            for (int i = 0; i < biomeVals.Length; i++)
                            {
                                sum += biomeVals[i];
                            }
                            if (sum > 1)                             //note that if sum is <1 usedBiomeNum can exceed total number of biomes - it means that none object is used here
                            {
                                for (int i = 0; i < biomeVals.Length; i++)
                                {
                                    biomeVals[i] = biomeVals[i] / sum;
                                }
                            }

                            //finding used biome num
                            float rnd          = noise.Random((int)obj.pos.x, (int)obj.pos.y);
                            int   usedBiomeNum = biomeVals.Length;                           //none biome by default
                            sum = 0;
                            for (int i = 0; i < biomeVals.Length; i++)
                            {
                                sum += biomeVals[i];
                                if (sum > rnd)
                                {
                                    usedBiomeNum = i; break;
                                }
                            }

                            //disable object using biome mask
                            if (usedBiomeNum != g)
                            {
                                continue;
                            }
                        }
                        //scale mode is applied a bit later

                        //flooring
                        float terrainHeight = 0;
                        if (layer.relativeHeight && results.heights != null)                         //if checbox enabled and heights exist (at least one height generator is in the graph)
                        {
                            terrainHeight = results.heights.GetInterpolated(obj.pos.x, obj.pos.y);
                        }
                        if (terrainHeight > 1)
                        {
                            terrainHeight = 1;
                        }

                        TreeInstance tree = new TreeInstance();
                        tree.position = new Vector3(
                            (obj.pos.x - hash.offset.x) / hash.size,
                            obj.height + terrainHeight,
                            (obj.pos.y - hash.offset.y) / hash.size);
                        tree.rotation       = layer.rotate ? obj.rotation % 360 : 0;
                        tree.widthScale     = layer.widthScale ? obj.size : 1;
                        tree.heightScale    = layer.heightScale ? obj.size : 1;
                        tree.prototypeIndex = prototypeNum;
                        tree.color          = layer.color;
                        tree.lightmapColor  = layer.color;

                        if (biomeBlendType == BiomeBlendType.Scale)
                        {
                            float biomeVal = 1;
                            if (allGensMasks[g].item2 != null)
                            {
                                biomeVal = allGensMasks[g].item2[obj.pos];
                            }
                            if (biomeVal < 0.001f)
                            {
                                continue;
                            }
                            tree.widthScale  *= biomeVal;
                            tree.heightScale *= biomeVal;
                        }

                        instancesList.Add(tree);
                    }
                }
            }

            //setting output
            if (stop != null && stop(0))
            {
                return;
            }
            if (instancesList.Count == 0 && prototypesList.Count == 0)
            {
                return;                                                                    //empty, process is caused by height change
            }
            TupleSet <TreeInstance[], TreePrototype[]> treesTuple = new TupleSet <TreeInstance[], TreePrototype[]>(instancesList.ToArray(), prototypesList.ToArray());

            results.apply.CheckAdd(typeof(MadMapsTreeOutput), treesTuple, replace: true);
        }
예제 #2
0
        public static void Process(MapMagic.CoordRect rect, Chunk.Results results, GeneratorsAsset gens, Chunk.Size terrainSize, Func <float, bool> stop = null)
        {
            if (stop != null && stop(0))
            {
                return;
            }

            Noise noise = new Noise(12345, permutationCount: 128);            //to pick objects based on biome

            //preparing output
            Dictionary <Transform, List <ObjectPool.Transition> > transitions = new Dictionary <Transform, List <ObjectPool.Transition> >();

            //find all of the biome masks - they will be used to determine object probability
            List <TupleSet <MadMapsObjectOutput, Matrix> > allGensMasks = new List <TupleSet <MadMapsObjectOutput, Matrix> >();

            foreach (MadMapsObjectOutput gen in gens.GeneratorsOfType <MadMapsObjectOutput>(onlyEnabled: true, checkBiomes: true))
            {
                Matrix biomeMask = null;
                if (gen.biome != null)
                {
                    object biomeMaskObj = gen.biome.mask.GetObject(results);
                    if (biomeMaskObj == null)
                    {
                        continue;                                           //adding nothing if biome has no mask
                    }
                    biomeMask = (Matrix)biomeMaskObj;
                    if (biomeMask == null)
                    {
                        continue;
                    }
                    if (biomeMask.IsEmpty())
                    {
                        continue;                                          //optimizing empty biomes
                    }
                }

                allGensMasks.Add(new TupleSet <MadMapsObjectOutput, Matrix>(gen, biomeMask));
            }
            int allGensMasksCount = allGensMasks.Count;

            //biome rect to find array pos faster
            MapMagic.CoordRect biomeRect = new MapMagic.CoordRect();
            for (int g = 0; g < allGensMasksCount; g++)
            {
                if (allGensMasks[g].item2 != null)
                {
                    biomeRect = allGensMasks[g].item2.rect; break;
                }
            }

            //prepare biome mask values stack to re-use it to find per-coord biome
            float[] biomeVals = new float[allGensMasksCount];             //+1 for not using any object at all

            //iterating all gens
            for (int g = 0; g < allGensMasksCount; g++)
            {
                MadMapsObjectOutput gen = allGensMasks[g].item1;

                //iterating in layers
                for (int b = 0; b < gen.baseLayers.Length; b++)
                {
                    if (stop != null && stop(0))
                    {
                        return;                                            //checking stop before reading output
                    }
                    Layer layer = gen.baseLayers[b];
                    if (!layer.prefab)
                    {
                        continue;
                    }

                    //loading objects from input
                    SpatialHash hash = (SpatialHash)gen.baseLayers[b].input.GetObject(results);
                    if (hash == null)
                    {
                        continue;
                    }

                    //finding/creating proper transitions list
                    List <ObjectPool.Transition> transitionsList;
                    if (!transitions.ContainsKey(layer.prefab))
                    {
                        transitionsList = new List <ObjectPool.Transition>(); transitions.Add(layer.prefab, transitionsList);
                    }
                    else
                    {
                        transitionsList = transitions[layer.prefab];
                    }

                    //filling instances (no need to check/add key in multidict)
                    foreach (SpatialObject obj in hash.AllObjs())
                    {
                        //blend biomes - calling continue if improper biome
                        if (biomeBlendType == BiomeBlendType.Sharp)
                        {
                            float biomeVal = 1;
                            if (allGensMasks[g].item2 != null)
                            {
                                biomeVal = allGensMasks[g].item2[obj.pos];
                            }
                            if (biomeVal < 0.5f)
                            {
                                continue;
                            }
                        }
                        else if (biomeBlendType == BiomeBlendType.AdditiveRandom)
                        {
                            float biomeVal = 1;
                            if (allGensMasks[g].item2 != null)
                            {
                                biomeVal = allGensMasks[g].item2[obj.pos];
                            }

                            float rnd = noise.Random((int)obj.pos.x, (int)obj.pos.y);

                            if (biomeVal > 0.5f)
                            {
                                rnd = 1 - rnd;
                            }

                            if (biomeVal < rnd)
                            {
                                continue;
                            }
                        }
                        else if (biomeBlendType == BiomeBlendType.NormalizedRandom)
                        {
                            //filling biome masks values
                            int pos = biomeRect.GetPos(obj.pos);

                            for (int i = 0; i < allGensMasksCount; i++)
                            {
                                if (allGensMasks[i].item2 != null)
                                {
                                    biomeVals[i] = allGensMasks[i].item2.array[pos];
                                }
                                else
                                {
                                    biomeVals[i] = 1;
                                }
                            }

                            //calculate normalized sum
                            float sum = 0;
                            for (int i = 0; i < biomeVals.Length; i++)
                            {
                                sum += biomeVals[i];
                            }
                            if (sum > 1)                             //note that if sum is <1 usedBiomeNum can exceed total number of biomes - it means that none object is used here
                            {
                                for (int i = 0; i < biomeVals.Length; i++)
                                {
                                    biomeVals[i] = biomeVals[i] / sum;
                                }
                            }

                            //finding used biome num
                            float rnd          = noise.Random((int)obj.pos.x, (int)obj.pos.y);
                            int   usedBiomeNum = biomeVals.Length;                           //none biome by default
                            sum = 0;
                            for (int i = 0; i < biomeVals.Length; i++)
                            {
                                sum += biomeVals[i];
                                if (sum > rnd)
                                {
                                    usedBiomeNum = i; break;
                                }
                            }

                            //disable object using biome mask
                            if (usedBiomeNum != g)
                            {
                                continue;
                            }
                        }
                        //scale mode is applied a bit later


                        //flooring
                        float terrainHeight = 0;
                        //if (layer.relativeHeight && results.heights != null) //if checbox enabled and heights exist (at least one height generator is in the graph)
                        //	terrainHeight = results.heights.GetInterpolated(obj.pos.x, obj.pos.y);
                        //if (terrainHeight > 1) terrainHeight = 1;


                        //world-space object position
                        Vector3 position = new Vector3(
                            (obj.pos.x) / hash.size * terrainSize.dimensions,                              // relative (0-1) position * terrain dimension
                            (obj.height + terrainHeight) * terrainSize.height,
                            (obj.pos.y) / hash.size * terrainSize.dimensions);

                        //rotation + taking terrain normal
                        Quaternion rotation;
                        float      objRotation = layer.rotate ? obj.rotation % 360 : 0;
                        if (layer.takeTerrainNormal)
                        {
                            Vector3 terrainNormal = GetTerrainNormal(obj.pos.x, obj.pos.y, results.heights, terrainSize.height, terrainSize.pixelSize);
                            Vector3 sideVector    = new Vector3(Mathf.Sin((obj.rotation + 90) * Mathf.Deg2Rad), 0, Mathf.Cos((obj.rotation + 90) * Mathf.Deg2Rad));
                            Vector3 frontVector   = Vector3.Cross(sideVector, terrainNormal);
                            rotation = Quaternion.LookRotation(frontVector, terrainNormal);
                        }
                        else
                        {
                            rotation = objRotation.EulerToQuat();
                        }

                        //scale + biome scale mode
                        Vector3 scale = layer.scale ? new Vector3(layer.scaleY ? 1 : obj.size, obj.size, layer.scaleY ? 1 : obj.size) : Vector3.one;

                        if (biomeBlendType == BiomeBlendType.Scale)
                        {
                            float biomeVal = 1;
                            if (allGensMasks[g].item2 != null)
                            {
                                biomeVal = allGensMasks[g].item2[obj.pos];
                            }
                            if (biomeVal < 0.001f)
                            {
                                continue;
                            }
                            scale *= biomeVal;
                        }

                        transitionsList.Add(new ObjectPool.Transition()
                        {
                            pos = position, rotation = rotation, scale = scale
                        });
                    }
                }
            }

            //queue apply
            if (stop != null && stop(0))
            {
                return;
            }
            results.apply.CheckAdd(typeof(MadMapsObjectOutput), transitions, replace: true);
        }
예제 #3
0
        public void Process(CoordRect rect, Chunk.Results results, GeneratorsAsset gens, Chunk.Size terrainSize, Func <float, bool> stop = null)
        {
                        #if VEGETATION_STUDIO
            if (stop != null && stop(0))
            {
                return;
            }
            Noise noise = new Noise(12345, permutationCount: 128);            //to pick objects based on biome

            if (stop != null && stop(0))
            {
                return;
            }

            List <VegetationStudioInstance> instances = new List <VegetationStudioInstance>();
            //object outputs
            foreach (MadMapsVSOutput gen in gens.GeneratorsOfType <MadMapsVSOutput>(onlyEnabled:true, checkBiomes:true))
            {
                //gen biome mask
                Matrix biomeMask = null;
                if (gen.biome != null)
                {
                    object biomeMaskObj = gen.biome.mask.GetObject(results);
                    if (biomeMaskObj == null)
                    {
                        continue;                                           //adding nothing if biome has no mask
                    }
                    biomeMask = (Matrix)biomeMaskObj;
                    if (biomeMask == null)
                    {
                        continue;
                    }
                    if (biomeMask.IsEmpty())
                    {
                        continue;                                          //optimizing empty biomes
                    }
                }

                //iterating in layers
                for (int b = 0; b < gen.layers.Length; b++)
                {
                    if (stop != null && stop(0))
                    {
                        return;                                            //checking stop before reading output
                    }
                    Layer layer = gen.layers[b];

                    string id = gen.package.VegetationInfoList[b].VegetationItemID;


                    //objects layer
                    if (layer.type == Layer.Type.Object)
                    {
                        //loading objects from input
                        SpatialHash hash = (SpatialHash)gen.layers[b].objInput.GetObject(results);
                        if (hash == null)
                        {
                            continue;
                        }

                        //filling instances (no need to check/add key in multidict)
                        foreach (SpatialObject obj in hash.AllObjs())
                        {
                            //skipping on biome not used
                            float biomeFactor = 0;
                            if (gen.biome == null)
                            {
                                biomeFactor = 1;
                            }
                            else if (biomeMask != null)
                            {
                                biomeFactor = biomeMask.GetInterpolated(obj.pos.x, obj.pos.y);
                            }
                            if (biomeFactor < 0.00001f)
                            {
                                continue;
                            }

                            float rnd;
                            switch (biomeBlendType)
                            {
                            case ObjectOutput.BiomeBlendType.Sharp: rnd = 0.5f; break;

                            case ObjectOutput.BiomeBlendType.AdditiveRandom:
                            case ObjectOutput.BiomeBlendType.NormalizedRandom:
                                rnd = noise.Random((int)obj.pos.x, (int)obj.pos.y);
                                if (biomeFactor > 0.5f)
                                {
                                    rnd = 1 - rnd;                                                           //test
                                }
                                break;

                            case ObjectOutput.BiomeBlendType.Scale: rnd = 0.0f; break;

                            default: rnd = 0.5f; break;
                            }

                            if (biomeFactor < rnd)
                            {
                                continue;
                            }

                            //flooring
                            float terrainHeight = 0;

                            /*if (layer.relativeHeight && results.heights != null) //if checbox enabled and heights exist (at least one height generator is in the graph)
                             *      terrainHeight = results.heights.GetInterpolated(obj.pos.x, obj.pos.y);
                             * if (terrainHeight > 1) terrainHeight = 1;*/


                            //terrain-space object position
                            Vector3 position = new Vector3(
                                (obj.pos.x - hash.offset.x) / hash.size,
                                (obj.height + terrainHeight) * terrainSize.height,
                                (obj.pos.y - hash.offset.y) / hash.size);


                            //rotation + taking terrain normal
                            Quaternion rotation;
                            float      objRotation = layer.rotate ? obj.rotation % 360 : 0;
                            if (layer.takeTerrainNormal)
                            {
                                Vector3 terrainNormal = ObjectOutput.GetTerrainNormal(obj.pos.x, obj.pos.y, results.heights, terrainSize.height, terrainSize.pixelSize);
                                Vector3 sideVector    = new Vector3(Mathf.Sin((obj.rotation + 90) * Mathf.Deg2Rad), 0, Mathf.Cos((obj.rotation + 90) * Mathf.Deg2Rad));
                                Vector3 frontVector   = Vector3.Cross(sideVector, terrainNormal);
                                rotation = Quaternion.LookRotation(frontVector, terrainNormal);
                            }
                            else
                            {
                                rotation = objRotation.EulerToQuat();
                            }

                            //scale + biome scale mode
                            Vector3 scale = layer.scale ? new Vector3(layer.scaleY ? 1 : obj.size, obj.size, layer.scaleY ? 1 : obj.size) : Vector3.one;

                            if (biomeBlendType == ObjectOutput.BiomeBlendType.Scale && gen.biome != null)
                            {
                                float biomeVal = 1;
                                if (biomeMask != null)
                                {
                                    biomeVal = biomeMask[obj.pos];
                                }
                                if (biomeVal < 0.001f)
                                {
                                    continue;                                                     //skip zero-scaled objects
                                }
                                scale *= biomeVal;
                            }

                            instances.Add(new VegetationStudioInstance()
                            {
                                VSID     = id,
                                Guid     = System.Guid.NewGuid().ToString(),
                                Package  = package,
                                Position = position,
                                Scale    = scale,
                                Rotation = rotation.eulerAngles,
                            });
                        }

                        if (stop != null && stop(0))
                        {
                            return;
                        }
                    }

                    int cellXCount = Mathf.CeilToInt(terrainSize.dimensions / cellSize);
                    int cellZCount = Mathf.CeilToInt(terrainSize.dimensions / cellSize);
                    //map outputs
                    if (layer.type == Layer.Type.Map)
                    {
                        //reading output directly
                        //Output output = gen.layers[b].output;
                        //if (stop!=null && stop(0)) return; //checking stop before reading output
                        //if (!results.results.ContainsKey(output)) continue;
                        //Matrix matrix = (Matrix)results.results[output];

                        //loading from input
                        if (stop != null && stop(0))
                        {
                            return;
                        }
                        Matrix matrix = (Matrix)gen.layers[b].mapInput.GetObject(results);
                        if (matrix == null)
                        {
                            continue;
                        }
                        Matrix heights = results.heights;                         //get heights before the chunk is removed

                        //setting bush by bush using the sample dist
                        float sampleDist = 1f / layer.density;

                        //filling
                        //float terrainPosX = 1f*rect.offset.x/terrainSize.resolution*terrainSize.dimensions;
                        //float terrainPosZ = 1f*rect.offset.z/terrainSize.resolution*terrainSize.dimensions;



                        for (int cx = 0; cx <= cellXCount - 1; cx++)
                        {
                            for (int cz = 0; cz <= cellZCount - 1; cz++)
                            {
                                //Vector3 cellCorner = new Vector3(terrainPosX + (cellSize * cx), 0, terrainPosZ + (cellSize * cz));
                                //PersistentVegetationCell cell = storage.PersistentVegetationStoragePackage.PersistentVegetationCellList[cz + cx*cellXCount];

                                for (float x = 0; x < cellSize; x += sampleDist)
                                {
                                    for (float z = 0; z < cellSize; z += sampleDist)
                                    {
                                        //world position
                                        float wx = cellSize * cx + x;
                                        float wz = cellSize * cz + z;

                                        //randomizing position
                                        wx += noise.Random((int)(wx * 10), (int)(wz * 10), 2) * sampleDist - sampleDist / 2;
                                        wz += noise.Random((int)(wx * 10), (int)(wz * 10), 3) * sampleDist - sampleDist / 2;

                                        //map position
                                        float mx = wx / terrainSize.dimensions * rect.size.x + rect.offset.x;                                    // relative (0-1) position * terrain res
                                        float mz = wz / terrainSize.dimensions * rect.size.z + rect.offset.z;

                                        float val = matrix.GetInterpolated(mx, mz);

                                        float biomeFactor = 0;
                                        if (gen.biome == null)
                                        {
                                            biomeFactor = 1;
                                        }
                                        else if (biomeMask != null)
                                        {
                                            biomeFactor = biomeMask.GetInterpolated(mx, mz);
                                        }

                                        //placing object
                                        float rnd = (noise.Random((int)(wx * 10), (int)(wz * 10)));
                                        if (rnd < val * biomeFactor)
                                        {
                                            //float terrainHeight = heights.GetInterpolated(mx,mz) * terrainSize.height;

                                            //rotation + taking terrain normal
                                            Quaternion rotation;
                                            float      rotRnd      = noise.Random((int)(wx * 10), (int)(wz * 10), 1);
                                            float      objRotation = layer.rotate ? rotRnd * 360 : 0;
                                            if (layer.takeTerrainNormal)
                                            {
                                                Vector3 terrainNormal = ObjectOutput.GetTerrainNormal(mx, mz, heights, terrainSize.height, terrainSize.pixelSize);
                                                Vector3 sideVector    = new Vector3(Mathf.Sin((objRotation + 90) * Mathf.Deg2Rad), 0, Mathf.Cos((objRotation + 90) * Mathf.Deg2Rad));
                                                Vector3 frontVector   = Vector3.Cross(sideVector, terrainNormal);
                                                rotation = Quaternion.LookRotation(frontVector, terrainNormal);
                                            }
                                            else
                                            {
                                                rotation = objRotation.EulerToQuat();
                                            }

                                            //scale
                                            float rndScale = noise.Random((int)(wx * 10), (int)(wz * 10), 1);
                                            rndScale = layer.scaleMinMax.x + (layer.scaleMinMax.y - layer.scaleMinMax.x) * rndScale;
                                            Vector3 scale = new Vector3(rndScale, rndScale, rndScale);

                                            //storage.AddVegetationItemInstance(id, new Vector3(wx,terrainHeight,wz), scale, rotation, layer.applyMeshRotation, VS_MM_id, true);
                                            //cell.AddVegetationItemInstance(id, new Vector3(wx,terrainHeight,wz), scale, rotation, VS_MM_id);
                                            var position = new Vector3(mx, 0, mz);
                                            instances.Add(new VegetationStudioInstance()
                                            {
                                                VSID     = id,
                                                Guid     = System.Guid.NewGuid().ToString(),
                                                Package  = package,
                                                Position = position,
                                                Scale    = scale,
                                                Rotation = rotation.eulerAngles,
                                            });
                                        }
                                    }
                                }

                                if (stop != null && stop(0))
                                {
                                    return;
                                }
                            }
                        }
                    }
                }
            }

            //refreshing billboards
            //calling it from thread ruins all the billboards
            //BillboardSystem billboardSys = billboardComponents[rect];
            //if (billboardSys != null)
            //	 billboardSys.RefreshBillboards();
                        #endif

            //pushing anything to apply
            if (stop != null && stop(0))
            {
                return;
            }
            results.apply.CheckAdd(typeof(MadMapsVSOutput), instances, replace: true);
        }