diff --git a/src/main/java/electrosphere/client/terrain/cells/DrawCellManager.java b/src/main/java/electrosphere/client/terrain/cells/DrawCellManager.java index 4f7a3508..7c1debf4 100644 --- a/src/main/java/electrosphere/client/terrain/cells/DrawCellManager.java +++ b/src/main/java/electrosphere/client/terrain/cells/DrawCellManager.java @@ -491,6 +491,182 @@ public class DrawCellManager { } + /** + transvoxel algorithm spacing management + + want to specify a radius and have it be a circle so we're not wasting resolution on far off corners + To benefit from the LOD, should have a series of for loops + First loop iterates over (-largest radius) -> (largest radius) at an interval of the width of the lowest level of detail chunk + We check all 8 corners of the chunk to see if they all fall within the largest lod concentric circle + There are a few cases to consider + - All fall outside the largest LOD radius (ignore) + - All but one fall outside thel argest LOD radius (ignore) + - All fall within the largest LOD circle (make LOD chunk) + - One is within the next LOD radius, others are within the current LOD radius (ignore for this pass) + - All are within a lower LOD radius (ignore) + + Once we're done with the largest LOD radius, we go to a higher resolution radius and iterate for smaller bounds + + In a middle LOD level, if all corners are outside, but the lower resolution didn't + already pick it up, still need to generate a chunk at the current resolution + + Detection of this case is tricky + We could snap the currently considered position to the nearest low-resolution chunk and then bounds check that low resolution chunk for every + higher resolution position we're considering + This is probably a bad idea + + We could recurse every time a chunk doesn't work for the current level of detail, then evaluate it for a higher level of detail at this closer value + + */ + + //the number of corners to consider for a valid chunk + static final int NUM_CORNERS_TO_CONSIDER = 8; + + //offsets to get from current position to the actual corner to consider + int[] cornerOffsetsX = new int[]{0,1,0,1,0,1,0,1,}; + int[] cornerOffsetsY = new int[]{0,0,0,0,1,1,1,1,}; + int[] cornerOffsetsZ = new int[]{0,0,1,1,0,0,1,1,}; + + /** + * Recursive function that does chunk validity checking + * @param playerChunkPos + * @param minPoint + * @param maxPoint + * @param currentLOD + */ + public void assesChunkPositionsAtLOD( + Vector3i playerChunkPos, + Vector3i minPoint, + Vector3i maxPoint, + int currentLOD + ){ + Vector3i currentChunkPositionConsidered = new Vector3i(playerChunkPos); // The chunk position we're currently considering + double currentRadius = lodLevelRadiusTable[currentLOD]; + double nextRadius = 0; + int increment = 1; + if(currentLOD > 0){ + //only works when the LOD is greater than 0. When it's 0, there is no lower bound on chunk positions to generate + nextRadius = lodLevelRadiusTable[currentLOD-1]; + increment = (int)Math.pow(2,currentLOD); + } + + //iterate + for(int x = minPoint.x; x < maxPoint.x; x = x + increment){ + for(int y = minPoint.y; y < maxPoint.x; y = y + increment){ + for(int z = minPoint.z; z < maxPoint.x; z = z + increment){ + //we have 8 corners to consider + //need to identify which case the current position is + int positionCase = 0; + for(int j = 0; j < NUM_CORNERS_TO_CONSIDER; j++){ + currentChunkPositionConsidered.set( + x + cornerOffsetsX[j] * increment, + y + cornerOffsetsY[j] * increment, + z + cornerOffsetsZ[j] * increment + ); + //figure out the case of this corner + double distance = currentChunkPositionConsidered.distance(playerChunkPos); + if(distance > currentRadius){ + positionCase = 1; + break; + } else if(distance <= nextRadius){ + positionCase = 2; + break; + } + } + switch(positionCase){ + case 0: { + //fully within current band, generate chunk + } break; + case 1: { + //partially outside bound, ignore + } break; + case 2: { + //partially inside higher resolution bound, recurse + assesChunkPositionsAtLOD( + playerChunkPos, + new Vector3i(x,y,z), + new Vector3i(x+increment,y+increment,z+increment), + currentLOD + ); + } break; + } + } + } + } + } + + /** + * Assess all LOD chunk levels + */ + public void assesLODChunks(){ + + //pre-existing values + Vector3d playerPosition = EntityUtils.getPosition(Globals.playerEntity); + Vector3i playerChunkPosition = Globals.clientWorldData.convertRealToChunkSpace(playerPosition); + + //variables used while iterating across chunk positions + double currentRadius = 0; //the current radius is in units of chunks, even though it's a double (it's discrete, not real) + double nextRadius = 0; //the next radius is in units of chunks, even though it's a double (it's discrete, not real) + int increment = 1; //the increment is in units of chunks, not real + //the offsets from the player's position to + //the nearest possible spot we could place a chunk of the current LOD at (in units of chunks) + Vector3i lowerOffsets = new Vector3i(0,0,0); + Vector3i currentChunkPositionConsidered = new Vector3i(playerChunkPosition); // The chunk position we're currently considering + + //actual logic to search for valid chunks + for(int i = NUMBER_OF_LOD_LEVELS - 1; i >= 0; i--){ + currentRadius = lodLevelRadiusTable[i]; + nextRadius = 0; + increment = 1; + if(i > 0){ + //only works when the LOD is greater than 0. When it's 0, there is no lower bound on chunk positions to generate + nextRadius = lodLevelRadiusTable[i-1]; + increment = (int)Math.pow(2,i); + } + //calculate offsets to get from player's current chunk position to the lower resolution grid for the current LOD + lowerOffsets.x = playerChunkPosition.x % ((int)increment); + lowerOffsets.y = playerChunkPosition.y % ((int)increment); + lowerOffsets.z = playerChunkPosition.z % ((int)increment); + + //iterate + for(int x = -(int)currentRadius - lowerOffsets.x; x < currentRadius; x = x + increment){ + for(int y = -(int)currentRadius - lowerOffsets.y; y < currentRadius; y = y + increment){ + for(int z = -(int)currentRadius - lowerOffsets.z; z < currentRadius; z = z + increment){ + //we have 8 corners to consider + //need to identify which case the current position is + int positionCase = 0; + for(int j = 0; j < NUM_CORNERS_TO_CONSIDER; j++){ + currentChunkPositionConsidered.set( + x + cornerOffsetsX[j] * increment, + y + cornerOffsetsY[j] * increment, + z + cornerOffsetsZ[j] * increment + ); + //figure out the case of this corner + double distance = currentChunkPositionConsidered.distance(playerChunkPosition); + if(distance > currentRadius){ + positionCase = 1; + break; + } else if(distance <= nextRadius){ + positionCase = 2; + break; + } + } + switch(positionCase){ + case 0: { + //fully within current band, generate chunk + } break; + case 1: { + //partially outside bound, ignore + } break; + case 2: { + //partially inside higher resolution bound, recurse + } break; + } + } + } + } + } + } }