public int Write(int x, int y, int z, VFVoxel voxel, int lod = 0, bool bUpdateLod = true)
    {
        _dirtyChunkList.Clear();

        int chunkNumX = LODOctreeMan._xChunkCount >> lod;
        int chunkNumY = LODOctreeMan._yChunkCount >> lod;
        int chunkNumZ = LODOctreeMan._zChunkCount >> lod;
        int cx        = x >> VoxelTerrainConstants._shift;
        int cy        = y >> VoxelTerrainConstants._shift;
        int cz        = z >> VoxelTerrainConstants._shift;
        int cxround   = (cx >> lod) % chunkNumX;
        int cyround   = (cy >> lod) % chunkNumY;
        int czround   = (cz >> lod) % chunkNumZ;

        if (cxround < 0)
        {
            cxround += chunkNumX;
        }
        if (cyround < 0)
        {
            cyround += chunkNumY;
        }
        if (czround < 0)
        {
            czround += chunkNumZ;
        }
        int              vx        = (x >> lod) & VoxelTerrainConstants._mask;
        int              vy        = (y >> lod) & VoxelTerrainConstants._mask;
        int              vz        = (z >> lod) & VoxelTerrainConstants._mask;
        LODOctreeNode    node      = _lodNodes[lod][cxround, cyround, czround];
        VFVoxelChunkData chunkData = (VFVoxelChunkData)node._data[_idxData];
        IntVector4       poslod    = chunkData.ChunkPosLod;

        if (poslod == null || poslod.x != cx || poslod.y != cy || poslod.z != cz)
        {
            return(0);
        }

        VFVoxelChunkData.ProcOnWriteVoxel onWriteVoxel = null;
        if (_idxData == 0 && VFVoxelWater.self != null)
        {
            onWriteVoxel = VFVoxelWater.self.OnWriteVoxelOfTerrain;
        }
        if (!chunkData.WriteVoxelAtIdx(vx, vy, vz, voxel, bUpdateLod, onWriteVoxel))
        {
            return(0x100);             //1<<8
        }
        _dirtyChunkList.Add(chunkData);
        int fx = 0, fy = 0, fz = 0;
        int dirtyMask = 0x80;           // bit 0,1,2 for xyz dirty mask;bit 4,5,6  for sign(neg->1);bit 7 for current pos(now not used)

        // Note: To write at lod boundary will cause wrong chunk writing because cxround/cyround/czround is incorrect.
        // To write edge voxel will cause neibour chunks being modified
        if (vx < VFVoxelChunkData.S_MinNoDirtyIdx)
        {
            fx = -1; dirtyMask |= 0x11;
        }
        else
        if (vx >= VFVoxelChunkData.S_MaxNoDirtyIdx)
        {
            fx = 1; dirtyMask |= 0x01;
        }
        if (vy < VFVoxelChunkData.S_MinNoDirtyIdx)
        {
            fy = -1; dirtyMask |= 0x22;
        }
        else
        if (vy >= VFVoxelChunkData.S_MaxNoDirtyIdx)
        {
            fy = 1; dirtyMask |= 0x02;
        }
        if (vz < VFVoxelChunkData.S_MinNoDirtyIdx)
        {
            fz = -1; dirtyMask |= 0x44;
        }
        else
        if (vz >= VFVoxelChunkData.S_MaxNoDirtyIdx)
        {
            fz = 1; dirtyMask |= 0x04;
        }

        if (dirtyMask != 0x80)
        {
            int cxlod = (cx >> lod);
            int cylod = (cy >> lod);
            int czlod = (cz >> lod);
            for (int i = 1; i < 8; i++)
            {
                if ((dirtyMask & i) == i)
                {
                    int dx = fx * VFVoxelChunkData.S_NearChunkOfs[i, 0], dy = fy * VFVoxelChunkData.S_NearChunkOfs[i, 1], dz = fz * VFVoxelChunkData.S_NearChunkOfs[i, 2];
                    cxround = (cxlod + dx) % chunkNumX;
                    cyround = (cylod + dy) % chunkNumY;
                    czround = (czlod + dz) % chunkNumZ;
                    if (cxround < 0)
                    {
                        cxround += chunkNumX;
                    }
                    if (cyround < 0)
                    {
                        cyround += chunkNumY;
                    }
                    if (czround < 0)
                    {
                        czround += chunkNumZ;
                    }
                    chunkData = (VFVoxelChunkData)_lodNodes[lod][cxround, cyround, czround]._data[_idxData];
                    if (!chunkData.WriteVoxelAtIdx(
                            vx - dx * VoxelTerrainConstants._numVoxelsPerAxis,
                            vy - dy * VoxelTerrainConstants._numVoxelsPerAxis,
                            vz - dz * VoxelTerrainConstants._numVoxelsPerAxis, voxel, bUpdateLod))
                    {
                        dirtyMask |= 1 << (i + 8);                      // flag for unsuccessful write
                    }
                    else
                    {
                        _dirtyChunkList.Add(chunkData);
                    }
                }
            }
        }
        return(dirtyMask);
    }
 public void writeChunk(int cposx, int cposy, int cposz, VFVoxelChunkData data, int lod = 0)
 {
     Debug.LogError("Unavailable interface: writeChunk");
 }
Example #3
0
    public bool IsInTerrain(float fx, float fy, float fz)
    {
        int x  = Mathf.RoundToInt(fx);
        int y  = Mathf.RoundToInt(fy);
        int z  = Mathf.RoundToInt(fz);
        int cx = x >> VoxelTerrainConstants._shift;
        int cy = y >> VoxelTerrainConstants._shift;
        int cz = z >> VoxelTerrainConstants._shift;
        VFVoxelChunkData chunk = _voxels.readChunk(cx, cy, cz);

        if (chunk == null || chunk.DataVT.Length < VFVoxel.c_VTSize)
        {
            return(false);
        }
        byte cVol;

        if (chunk.IsHollow)
        {
            cVol = chunk.DataVT[0];
            if (cVol < 128)
            {
                return(false);
            }
            else
            {
                return(true);
            }
        }
        int idx = VFVoxelChunkData.OneIndex(x & VoxelTerrainConstants._mask,
                                            y & VoxelTerrainConstants._mask,
                                            z & VoxelTerrainConstants._mask);
        int idxVT = idx << VFVoxel.c_shift;

        cVol = chunk.DataVT[idxVT];
        if (cVol == 0)
        {
            return(false);
        }
        if (cVol == 255)
        {
            return(true);
        }
        byte oVol;

        if (cVol < 128)
        {
            oVol = chunk.DataVT[idxVT - VoxelTerrainConstants.VOXEL_ARRAY_AXIS_SIZE_VT];
            if (oVol >= 128)
            {
                return(((128 - oVol) / (float)(cVol - oVol) + y - 1) > fy);
            }
            oVol = chunk.DataVT[idxVT + VoxelTerrainConstants.VOXEL_ARRAY_AXIS_SIZE_VT];
            if (oVol >= 128)
            {
                return(((128 - cVol) / (float)(oVol - cVol) + y) < fy);
            }
            return(false);
        }
        else
        {
            oVol = chunk.DataVT[idxVT - VoxelTerrainConstants.VOXEL_ARRAY_AXIS_SIZE_VT];
            if (oVol < 128)
            {
                return(((128 - oVol) / (float)(cVol - oVol) + y - 1) < fy);
            }
            oVol = chunk.DataVT[idxVT + VoxelTerrainConstants.VOXEL_ARRAY_AXIS_SIZE_VT];
            if (oVol < 128)
            {
                return(((128 - cVol) / (float)(oVol - cVol) + y) > fy);
            }
            return(true);
        }
    }
 private static void OnChunkDataLoad(VFVoxelChunkData chunkData, byte[] chunkDataVT, bool bFromPool)     // do not add to buildLiat
 {
     chunkData.SetDataVT(chunkDataVT, bFromPool);
 }
Example #5
0
 public void ProcPostLodRefresh()
 {
     VFVoxelChunkData.EndAllReqs();
     _dataLoader.ProcessReqs();
 }
Example #6
0
    public VFVoxel ChunkProcExtractData(ILODNodeData ndata, int x, int y, int z)
    {
        VFVoxelChunkData cdata = ndata as VFVoxelChunkData;

        return(new VFVoxel(cdata.DataVT[0], cdata.DataVT[1]));
    }
 public SurfExtractReqTrans(int faceMask, VFVoxelChunkData chunkData)
 {
     _faceMask   = faceMask;
     _chunkStamp = chunkData.ChunkPosLod.GetHashCode();
     _chunkData  = chunkData;
 }
Example #8
0
    void ScanOneChunk(IntVector4 cposlod, out List <Vector3> outputVerts, out List <Color32> outputCols)
    {
        outputVerts = new List <Vector3>();
        outputCols  = new List <Color32>();
        VFVoxelChunkData cdata = _dataSource.readChunk(cposlod.x, cposlod.y, cposlod.z, cposlod.w);

        if (cdata == null)
        {
            return;
        }
        byte[] data = cdata.DataVT;
        int    nLen = data.Length;

        if (nLen == 0)
        {
            return;
        }
        if (nLen == VFVoxel.c_VTSize)
        {
            if (mMatList.Contains(data[1]))
            {
                int nVerts = 1 << (VoxelTerrainConstants._shift * 3);
                outputVerts = new List <Vector3>(nVerts);
                outputCols  = new List <Color32>(nVerts);
                Vector3 point = new Vector3(0, 0, 0);
                Color32 col   = MetalScanData.GetColorByType((byte)(data[0] * 2));            // new Color32((byte)(data[0]*2), 0, 0, 255);
                for (int z = 0; z < VoxelTerrainConstants._numVoxelsPerAxis; z++, point.z++)
                {
                    for (int y = 0; y < VoxelTerrainConstants._numVoxelsPerAxis; y++, point.y++)
                    {
                        for (int x = 0; x < VoxelTerrainConstants._numVoxelsPerAxis; x++, point.x++)
                        {
                            outputVerts.Add(point);
                            outputCols.Add(col);
                        }
                        point.x = 0;
                    }
                    point.y = 0;
                }
                return;
            }
            return;
        }
        else
        {
            int idx = (VoxelTerrainConstants._numVoxelsPrefix * VoxelTerrainConstants.VOXEL_ARRAY_AXIS_SIZE + VoxelTerrainConstants._numVoxelsPrefix)
                      * VoxelTerrainConstants.VOXEL_ARRAY_AXIS_SIZE + VoxelTerrainConstants._numVoxelsPrefix;
            for (int z = 0; z < VoxelTerrainConstants._numVoxelsPerAxis; z++)
            {
                for (int y = 0; y < VoxelTerrainConstants._numVoxelsPerAxis; y++)
                {
                    for (int x = 0; x < VoxelTerrainConstants._numVoxelsPerAxis; x++, idx++)
                    {
                        int idxBy = idx << 1;
                        if (data[idxBy] >= 128)
                        {
                            byte  curType = data[idxBy + 1];
                            Color col     = MetalScanData.GetColorByType(curType);
                            if (mMatList.Contains(curType))
                            {
                                outputVerts.Add(new Vector3(x, y, z));
                                outputCols.Add(col);
                                //outputCols.Add(new Color32(255, 0, 0, 255));
                            }
                        }
                    }
                    idx += VoxelTerrainConstants._numVoxelsPrefix + VoxelTerrainConstants._numVoxelsPostfix;
                }
                idx += (VoxelTerrainConstants._numVoxelsPrefix + VoxelTerrainConstants._numVoxelsPostfix) * VoxelTerrainConstants.VOXEL_ARRAY_AXIS_SIZE;
            }
        }
        return;
    }
Example #9
0
 public LODUpdateCmd(VFVoxelChunkData _chunk)
 {
     chunk      = _chunk;
     posToRead  = null;
     posToWrite = null;
 }
Example #10
0
    public void GenUpdateCmd(IntVector3 chunkPos, IntVector3 localPos, List <LODUpdateCmd> updateCmdList)
    {
        //int dim = 0;
        IntVector3 modPos = null;

        localPos.x += 1;
        localPos.y += 1;
        localPos.z += 1;

        IntVector3 runningPos = new IntVector3(localPos);

        for (int i = 0; i < LODOctreeMan.MaxLod; i++)
        {
            //dim = 32 * (1 << i);

            IntVector3 lodChunkPos = new IntVector3(chunkPos);

            lodChunkPos.x = lodChunkPos.x >> i << i;
            lodChunkPos.y = lodChunkPos.y >> i << i;
            lodChunkPos.z = lodChunkPos.z >> i << i;

            // attach a dummy octreenode
            VFVoxelChunkData cd = ForgeChunk(lodChunkPos, i);
            if (modPos == null)
            {
                modPos = cd.ChunkPosLod.XYZ;
            }

            LODUpdateCmd cmd = new LODUpdateCmd(cd);
            if (i > 0)
            {
                if (runningPos.x < 0 || runningPos.y < 0 || runningPos.z < 0)
                {
                    break;
                }
                cmd.posToWrite = new IntVector3(runningPos);
            }

//			LODUpdateCmd.PreReadOps(runningPos);

            cmd.posToRead = new IntVector3(runningPos);
            //LODUpdateCmd.PostReadOps(runningPos, modPos);

            runningPos.x += (modPos.x % 2) * 35;
            runningPos.y += (modPos.y % 2) * 35;
            runningPos.z += (modPos.z % 2) * 35;

            int xIdx = voxelIndexInverted[runningPos.x];
            int yIdx = voxelIndexInverted[runningPos.y];
            int zIdx = voxelIndexInverted[runningPos.z];

            runningPos.x = xIdx;
            runningPos.y = yIdx;
            runningPos.z = zIdx;

            modPos.x = modPos.x >> 1;
            modPos.y = modPos.y >> 1;
            modPos.z = modPos.z >> 1;

            IntVector4   cmdVec = new IntVector4(cmd.posToRead.x, cmd.posToRead.y, cmd.posToRead.z, i);
            LODUpdateCmd outCmd;
            if (cmdCollision.TryGetValue(cmdVec, out outCmd) == true)
            {
                if (!outCmd.Equals(cmd))
                {
                    updateCmdList.Add(cmd);
                }
            }
            else
            {
                cmdCollision.Add(cmdVec, cmd);
                updateCmdList.Add(cmd);
            }
        }
    }
Example #11
0
    private VFVoxelChunkData[] GenerateFluidConstWater(VFVoxelChunkData curChunk, VFVoxelChunkData[] neibourChunks, VFVoxelChunkData[] dirtyNeibourChunks, bool bRebuildNow)
    {
        byte[] data = curChunk.DataVT;
        byte[] terData = GetTerraDataForWater(curChunk);
        int    fluidDataLevel1, fluidDataLevel2, fluidDataLevel3, fluidDataLevel4, fluidDataLevel5, fluidDataLevel6;
        int    terraDataLevel6;

        for (int j = 0; j < VoxelTerrainConstants._numVoxelsPerAxis; j++)               // Y
        {
            for (int k = 0; k < VoxelTerrainConstants._numVoxelsPerAxis; k++)           // X
            {
                for (int l = 0; l < VoxelTerrainConstants._numVoxelsPerAxis; l++)       // Z
                {
                    int idx6   = VFVoxelChunkData.OneIndex(k, j, l);
                    int idxVT6 = idx6 * VFVoxel.c_VTSize;
                    fluidDataLevel6 = data[idxVT6];
                    terraDataLevel6 = terData[idxVT6];
                    // Stratege: Fluid only if volume>terVolume
                    if (fluidDataLevel6 > terraDataLevel6)
                    {
                        byte type   = data[idxVT6 + 1];
                        int  idxVT3 = idxVT6 - VoxelTerrainConstants.VOXEL_ARRAY_AXIS_SIZE_VT;                                  // y-1
                        fluidDataLevel3 = data[idxVT3];
                        if (fluidDataLevel3 < 255 && (terData[idxVT3] < 255 || terraDataLevel6 == 0))                           // avoiding water-mesh z-fight with ter-mesh
                        {
                            fluidDataLevel3 = 255;
                            VFVoxelChunkData.ModVolumeType(curChunk, idxVT3, (byte)fluidDataLevel3, type, neibourChunks, dirtyNeibourChunks);
                        }
                        EulerianMatrix eulerianMatrix = EulerianMatrix.None;
                        int            idxVT1         = idxVT6 - VFVoxel.c_VTSize;                                              // x-1
                        int            idxVT2         = idxVT6 + VFVoxel.c_VTSize;                                              // x+1
                        int            idxVT4         = idxVT6 + VoxelTerrainConstants.VOXEL_ARRAY_AXIS_SQUARED_VT;             // z+1
                        int            idxVT5         = idxVT6 - VoxelTerrainConstants.VOXEL_ARRAY_AXIS_SQUARED_VT;             // z-1
                        fluidDataLevel1 = data[idxVT1];
                        fluidDataLevel2 = data[idxVT2];
                        fluidDataLevel4 = data[idxVT4];
                        fluidDataLevel5 = data[idxVT5];
                        int maxFluidableLevel = fluidDataLevel6 - Viscosity;
                        if (fluidDataLevel1 < maxFluidableLevel && terData[idxVT1] < fluidDataLevel6)
                        {
                            eulerianMatrix |= EulerianMatrix.Left;
                        }
                        if (fluidDataLevel2 < maxFluidableLevel && terData[idxVT2] < fluidDataLevel6)
                        {
                            eulerianMatrix |= EulerianMatrix.Right;
                        }
                        if (fluidDataLevel4 < maxFluidableLevel && terData[idxVT4] < fluidDataLevel6)
                        {
                            eulerianMatrix |= EulerianMatrix.Forward;
                        }
                        if (fluidDataLevel5 < maxFluidableLevel && terData[idxVT5] < fluidDataLevel6)
                        {
                            eulerianMatrix |= EulerianMatrix.Backward;
                        }
                        if (eulerianMatrix != EulerianMatrix.None)
                        {
                            if (0 != (eulerianMatrix & EulerianMatrix.Left) && data[idxVT1] != maxFluidableLevel)
                            {
                                VFVoxelChunkData.ModVolumeType(curChunk, idxVT1, (byte)maxFluidableLevel, type, neibourChunks, dirtyNeibourChunks);
                            }
                            if (0 != (eulerianMatrix & EulerianMatrix.Right) && data[idxVT2] != maxFluidableLevel)
                            {
                                VFVoxelChunkData.ModVolumeType(curChunk, idxVT2, (byte)maxFluidableLevel, type, neibourChunks, dirtyNeibourChunks);
                            }
                            if (0 != (eulerianMatrix & EulerianMatrix.Forward) && data[idxVT4] != maxFluidableLevel)
                            {
                                VFVoxelChunkData.ModVolumeType(curChunk, idxVT4, (byte)maxFluidableLevel, type, neibourChunks, dirtyNeibourChunks);
                            }
                            if (0 != (eulerianMatrix & EulerianMatrix.Backward) && data[idxVT5] != maxFluidableLevel)
                            {
                                VFVoxelChunkData.ModVolumeType(curChunk, idxVT5, (byte)maxFluidableLevel, type, neibourChunks, dirtyNeibourChunks);
                            }
                        }
                    }
                }
            }
        }
        if (bRebuildNow)
        {
            for (int i = 0; i < 27; i++)
            {
                if (dirtyNeibourChunks[i] != null)
                {
                    dirtyNeibourChunks[i].EndBatchWriteVoxels();
                }
            }
        }
        return(dirtyNeibourChunks);
    }
Example #12
0
    // For water data generation, invoke GenerateFluidConstWater instead of GenerateFluid
    public bool UpdateFluidConstWater(bool bRebuild)
    {
        int nDirtyChunkPos = _dirtyChunkPosList.Count;

        if (nDirtyChunkPos == 0)
        {
            return(false);
        }

        _tmpDirtyChunks.Clear();
        _tmpDirtyChunkPosList.Clear();
        for (int n = 0; n < nDirtyChunkPos; n++)
        {
            IntVector4       chunkPos      = _dirtyChunkPosList[n];
            VFVoxelChunkData curWaterChunk = VFVoxelWater.self.Voxels.readChunk(chunkPos.x, chunkPos.y, chunkPos.z, 0);
            if (curWaterChunk == null || curWaterChunk.DataVT.Length <= VFVoxel.c_VTSize)
            {
                if (!_tmpDirtyChunkPosList.Contains(chunkPos))
                {
                    _tmpDirtyChunkPosList.Add(chunkPos);
                }
                continue;
            }

            int idx = 0;
            for (int z = -1; z <= 1; z++)
            {
                for (int y = -1; y <= 1; y++)
                {
                    for (int x = -1; x <= 1; x++)
                    {
                        VFVoxelChunkData chunk = idx == 13 ? curWaterChunk :
                                                 VFVoxelWater.self.Voxels.readChunk(chunkPos.x + x, chunkPos.y + y, chunkPos.z + z, 0);
                        if (chunk == null || chunk.DataVT.Length < VFVoxel.c_VTSize)
                        {
                            x = y = z = 2;                             //skip
                        }
                        else
                        {
                            _tmpNeibourChunks[idx++] = chunk;
                        }
                    }
                }
            }
            if (idx < 27)
            {
                if (!_tmpDirtyChunkPosList.Contains(chunkPos))
                {
                    _tmpDirtyChunkPosList.Add(chunkPos);
                }
                continue;
            }

            Array.Clear(_tmpDirtyNeibourChunks, 0, _tmpDirtyNeibourChunks.Length);                              // ready for output
            GenerateFluidConstWater(curWaterChunk, _tmpNeibourChunks, _tmpDirtyNeibourChunks, false);           // Not rebuild right now
            for (int i = 0; i < 27; i++)
            {
                if (_tmpDirtyNeibourChunks[i] != null)
                {
                    IntVector4 curChunkPos = _tmpDirtyNeibourChunks[i].ChunkPosLod;
                    if (!_tmpDirtyChunkPosList.Contains(curChunkPos))
                    {
                        _tmpDirtyChunkPosList.Add(curChunkPos);
                        _tmpDirtyChunks.Add(_tmpDirtyNeibourChunks[i]);                                 // for Fluid's flag of bRebuildNow=false
                    }
                }
            }
        }
        List <IntVector4> _tmpPosList = _dirtyChunkPosList;

        _dirtyChunkPosList    = _tmpDirtyChunkPosList;
        _tmpDirtyChunkPosList = _tmpPosList;
        if (bRebuild)
        {
            int n = _tmpDirtyChunks.Count;
            for (int i = 0; i < n; i++)
            {
                _tmpDirtyChunks[i].EndBatchWriteVoxels();
            }
        }
        return(true);
    }
Example #13
0
    private VFVoxelChunkData[] GenerateFluid(VFVoxelChunkData curChunk, VFVoxelChunkData[] neibourChunks, VFVoxelChunkData[] dirtyNeibourChunks, bool bRebuildNow)
    {
        byte[] data = curChunk.DataVT;
        if (data.Length < VoxelTerrainConstants.VOXEL_ARRAY_LENGTH_VT)          // Safe code for multi mode may no data
        {
            return(dirtyNeibourChunks);
        }

        byte[] terData = GetTerraDataForWater(curChunk);
        int    fluidDataLevel1, fluidDataLevel2, fluidDataLevel3, fluidDataLevel4, fluidDataLevel5, fluidDataLevel6;
        int    terraDataLevel6;

        for (int j = 0; j < VoxelTerrainConstants._numVoxelsPerAxis; j++)               // Y
        {
            for (int k = 0; k < VoxelTerrainConstants._numVoxelsPerAxis; k++)           // X
            {
                for (int l = 0; l < VoxelTerrainConstants._numVoxelsPerAxis; l++)       // Z
                {
                    int idx6   = VFVoxelChunkData.OneIndex(k, j, l);
                    int idxVT6 = idx6 * VFVoxel.c_VTSize;
                    fluidDataLevel6 = data[idxVT6];
                    terraDataLevel6 = terData[idxVT6];
                    // Stratege: Fluid only if volume>terVolume
                    if (fluidDataLevel6 > terraDataLevel6)
                    {
                        byte type        = data[idxVT6 + 1];
                        bool bConstWater = type >= (byte)VFVoxel.EType.WaterSourceBeg;
                        int  idxVT3      = idxVT6 - VoxelTerrainConstants.VOXEL_ARRAY_AXIS_SIZE_VT;   // y-1
                        fluidDataLevel3 = data[idxVT3];
                        if (fluidDataLevel3 < 255 && (terData[idxVT3] < 255 || terData[idxVT6] == 0)) // Add terData[idxVT6] == 0 to avoid seam between terrain and water
                        {
                            if (bConstWater)                                                          //TMP CODE
                            {
                                fluidDataLevel3 = 255;
                                VFVoxelChunkData.ModVolumeType(curChunk, idxVT3, (byte)fluidDataLevel3, type, neibourChunks, dirtyNeibourChunks);
                                if (data[idxVT6 + VoxelTerrainConstants.VOXEL_ARRAY_AXIS_SIZE_VT] != 0)
                                {
                                    fluidDataLevel6 = 255;
                                }
                                if (data[idxVT6] != fluidDataLevel6)
                                {
                                    VFVoxelChunkData.ModVolumeType(curChunk, idxVT6, (byte)fluidDataLevel6, type, neibourChunks, dirtyNeibourChunks);
                                    continue;
                                }
                            }
                            else
                            {
                                this.FlowBottom(ref fluidDataLevel6, ref fluidDataLevel3);
                                VFVoxelChunkData.ModVolume(curChunk, idxVT3, (byte)fluidDataLevel3, neibourChunks, dirtyNeibourChunks);
                            }
                        }
                        if (fluidDataLevel6 > terraDataLevel6)
                        {
                            EulerianMatrix eulerianMatrix = EulerianMatrix.None;
                            int            idxVT1         = idxVT6 - VFVoxel.c_VTSize;                                                  // x-1
                            int            idxVT2         = idxVT6 + VFVoxel.c_VTSize;                                                  // x+1
                            int            idxVT4         = idxVT6 + VoxelTerrainConstants.VOXEL_ARRAY_AXIS_SQUARED_VT;                 // z+1
                            int            idxVT5         = idxVT6 - VoxelTerrainConstants.VOXEL_ARRAY_AXIS_SQUARED_VT;                 // z-1
                            fluidDataLevel1 = data[idxVT1];
                            fluidDataLevel2 = data[idxVT2];
                            fluidDataLevel4 = data[idxVT4];
                            fluidDataLevel5 = data[idxVT5];
                            int maxFluidableLevel = fluidDataLevel6 - Viscosity;
                            if (fluidDataLevel1 < maxFluidableLevel && terData[idxVT1] < fluidDataLevel6)
                            {
                                eulerianMatrix |= EulerianMatrix.Left;
                            }
                            if (fluidDataLevel2 < maxFluidableLevel && terData[idxVT2] < fluidDataLevel6)
                            {
                                eulerianMatrix |= EulerianMatrix.Right;
                            }
                            if (fluidDataLevel4 < maxFluidableLevel && terData[idxVT4] < fluidDataLevel6)
                            {
                                eulerianMatrix |= EulerianMatrix.Forward;
                            }
                            if (fluidDataLevel5 < maxFluidableLevel && terData[idxVT5] < fluidDataLevel6)
                            {
                                eulerianMatrix |= EulerianMatrix.Backward;
                            }
                            if (eulerianMatrix != EulerianMatrix.None)
                            {
                                switch (eulerianMatrix)
                                {
                                case EulerianMatrix.Left:
                                    this.Flow1(ref fluidDataLevel6, ref fluidDataLevel1);
                                    break;

                                case EulerianMatrix.Right:
                                    this.Flow1(ref fluidDataLevel6, ref fluidDataLevel2);
                                    break;

                                case EulerianMatrix.Left | EulerianMatrix.Right:
                                    this.Flow2(ref fluidDataLevel6, ref fluidDataLevel1, ref fluidDataLevel2);
                                    break;

                                case EulerianMatrix.Forward:
                                    this.Flow1(ref fluidDataLevel6, ref fluidDataLevel4);
                                    break;

                                case EulerianMatrix.Left | EulerianMatrix.Forward:
                                    this.Flow2(ref fluidDataLevel6, ref fluidDataLevel4, ref fluidDataLevel1);
                                    break;

                                case EulerianMatrix.Right | EulerianMatrix.Forward:
                                    this.Flow2(ref fluidDataLevel6, ref fluidDataLevel4, ref fluidDataLevel2);
                                    break;

                                case EulerianMatrix.Left | EulerianMatrix.Right | EulerianMatrix.Forward:
                                    this.Flow3(ref fluidDataLevel6, ref fluidDataLevel1, ref fluidDataLevel2, ref fluidDataLevel4);
                                    break;

                                case EulerianMatrix.Backward:
                                    this.Flow1(ref fluidDataLevel6, ref fluidDataLevel5);
                                    break;

                                case EulerianMatrix.Left | EulerianMatrix.Backward:
                                    this.Flow2(ref fluidDataLevel6, ref fluidDataLevel5, ref fluidDataLevel1);
                                    break;

                                case EulerianMatrix.Right | EulerianMatrix.Backward:
                                    this.Flow2(ref fluidDataLevel6, ref fluidDataLevel5, ref fluidDataLevel2);
                                    break;

                                case EulerianMatrix.Left | EulerianMatrix.Right | EulerianMatrix.Backward:
                                    this.Flow3(ref fluidDataLevel6, ref fluidDataLevel1, ref fluidDataLevel2, ref fluidDataLevel5);
                                    break;

                                case EulerianMatrix.Forward | EulerianMatrix.Backward:
                                    this.Flow2(ref fluidDataLevel6, ref fluidDataLevel4, ref fluidDataLevel5);
                                    break;

                                case EulerianMatrix.Left | EulerianMatrix.Forward | EulerianMatrix.Backward:
                                    this.Flow3(ref fluidDataLevel6, ref fluidDataLevel4, ref fluidDataLevel5, ref fluidDataLevel1);
                                    break;

                                case EulerianMatrix.Right | EulerianMatrix.Forward | EulerianMatrix.Backward:
                                    this.Flow3(ref fluidDataLevel6, ref fluidDataLevel4, ref fluidDataLevel5, ref fluidDataLevel2);
                                    break;

                                case EulerianMatrix.Left | EulerianMatrix.Right | EulerianMatrix.Forward | EulerianMatrix.Backward:
                                    this.Flow4(ref fluidDataLevel6, ref fluidDataLevel4, ref fluidDataLevel5, ref fluidDataLevel1, ref fluidDataLevel2);
                                    break;
                                }
                                // Stratege: Sea(type>=128) can not be flowed into except from top
                                if (0 != (eulerianMatrix & EulerianMatrix.Left) && data[idxVT1 + 1] < (byte)VFVoxel.EType.WaterSourceBeg && data[idxVT1] != fluidDataLevel1 && data[idxVT1 + 1 - VoxelTerrainConstants.VOXEL_ARRAY_AXIS_SIZE_VT] < (byte)VFVoxel.EType.WaterSourceBeg)
                                {
                                    VFVoxelChunkData.ModVolume(curChunk, idxVT1, (byte)fluidDataLevel1, neibourChunks, dirtyNeibourChunks);
                                }
                                if (0 != (eulerianMatrix & EulerianMatrix.Right) && data[idxVT2 + 1] < (byte)VFVoxel.EType.WaterSourceBeg && data[idxVT2] != fluidDataLevel2 && data[idxVT2 + 1 - VoxelTerrainConstants.VOXEL_ARRAY_AXIS_SIZE_VT] < (byte)VFVoxel.EType.WaterSourceBeg)
                                {
                                    VFVoxelChunkData.ModVolume(curChunk, idxVT2, (byte)fluidDataLevel2, neibourChunks, dirtyNeibourChunks);
                                }
                                if (0 != (eulerianMatrix & EulerianMatrix.Forward) && data[idxVT4 + 1] < (byte)VFVoxel.EType.WaterSourceBeg && data[idxVT4] != fluidDataLevel4 && data[idxVT4 + 1 - VoxelTerrainConstants.VOXEL_ARRAY_AXIS_SIZE_VT] < (byte)VFVoxel.EType.WaterSourceBeg)
                                {
                                    VFVoxelChunkData.ModVolume(curChunk, idxVT4, (byte)fluidDataLevel4, neibourChunks, dirtyNeibourChunks);
                                }
                                if (0 != (eulerianMatrix & EulerianMatrix.Backward) && data[idxVT5 + 1] < (byte)VFVoxel.EType.WaterSourceBeg && data[idxVT5] != fluidDataLevel5 && data[idxVT5 + 1 - VoxelTerrainConstants.VOXEL_ARRAY_AXIS_SIZE_VT] < (byte)VFVoxel.EType.WaterSourceBeg)
                                {
                                    VFVoxelChunkData.ModVolume(curChunk, idxVT5, (byte)fluidDataLevel5, neibourChunks, dirtyNeibourChunks);
                                }
                            }
                        }
                        if (data[idxVT6] != fluidDataLevel6 && !bConstWater)
                        {
                            VFVoxelChunkData.ModVolume(curChunk, idxVT6, (byte)fluidDataLevel6, neibourChunks, dirtyNeibourChunks);
                        }
                    }
                }
            }
        }
        if (bRebuildNow)
        {
            for (int i = 0; i < 27; i++)
            {
                if (dirtyNeibourChunks[i] != null)
                {
                    dirtyNeibourChunks[i].EndBatchWriteVoxels();
                }
            }
        }
        return(dirtyNeibourChunks);
    }
    public int Write(int x, int y, int z, VFVoxel voxel, int lod = 0, bool bUpdateLod = true)
    {
        _dirtyChunkList.Clear();

        int _shift  = VoxelTerrainConstants._shift;
        int cx      = (x >> _shift);
        int cy      = (y >> _shift);
        int cz      = (z >> _shift);
        int cxround = cx % _chunkNumX;
        int cyround = cy % _chunkNumY;
        int czround = cz % _chunkNumZ;
        int vx      = (x) & VoxelTerrainConstants._mask;
        int vy      = (y) & VoxelTerrainConstants._mask;
        int vz      = (z) & VoxelTerrainConstants._mask;
        VFVoxelChunkData chunkData = _chunks[cxround, cyround, czround];

        if (!chunkData.WriteVoxelAtIdx(vx, vy, vz, voxel))
        {
            return(0);
        }

        _dirtyChunkList.Add(chunkData);

        int fx = 0, fy = 0, fz = 0;
        int dirtyMask = 0x80;           // 0,1,2 bit for xyz dirty mask;4,5,6 bit for sign(neg->1);7 bit for current pos(now not used)

        // If write one edge's voxel may cause the other edge being modified
        if (vx < VFVoxelChunkData.S_MinNoDirtyIdx)
        {
            fx = -1; dirtyMask |= 0x11;
        }
        else
        if (vx >= VFVoxelChunkData.S_MaxNoDirtyIdx)
        {
            fx = 1; dirtyMask |= 0x01;
        }
        if (vy < VFVoxelChunkData.S_MinNoDirtyIdx)
        {
            fy = -1; dirtyMask |= 0x22;
        }
        else
        if (vy >= VFVoxelChunkData.S_MaxNoDirtyIdx)
        {
            fy = 1; dirtyMask |= 0x02;
        }
        if (vz < VFVoxelChunkData.S_MinNoDirtyIdx)
        {
            fz = -1; dirtyMask |= 0x44;
        }
        else
        if (vz >= VFVoxelChunkData.S_MaxNoDirtyIdx)
        {
            fz = 1; dirtyMask |= 0x04;
        }

        if (dirtyMask != 0x80)
        {
            for (int i = 1; i < 8; i++)
            {
                if ((dirtyMask & i) == i)
                {
                    int dx = fx * VFVoxelChunkData.S_NearChunkOfs[i, 0], dy = fy * VFVoxelChunkData.S_NearChunkOfs[i, 1], dz = fz * VFVoxelChunkData.S_NearChunkOfs[i, 2];
                    cxround = (cx + dx) % _chunkNumX;
                    cyround = (cy + dy) % _chunkNumY;
                    czround = (cz + dz) % _chunkNumZ;
                    try
                    {
                        chunkData = _chunks[cxround, cyround, czround];
                        if (!chunkData.WriteVoxelAtIdx(
                                vx - dx * VoxelTerrainConstants._numVoxelsPerAxis,
                                vy - dy * VoxelTerrainConstants._numVoxelsPerAxis,
                                vz - dz * VoxelTerrainConstants._numVoxelsPerAxis, voxel))
                        {
                            dirtyMask |= i << 8;                                // flag for unsuccessful write
                        }
                        else
                        {
                            _dirtyChunkList.Add(chunkData);
                        }
                    }catch (Exception ex)
                    {
                        Debug.LogError("Unexpected voxel write at(" + cxround + "," + cyround + "," + czround + ")" + ex.ToString());
                    }
                }
            }
        }
        return(dirtyMask);
    }
Example #15
0
    private void GenARiverChunk(ref Vector3 boundMin, ref Vector3 boundMax, MeshCollider mc, IntVector4 chunkPos, string filePrefix)
    {
        int lodPrefix   = VoxelTerrainConstants._numVoxelsPrefix << chunkPos.w;
        int lodAxisSize = VoxelTerrainConstants.VOXEL_ARRAY_AXIS_SIZE << chunkPos.w;
        int sx          = (chunkPos.x << VoxelTerrainConstants._shift) - lodPrefix;
        int sy          = (chunkPos.y << VoxelTerrainConstants._shift) - lodPrefix;
        int sz          = (chunkPos.z << VoxelTerrainConstants._shift) - lodPrefix;
        int ex          = sx + lodAxisSize;
        int ey          = sy + lodAxisSize;
        int ez          = sz + lodAxisSize;
        int minx        = Mathf.Max((int)boundMin.x, sx);
        int miny        = Mathf.Max((int)boundMin.y, sy);
        int minz        = Mathf.Max((int)boundMin.z, sz);
        int maxx        = Mathf.Min((int)boundMax.x, ex);
        int maxy        = Mathf.Min((int)boundMax.y, ey);
        int maxz        = Mathf.Min((int)boundMax.z, ez);

        if (minx >= maxx || miny >= maxy || minz >= maxz)
        {
            return;
        }
        //if(miny < VFVoxelWater.c_fWaterLvl)	miny = (int)VFVoxelWater.c_fWaterLvl;

        VFVoxelChunkData terraChunkData = terraReader.ReadChunkImm(chunkPos);

        byte[] terraData = terraChunkData.DataVT;

        VFVoxelChunkData waterChunkData0 = waterReader.ReadChunkImm(chunkPos);

        byte[] waterData0 = waterChunkData0.DataVT;

        //int idxOfs = 32*VoxelTerrainConstants.VOXEL_ARRAY_AXIS_SIZE_VT;
        //int yOverlap = VoxelTerrainConstants._numVoxelsPrefix + VoxelTerrainConstants._numVoxelsPostfix;

        Ray ray = new Ray();

        ray.direction = Vector3.down;
        Vector3    origin   = new Vector3(0, boundMax.y + 0.5f, 0);
        float      distance = boundMax.y - miny + 1;
        RaycastHit hitInfo;
        int        step = 1 << chunkPos.w;
        int        mask = (-1) << chunkPos.w;

        minx &= mask;
        miny &= mask;
        minz &= mask;
        int  minYIdx      = sy < 0 ? 1 : 0;     // ignore pos -1;
        int  start        = VFVoxelChunkData.OneIndexNoPrefix((minx - sx) >> chunkPos.w, 0, (minz - sz) >> chunkPos.w);
        bool bChunkDirty0 = false;
        bool bColDirty;
        int  cur, y, idx, leftVol, tmpVol;

        for (int z = minz; z < maxz; z += step, start += VoxelTerrainConstants.VOXEL_ARRAY_AXIS_SQUARED)
        {
            cur      = start;
            origin.z = z;
            for (int x = minx; x < maxx; x += step, cur++)
            {
                origin.x   = x;
                ray.origin = origin;
                if (mc.Raycast(ray, out hitInfo, distance) &&
                    hitInfo.point.y >= VFVoxelWater.c_fWaterLvl)                   // this check of y can be removed if neccessary
                {
                    float fHitY = hitInfo.point.y;
                    int   iHitY = (int)(fHitY + 0.5f * step);
                    int   iy    = (iHitY - sy) >> chunkPos.w;
                    if (iy >= 0)
                    {
                        bColDirty = false;
                        if (iy >= VoxelTerrainConstants.VOXEL_ARRAY_AXIS_SIZE)
                        {
                            iy  = VoxelTerrainConstants.VOXEL_ARRAY_AXIS_SIZE;
                            y   = (VoxelTerrainConstants.VOXEL_ARRAY_AXIS_SIZE - 1);
                            idx = (cur << 1) + y * VoxelTerrainConstants.VOXEL_ARRAY_AXIS_SIZE_VT;
                        }
                        else
                        {
                            idx     = (cur << 1) + iy * VoxelTerrainConstants.VOXEL_ARRAY_AXIS_SIZE_VT;
                            leftVol = 255 - terraData[idx];
                            byte surfVol = 0;
                            if (leftVol > 0)
                            {
                                float fLodHitY    = fHitY / step;
                                float fLodHitYDec = fLodHitY - (int)fLodHitY;
                                surfVol = fLodHitYDec < 0.5f ? (byte)(256.0f * 0.5f / (1 - fLodHitYDec)) : (byte)(255.999f * (1 - 0.5f / fLodHitYDec));
                                if (surfVol > waterData0[idx])
                                {
                                    waterData0[idx]     = surfVol;
                                    waterData0[idx + 1] = (byte)VFVoxel.EType.WaterSourceBeg;
                                    bColDirty           = true;
                                }
                            }
                            idx -= VoxelTerrainConstants.VOXEL_ARRAY_AXIS_SIZE_VT;
                            y    = iy - 1;
                            if (bColDirty && y >= 0)                            //for seamlessness with terrain
                            {
                                if (surfVol < 128)
                                {
                                    waterData0[idx]     = 255;
                                    waterData0[idx + 1] = (byte)VFVoxel.EType.WaterSourceBeg;
                                    idx -= VoxelTerrainConstants.VOXEL_ARRAY_AXIS_SIZE_VT;
                                    y--;
                                }
                                else
                                {
                                    waterData0[idx]     = 128;
                                    waterData0[idx + 1] = (byte)VFVoxel.EType.WaterSourceBeg;
                                }
                            }
                        }
                        bool bOverChanged = false, bTmpOverChange = false;
                        for (; y >= minYIdx; y--, idx -= VoxelTerrainConstants.VOXEL_ARRAY_AXIS_SIZE_VT)
                        {
                            bTmpOverChange = false;
                            leftVol        = 255 - terraData[idx];
                            if (bOverChanged)
                            {
                                leftVol += VolPlus;
                            }
                            if (leftVol > waterData0[idx])
                            {
                                if (!bOverChanged)
                                {
                                    leftVol += VolPlus;
                                }
                                if (leftVol > 255)
                                {
                                    if (y + 1 < iy)
                                    {
                                        tmpVol = waterData0[idx + VoxelTerrainConstants.VOXEL_ARRAY_AXIS_SIZE_VT];
                                        if (tmpVol < 255)
                                        {
                                            tmpVol += VolPlus;
                                            if (tmpVol > 255)
                                            {
                                                tmpVol = 255;
                                            }
                                            waterData0[idx + VoxelTerrainConstants.VOXEL_ARRAY_AXIS_SIZE_VT]     = (byte)tmpVol;
                                            waterData0[idx + VoxelTerrainConstants.VOXEL_ARRAY_AXIS_SIZE_VT + 1] = (byte)VFVoxel.EType.WaterSourceBeg;
                                        }
                                    }
                                    bTmpOverChange = true;
                                    leftVol        = 255;
                                }
                                waterData0[idx]     = (byte)(leftVol);
                                waterData0[idx + 1] = (byte)VFVoxel.EType.WaterSourceBeg;
                                bColDirty           = true;
                            }
                            bOverChanged = bTmpOverChange;
                        }

                        if (bColDirty)
                        {
                            bChunkDirty0 = true;
                        }
                    }
                }
            }
        }
        if (bChunkDirty0)
        {
            WriteChunkToFile(filePrefix, waterChunkData0);
        }

        waterChunkData0.ClearMem();
        terraChunkData.ClearMem();
    }
    public int Write(int x, int y, int z, VFVoxel voxel, int lod = 0, bool bUpdateLod = false)
    {
        int cx = x >> SHIFT;
        int cy = y >> SHIFT;
        int cz = z >> SHIFT;
        int vx = x & MASK;
        int vy = y & MASK;
        int vz = z & MASK;

        VFVoxelChunkData chunkData = m_Chunks[cx, cy, cz];

        if (!chunkData.WriteVoxelAtIdxNoReq(vx, vy, vz, voxel, false))
        {
            return(0);
        }

        m_ChunkDirtyFlags[cx, cy, cz]++;
        int minIdx = VoxelTerrainConstants._numVoxelsPostfix;
        int maxIdx = VoxelTerrainConstants._numVoxelsPerAxis - VoxelTerrainConstants._numVoxelsPrefix;
        int fx = 0, fy = 0, fz = 0;
        int dirtyMask = 0x80;           // 0,1,2 bit for xyz dirty mask

        // 4,5,6 bit for sign (neg->1)
        // 7 bit not used

        // If write one edge's voxel may cause the other edge being modified
        if (vx < minIdx && cx > 0)
        {
            fx = -1; dirtyMask |= 0x11;
        }
        else
        if (vx >= maxIdx && cx < m_ChunkNumX - 1)
        {
            fx = 1; dirtyMask |= 0x01;
        }
        if (vy < minIdx && cy > 0)
        {
            fy = -1; dirtyMask |= 0x22;
        }
        else
        if (vy >= maxIdx && cy < m_ChunkNumY - 1)
        {
            fy = 1; dirtyMask |= 0x02;
        }
        if (vz < minIdx && cz > 0)
        {
            fz = -1; dirtyMask |= 0x44;
        }
        else
        if (vz >= maxIdx && cz < m_ChunkNumZ - 1)
        {
            fz = 1; dirtyMask |= 0x04;
        }

        if (dirtyMask != 0x80)
        {
            for (int i = 1; i < 8; ++i)
            {
                if ((dirtyMask & i) == i)
                {
                    int dx = fx * VFVoxelChunkData.S_NearChunkOfs[i, 0];
                    int dy = fy * VFVoxelChunkData.S_NearChunkOfs[i, 1];
                    int dz = fz * VFVoxelChunkData.S_NearChunkOfs[i, 2];
                    try
                    {
                        chunkData = m_Chunks[cx + dx, cy + dy, cz + dz];
                        if (chunkData.WriteVoxelAtIdxNoReq(vx - dx * VOXELCNT, vy - dy * VOXELCNT, vz - dz * VOXELCNT, voxel, false))
                        {
                            // Successful write
                            m_ChunkDirtyFlags[cx + dx, cy + dy, cz + dz]++;
                        }
                        else
                        {
                            // Flag for unsuccessful write
                            dirtyMask |= i << 8;
                        }
                    }
                    catch (Exception e)
                    {
                        Debug.LogError("Unexpected voxel write at (" + (cx + dx).ToString() + "," + (cy + dy).ToString() + "," + (cz + dz).ToString() + ") Error :" + e.ToString());
                    }
                }
            }
        }
        return(dirtyMask);
    }
        public static int PolygonizeTransitionCell(
            int x, int y,                               // The x and y position of the cell within the block face.
            int dirIndex,                               // ref to TransitionFaceCoords
            float cellSize,                             // The width of a cell in world scale.
            VFVoxelChunkData chunkData,
            TransVertices verts, List <int> indices,    // output verts' pos is relative to cur chunk
            TransitionCache cache)
        {
            int        lod2Sample = chunkData.LOD;
            int        sampleStep = 1;      // << lod2Sample;
            int        spacing    = 1 << 1; // Spacing between low-res corners.
            int        scale      = 1 << lod2Sample;
            IntVector3 xAxis      = Tables.TransitionFaceCoords[dirIndex, 0];
            IntVector3 yAxis      = Tables.TransitionFaceCoords[dirIndex, 1];
            IntVector3 zAxis      = Tables.TransitionFaceCoords[dirIndex, 2];
            IntVector3 axisExtend = Tables.TransitionFaceCoords[dirIndex, 4];                                                              // mesh width.
            IntVector3 relOrigin  = Tables.TransitionFaceCoords[dirIndex, 3] * ChunkWidth + xAxis * (x * spacing) + yAxis * (y * spacing); // Origin in sample space(current cell).

            // Rotate to change coordinate
            Matrix3X3 basis = new Matrix3X3(xAxis * sampleStep, yAxis * sampleStep, zAxis * sampleStep);

            IntVector3[] relPos =
            {
                relOrigin + basis * Tables.TransitionCornerCoords[0x00], relOrigin + basis * Tables.TransitionCornerCoords[0x01], relOrigin + basis * Tables.TransitionCornerCoords[0x02],
                relOrigin + basis * Tables.TransitionCornerCoords[0x03], relOrigin + basis * Tables.TransitionCornerCoords[0x04], relOrigin + basis * Tables.TransitionCornerCoords[0x05],
                relOrigin + basis * Tables.TransitionCornerCoords[0x06], relOrigin + basis * Tables.TransitionCornerCoords[0x07], relOrigin + basis * Tables.TransitionCornerCoords[0x08],
                relOrigin + basis * Tables.TransitionCornerCoords[0x09], relOrigin + basis * Tables.TransitionCornerCoords[0x0A],
                relOrigin + basis * Tables.TransitionCornerCoords[0x0B], relOrigin + basis * Tables.TransitionCornerCoords[0x0C]
            };

            // Compute case code(indexing as described in Figure4.17)
            VFVoxel[] voxels =
            {
                chunkData[relPos[0]], chunkData[relPos[1]], chunkData[relPos[2]],
                chunkData[relPos[3]], chunkData[relPos[4]], chunkData[relPos[5]],
                chunkData[relPos[6]], chunkData[relPos[7]], chunkData[relPos[8]],
            };
            uint caseCode = (uint)((voxels[0].Volume >> 7) & 0x001 |
                                   (voxels[1].Volume >> 6) & 0x002 |
                                   (voxels[2].Volume >> 5) & 0x004 |
                                   (voxels[5].Volume >> 4) & 0x008 |
                                   (voxels[8].Volume >> 3) & 0x010 |
                                   (voxels[7].Volume >> 2) & 0x020 |
                                   (voxels[6].Volume >> 1) & 0x040 |
                                   (voxels[3].Volume) & 0x080 |
                                   (voxels[4].Volume << 1) & 0x100);

            if (caseCode == 0 || caseCode == 511)
            {
                return(0);
            }

            cache[x, y].CaseIndex = (byte)caseCode;
            byte[] vols =
            {
                voxels[0].Volume, voxels[1].Volume, voxels[2].Volume,
                voxels[3].Volume, voxels[4].Volume, voxels[5].Volume,
                voxels[6].Volume, voxels[7].Volume, voxels[8].Volume,
                voxels[0].Volume, voxels[2].Volume, voxels[6].Volume, voxels[8].Volume
            };
            byte[] types =
            {
                voxels[0].Type, voxels[1].Type, voxels[2].Type,
                voxels[3].Type, voxels[4].Type, voxels[5].Type,
                voxels[6].Type, voxels[7].Type, voxels[8].Type,
                voxels[0].Type, voxels[2].Type, voxels[6].Type, voxels[8].Type
            };
            // Compute normal based on volumes
            Vector3[] normals = new Vector3[13];
            for (int i = 0; i < 9; i++)
            {
                IntVector3 p  = relPos[i];
                float      nx = p.x >= 1 ? (chunkData[p + IntVector3.UnitX].Volume - chunkData[p - IntVector3.UnitX].Volume) : (chunkData[p + IntVector3.UnitX].Volume - vols[i]);
                float      ny = p.y >= 1 ? (chunkData[p + IntVector3.UnitY].Volume - chunkData[p - IntVector3.UnitY].Volume) : (chunkData[p + IntVector3.UnitY].Volume - vols[i]);
                float      nz = p.z >= 1 ? (chunkData[p + IntVector3.UnitZ].Volume - chunkData[p - IntVector3.UnitZ].Volume) : (chunkData[p + IntVector3.UnitZ].Volume - vols[i]);
                normals[i] = new Vector3(nx, ny, nz);
                //normals[i].Normalize();
            }
            normals[0x9] = normals[0];
            normals[0xA] = normals[2];
            normals[0xB] = normals[6];
            normals[0xC] = normals[8];

            // Compute which of the six faces of the block that the vertex
            // is near. (near is defined as being in boundary cell.)
            byte near = 0;

            if (relOrigin.x == 0)
            {
                near |= (byte)(1 << 0);
            }                                                        // Vertex close to negativeX face.
            if (relOrigin.x == ChunkWidth)
            {
                near |= (byte)(1 << 1);
            }                                                        // Vertex close to positiveX face.
            if (relOrigin.y == 0)
            {
                near |= (byte)(1 << 2);
            }                                                        // Vertex close to negativeY face.
            if (relOrigin.y == ChunkWidth)
            {
                near |= (byte)(1 << 3);
            }                                                        // Vertex close to positiveY face.
            if (relOrigin.z == 0)
            {
                near |= (byte)(1 << 4);
            }                                                        // Vertex close to negativeZ face.
            if (relOrigin.z == ChunkWidth)
            {
                near |= (byte)(1 << 5);
            }                                                                      // Vertex close to positiveZ face.

            byte directionMask = (byte)((x > 0 ? 1 : 0) | ((y > 0 ? 1 : 0) << 1)); // Used to determine which previous cells that are available.on edge, dirmask will be cut
            byte classIndex    = Tables.TransitionCellClass[caseCode];             // Equivalence class index.
            var  data          = Tables.TransitionRegularCellData[classIndex & 0x7F];
            bool inverse       = (classIndex & 0x80) != 0;

            int[] localVertexMapping = new int[12];     //TransitionRegularCellData's hinibble means vertex count(max is 0x0c)

            int nv = (int)data.GetVertexCount();
            int nt = (int)data.GetTriangleCount();

            for (int i = 0; i < nv; i++)
            {
                // HiByte:reuse data shown in Figure 4.18; LoByte:2 end points shown in Figure 4.16
                ushort edgeCode  = Tables.TransitionVertexData[caseCode][i];
                byte   pointCode = (byte)edgeCode;
                byte   reuseCode = (byte)(edgeCode >> 8);
                // v0, v1: 2 end points. v0<v1
                byte v0 = HiNibble(pointCode);
                byte v1 = LoNibble(pointCode);
                //Vector3 n0 = normals[v0];
                //Vector3 n1 = normals[v1];
                byte  d0 = vols[v0];
                byte  d1 = vols[v1];
                int   t  = ((IsoLevel - d0) << 8) / (d1 - d0);
                int   u  = 0x0100 - t;
                float t0 = u * S;
                float t1 = t * S;

                byte v_ = 0;
                byte dir, idx;
                bool bLowSide, bAddCache, bCorner;
                if ((t & 0x00ff) != 0)
                {
                    // Use the reuse information in transitionVertexData, shown in Figure 4.18
                    // directionMask is voxel's dir in current processing planar: (byte)((x > 0 ? 1 : 0) | ((y > 0 ? 1 : 0) << 1))
                    // dir is voxel's dir in current cell
                    dir       = HiNibble(reuseCode);
                    idx       = LoNibble(reuseCode);
                    bLowSide  = ((v0 > 8) && (v1 > 8));
                    bAddCache = (dir & 8) != 0;
                    bCorner   = false;
                }
                else
                {
                    // Try to reuse corner vertex from a preceding cell.
                    // Use the reuse information in transitionCornerData.
                    v_ = t == 0 ? v0 : v1;
                    byte cornerData = Tables.TransitionCornerData[v_];
                    dir       = HiNibble(cornerData);
                    idx       = LoNibble((cornerData));
                    bLowSide  = v_ > 8;
                    bAddCache = true;
                    bCorner   = true;
                }
                bool present = (dir & directionMask) == dir;    // dir is 1 or 2 && not a edge voxel, then the verts is available
                if (present)
                {
                    // The previous cell is available. Retrieve the cached cell
                    // from which to retrieve the reused vertex index from.
                    var prev = cache[x - (dir & 1), y - ((dir >> 1) & 1)];
                    if (prev.CaseIndex == 0 || prev.CaseIndex == 511)
                    {
                        // Previous cell does not contain any geometry.
                        localVertexMapping[i] = -1;
                    }
                    else
                    {
                        // Reuse the vertex index from the previous cell.
                        localVertexMapping[i] = prev.Verts[idx];
                    }
                }
                if (!present || localVertexMapping[i] < 0)
                {
                    localVertexMapping[i] = verts.Count;
                    if (bAddCache)      // The vertex can be reused.
                    {
                        cache[x, y].Verts[idx] = localVertexMapping[i];
                    }

                    verts.IsLowside.Add(bLowSide);                      // half resolution side
                    byte typev_ = types[v_];
                    byte typev0 = types[v0];
                    byte typev1 = types[v1];
                    if (typev_ == 0 || typev0 == 0 || typev1 == 0)                    // type 0 will gen black tri
                    {
                        if (typev_ == 0)
                        {
                            typev_ = typev0;
                        }
                        if (typev_ == 0)
                        {
                            typev_ = typev0 = typev1;
                        }
                        if (typev_ == 0)
                        {
                            typev_ = typev0 = typev1 = 1;
                        }
                        else
                        {
                            if (typev0 == 0)
                            {
                                typev0 = typev_;
                            }
                            if (typev1 == 0)
                            {
                                typev1 = typev_;
                            }
                        }
                    }
                    byte    curType = bCorner ? typev_ : (t0 < 0.5f ? typev1 : typev0);
                    Vector3 vNormal = normals[v1] * t1 + normals[v0] * t0;
                    verts.Normal_t.Add(new Vector4(vNormal.x / 256.0f, vNormal.y / 256.0f, vNormal.z / 256.0f, curType));
                    Vector3 pi = bCorner ? (Vector3)relPos[v_] :
                                 ((Vector3)relPos[v1]) * t1 + ((Vector3)relPos[v0]) * t0;
                    if (bLowSide)
                    {
                        // Variant algo for PE's lod data
                        // Necessary to translate the intersection point to the
                        // high-res side so that it is transformed the same way
                        // as the vertices in the regular cell.
                        Vector3 offset = Vector3.zero;
                        switch (axisExtend.x)
                        {
                        case 0:
                            offset.x = axisExtend.y * cellSize;
                            pi.x     = (float)(relOrigin.x);
                            break;

                        case 1:
                            offset.y = axisExtend.y * cellSize;
                            pi.y     = (float)(relOrigin.y);
                            break;

                        case 2:
                            offset.z = axisExtend.y * cellSize;
                            pi.z     = (float)(relOrigin.z);
                            break;
                        }
#if DELTA_ENABLE
                        deltaCnt++;
                        if (deltaCnt == 17)
                        {
                            deltaCnt = 17;
                        }
                        Vector3 delta = ComputeDelta(pi, lodIndex, ChunkWidth);
                        Vector3 proj  = ProjectNormal(vert.Normal, delta);
                        verts.Near.Add(near);
                        verts.Position.Add((offset + pi + proj) * scale);
#else
                        verts.Near.Add(near);
                        verts.Position.Add((offset + pi) * scale);
#endif
                    }
                    else
                    {
                        // On high-resolution side.
                        verts.Near.Add(0); // Vertices on high-res side are never moved.
                        verts.Position.Add(pi * scale);
                    }
                }
            }

            for (int t = 0; t < nt; ++t)
            {
                if (inverse)
                {
                    indices.Add(localVertexMapping[data[t * 3 + 0]]);
                    indices.Add(localVertexMapping[data[t * 3 + 1]]);
                    indices.Add(localVertexMapping[data[t * 3 + 2]]);
                }
                else
                {
                    indices.Add(localVertexMapping[data[t * 3 + 2]]);
                    indices.Add(localVertexMapping[data[t * 3 + 1]]);
                    indices.Add(localVertexMapping[data[t * 3 + 0]]);
                }
            }

            return(nt);
        }