Beispiel #1
0
        void SpawnOre(VoxelChunk chunk, VoxelDefinition oreDefinition, Vector3 veinPos, int px, int py, int pz, int veinSize, int minDepth, int maxDepth)
        {
            int voxelIndex = py * ONE_Y_ROW + pz * ONE_Z_ROW + px;

            while (veinSize-- > 0 && voxelIndex >= 0 && voxelIndex < chunk.voxels.Length)
            {
                // Get height at position
                int groundLevel = heightChunkData [pz * 16 + px].groundLevel;
                int depth       = (int)(groundLevel - veinPos.y);
                if (depth < minDepth || depth > maxDepth)
                {
                    return;
                }

                // Replace solid voxels with ore
                if (chunk.voxels [voxelIndex].opaque >= 15)
                {
                    chunk.voxels [voxelIndex].SetFastOpaque(oreDefinition);
                }
                // Check if spawn continues
                Vector3 prevPos = veinPos;
                float   v       = WorldRand.GetValue(veinPos);
                int     dir     = (int)(v * 5);
                switch (dir)
                {
                case 0:                 // down
                    veinPos.y--;
                    voxelIndex -= ONE_Y_ROW;
                    break;

                case 1:                 // right
                    veinPos.x++;
                    voxelIndex++;
                    break;

                case 2:                 // back
                    veinPos.z--;
                    voxelIndex -= ONE_Z_ROW;
                    break;

                case 3:                 // left
                    veinPos.x--;
                    voxelIndex--;
                    break;

                case 4:                 // forward
                    veinPos.z++;
                    voxelIndex += ONE_Z_ROW;
                    break;
                }
                if (veinPos.x == prevPos.x && veinPos.y == prevPos.y && veinPos.z == prevPos.z)
                {
                    veinPos.y--;
                    voxelIndex -= ONE_Y_ROW;
                }
            }
        }
Beispiel #2
0
        public Vector3 GetOffset(Vector3 position)
        {
            Vector3 shiftedOffset = offset;

            if (offsetRandom)
            {
                shiftedOffset += WorldRand.GetVector3(position, offsetRandomRange, -0.5f);
            }
            return(shiftedOffset);
        }
Beispiel #3
0
        public Quaternion GetRotation(Vector3 position)
        {
            Vector3 rot = rotation;

            if (rotationRandomY)
            {
                rot.y += WorldRand.GetValue(position) * 360f;
            }
            return(Quaternion.Euler(rot));
        }
        /// <summary>
        /// Destroyes everything and initializes world
        /// </summary>
        void LoadWorldInt()
        {
            DisposeAll();

            if (world == null)
            {
                if (Application.isPlaying)
                {
                    world = ScriptableObject.CreateInstance <WorldDefinition> ();
                    Debug.LogWarning("World Definition asset missing in Voxel Play Environment. Assigning a temporary asset.");
                }
                else
                {
                    return;
                }
            }

            // Create world root
            if (worldRoot == null)
            {
                GameObject wr = GameObject.Find(VOXELPLAY_WORLD_ROOT);
                if (wr == null)
                {
                    wr = new GameObject(VOXELPLAY_WORLD_ROOT);
                    wr.transform.position = Misc.vector3zero;
                }
                worldRoot = wr.transform;
            }

            WorldRand.Randomize(world.seed);
            Physics.gravity = new Vector3(0, world.gravity, 0);
            InitSaveGameStructs();
            InitWater();
            InitSky();
            InitRenderer();
            InitTrees();
            InitVegetation();
            LoadWorldTextures();
            InitItems();
            InitNavMesh();
            InitChunkManager();
            NotifyCameraMove();  // forces check chunks in frustum
            if (applicationIsPlaying)
            {
                Invoke("InitClouds", 3f);
            }
            //InitClouds ();
            InitPhysics();
            InitParticles();
            InitTileRules();
            UpdateMaterialProperties();
            SetBuildMode(buildMode);
        }
        /// <summary>
        /// Called by Voxel Play to inform that player has moved onto another chunk so new detail can start generating
        /// </summary>
        /// <param name="currentPosition">Current player position.</param>
        /// <param name="checkOnlyBorders">True means the player has moved to next chunk. False means player position is completely new and all chunks in
        /// range should be checked for detail in this call.</param>
        /// <param name="position">Position.</param>
        public override void ExploreArea(Vector3 position, bool checkOnlyBorders)
        {
            int      explorationRange = env.visibleChunksDistance + 10;
            int      minz             = -explorationRange;
            int      maxz             = +explorationRange;
            int      minx             = -explorationRange;
            int      maxx             = +explorationRange;
            HoleWorm worm;
            Vector3  pos = position;

            for (int z = minz; z <= maxz; z++)
            {
                for (int x = minx; x < maxx; x++)
                {
                    if (checkOnlyBorders && z > minz && z < maxz && x > minx && x < maxx)
                    {
                        continue;
                    }
                    pos.x = position.x + x * 16;
                    pos.z = position.z + z * 16;
                    pos   = env.GetChunkPosition(pos);
                    if (WorldRand.GetValue(pos) > 0.98f)
                    {
                        bool born;
                        pos.y = env.GetTerrainHeight(pos);
                        if (pos.y > env.waterLevel && !wormBorn.TryGetValue(pos, out born))
                        {
                            if (!born)
                            {
                                worm.head  = pos;
                                worm.life  = 2000;
                                worm.lastX = worm.lastY = worm.lastZ = int.MinValue;
                                worm.ax    = worm.ay = worm.az = 0;
                                worms.Add(worm);
                            }
                            wormBorn [pos] = true;
                        }
                    }
                }
            }

            if (!checkOnlyBorders)
            {
                for (int k = 0; k < 1000; k++)
                {
                    if (!DoWork(long.MaxValue))
                    {
                        break;
                    }
                }
            }
        }
        /// <summary>
        /// Called by Voxel Play to inform that player has moved onto another chunk so new detail can start generating
        /// </summary>
        /// <param name="currentPosition">Current player position.</param>
        /// <param name="checkOnlyBorders">True means the player has moved to next chunk. False means player position is completely new and all chunks in
        /// range should be checked for detail in this call.</param>
        /// <param name="position">Position.</param>
        public override void ExploreArea(Vector3 position, bool checkOnlyBorders)
        {
            int     explorationRange = env.visibleChunksDistance + 10;
            int     minz             = -explorationRange;
            int     maxz             = +explorationRange;
            int     minx             = -explorationRange;
            int     maxx             = +explorationRange;
            Vector3 pos = position;

            for (int z = minz; z <= maxz; z++)
            {
                for (int x = minx; x < maxx; x++)
                {
                    if (checkOnlyBorders && z > minz && z < maxz && x > minx && x < maxx)
                    {
                        continue;
                    }
                    pos.x = position.x + x * 16;
                    pos.z = position.z + z * 16;
                    pos   = env.GetChunkPosition(pos);
                    if (WorldRand.GetValue(pos) > 0.98f)
                    {
                        BuildingStatus bs;
                        if (!buildingPositions.TryGetValue(pos, out bs))
                        {
                            float h = env.GetTerrainHeight(pos, false);
                            if (h > env.waterLevel)
                            {
                                bs.height          = h;
                                bs.placementStatus = false;

                                // No trees on this chunk
                                VoxelChunk chunk;
                                env.GetChunk(pos, out chunk, false);
                                if (chunk != null)
                                {
                                    chunk.allowTrees = false;
                                }
                            }
                            else
                            {
                                bs.placementStatus = true;
                            }
                            buildingPositions[pos] = bs;
                        }
                    }
                }
            }
        }
Beispiel #7
0
        /// <summary>
        /// Fills the given chunk with detail. Filled voxels won't be replaced by the terrain generator.
        /// Use Voxel.Empty to fill with void.
        /// </summary>
        /// <param name="chunk">Chunk.</param>
        public override void AddDetail(VoxelChunk chunk)
        {
            // if chunk is within distance any village center, render the village
            BuildingStatus bs;

            if (buildingPositions.TryGetValue(chunk.position, out bs))
            {
                if (!bs.placementStatus)
                {
                    bs.placementStatus = true;
                    buildingPositions[chunk.position] = bs;
                    Vector3 pos = chunk.position;
                    pos.y = bs.height;
                    ModelDefinition buildingModel = buildings[WorldRand.Range(0, buildings.Length, pos)];
                    env.ModelPlace(pos, buildingModel, WorldRand.Range(0, 3) * 90, 1f, true);
                }
            }
        }
Beispiel #8
0
        /// <summary>
        /// Paints the terrain inside the chunk defined by its central "position"
        /// </summary>
        /// <returns><c>true</c>, if terrain was painted, <c>false</c> otherwise.</returns>
        /// <param name="position">Central position of the chunk.</param>
        public override bool PaintChunk(VoxelChunk chunk)
        {
            Vector3 position = chunk.position;

            if (position.y + 8 < minHeight)
            {
                chunk.isAboveSurface = false;
                return(false);
            }
            int bedrockRow = -1;

            if ((object)bedrockVoxel != null && position.y < minHeight + 8)
            {
                bedrockRow = (int)(minHeight - (position.y - 8) + 1) * ONE_Y_ROW;
            }
            position.x -= 8;
            position.y -= 8;
            position.z -= 8;
            Vector3 pos;

            int waterLevel = env.waterLevel > 0 ? env.waterLevel : -1;

            Voxel[] voxels = chunk.voxels;

            bool hasContent     = false;
            bool isAboveSurface = false;

            generation++;
            env.GetHeightMapInfoFast(position.x, position.z, heightChunkData);

            // iterate 256 slice of chunk (z/x plane = 16*16 positions)
            for (int arrayIndex = 0; arrayIndex < 256; arrayIndex++)
            {
                float groundLevel  = heightChunkData [arrayIndex].groundLevel;
                float surfaceLevel = waterLevel > groundLevel ? waterLevel : groundLevel;
                if (surfaceLevel < position.y)
                {
                    // position is above terrain or water
                    isAboveSurface = true;
                    continue;
                }
                BiomeDefinition biome = heightChunkData [arrayIndex].biome;
                if ((object)biome == null)
                {
                    biome = world.defaultBiome;
                    if ((object)biome == null)
                    {
                        continue;
                    }
                }

                int y = (int)(surfaceLevel - position.y);
                if (y > 15)
                {
                    y = 15;
                }
                pos.y = position.y + y;
                pos.x = position.x + (arrayIndex & 0xF);
                pos.z = position.z + (arrayIndex >> 4);

                // Place voxels
                int voxelIndex = y * ONE_Y_ROW + arrayIndex;
                if (pos.y > groundLevel)
                {
                    // water above terrain
                    if (pos.y == surfaceLevel)
                    {
                        isAboveSurface = true;
                    }
                    while (pos.y > groundLevel && voxelIndex >= 0)
                    {
                        voxels [voxelIndex].Set(waterVoxel);
                        voxelIndex -= ONE_Y_ROW;
                        pos.y--;
                    }
                }
                else if (pos.y == groundLevel)
                {
                    isAboveSurface = true;
                    if (voxels [voxelIndex].hasContent == 0)
                    {
                        if (paintShore && pos.y == waterLevel)
                        {
                            // this is on the shore, place a shoreVoxel
                            voxels [voxelIndex].Set(shoreVoxel);
                        }
                        else
                        {
                            // we're at the surface of the biome => draw the voxel top of the biome and also check for random vegetation and trees
                            voxels [voxelIndex].Set(biome.voxelTop);
#if UNITY_EDITOR
                            if (!env.draftModeActive)
                            {
#endif
                            // Check tree probability
                            if (pos.y > waterLevel)
                            {
                                float rn = WorldRand.GetValue(pos);
                                if (env.enableTrees && biome.treeDensity > 0 && rn < biome.treeDensity && biome.trees.Length > 0)
                                {
                                    // request one tree at this position
                                    env.RequestTreeCreation(chunk, pos, env.GetTree(biome.trees, rn / biome.treeDensity));
                                }
                                else if (env.enableVegetation && biome.vegetationDensity > 0 && rn < biome.vegetationDensity && biome.vegetation.Length > 0)
                                {
                                    if (voxelIndex >= 15 * ONE_Y_ROW)
                                    {
                                        // request one vegetation voxel one position above which means the chunk above this one
                                        env.RequestVegetationCreation(chunk.top, voxelIndex - ONE_Y_ROW * 15, env.GetVegetation(biome, rn / biome.vegetationDensity));
                                    }
                                    else
                                    {
                                        // directly place a vegetation voxel above this voxel
                                        voxels [voxelIndex + ONE_Y_ROW].Set(env.GetVegetation(biome, rn / biome.vegetationDensity));
                                        env.vegetationCreated++;
                                    }
                                }
                            }
#if UNITY_EDITOR
                        }
#endif
                        }
                    }
                    voxelIndex -= ONE_Y_ROW;
                }

                // Continue filling down
                biome.biomeGeneration = generation;
                while (voxelIndex > bedrockRow)
                {
                    if (voxels [voxelIndex].hasContent == 0)
                    {
                        voxels [voxelIndex].SetFastOpaque(biome.voxelDirt);
                    }
                    voxelIndex -= ONE_Y_ROW;
                }
                if (bedrockRow >= 0)
                {
                    voxels [voxelIndex].SetFastOpaque(bedrockVoxel);
                }
                hasContent = true;
            }

            // Spawn random ore
            if (addOre)
            {
                // Check if there's any ore in this chunk (randomly)
                float noiseValue = WorldRand.GetValue(chunk.position);
                for (int b = 0; b < world.biomes.Length; b++)
                {
                    BiomeDefinition biome = world.biomes [b];
                    if (biome.biomeGeneration != generation)
                    {
                        continue;
                    }
                    for (int o = 0; o < biome.ores.Length; o++)
                    {
                        if (biome.ores [o].ore == null)
                        {
                            continue;
                        }
                        if (biome.ores [o].probabilityMin <= noiseValue && biome.ores [o].probabilityMax >= noiseValue)
                        {
                            // ore picked; determine the number of veins in this chunk
                            int veinsCount = biome.ores [o].veinsCountMin + (int)(WorldRand.GetValue() * (biome.ores [o].veinsCountMax - biome.ores [o].veinsCountMin + 1f));
                            for (int vein = 0; vein < veinsCount; vein++)
                            {
                                Vector3 veinPos = chunk.position;
                                veinPos.x += vein;
                                // Determine random vein position in the chunk
                                Vector3 v  = WorldRand.GetVector3(veinPos, 16);
                                int     px = (int)v.x;
                                int     py = (int)v.y;
                                int     pz = (int)v.z;
                                veinPos = env.GetVoxelPosition(veinPos, px, py, pz);
                                int oreIndex = py * ONE_Y_ROW + pz * ONE_Z_ROW + px;
                                int veinSize = biome.ores [o].veinMinSize + (oreIndex % (biome.ores [o].veinMaxSize - biome.ores [o].veinMinSize + 1));
                                // span ore vein
                                SpawnOre(chunk, biome.ores [o].ore, veinPos, px, py, pz, veinSize, biome.ores [o].depthMin, biome.ores [o].depthMax);
                            }
                            break;
                        }
                    }
                }
            }

            // Finish, return
            chunk.isAboveSurface = isAboveSurface;
            return(hasContent);
        }
Beispiel #9
0
        /// <summary>
        /// Gets the altitude and moisture (in 0-1 range).
        /// </summary>
        /// <param name="x">The x coordinate.</param>
        /// <param name="z">The z coordinate.</param>
        /// <param name="altitude">Altitude.</param>
        /// <param name="moisture">Moisture.</param>
        public override void GetHeightAndMoisture(float x, float z, out float altitude, out float moisture)
        {
            if (!isInitialized)
            {
                Initialize();
            }

            bool allowBeach = true;

            altitude = 0;
            if (steps != null && steps.Length > 0)
            {
                float value = 0;
                for (int k = 0; k < steps.Length; k++)
                {
                    if (steps [k].enabled)
                    {
                        switch (steps [k].operation)
                        {
                        case TerrainStepType.SampleHeightMapTexture:
                            value = NoiseTools.GetNoiseValueBilinear(steps [k].noiseValues, steps [k].noiseTextureSize, x * steps [k].frecuency, z * steps [k].frecuency);
                            value = value * (steps [k].noiseRangeMax - steps [k].noiseRangeMin) + steps [k].noiseRangeMin;
                            break;

                        case TerrainStepType.SampleRidgeNoiseFromTexture:
                            value = NoiseTools.GetNoiseValueBilinear(steps [k].noiseValues, steps [k].noiseTextureSize, x * steps [k].frecuency, z * steps [k].frecuency, true);
                            value = value * (steps [k].noiseRangeMax - steps [k].noiseRangeMin) + steps [k].noiseRangeMin;
                            break;

                        case TerrainStepType.Shift:
                            value += steps [k].param;
                            break;

                        case TerrainStepType.BeachMask:
                        {
                            int i1 = steps [k].inputIndex0;
                            if (steps [i1].value > steps [k].threshold)
                            {
                                allowBeach = false;
                            }
                        }
                        break;

                        case TerrainStepType.AddAndMultiply:
                            value = (value + steps [k].param) * steps [k].param2;
                            break;

                        case TerrainStepType.MultiplyAndAdd:
                            value = (value * steps [k].param) + steps [k].param2;
                            break;

                        case TerrainStepType.Exponential:
                            if (value < 0)
                            {
                                value = 0;
                            }
                            value = (float)System.Math.Pow(value, steps [k].param);
                            break;

                        case TerrainStepType.Constant:
                            value = steps [k].param;
                            break;

                        case TerrainStepType.Invert:
                            value = 1f - value;
                            break;

                        case TerrainStepType.Copy:
                        {
                            int i1 = steps [k].inputIndex0;
                            value = steps [i1].value;
                        }
                        break;

                        case TerrainStepType.Random:
                            value = WorldRand.GetValue(x, z);
                            break;

                        case TerrainStepType.BlendAdditive:
                        {
                            int i1 = steps [k].inputIndex0;
                            int i2 = steps [k].inputIndex1;
                            value = steps [i1].value * steps [k].weight0 + steps [i2].value * steps [k].weight1;
                        }
                        break;

                        case TerrainStepType.BlendMultiply:
                        {
                            int i1 = steps [k].inputIndex0;
                            int i2 = steps [k].inputIndex1;
                            value = steps [i1].value * steps [i2].value;
                        }
                        break;

                        case TerrainStepType.Threshold:
                        {
                            int i1 = steps [k].inputIndex0;
                            if (steps [i1].value >= steps [k].threshold)
                            {
                                value = steps [i1].value + steps [k].thresholdShift;
                            }
                            else
                            {
                                value = steps [k].thresholdParam;
                            }
                        }
                        break;

                        case TerrainStepType.FlattenOrRaise:
                            if (value >= steps [k].threshold)
                            {
                                value = (value - steps [k].threshold) * steps [k].thresholdParam + steps [k].threshold;
                            }
                            break;

                        case TerrainStepType.Clamp:
                            if (value < steps [k].min)
                            {
                                value = steps [k].min;
                            }
                            else if (value > steps [k].max)
                            {
                                value = steps [k].max;
                            }
                            break;

                        case TerrainStepType.Select:
                        {
                            int i1 = steps [k].inputIndex0;
                            if (steps [i1].value < steps [k].min)
                            {
                                value = steps [k].thresholdParam;
                            }
                            else if (steps [i1].value > steps [k].max)
                            {
                                value = steps [k].thresholdParam;
                            }
                            else
                            {
                                value = steps [i1].value;
                            }
                        }
                        break;

                        case TerrainStepType.Fill:
                        {
                            int i1 = steps [k].inputIndex0;
                            if (steps [i1].value >= steps [k].min && steps [i1].value <= steps [k].max)
                            {
                                value = steps [k].thresholdParam;
                            }
                        }
                        break;

                        case TerrainStepType.Test:
                        {
                            int i1 = steps [k].inputIndex0;
                            if (steps [i1].value >= steps [k].min && steps [i1].value <= steps [k].max)
                            {
                                value = 1f;
                            }
                            else
                            {
                                value = 0f;
                            }
                        }
                        break;
                        }
                    }
                    steps [k].value = value;
                }
                altitude = value;
            }
            else
            {
                altitude = -9999;                 // no terrain so make altitude very low so every chunk be considered above terrain for GI purposes
            }

            // Moisture
            moisture = NoiseTools.GetNoiseValueBilinear(moistureValues, noiseMoistureTextureSize, x * moistureScale, z * moistureScale);


            // Remove any potential beach
            if (altitude < beachLevelAlignedWithInt && altitude >= seaLevelAlignedWithInt)
            {
                float depth = beachLevelAlignedWithInt - altitude;
                if (depth > beachWidth || !allowBeach)
                {
                    altitude = seaLevelAlignedWithInt - 0.0001f;
                }
            }

            // Adjusts sea depth
            if (altitude < seaLevelAlignedWithInt)
            {
                float depth = seaLevelAlignedWithInt - altitude;
                altitude = seaLevelAlignedWithInt - 0.0001f - depth * seaDepthMultiplier;
            }
        }
Beispiel #10
0
        /// <summary>
        /// Uses geometry-shader-based materials and mesh to render the chunk
        /// </summary>
        void GenerateMeshData_Geo(int jobIndex)
        {
            VoxelChunk chunk = meshJobs [jobIndex].chunk;

            tempChunkVertices    = meshJobs [jobIndex].vertices;
            tempChunkUV0         = meshJobs [jobIndex].uv0;
            tempChunkUV2         = meshJobs [jobIndex].uv2;
            tempChunkColors32    = meshJobs [jobIndex].colors;
            meshColliderVertices = meshJobs [jobIndex].colliderVertices;
            meshColliderIndices  = meshJobs [jobIndex].colliderIndices;
            navMeshVertices      = meshJobs [jobIndex].navMeshVertices;
            navMeshIndices       = meshJobs [jobIndex].navMeshIndices;
            mivs = meshJobs [jobIndex].mivs;

            tempChunkVertices.Clear();
            tempChunkUV0.Clear();
            tempChunkColors32.Clear();
            if (enableColliders)
            {
                meshColliderIndices.Clear();
                meshColliderVertices.Clear();
                if (enableNavMesh)
                {
                    navMeshIndices.Clear();
                    navMeshVertices.Clear();
                }
            }
            mivs.Clear();

            Voxel[] voxels = chunk.voxels;
            Vector4 uvAux, uv2Aux;

            tempChunkUV2.Clear();

            int          chunkUVIndex    = -1;
            int          chunkVoxelCount = 0;
            Color32      tintColor       = Misc.color32White;
            Vector3      pos             = Misc.vector3zero;
            ModelInVoxel miv             = new ModelInVoxel();

            const int V_ONE_Y_ROW = 18 * 18;
            const int V_ONE_Z_ROW = 18;

            int voxelIndex     = 0;
            int voxelSignature = 1;

            for (int y = 0; y < 16; y++)
            {
                int vy = (y + 1) * 18 * 18;
                for (int z = 0; z < 16; z++)
                {
                    int vyz = vy + (z + 1) * 18;
                    for (int x = 0; x < 16; x++, voxelIndex++)
                    {
                        voxels [voxelIndex].lightMesh = voxels [voxelIndex].light;
                        if (voxels [voxelIndex].hasContent != 1)
                        {
                            continue;
                        }

                        int vxyz = vyz + x + 1;

                        int     vindex = vxyz - 1;
                        Voxel[] chunk_middle_middle_left = chunk9 [virtualChunk [vindex].chunk9Index];
                        int     middle_middle_left       = virtualChunk [vindex].voxelIndex;

                        vindex = vxyz + 1;
                        Voxel[] chunk_middle_middle_right = chunk9 [virtualChunk [vindex].chunk9Index];
                        int     middle_middle_right       = virtualChunk [vindex].voxelIndex;

                        vindex = vxyz + V_ONE_Y_ROW;
                        Voxel[] chunk_top_middle_middle = chunk9 [virtualChunk [vindex].chunk9Index];
                        int     top_middle_middle       = virtualChunk [vindex].voxelIndex;

                        vindex = vxyz - V_ONE_Y_ROW;
                        Voxel[] chunk_bottom_middle_middle = chunk9 [virtualChunk [vindex].chunk9Index];
                        int     bottom_middle_middle       = virtualChunk [vindex].voxelIndex;

                        vindex = vxyz + V_ONE_Z_ROW;
                        Voxel[] chunk_middle_forward_middle = chunk9 [virtualChunk [vindex].chunk9Index];
                        int     middle_forward_middle       = virtualChunk [vindex].voxelIndex;

                        vindex = vxyz - V_ONE_Z_ROW;
                        Voxel[] chunk_middle_back_middle = chunk9 [virtualChunk [vindex].chunk9Index];
                        int     middle_back_middle       = virtualChunk [vindex].voxelIndex;

                        // If voxel is surrounded by material, don't render
                        int v1u = chunk_top_middle_middle [top_middle_middle].opaque;
                        int v1f = chunk_middle_forward_middle [middle_forward_middle].opaque;
                        int v1b = chunk_middle_back_middle [middle_back_middle].opaque;
                        int v1l = chunk_middle_middle_left [middle_middle_left].opaque;
                        int v1r = chunk_middle_middle_right [middle_middle_right].opaque;
                        int v1d = chunk_bottom_middle_middle [bottom_middle_middle].opaque;
                        if (v1u + v1f + v1b + v1l + v1r + v1d == 90)                         // 90 = 15 * 6
                        {
                            continue;
                        }

                        // top
                        vindex = vxyz + V_ONE_Y_ROW + V_ONE_Z_ROW - 1;
                        Voxel[] chunk_top_forward_left = chunk9 [virtualChunk [vindex].chunk9Index];
                        int     top_forward_left       = virtualChunk [vindex].voxelIndex;

                        vindex++;
                        Voxel[] chunk_top_forward_middle = chunk9 [virtualChunk [vindex].chunk9Index];
                        int     top_forward_middle       = virtualChunk [vindex].voxelIndex;

                        vindex++;
                        Voxel[] chunk_top_forward_right = chunk9 [virtualChunk [vindex].chunk9Index];
                        int     top_forward_right       = virtualChunk [vindex].voxelIndex;

                        vindex = vxyz + V_ONE_Y_ROW - 1;
                        Voxel[] chunk_top_middle_left = chunk9 [virtualChunk [vindex].chunk9Index];
                        int     top_middle_left       = virtualChunk [vindex].voxelIndex;

                        vindex += 2;
                        Voxel[] chunk_top_middle_right = chunk9 [virtualChunk [vindex].chunk9Index];
                        int     top_middle_right       = virtualChunk [vindex].voxelIndex;

                        vindex = vxyz + V_ONE_Y_ROW - V_ONE_Z_ROW - 1;
                        Voxel[] chunk_top_back_left = chunk9 [virtualChunk [vindex].chunk9Index];
                        int     top_back_left       = virtualChunk [vindex].voxelIndex;

                        vindex++;
                        Voxel[] chunk_top_back_middle = chunk9 [virtualChunk [vindex].chunk9Index];
                        int     top_back_middle       = virtualChunk [vindex].voxelIndex;

                        vindex++;
                        Voxel[] chunk_top_back_right = chunk9 [virtualChunk [vindex].chunk9Index];
                        int     top_back_right       = virtualChunk [vindex].voxelIndex;

                        // middle
                        vindex = vxyz + V_ONE_Z_ROW - 1;
                        Voxel[] chunk_middle_forward_left = chunk9 [virtualChunk [vindex].chunk9Index];
                        int     middle_forward_left       = virtualChunk [vindex].voxelIndex;

                        vindex += 2;
                        Voxel[] chunk_middle_forward_right = chunk9 [virtualChunk [vindex].chunk9Index];
                        int     middle_forward_right       = virtualChunk [vindex].voxelIndex;

                        vindex = vxyz - V_ONE_Z_ROW - 1;
                        Voxel[] chunk_middle_back_left = chunk9 [virtualChunk [vindex].chunk9Index];
                        int     middle_back_left       = virtualChunk [vindex].voxelIndex;

                        vindex += 2;
                        Voxel[] chunk_middle_back_right = chunk9 [virtualChunk [vindex].chunk9Index];
                        int     middle_back_right       = virtualChunk [vindex].voxelIndex;

                        // bottom
                        vindex = vxyz - V_ONE_Y_ROW + V_ONE_Z_ROW - 1;
                        Voxel[] chunk_bottom_forward_left = chunk9 [virtualChunk [vindex].chunk9Index];
                        int     bottom_forward_left       = virtualChunk [vindex].voxelIndex;

                        vindex++;
                        Voxel[] chunk_bottom_forward_middle = chunk9 [virtualChunk [vindex].chunk9Index];
                        int     bottom_forward_middle       = virtualChunk [vindex].voxelIndex;

                        vindex++;
                        Voxel[] chunk_bottom_forward_right = chunk9 [virtualChunk [vindex].chunk9Index];
                        int     bottom_forward_right       = virtualChunk [vindex].voxelIndex;

                        vindex = vxyz - V_ONE_Y_ROW - 1;
                        Voxel[] chunk_bottom_middle_left = chunk9 [virtualChunk [vindex].chunk9Index];
                        int     bottom_middle_left       = virtualChunk [vindex].voxelIndex;

                        vindex += 2;
                        Voxel[] chunk_bottom_middle_right = chunk9 [virtualChunk [vindex].chunk9Index];
                        int     bottom_middle_right       = virtualChunk [vindex].voxelIndex;

                        vindex = vxyz - V_ONE_Y_ROW - V_ONE_Z_ROW - 1;
                        Voxel[] chunk_bottom_back_left = chunk9 [virtualChunk [vindex].chunk9Index];
                        int     bottom_back_left       = virtualChunk [vindex].voxelIndex;

                        vindex++;
                        Voxel[] chunk_bottom_back_middle = chunk9 [virtualChunk [vindex].chunk9Index];
                        int     bottom_back_middle       = virtualChunk [vindex].voxelIndex;

                        vindex++;
                        Voxel[] chunk_bottom_back_right = chunk9 [virtualChunk [vindex].chunk9Index];
                        int     bottom_back_right       = virtualChunk [vindex].voxelIndex;


                        pos.y = y - 7.5f;
                        pos.z = z - 7.5f;
                        pos.x = x - 7.5f;

                        voxelSignature += voxelIndex;
                        chunkVoxelCount++;

                        VoxelDefinition       type    = voxelDefinitions [voxels [voxelIndex].typeIndex];
                        FastFixedBuffer <int> indices = tempGeoIndices[type.materialBufferIndex];

                        uvAux.x = type.textureIndexSide;
                        uvAux.y = type.textureIndexTop;
                        uvAux.z = type.textureIndexBottom;
                        uvAux.w = 0;

                        int occlusionX = 0;
                        int occlusionY = 0;
                        int occlusionZ = 0;
                        int occlusionW = 0;
                        int occ        = 0;

                        RenderType rt = type.renderType;
                        switch (rt)
                        {
                        case RenderType.Water:
                        {
                            ++chunkUVIndex;
                            indices.Add(chunkUVIndex);

                            uvAux.w = voxels [voxelIndex].light / 15f;

                            int hf = chunk_middle_forward_middle [middle_forward_middle].GetWaterLevel();
                            int hb = chunk_middle_back_middle [middle_back_middle].GetWaterLevel();
                            int hr = chunk_middle_middle_right [middle_middle_right].GetWaterLevel();
                            int hl = chunk_middle_middle_left [middle_middle_left].GetWaterLevel();

                            // compute water neighbours and account for foam
                            // back
                            occ = chunk_middle_back_middle [middle_back_middle].hasContent;
                            if (occ == 1)
                            {
                                // occlusionX bit = 0 means that face is visible
                                occlusionX |= 1;
                                if (hb == 0)
                                {
                                    occlusionY |= 1;
                                }
                            }

                            // front
                            occ = chunk_middle_forward_middle [middle_forward_middle].hasContent;
                            if (occ == 1)
                            {
                                occlusionX |= (1 << 1);
                                if (hf == 0)
                                {
                                    occlusionY |= 2;
                                }
                            }

                            int wh = voxels [voxelIndex].GetWaterLevel();
                            int th = chunk_top_middle_middle [top_middle_middle].GetWaterLevel();

                            // top (hide only if water level is full or voxel on top is water)
                            if (wh == 15 || th > 0)
                            {
                                occlusionX += ((chunk_top_middle_middle [top_middle_middle].hasContent & 1) << 2);
                            }

                            // down
                            occlusionX += ((chunk_bottom_middle_middle [bottom_middle_middle].hasContent & 1) << 3);

                            // left
                            occ = chunk_middle_middle_left [middle_middle_left].hasContent;
                            if (occ == 1)
                            {
                                occlusionX |= (1 << 4);
                                if (hl == 0)
                                {
                                    occlusionY |= 4;
                                }
                            }
                            // right
                            occ = chunk_middle_middle_right [middle_middle_right].hasContent;
                            if (occ == 1)
                            {
                                occlusionX += (1 << 5);
                                if (hr == 0)
                                {
                                    occlusionY |= 8;
                                }
                            }

                            // If there's water on top, full size
                            if (th > 0)
                            {
                                occlusionW  = 15 + (15 << 4) + (15 << 8) + (15 << 12);                          // full height
                                occlusionY += (1 << 8) + (1 << 10);                                             // neutral/no flow
                            }
                            else
                            {
                                // Get corners heights
                                int hfr = chunk_middle_forward_right [middle_forward_right].GetWaterLevel();
                                int hbr = chunk_middle_back_right [middle_back_right].GetWaterLevel();
                                int hbl = chunk_middle_back_left [middle_back_left].GetWaterLevel();
                                int hfl = chunk_middle_forward_left [middle_forward_left].GetWaterLevel();

                                // corner foam
                                if (type.showFoam)
                                {
                                    if (hbl == 0)
                                    {
                                        occlusionY |= chunk_middle_back_left [middle_back_left].hasContent << 4;
                                    }
                                    if (hfl == 0)
                                    {
                                        occlusionY |= chunk_middle_forward_left [middle_forward_left].hasContent << 5;
                                    }
                                    if (hfr == 0)
                                    {
                                        occlusionY |= chunk_middle_forward_right [middle_forward_right].hasContent << 6;
                                    }
                                    if (hbr == 0)
                                    {
                                        occlusionY |= chunk_middle_back_right [middle_back_right].hasContent << 7;
                                    }
                                }

                                int tf  = chunk_top_forward_middle [top_forward_middle].GetWaterLevel();
                                int tfr = chunk_top_forward_right [top_forward_right].GetWaterLevel();
                                int tr  = chunk_top_middle_right [top_middle_right].GetWaterLevel();
                                int tbr = chunk_top_back_right [top_back_right].GetWaterLevel();
                                int tb  = chunk_top_back_middle [top_back_middle].GetWaterLevel();
                                int tbl = chunk_top_back_left [top_back_left].GetWaterLevel();
                                int tl  = chunk_top_middle_left [top_middle_left].GetWaterLevel();
                                int tfl = chunk_top_forward_left [top_forward_left].GetWaterLevel();

                                // forward right corner
                                if (tf * hf + tfr * hfr + tr * hr > 0)
                                {
                                    hfr = 15;
                                }
                                else
                                {
                                    hfr = wh > hfr ? wh : hfr;
                                    if (hf > hfr)
                                    {
                                        hfr = hf;
                                    }
                                    if (hr > hfr)
                                    {
                                        hfr = hr;
                                    }
                                }
                                // bottom right corner
                                if (tr * hr + tbr * hbr + tb * hb > 0)
                                {
                                    hbr = 15;
                                }
                                else
                                {
                                    hbr = wh > hbr ? wh : hbr;
                                    if (hr > hbr)
                                    {
                                        hbr = hr;
                                    }
                                    if (hb > hbr)
                                    {
                                        hbr = hb;
                                    }
                                }
                                // bottom left corner
                                if (tb * hb + tbl * hbl + tl * hl > 0)
                                {
                                    hbl = 15;
                                }
                                else
                                {
                                    hbl = wh > hbl ? wh : hbl;
                                    if (hb > hbl)
                                    {
                                        hbl = hb;
                                    }
                                    if (hl > hbl)
                                    {
                                        hbl = hl;
                                    }
                                }
                                // forward left corner
                                if (tl * hl + tfl * hfl + tf * hf > 0)
                                {
                                    hfl = 15;
                                }
                                else
                                {
                                    hfl = wh > hfl ? wh : hfl;
                                    if (hl > hfl)
                                    {
                                        hfl = hl;
                                    }
                                    if (hf > hfl)
                                    {
                                        hfl = hf;
                                    }
                                }
                                occlusionW = hfr + (hbr << 4) + (hbl << 8) + (hfl << 12);

                                // flow
                                int fx = hfr + hbr - hfl - hbl;
                                if (fx > 0)
                                {
                                    fx = 2;
                                }
                                else if (fx < 0)
                                {
                                    fx = 0;
                                }
                                else
                                {
                                    fx = 1;
                                }
                                int fz = hfl + hfr - hbl - hbr;
                                if (fz > 0)
                                {
                                    fz = 2;
                                }
                                else if (fz < 0)
                                {
                                    fz = 0;
                                }
                                else
                                {
                                    fz = 1;
                                }

                                occlusionY += (fx << 8) + (fz << 10);
                            }

                            if (!type.showFoam)
                            {
                                occlusionY &= 0xFF00;
                            }
                            pos.y -= 0.5f;
                            tempChunkVertices.Add(pos);
                        }
                        break;

                        case RenderType.CutoutCross:
                        {
                            ++chunkUVIndex;
                            indices.Add(chunkUVIndex);
                            uvAux.w = voxels [voxelIndex].light / 15f;
                            Vector3 aux    = pos;
                            float   random = WorldRand.GetValue(pos);
                            uvAux.w *= 1f + (random - 0.45f) * type.colorVariation;                                     // * (1f + random * 0.3f;  // adds color variation
                            pos.x   += random * 0.5f - 0.25f;
                            aux.x   += 1f;
                            random   = WorldRand.GetValue(aux);
                            pos.z   += random * 0.5f - 0.25f;
                            pos.y   -= random * 0.1f;
                            tempChunkVertices.Add(pos);
                        }
                        break;

                        case RenderType.OpaqueNoAO:
                            ++chunkUVIndex;
                            tempChunkVertices.Add(pos);

                            v1b     = (v1b + 1) >> 4;                           // substitutes a comparisson with FULL_OPAQUE (15)
                            v1f     = (v1f + 1) >> 4;
                            v1u     = (v1u + 1) >> 4;
                            v1d     = (v1d + 1) >> 4;
                            v1l     = (v1l + 1) >> 4;
                            v1r     = (v1r + 1) >> 4;
                            uvAux.w = v1b + (v1f << 1) + (v1u << 2) + (v1d << 3) + (v1l << 4) + (v1r << 5);
                            indices.Add(chunkUVIndex);
                            break;

                        case RenderType.Transp6tex:
                        {
                            ++chunkUVIndex;
                            indices.Add(chunkUVIndex);
                            int rotation = voxels [voxelIndex].GetTextureRotation();
                            uvAux   = type.textureSideIndices [rotation].xyzw;
                            uvAux.w = voxels [voxelIndex].light;

                            // Avoid overlapping faces of same glass material
                            int typeIndex = voxels [voxelIndex].typeIndex;

                            // back
                            if (v1b == FULL_OPAQUE || chunk_middle_back_middle [middle_back_middle].typeIndex == typeIndex)
                            {
                                // occlusionX bit = 0 means that face is visible
                                occlusionX |= 1;
                            }

                            // front
                            if (v1f == FULL_OPAQUE || chunk_middle_forward_middle [middle_forward_middle].typeIndex == typeIndex)
                            {
                                occlusionX |= 2;
                            }

                            // up
                            if (v1u == FULL_OPAQUE || chunk_top_middle_middle [top_middle_middle].typeIndex == typeIndex)
                            {
                                occlusionX |= 4;
                            }

                            // down
                            if (v1d == FULL_OPAQUE || chunk_bottom_middle_middle [bottom_middle_middle].typeIndex == typeIndex)
                            {
                                occlusionX |= 8;
                            }

                            // left
                            if (v1l == FULL_OPAQUE || chunk_middle_middle_left [middle_middle_left].typeIndex == typeIndex)
                            {
                                occlusionX |= 16;
                            }
                            // right
                            if (v1r == FULL_OPAQUE || chunk_middle_middle_right [middle_middle_right].typeIndex == typeIndex)
                            {
                                occlusionX |= 32;
                            }
                            tempChunkVertices.Add(pos);

                            // Pass custom alpha
                            occlusionY = (int)(255 * type.alpha);

                            // Add collider data
                            if (enableColliders)
                            {
                                if (v1b == 0)
                                {
                                    greedyCollider.AddQuad(FaceDirection.Back, x, y, z);
                                }
                                if (v1f == 0)
                                {
                                    greedyCollider.AddQuad(FaceDirection.Forward, x, y, z);
                                }
                                if (v1u == 0)
                                {
                                    greedyCollider.AddQuad(FaceDirection.Top, x, z, y);
                                }
                                if (v1d == 0)
                                {
                                    greedyCollider.AddQuad(FaceDirection.Bottom, x, z, y);
                                }
                                if (v1l == 0)
                                {
                                    greedyCollider.AddQuad(FaceDirection.Left, z, y, x);
                                }
                                if (v1r == 0)
                                {
                                    greedyCollider.AddQuad(FaceDirection.Right, z, y, x);
                                }
                                if (enableNavMesh && type.navigatable)
                                {
                                    if (v1b == 0)
                                    {
                                        greedyNavMesh.AddQuad(FaceDirection.Back, x, y, z);
                                    }
                                    if (v1f == 0)
                                    {
                                        greedyNavMesh.AddQuad(FaceDirection.Forward, x, y, z);
                                    }
                                    if (v1u == 0)
                                    {
                                        greedyNavMesh.AddQuad(FaceDirection.Top, x, z, y);
                                    }
                                    if (v1l == 0)
                                    {
                                        greedyNavMesh.AddQuad(FaceDirection.Left, z, y, x);
                                    }
                                    if (v1r == 0)
                                    {
                                        greedyNavMesh.AddQuad(FaceDirection.Right, z, y, x);
                                    }
                                }
                            }
                        }
                        break;

                        default:                         //case RenderType.Custom:
                            miv.voxelIndex = voxelIndex;
                            miv.vd         = type;
                            mivs.Add(miv);
                            continue;

                        case RenderType.Empty:
                        {
                            v1b = (v1b + 1) >> 4;                                       // substitutes a comparison with FULL_OPAQUE (15)
                            v1f = (v1f + 1) >> 4;
                            v1u = (v1u + 1) >> 4;
                            v1d = (v1d + 1) >> 4;
                            v1l = (v1l + 1) >> 4;
                            v1r = (v1r + 1) >> 4;

                            // Add collider data
                            if (enableColliders)
                            {
                                if (v1b == 0)
                                {
                                    greedyCollider.AddQuad(FaceDirection.Back, x, y, z);
                                }
                                if (v1f == 0)
                                {
                                    greedyCollider.AddQuad(FaceDirection.Forward, x, y, z);
                                }
                                if (v1u == 0)
                                {
                                    greedyCollider.AddQuad(FaceDirection.Top, x, z, y);
                                }
                                if (v1d == 0)
                                {
                                    greedyCollider.AddQuad(FaceDirection.Bottom, x, z, y);
                                }
                                if (v1l == 0)
                                {
                                    greedyCollider.AddQuad(FaceDirection.Left, z, y, x);
                                }
                                if (v1r == 0)
                                {
                                    greedyCollider.AddQuad(FaceDirection.Right, z, y, x);
                                }
                                if (enableNavMesh && type.navigatable)
                                {
                                    if (v1b == 0)
                                    {
                                        greedyNavMesh.AddQuad(FaceDirection.Back, x, y, z);
                                    }
                                    if (v1f == 0)
                                    {
                                        greedyNavMesh.AddQuad(FaceDirection.Forward, x, y, z);
                                    }
                                    if (v1u == 0)
                                    {
                                        greedyNavMesh.AddQuad(FaceDirection.Top, x, z, y);
                                    }
                                    if (v1l == 0)
                                    {
                                        greedyNavMesh.AddQuad(FaceDirection.Left, z, y, x);
                                    }
                                    if (v1r == 0)
                                    {
                                        greedyNavMesh.AddQuad(FaceDirection.Right, z, y, x);
                                    }
                                }
                            }
                        }
                            continue;                             // loop

                        case RenderType.Opaque:
                        case RenderType.Opaque6tex:
                        case RenderType.Cutout:                         // Opaque & Cutout
                            ++chunkUVIndex;
                            tempChunkVertices.Add(pos);

                            if (rt == RenderType.Cutout)
                            {
                                indices.Add(chunkUVIndex);
                            }
                            else
                            {
                                indices.Add(chunkUVIndex);
                                int rotation = voxels [voxelIndex].GetTextureRotation();
                                uvAux = type.textureSideIndices [rotation].xyzw;
                            }

                            if (denseTrees && rt == RenderType.Cutout)
                            {
                                uvAux.w = 0;
                            }
                            else
                            {
                                v1b     = (v1b + 1) >> 4;                               // substitutes a comparisson with FULL_OPAQUE (15)
                                v1f     = (v1f + 1) >> 4;
                                v1u     = (v1u + 1) >> 4;
                                v1d     = (v1d + 1) >> 4;
                                v1l     = (v1l + 1) >> 4;
                                v1r     = (v1r + 1) >> 4;
                                uvAux.w = v1b + (v1f << 1) + (v1u << 2) + (v1d << 3) + (v1l << 4) + (v1r << 5);

                                // Add collider data
                                if (enableColliders && rt != RenderType.Cutout)
                                {
                                    if (v1b == 0)
                                    {
                                        greedyCollider.AddQuad(FaceDirection.Back, x, y, z);
                                    }
                                    if (v1f == 0)
                                    {
                                        greedyCollider.AddQuad(FaceDirection.Forward, x, y, z);
                                    }
                                    if (v1u == 0)
                                    {
                                        greedyCollider.AddQuad(FaceDirection.Top, x, z, y);
                                    }
                                    if (v1d == 0)
                                    {
                                        greedyCollider.AddQuad(FaceDirection.Bottom, x, z, y);
                                    }
                                    if (v1l == 0)
                                    {
                                        greedyCollider.AddQuad(FaceDirection.Left, z, y, x);
                                    }
                                    if (v1r == 0)
                                    {
                                        greedyCollider.AddQuad(FaceDirection.Right, z, y, x);
                                    }
                                    if (enableNavMesh && type.navigatable)
                                    {
                                        if (v1b == 0)
                                        {
                                            greedyNavMesh.AddQuad(FaceDirection.Back, x, y, z);
                                        }
                                        if (v1f == 0)
                                        {
                                            greedyNavMesh.AddQuad(FaceDirection.Forward, x, y, z);
                                        }
                                        if (v1u == 0)
                                        {
                                            greedyNavMesh.AddQuad(FaceDirection.Top, x, z, y);
                                        }
                                        if (v1l == 0)
                                        {
                                            greedyNavMesh.AddQuad(FaceDirection.Left, z, y, x);
                                        }
                                        if (v1r == 0)
                                        {
                                            greedyNavMesh.AddQuad(FaceDirection.Right, z, y, x);
                                        }
                                    }
                                }
                            }
                            if (rt == RenderType.Cutout)
                            {
                                // Add color variation
                                float random = WorldRand.GetValue(pos);
                                int   r      = (int)(255f * (1f + (random - 0.45f) * type.colorVariation));
                                uvAux.w += (r << 6);
                                if (type.windAnimation)
                                {
                                    uvAux.w += 65536;                                     //1 << 16;
                                }
                            }

                            int lu = chunk_top_middle_middle [top_middle_middle].light;
                            int ll = chunk_middle_middle_left [middle_middle_left].light;
                            int lf = chunk_middle_forward_middle [middle_forward_middle].light;
                            int lr = chunk_middle_middle_right [middle_middle_right].light;
                            int lb = chunk_middle_back_middle [middle_back_middle].light;
                            int ld = chunk_bottom_middle_middle [bottom_middle_middle].light;

                                                                                        #if UNITY_EDITOR
                            if (enableSmoothLighting && !draftModeActive)
                            {
                                                                #else
                            if (enableSmoothLighting)
                            {
                                                                #endif
                                int v2r  = chunk_top_middle_right [top_middle_right].light;
                                int v2br = chunk_top_back_right [top_back_right].light;
                                int v2b  = chunk_top_back_middle [top_back_middle].light;
                                int v2bl = chunk_top_back_left [top_back_left].light;
                                int v2l  = chunk_top_middle_left [top_middle_left].light;
                                int v2fl = chunk_top_forward_left [top_forward_left].light;
                                int v2f  = chunk_top_forward_middle [top_forward_middle].light;
                                int v2fr = chunk_top_forward_right [top_forward_right].light;

                                int v1fr = chunk_middle_forward_right [middle_forward_right].light;
                                int v1br = chunk_middle_back_right [middle_back_right].light;
                                int v1bl = chunk_middle_back_left [middle_back_left].light;
                                int v1fl = chunk_middle_forward_left [middle_forward_left].light;

                                int v0r  = chunk_bottom_middle_right [bottom_middle_right].light;
                                int v0br = chunk_bottom_back_right [bottom_back_right].light;
                                int v0b  = chunk_bottom_back_middle [bottom_back_middle].light;
                                int v0bl = chunk_bottom_back_left [bottom_back_left].light;
                                int v0l  = chunk_bottom_middle_left [bottom_middle_left].light;
                                int v0fl = chunk_bottom_forward_left [bottom_forward_left].light;
                                int v0f  = chunk_bottom_forward_middle [bottom_forward_middle].light;
                                int v0fr = chunk_bottom_forward_right [bottom_forward_right].light;

                                // Backwards face
                                // Vertex 0
                                occ         = ((lb + v0b + v0bl + v1bl) >> 2);
                                occlusionX += occ;
                                // Vertex 1
                                occ         = ((lb + v0b + v0br + v1br) >> 2);
                                occlusionX += occ << 4;
                                // Vertex 2
                                occ         = ((lb + v1bl + v2bl + v2b) >> 2);
                                occlusionX += occ << 8;
                                // Vertex 3
                                occ         = ((lb + v2b + v2br + v1br) >> 2);
                                occlusionX += occ << 12;

                                // Forward face
                                // Vertex 5
                                occ         = ((lf + v0f + v0fr + v1fr) >> 2);
                                occlusionX += occ << 16;
                                // Vertex 4
                                occ         = ((lf + v0f + v0fl + v1fl) >> 2);
                                occlusionX += occ << 20;
                                // Vertex 6
                                occ         = ((lf + v1fr + v2fr + v2f) >> 2);
                                occlusionY += occ;
                                // Vertex 7
                                occ         = ((lf + v2f + v2fl + v1fl) >> 2);
                                occlusionY += occ << 4;

                                // Top face
                                // Vertex 2
                                occ         = ((lu + v2b + v2bl + v2l) >> 2);
                                occlusionY += occ << 8;
                                // Vertex 3
                                occ         = ((lu + v2b + v2br + v2r) >> 2);
                                occlusionY += occ << 12;
                                // Vertex 7
                                occ         = ((lu + v2l + v2fl + v2f)) >> 2;
                                occlusionY += occ << 16;
                                // Vertex 6
                                occ         = ((lu + v2r + v2fr + v2f) >> 2);
                                occlusionY += occ << 20;

                                // Left face
                                // Vertex 0
                                occ         = ((ll + v1bl + v0l + v0bl) >> 2);
                                occlusionZ += occ;
                                // Vertex 4
                                occ         = ((ll + v1fl + v0l + v0fl) >> 2);
                                occlusionZ += occ << 4;
                                // Vertex 2
                                occ         = ((ll + v2l + v2bl + v1bl) >> 2);
                                occlusionZ += occ << 8;
                                // Vertex 7
                                occ         = ((ll + v2l + v2fl + v1fl) >> 2);
                                occlusionZ += occ << 12;

                                // Right face
                                // Vertex 1
                                occ         = ((lr + v1br + v0r + v0br) >> 2);
                                occlusionZ += occ << 16;
                                // Vertex 5
                                occ         = ((lr + v1fr + v0r + v0fr) >> 2);
                                occlusionZ += occ << 20;
                                // Vertex 3
                                occ         = ((lr + v2r + v2br + v1br) >> 2);
                                occlusionW += occ;
                                // Vertex 6
                                occ         = ((lr + v2r + v2fr + v1fr) >> 2);
                                occlusionW += occ << 4;

                                // Bottom face
                                // Vertex 0
                                occ         = ((ld + v0b + v0l + v0bl) >> 2);
                                occlusionW += occ << 8;
                                // Vertex 1
                                occ         = ((ld + v0b + v0r + v0br) >> 2);
                                occlusionW += occ << 12;
                                // Vertex 4
                                occ         = ((ld + v0f + v0l + v0fl) >> 2);
                                occlusionW += occ << 16;
                                // Vertex 5
                                occ         = ((ld + v0f + v0r + v0fr) >> 2);
                                occlusionW += occ << 20;
                            }
                            else
                            {
                                occlusionX  = lb;                                // back
                                occlusionX += lf << 4;                           // forward
                                occlusionX += lu << 8;                           // top
                                occlusionX += ll << 12;                          // // left
                                occlusionX += lr << 16;                          // right
                                occlusionX += ld << 20;                          // bottom
                            }
                            break;
                        }
                        tempChunkUV0.Add(uvAux);
                        uv2Aux.x = occlusionX;
                        uv2Aux.y = occlusionY;
                        uv2Aux.z = occlusionZ;
                        uv2Aux.w = occlusionW;
                        tempChunkUV2.Add(uv2Aux);

                        if (enableTinting)
                        {
                            tintColor.r = voxels [voxelIndex].red;
                            tintColor.g = voxels [voxelIndex].green;
                            tintColor.b = voxels [voxelIndex].blue;
                            tempChunkColors32.Add(tintColor);
                        }
                    }
                }
            }

            meshJobs [jobIndex].chunk = chunk;

            // chunkVoxelCount includes MIVs
            int nonMivsCount = chunkUVIndex + 1;
            meshJobs [jobIndex].totalVisibleVoxels = nonMivsCount;

            if (chunkVoxelCount == 0)
            {
                return;
            }

            if (voxelSignature != chunk.voxelSignature)
            {
                chunk.needsColliderRebuild = true;
            }
            chunk.voxelSignature = voxelSignature;

            if (enableColliders)
            {
                if (chunk.needsColliderRebuild)
                {
                    greedyCollider.FlushTriangles(meshColliderVertices, meshColliderIndices);
                    if (enableNavMesh)
                    {
                        greedyNavMesh.FlushTriangles(navMeshVertices, navMeshIndices);
                    }
                }
                else
                {
                    greedyCollider.Clear();
                    greedyNavMesh.Clear();
                }
            }

            // job index 0 lists are used as generic buffers but we need to convert them to array to use SetIndices API :(
            int subMeshCount = 0;
            for (int k = 0; k < MAX_MATERIALS_PER_CHUNK; k++)
            {
                if (tempGeoIndices [k].count > 0)
                {
                    subMeshCount++;
                    meshJobs [jobIndex].buffers [k].indicesArray = tempGeoIndices [k].ToArray();
                    meshJobs [jobIndex].buffers [k].indicesCount = meshJobs [jobIndex].buffers [k].indicesArray.Length;
                }
            }
            meshJobs [jobIndex].subMeshCount = subMeshCount;

            meshJobs [jobIndex].colliderVertices = meshColliderVertices;
            meshJobs [jobIndex].colliderIndices  = meshColliderIndices;

            meshJobs [jobIndex].navMeshVertices = navMeshVertices;
            meshJobs [jobIndex].navMeshIndices  = navMeshIndices;

            meshJobs [jobIndex].mivs = mivs;
        }
    }
 static WorldRand()
 {
     WorldRand.Randomize(0);
 }
        void InitChunkManager()
        {
            if (chunksPool == null)
            {
                chunksPool = new VoxelChunk[maxChunks];
            }

            cachedChunks     = new Dictionary <int, CachedChunk> (CHUNKS_CREATION_BUFFER_SIZE);
            chunkRequests    = new Octree[CHUNKS_CREATION_BUFFER_SIZE];
            chunkRequestLast = -1;
            linkedChunks     = new LinkedChunk[CHUNKS_RENDER_BUFFER_SIZE];
            chunkQueueRoot   = 0;
            tempLightmapPos  = new int[16 * 16 * 16 * 9];

            InitOctrees();
            InitHeightMap();
            InitBiomes();

            NoiseTools.seedOffset = WorldRand.GetVector3(Misc.vector3zero, 1024);
            frustumCheckIteration = 1;
            forceChunkSqrDistance = (forceChunkDistance * 16) * (forceChunkDistance * 16);
            if (updatedChunks == null)
            {
                updatedChunks = new List <VoxelChunk> (50);
            }
            else
            {
                updatedChunks.Clear();
            }

            if (world != null)
            {
                if (world.terrainGenerator == null)
                {
                    world.terrainGenerator = Resources.Load <TerrainDefaultGenerator> ("VoxelPlay/Defaults/NullTerrainGenerator");
                }
                world.terrainGenerator.Initialize();

                worldHasDetailGenerators = world.detailGenerators != null && world.detailGenerators.Length > 0;
                if (worldHasDetailGenerators)
                {
                    for (int d = 0; d < world.detailGenerators.Length; d++)
                    {
                        if (world.detailGenerators [d] == null)
                        {
                            Debug.LogWarning("Voxel Play: one world detail generator is missing!");
                            world.detailGenerators = Misc.PackArray <VoxelPlayDetailGenerator> (world.detailGenerators);
                            d--;
                            continue;
                        }
                        world.detailGenerators [d].Init();
                    }
                }
            }

            ClearStats();

            // Prepare scene root object
            if (chunkPlaceholderPrefab == null)
            {
                chunkPlaceholderPrefab = Resources.Load <GameObject> ("VoxelPlay/Prefabs/ChunkGEO");
            }
            if (chunksRoot == null)
            {
                chunksRoot = transform.Find(CHUNKS_ROOT);
                if (chunksRoot != null)
                {
                    DestroyImmediate(chunksRoot.gameObject);
                }
            }
            if (chunksRoot == null)
            {
                GameObject cr = new GameObject(CHUNKS_ROOT);
                cr.hideFlags = HideFlags.DontSave;
                chunksRoot   = cr.transform;
                chunksRoot.hierarchyCapacity = 20000;
                chunksRoot.SetParent(worldRoot, false);
            }
            chunksRoot.gameObject.SetActive(true);
        }
        void ModelPlace(Vector3 position, ModelDefinition model, ref Bounds bounds, int rotationDegrees = 0, float colorBrightness = 1f, bool fitTerrain = false, List <VoxelIndex> indices = null, int indexStart = -1, int indexEnd = -1, bool useUnpopulatedChunks = false, bool refreshChunks = true)
        {
            if (model == null)
            {
                return;
            }
            if (indexStart < 0)
            {
                indexStart = 0;
            }
            if (indexEnd < 0)
            {
                indexEnd = model.bits.Length - 1;
            }

            Vector3 pos;
            int     modelOneYRow = model.sizeZ * model.sizeX;
            int     modelOneZRow = model.sizeX;

            if (rotationDegrees == 360)
            {
                switch (WorldRand.Range(0, 4))
                {
                case 1:
                    rotationDegrees = 90;
                    break;

                case 2:
                    rotationDegrees = 180;
                    break;

                case 3:
                    rotationDegrees = 270;
                    break;
                }
            }

            int     halfSizeX = model.sizeX / 2;
            int     halfSizeZ = model.sizeZ / 2;
            Vector3 zeroPos   = Quaternion.Euler(0, rotationDegrees, 0) * new Vector3(-halfSizeX, 0, -halfSizeZ);

            // ensure all voxel definitions are present
            //bool reloadTextures = false;
            for (int b = indexStart; b <= indexEnd; b++)
            {
                VoxelDefinition vd = model.bits [b].voxelDefinition;
                if (vd != null && vd.index == 0)
                {
                    AddVoxelDefinition(vd);
                    //reloadTextures = true;
                }
            }
            //if (reloadTextures) { // TODO: RML (AddVoxelDefinition already marks reload world textures flag)
            //    LoadWorldTextures();
            //}

            bool indicesProvided = indices != null;

            if (indicesProvided && indexStart < 0 && indexEnd < 0)
            {
                indices.Clear();
            }
            VoxelIndex index = new VoxelIndex();
            Vector3    min   = bounds.min;
            Vector3    max   = bounds.max;

            for (int b = indexStart; b <= indexEnd; b++)
            {
                int bitIndex = model.bits [b].voxelIndex;
                int py       = bitIndex / modelOneYRow;
                int remy     = bitIndex - py * modelOneYRow;
                int pz       = remy / modelOneZRow;
                int px       = remy - pz * modelOneZRow;

                float wx = zeroPos.x, wz = zeroPos.z;
                switch (rotationDegrees)
                {
                case 90:
                    wx += pz;
                    wz -= px;
                    break;

                case 180:
                    wx -= px;
                    wz -= pz;
                    break;

                case 270:
                    wx -= pz;
                    wz += px;
                    break;

                default:
                    wx += px;
                    wz += pz;
                    break;
                }

                pos.x = position.x + model.offsetX + wx;
                pos.y = position.y + model.offsetY + py;
                pos.z = position.z + model.offsetZ + wz;

                VoxelChunk chunk;
                int        voxelIndex;
                if (useUnpopulatedChunks)
                {
                    chunk = GetChunkUnpopulated(pos);
                }
                if (GetVoxelIndex(pos, out chunk, out voxelIndex))
                {
                    bool emptyVoxel = model.bits [b].isEmpty;
                    if (emptyVoxel)
                    {
                        chunk.voxels [voxelIndex] = Voxel.Hole;
                    }
                    else
                    {
                        Color32 color = model.bits [b].finalColor;
                        if (colorBrightness != 1f)
                        {
                            color.r = (byte)(color.r * colorBrightness);
                            color.g = (byte)(color.g * colorBrightness);
                            color.b = (byte)(color.b * colorBrightness);
                        }
                        VoxelDefinition vd = model.bits [b].voxelDefinition ?? defaultVoxel;
                        chunk.voxels [voxelIndex].Set(vd, color);
                        float rotation = (model.bits [b].rotation + 360 + rotationDegrees) % 360;
                        if (rotation != 0)
                        {
                            chunk.voxels [voxelIndex].SetTextureRotation(Voxel.GetTextureRotationFromDegrees(rotation));
                        }

                        // Add index
                        if (indicesProvided)
                        {
                            index.chunk      = chunk;
                            index.voxelIndex = voxelIndex;
                            index.position   = pos;
                            indices.Add(index);
                        }
                        if (pos.x < min.x)
                        {
                            min.x = pos.x;
                        }
                        if (pos.y < min.y)
                        {
                            min.y = pos.y;
                        }
                        if (pos.z < min.z)
                        {
                            min.z = pos.z;
                        }
                        if (pos.x > max.x)
                        {
                            max.x = pos.x;
                        }
                        if (pos.y > max.y)
                        {
                            max.y = pos.y;
                        }
                        if (pos.z > max.z)
                        {
                            max.z = pos.z;
                        }

                        if (fitTerrain)
                        {
                            // Fill beneath row 1
                            if (py == 0)
                            {
                                Vector3 under = pos;
                                under.y -= 1;
                                for (int k = 0; k < 100; k++, under.y--)
                                {
                                    VoxelChunk lowChunk;
                                    int        vindex;
                                    GetVoxelIndex(under, out lowChunk, out vindex, false);
                                    if (lowChunk != null && lowChunk.voxels [vindex].opaque < FULL_OPAQUE)
                                    {
                                        lowChunk.voxels [vindex].Set(vd, color);
                                        lowChunk.modified = true;
                                        if (!lowChunk.inqueue && !useUnpopulatedChunks)
                                        {
                                            ChunkRequestRefresh(lowChunk, true, true);
                                        }
                                    }
                                    else
                                    {
                                        break;
                                    }
                                }
                            }
                        }
                    }

                    // Prevent tree population
                    chunk.allowTrees = false;
                    chunk.modified   = true;

                    if (!chunk.inqueue && !useUnpopulatedChunks)
                    {
                        chunk.MarkAsInconclusive();
                        if (refreshChunks)
                        {
                            ChunkRequestRefresh(chunk, true, true);
                        }
                    }
                }
            }

            FastVector.Floor(ref min);
            FastVector.Ceiling(ref max);
            bounds.center = (max + min) * 0.5f;
            bounds.size   = max - min;
        }
Beispiel #14
0
        /// <summary>
        /// Called by Voxel Play to inform that player has moved onto another chunk so new detail can start generating
        /// </summary>
        /// <param name="position">Current player position.</param>
        /// <param name="checkOnlyBorders">True means the player has moved to next chunk. False means player position is completely new and all chunks in
        /// range should be checked for detail in this call.</param>
        /// <param name="endTime">Provides a maximum time frame for execution this frame. Compare this with env.stopwatch milliseconds.</param>
        public override void ExploreArea(Vector3 position, bool checkOnlyBorders, long endTime)
        {
            float prob             = Mathf.Clamp01(1f - spawnProbability);
            int   explorationRange = env.visibleChunksDistance + 10;
            int   minz             = -explorationRange;
            int   maxz             = +explorationRange;
            int   minx             = -explorationRange;
            int   maxx             = +explorationRange;

            position = env.GetChunkPosition(position);
            Vector3 pos  = position;
            bool    temp = true;

            for (int z = minz; z <= maxz; z++)
            {
                for (int x = minx; x < maxx; x++)
                {
                    if (checkOnlyBorders && z > minz && z < maxz && x > minx && x < maxx)
                    {
                        continue;
                    }
                    pos.x = position.x + x * VoxelPlayEnvironment.CHUNK_SIZE;
                    pos.z = position.z + z * VoxelPlayEnvironment.CHUNK_SIZE;
                    temp  = true;
                    foreach (KeyValuePair <Vector3, BuildingStatus> kv in buildingPositions)
                    {
                        if (pos != kv.Key)
                        {
                            if (Vector3.Distance(pos, kv.Key) < spawnDistance)
                            {
                                temp = false;
                                break;
                            }
                        }
                    }
                    if (WorldRand.GetValue(pos) > prob && temp)
                    {
                        BuildingStatus bs;
                        if (!buildingPositions.TryGetValue(pos, out bs))
                        {
                            float h = env.GetTerrainHeight(pos, false);



                            if (h > env.waterLevel)
                            {
                                //added -5
                                bs.height          = h - 5;
                                bs.placementStatus = false;

                                // No trees on this chunk
                                VoxelChunk chunk;
                                env.GetChunk(pos, out chunk, false);
                                if (chunk != null)
                                {
                                    chunk.allowTrees = false;
                                }
                            }
                            else
                            {
                                bs.placementStatus = true;
                            }
                            if (temp)
                            {
                                buildingPositions[pos] = bs;
                            }
                        }
                    }
                }
            }
        }