Пример #1
0
        protected override float Value2D(Vector3 point, NoiseStruct noiseStruct)
        {
            point *= noiseStruct.frequency;
            //Calculate Integer Lattice Points and interpolants t
            int i0X = Mathf.FloorToInt(point.x);
            int i0Y = Mathf.FloorToInt(point.y);
            var t0  = new Vector2(point.x - i0X, point.y - i0Y);

            i0X &= HashMask;
            i0Y &= HashMask;
            int i1X = i0X + 1;
            int i1Y = i0Y + 1;

            int h0  = NoiseUtils.PerlinHash[i0X];
            int h1  = NoiseUtils.PerlinHash[i1X];
            int h00 = NoiseUtils.PerlinHash[h0 + i0Y];
            int h01 = NoiseUtils.PerlinHash[h0 + i1Y];
            int h10 = NoiseUtils.PerlinHash[h1 + i0Y];
            int h11 = NoiseUtils.PerlinHash[h1 + i1Y];

            t0.x = NoiseUtils.Splerp(ref noiseStruct.splerp, 0f, 1f, t0.x);
            t0.y = NoiseUtils.Splerp(ref noiseStruct.splerp, 0f, 1f, t0.y);
            return
                (Mathf.Lerp(Mathf.Lerp(h00, h10, t0.x),
                            Mathf.Lerp(h01, h11, t0.x), t0.y) * (1f / HashMask));
        }
Пример #2
0
    private void GenerateResources(NoiseConfig noiseConfig)
    {
        noiseMap = NoiseUtils.GenerateNoiseMap(width, height, noiseConfig);

        for (int x = 0; x < noiseMap.GetLength(0); x++)
        {
            for (int z = 0; z < noiseMap.GetLength(1); z++)
            {
                if (tiles[x, z] != TileType.Empty)
                {
                    continue;
                }
                else if (MathUtils.InRange(Settings.World_Gen_CopperNoiseRangeFrom, Settings.World_Gen_CopperNoiseRangeTo, noiseMap[x, z]))
                {
                    SetTile(x, z, TileType.CopperNode);
                }
                else if (MathUtils.InRange(Settings.World_Gen_IronNoiseRangeFrom, Settings.World_Gen_IronNoiseRangeTo, noiseMap[x, z]))
                {
                    SetTile(x, z, TileType.IronNode);
                }
                else if (MathUtils.InRange(Settings.World_Gen_FoodNoiseRangeFrom, Settings.World_Gen_FoodNoiseRangeTo, noiseMap[x, z]))
                {
                    SetTile(x, z, TileType.FoodNode);
                }
                //else
                //Debug.Log("Wierd noise value: " + noiseMap[x, y]);
            }
        }
    }
Пример #3
0
    private Block.BlockType GetBlockType(int worldX, int worldY, int worldZ)
    {
        Block.BlockType blockType;
        if (worldY <= NoiseUtils.GenerateStoneHeight(worldX, worldZ))
        {
            if (NoiseUtils.FractalBrownianMotion3D(worldX, worldY, worldZ, 0.1f, 2) < 0.42f)
            {
                blockType = Block.BlockType.DIAMOND;
            }
            else
            {
                blockType = Block.BlockType.STONE;
            }
        }
        else if (worldY < NoiseUtils.GenerateHeight(worldX, worldZ))
        {
            blockType = Block.BlockType.DIRT;
        }
        else if (worldY == NoiseUtils.GenerateHeight(worldX, worldZ))
        {
            blockType = Block.BlockType.GRASS;
        }
        else
        {
            blockType = Block.BlockType.AIR;
        }

        // for now stub this
        //blockType = (Random.Range(0, 100) < 50 ? Block.BlockType.GRASS : Block.BlockType.AIR);
        return(blockType);
    }
Пример #4
0
    public void Initialize(int width, int height)
    {
        this.width  = width;
        this.height = height;
        tileInfectionGameObjects = new GameObject[width, height];
        maxInfectionNoiseMap     = NoiseUtils.GenerateNoiseMap(width, height, 0.12f);

        WorldTickController.instance.OnTick += Tick;
    }
 /// <summary>
 /// Applies the filter.
 /// </summary>
 public void ApplyFilter()
 {
     for (int z = 0; z < Level.CWMap.Size.z; z++)
     {
         for (int x = 0; x < Level.CWMap.Size.x; x++)
         {
             map[x, z] = NoiseUtils.GetAverage9(map, x, z);
         }
     }
 }
Пример #6
0
    int GetSurfaceY(Vector3 worldPosition)
    {
        int stoneHeight = NoiseUtils.GenerateStoneHeight(worldPosition.x, worldPosition.z);
        int grassHeight = NoiseUtils.GenerateHeight(worldPosition.x, worldPosition.z);

        if (grassHeight > stoneHeight)
        {
            return(grassHeight);
        }
        return(stoneHeight);
    }
Пример #7
0
        public override void PreProcess(Chunk chunk, int layerIndex)
        {
            LocalPools pools = Globals.WorkPool.GetPool(chunk.ThreadID);
            NoiseItem  ni    = pools.noiseItems[layerIndex];

            ni.noiseGen.SetInterpBitStep(Env.CHUNK_SIZE_WITH_PADDING, 2);
            ni.lookupTable = pools.floatArrayPool.Pop((ni.noiseGen.Size + 1) * (ni.noiseGen.Size + 1));

#if (UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN) && ENABLE_FASTSIMD
            float[] noiseSet = pools.floatArrayPool.Pop(ni.noiseGen.Size * ni.noiseGen.Size * ni.noiseGen.Size);

            // Generate SIMD noise
            int   offsetShift   = Env.CHUNK_POW - ni.noiseGen.Step;
            int   xStart        = (chunk.Pos.x * Env.CHUNK_SIZE) << offsetShift;
            int   yStart        = (chunk.Pos.y * Env.CHUNK_SIZE) << offsetShift;
            int   zStart        = (chunk.Pos.z * Env.CHUNK_SIZE) << offsetShift;
            float scaleModifier = 1 << ni.noiseGen.Step;
            noiseSIMD.Noise.FillNoiseSet(noiseSet, xStart, yStart, zStart, ni.noiseGen.Size, ni.noiseGen.Size, ni.noiseGen.Size, scaleModifier);

            // Generate a lookup table
            int i = 0;
            for (int z = 0; z < ni.noiseGen.Size; z++)
            {
                for (int x = 0; x < ni.noiseGen.Size; x++)
                {
                    ni.lookupTable[i++] = NoiseUtilsSIMD.GetNoise(noiseSet, ni.noiseGen.Size, x, 0, z, amplitude, noise.Gain);
                }
            }

            pools.floatArrayPool.Push(noiseSet);
#else
            int xOffset = chunk.Pos.x;
            int zOffset = chunk.Pos.z;

            // Generate a lookup table
            int i = 0;
            for (int z = 0; z < ni.noiseGen.Size; z++)
            {
                float zf = (z << ni.noiseGen.Step) + zOffset;

                for (int x = 0; x < ni.noiseGen.Size; x++)
                {
                    float xf = (x << ni.noiseGen.Step) + xOffset;
                    ni.lookupTable[i++] = NoiseUtils.GetNoise(noise.Noise, xf, 0, zf, 1f, amplitude, noise.Gain);
                }
            }
#endif
        }
Пример #8
0
        protected override float Value1D(Vector3 point, NoiseStruct noiseStruct)
        {
            point *= noiseStruct.frequency;
            //Calculate Integer Lattice Points and interpolants t
            int   i0X = Mathf.FloorToInt(point.x);
            float t   = point.x - i0X;

            i0X &= HashMask;
            int i1X = i0X + 1;

            int h0 = NoiseUtils.PerlinHash[i0X];
            int h1 = NoiseUtils.PerlinHash[i1X];

            t = NoiseUtils.Splerp(ref noiseStruct.splerp, 0f, 1f, t);
            return(Mathf.Lerp(h0, h1, t) * (1f / HashMask));
        }
        /// <summary>
        /// Sets the blocks.
        /// </summary>
        public void SetBlocks()
        {
            for (int i = 0; i < overlay.Length - 1; i++)
            {
                int x = i % (Level.CWMap.Size.x);
                int z = i / (Level.CWMap.Size.x);
                int y = (int)NoiseUtils.Range(overlay[x, z],
                                              (int)GenArgs.MinLevelGenerationHeight - NoiseUtils.NegateEdge(x, z, Level.CWMap.Size.x, Level.CWMap.Size.z),
                                              (int)GenArgs.MaxLevelGenerationHeight - NoiseUtils.NegateEdge(x, z, Level.CWMap.Size.x, Level.CWMap.Size.z));


                if (x >= Level.CWMap.Size.x || y >= Level.CWMap.Size.y || z >= Level.CWMap.Size.z)
                {
                    continue;
                }



                Level.SetBlock(x, z, y, GenArgs.TopLayer);
                if (y > 0)
                {
                    Level.SetBlock(x, z, y - 1, GenArgs.TopLayer);
                }

                for (int toGround = y - 1; toGround >= GenArgs.MinLevelGenerationHeight; toGround--)
                {
                    Level.SetBlock(x, z, toGround, GenArgs.BottomLayer);
                }

                if (y <= GenArgs.LiquidLine)
                {
                    for (int toGround = (int)GenArgs.LiquidLine; toGround >= 0; toGround--)
                    {
                        if (Level.GetBlock(x, z, toGround) == 0)
                        {
                            Level.SetBlock(x, z, toGround, GenArgs.LiquidBlock);
                        }
                    }
                }
            }
        }
Пример #10
0
        protected override float Value2D(Vector3 point, NoiseStruct noiseStruct)
        {
            point *= noiseStruct.frequency;
            //Calculate Integer Lattice Points and interpolants t
            int i0X = Mathf.FloorToInt(point.x);
            int i0Y = Mathf.FloorToInt(point.y);

            var t0 = new Vector2(point.x - i0X, point.y - i0Y);
            var t1 = new Vector2(t0.x - 1f, t0.y - 1f);

            i0X &= NoiseUtils.HashMask;
            i0Y &= NoiseUtils.HashMask;
            int i1X = i0X + 1;
            int i1Y = i0Y + 1;

            int h0  = NoiseUtils.PerlinHash[i0X];
            int h1  = NoiseUtils.PerlinHash[i1X];
            int h00 = NoiseUtils.PerlinHash[h0 + i0Y];
            int h01 = NoiseUtils.PerlinHash[h0 + i1Y];
            int h10 = NoiseUtils.PerlinHash[h1 + i0Y];
            int h11 = NoiseUtils.PerlinHash[h1 + i1Y];

            var g00 = NoiseUtils.Gradients2D[h00 & NoiseUtils.GradientsMask2D];
            var g01 = NoiseUtils.Gradients2D[h01 & NoiseUtils.GradientsMask2D];
            var g10 = NoiseUtils.Gradients2D[h10 & NoiseUtils.GradientsMask2D];
            var g11 = NoiseUtils.Gradients2D[h11 & NoiseUtils.GradientsMask2D];

            float v00 = Vector2.Dot(g00, new Vector2(t0.x, t0.y));
            float v01 = Vector2.Dot(g01, new Vector2(t0.x, t1.y));
            float v10 = Vector2.Dot(g10, new Vector2(t1.x, t0.y));
            float v11 = Vector2.Dot(g11, new Vector2(t1.x, t1.y));

            //t0.x = NoiseUtils.Splerp(ref noiseStruct.splerp, 0f, 1f, t0.x);
            //t0.y = NoiseUtils.Splerp(ref noiseStruct.splerp, 0f, 1f, t0.y);
            t0.x = NoiseUtils.SmootherStep(t0.x);
            t0.y = NoiseUtils.SmootherStep(t0.y);
            return
                (Mathf.Lerp(Mathf.Lerp(v00, v10, t0.x),
                            Mathf.Lerp(v01, v11, t0.x), t0.y) * NoiseUtils.Sqr2);
        }
Пример #11
0
    public void CalculateChunkData(int chunkSize, int chunkHeight, int seed)
    {
        chunkData = new Block[chunkSize, chunkHeight, chunkSize];

        //create blocks
        for (int x = 0; x < chunkSize; x++)
        {
            for (int y = 0; y < chunkHeight; y++)
            {
                for (int z = 0; z < chunkSize; z++)
                {
                    Vector3 pos = new Vector3(x, y, z);

                    int worldX = x + (int)chunk.transform.position.x;
                    int worldY = y + (int)chunk.transform.position.y;
                    int worldZ = z + (int)chunk.transform.position.z;

                    int baseSurfaceHeight = NoiseUtils.GenerateHeight(worldX, worldZ, seed);

                    // generate surface terrain
                    if (worldY <= baseSurfaceHeight - 5)
                    {
                        chunkData[x, y, z] = new Block(Block.BlockType.STONE, pos, chunk, this);
                    }
                    else if (worldY == baseSurfaceHeight)
                    {
                        chunkData[x, y, z] = new Block(Block.BlockType.GRASS, pos, chunk, this);
                    }
                    else if (worldY < baseSurfaceHeight)
                    {
                        chunkData[x, y, z] = new Block(Block.BlockType.DIRT, pos, chunk, this);
                    }
                    else
                    {
                        chunkData[x, y, z] = new Block(Block.BlockType.AIR, pos, chunk, this);
                    }
                }
            }
        }
    }
Пример #12
0
        protected override float Value1D(Vector3 point, NoiseStruct noiseStruct)
        {
            point *= noiseStruct.frequency;
            //Calculate Integer Lattice Points and interpolants t
            int   i0X = Mathf.FloorToInt(point.x);
            float t0  = point.x - i0X;
            float t1  = t0 - 1f;

            i0X &= NoiseUtils.HashMask;
            int i1X = i0X + 1;

            int h0 = NoiseUtils.PerlinHash[i0X];
            int h1 = NoiseUtils.PerlinHash[i1X];

            float g0 = NoiseUtils.Gradients1D[h0 & NoiseUtils.GradientsMask1D];
            float g1 = NoiseUtils.Gradients1D[h1 & NoiseUtils.GradientsMask1D];

            float v0 = g0 * t0;
            float v1 = g1 * t1;

            //t0 = NoiseUtils.Splerp(ref noiseStruct.splerp, 0f, 1f, t0);
            t0 = NoiseUtils.SmootherStep(t0);
            return(Mathf.Lerp(v0, v1, t0) * 2f);
        }
Пример #13
0
        /// <summary>
        /// Generates the map.
        /// </summary>
        public void Generate()
        {
            if (Level == null)
            {
                throw new NullReferenceException("Level to generate was null");
            }

            if (OnProgressArgs != null)
            {
                OnProgressArgs(this, new GenerationEventArgs("Creating Dimentions...", 10));
            }

            NoiseGenerator = new PerlinNoise()
            {
                Amplitude   = GenArgs.Amplitude,
                Frequency   = GenArgs.WaveFrequency,
                Octaves     = GenArgs.MoutainOctaves,
                Persistence = GenArgs.Persistence
            };

            NoiseGenerator.InitNoiseFunctions();
            map     = new float[Level.CWMap.Size.x, Level.CWMap.Size.z];
            overlay = new float[Level.CWMap.Size.x, Level.CWMap.Size.z];

            if (GenArgs.PlantMushrooms || GenArgs.PlantFlowers || GenArgs.PlantSaplings)
            {
                plants = new float[Level.CWMap.Size.x, Level.CWMap.Size.z];
            }


            if (OnProgressArgs != null)
            {
                OnProgressArgs(this, new GenerationEventArgs("Building...", 20));
            }
            Generate3DTerrain();

            if (OnProgressArgs != null)
            {
                OnProgressArgs(this, new GenerationEventArgs("Raking...", 10));
            }
            ApplyFilter();

            if (OnProgressArgs != null)
            {
                OnProgressArgs(this, new GenerationEventArgs("Creating Moutains...", 20));
            }
            GenerateNoise();


            if (OnProgressArgs != null)
            {
                OnProgressArgs(this, new GenerationEventArgs("Cleaning Moutains..", 10));
            }
            NoiseUtils.Normalize(map);

            if (OnProgressArgs != null)
            {
                OnProgressArgs(this, new GenerationEventArgs("Setting blocks...", 20));
            }
            SetBlocks();

            if (OnProgressArgs != null)
            {
                OnProgressArgs(this, new GenerationEventArgs("Planting..", 20));
            }
            SetPlants();


            if (OnProgressArgs != null)
            {
                OnProgressArgs(this, new GenerationEventArgs("Created map " + Level.Name, 10));
            }
            Finalize();
        }
Пример #14
0
        protected override float Value3D(Vector3 point, NoiseStruct noiseStruct)
        {
            point *= noiseStruct.frequency;
            //Calculate Integer Lattice Points and interpolants t
            int i0X = Mathf.FloorToInt(point.x);
            int i0Y = Mathf.FloorToInt(point.y);
            int i0Z = Mathf.FloorToInt(point.z);
            //Get point relative to wavelet center
            var t0 = new Vector3(point.x - i0X, point.y - i0Y, point.z - i0Z);
            var t1 = new Vector3(t0.x - 1f, t0.y - 1f, t0.z - 1f);

            i0X &= NoiseUtils.HashMask;
            i0Y &= NoiseUtils.HashMask;
            i0Z &= NoiseUtils.HashMask;
            int i1X = i0X + 1;
            int i1Y = i0Y + 1;
            int i1Z = i0Z + 1;

            // Fold x,y,z using permuation table
            int h0   = NoiseUtils.PerlinHash[i0X];
            int h1   = NoiseUtils.PerlinHash[i1X];
            int h00  = NoiseUtils.PerlinHash[h0 + i0Y];
            int h01  = NoiseUtils.PerlinHash[h0 + i1Y];
            int h10  = NoiseUtils.PerlinHash[h1 + i0Y];
            int h11  = NoiseUtils.PerlinHash[h1 + i1Y];
            int h000 = NoiseUtils.PerlinHash[h00 + i0Z];
            int h001 = NoiseUtils.PerlinHash[h00 + i1Z];
            int h010 = NoiseUtils.PerlinHash[h01 + i0Z];
            int h011 = NoiseUtils.PerlinHash[h01 + i1Z];
            int h100 = NoiseUtils.PerlinHash[h10 + i0Z];
            int h101 = NoiseUtils.PerlinHash[h10 + i1Z];
            int h110 = NoiseUtils.PerlinHash[h11 + i0Z];
            int h111 = NoiseUtils.PerlinHash[h11 + i1Z];

            var g000 = NoiseUtils.Gradients3D[h000 & NoiseUtils.GradientsMask3D];
            var g001 = NoiseUtils.Gradients3D[h001 & NoiseUtils.GradientsMask3D];
            var g010 = NoiseUtils.Gradients3D[h010 & NoiseUtils.GradientsMask3D];
            var g011 = NoiseUtils.Gradients3D[h011 & NoiseUtils.GradientsMask3D];
            var g100 = NoiseUtils.Gradients3D[h100 & NoiseUtils.GradientsMask3D];
            var g101 = NoiseUtils.Gradients3D[h101 & NoiseUtils.GradientsMask3D];
            var g110 = NoiseUtils.Gradients3D[h110 & NoiseUtils.GradientsMask3D];
            var g111 = NoiseUtils.Gradients3D[h111 & NoiseUtils.GradientsMask3D];

            float v000 = Vector3.Dot(g000, new Vector3(t0.x, t0.y, t0.z));
            float v001 = Vector3.Dot(g001, new Vector3(t0.x, t0.y, t1.z));
            float v010 = Vector3.Dot(g010, new Vector3(t0.x, t1.y, t0.z));
            float v011 = Vector3.Dot(g011, new Vector3(t0.x, t1.y, t1.z));
            float v100 = Vector3.Dot(g100, new Vector3(t1.x, t0.y, t0.z));
            float v101 = Vector3.Dot(g101, new Vector3(t1.x, t0.y, t1.z));
            float v110 = Vector3.Dot(g110, new Vector3(t1.x, t1.y, t0.z));
            float v111 = Vector3.Dot(g111, new Vector3(t1.x, t1.y, t1.z));

            //t0.x = NoiseUtils.Splerp(ref noiseStruct.splerp, 0f, 1f, t0.x);
            //t0.y = NoiseUtils.Splerp(ref noiseStruct.splerp, 0f, 1f, t0.y);
            //t0.z = NoiseUtils.Splerp(ref noiseStruct.splerp, 0f, 1f, t0.z);

            //Compute the dropoff
            t0.x = NoiseUtils.SmootherStep(t0.x);
            t0.y = NoiseUtils.SmootherStep(t0.y);
            t0.z = NoiseUtils.SmootherStep(t0.z);
            return(Mathf.Lerp(
                       Mathf.Lerp(Mathf.Lerp(v000, v100, t0.x),
                                  Mathf.Lerp(v010, v110, t0.x), t0.y),
                       Mathf.Lerp(Mathf.Lerp(v001, v101, t0.x),
                                  Mathf.Lerp(v011, v111, t0.x), t0.y),
                       t0.z));
        }
Пример #15
0
    public override void Build(Chunk chunk, int id, ref Vector3Int worldPos, TerrainLayer layer)
    {
        World world = chunk.world;

        int noise =
            Helpers.FastFloor(NoiseUtils.GetNoise(layer.Noise.Noise, worldPos.x, worldPos.y, worldPos.z, 1f, 3, 1f));
        int leavesRange  = minCrownSize + noise;
        int leavesRange1 = leavesRange - 1;
        int trunkHeight  = minTrunkSize + noise;

        // Make the crown an ellipsoid flattened on the y axis
        float a2inv = 1.0f / (leavesRange * leavesRange);
        float b2inv = 1.0f / (leavesRange1 * leavesRange1);

        int x1 = worldPos.x - leavesRange;
        int x2 = worldPos.x + leavesRange;
        int y1 = worldPos.y + 1 + trunkHeight;
        int y2 = y1 + 1 + 2 * leavesRange1;
        int z1 = worldPos.z - leavesRange;
        int z2 = worldPos.z + leavesRange;

        int cx, cy, cz;
        int minX, minY, minZ;
        int maxX, maxY, maxZ;

        AABBInt       bounds   = new AABBInt(x1, worldPos.y, z1, x2, y2, z2);
        Vector3Int    chunkPos = chunk.Pos;
        StructureInfo info     = null;

        // Generate the crown
        Vector3Int posFrom      = new Vector3Int(x1, y1, z1);
        Vector3Int posTo        = new Vector3Int(x2, y2, z2);
        Vector3Int chunkPosFrom = Helpers.ContainingChunkPos(ref posFrom);
        Vector3Int chunkPosTo   = Helpers.ContainingChunkPos(ref posTo);

        minY = Helpers.Mod(posFrom.y, Env.ChunkSize);
        for (cy = chunkPosFrom.y; cy <= chunkPosTo.y; cy += Env.ChunkSize, minY = 0)
        {
            maxY = Math.Min(posTo.y - cy, Env.ChunkSize1);
            minZ = Helpers.Mod(posFrom.z, Env.ChunkSize);
            for (cz = chunkPosFrom.z; cz <= chunkPosTo.z; cz += Env.ChunkSize, minZ = 0)
            {
                maxZ = Math.Min(posTo.z - cz, Env.ChunkSize1);
                minX = Helpers.Mod(posFrom.x, Env.ChunkSize);
                for (cx = chunkPosFrom.x; cx <= chunkPosTo.x; cx += Env.ChunkSize, minX = 0)
                {
                    maxX = Math.Min(posTo.x - cx, Env.ChunkSize1);

                    int xOff = cx - worldPos.x;
                    int yOff = cy - y1 - leavesRange1;
                    int zOff = cz - worldPos.z;

                    if (cx != chunk.Pos.x || cy != chunk.Pos.y || cz != chunk.Pos.z)
                    {
                        Vector3Int pos = new Vector3Int(cx, cy, cz);
                        Vector3Int min = new Vector3Int(minX, minY, minZ);
                        Vector3Int max = new Vector3Int(maxX, maxY, maxZ);

                        if (info == null)
                        {
                            info = new StructureInfo(id, ref chunkPos, ref bounds);
                        }
                        world.RegisterPendingStructure(
                            info,
                            new StructureContextTreeCrown(id, ref pos, ref worldPos, ref min, ref max, noise));

                        continue;
                    }

                    // Actual crown construction
                    ChunkBlocks blocks  = chunk.Blocks;
                    int         index   = Helpers.GetChunkIndex1DFrom3D(minX, minY, minZ);
                    int         yOffset = Env.ChunkSizeWithPaddingPow2 - (maxZ - minZ + 1) * Env.ChunkSizeWithPadding;
                    int         zOffset = Env.ChunkSizeWithPadding - (maxX - minX + 1);
                    for (int y = minY; y <= maxY; ++y, index += yOffset)
                    {
                        for (int z = minZ; z <= maxZ; ++z, index += zOffset)
                        {
                            for (int x = minX; x <= maxX; ++x, ++index)
                            {
                                int xx = x + xOff;
                                int yy = y + yOff;
                                int zz = z + zOff;

                                float _x = xx * xx * a2inv;
                                float _y = yy * yy * b2inv;
                                float _z = zz * zz * a2inv;
                                if (_x + _y + _z <= 1.0f)
                                {
                                    blocks.SetRaw(index, leaves);
                                }
                            }
                        }
                    }
                }
            }
        }

        // Generate the trunk
        posFrom      = new Vector3Int(worldPos.x, worldPos.y, worldPos.z);
        posTo        = new Vector3Int(worldPos.x, worldPos.y + trunkHeight, worldPos.z);
        chunkPosFrom = Helpers.ContainingChunkPos(ref posFrom);
        chunkPosTo   = Helpers.ContainingChunkPos(ref posTo);

        cx = Helpers.MakeChunkCoordinate(worldPos.x);
        cz = Helpers.MakeChunkCoordinate(worldPos.z);

        int tx = Helpers.Mod(worldPos.x, Env.ChunkSize);
        int tz = Helpers.Mod(worldPos.z, Env.ChunkSize);

        minY = Helpers.Mod(posFrom.y, Env.ChunkSize);
        for (cy = chunkPosFrom.y; cy <= chunkPosTo.y; cy += Env.ChunkSize, minY = 0)
        {
            maxY = Math.Min(posTo.y - cy, Env.ChunkSize1);

            if (cx != chunk.Pos.x || cy != chunk.Pos.y || cz != chunk.Pos.z)
            {
                Vector3Int pos = new Vector3Int(cx, cy, cz);
                Vector3Int min = new Vector3Int(tx, minY, tz);
                Vector3Int max = new Vector3Int(tx, maxY, tz);

                if (info == null)
                {
                    info = new StructureInfo(id, ref chunkPos, ref bounds);
                }
                world.RegisterPendingStructure(
                    info,
                    new StructureContextTreeTrunk(id, ref pos, ref min, ref max));

                continue;
            }

            // Actual trunk construction
            ChunkBlocks blocks = chunk.Blocks;
            int         index  = Helpers.GetChunkIndex1DFrom3D(tx, minY, tz);
            for (int y = minY; y <= maxY; ++y, index += Env.ChunkSizeWithPaddingPow2)
            {
                blocks.SetRaw(index, log);
            }
        }
    }