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"); }
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); }
public void ProcPostLodRefresh() { VFVoxelChunkData.EndAllReqs(); _dataLoader.ProcessReqs(); }
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; }
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; }
public LODUpdateCmd(VFVoxelChunkData _chunk) { chunk = _chunk; posToRead = null; posToWrite = null; }
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); } } }
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); }
// 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); }
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); }
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); }