fix foliage bugs
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2025-03-30 20:01:58 -04:00
parent 67212d6003
commit a1aef00d23
8 changed files with 149 additions and 60 deletions

View File

@ -49,6 +49,37 @@
] ]
} }
], ],
"surfaceGenerationParams": {
"surfaceGenTag": "hills",
"heightOffset": 10,
"floorVariants": [
],
"foliageDescriptions": [
]
}
},
{
"id": "hills_forested",
"displayName": "Hills (Forested)",
"isAerial": false,
"isSurface": true,
"isSubterranean": false,
"regions": [
{
"frequency": 1.0,
"baseFloorVoxel": 1,
"floorVariants": [
{
"voxelId": 2,
"frequency": 1.0,
"dispersion": 1.0,
"priority": 1.0
}
],
"foliageDescription": [
]
}
],
"surfaceGenerationParams": { "surfaceGenerationParams": {
"surfaceGenTag": "hills", "surfaceGenTag": "hills",
"heightOffset": 10, "heightOffset": 10,
@ -60,7 +91,7 @@
"pine2" "pine2"
], ],
"regularity": 0.6, "regularity": 0.6,
"threshold": 0.05, "threshold": 0.2,
"scale": 0.5, "scale": 0.5,
"priority": 1.0 "priority": 1.0
} }

View File

@ -1395,6 +1395,8 @@ Simplify WorldOctTree to reduce lag with large node counts
Increase memory allowance, mostly fixed latency while walking around Increase memory allowance, mostly fixed latency while walking around
AssetManager streaming budget AssetManager streaming budget
Better chunk position hashing algo Better chunk position hashing algo
Hills generator work
Fix foliage manager and cells confusing worldpos and absolutevoxelpos

View File

@ -17,7 +17,6 @@ import electrosphere.entity.Entity;
import electrosphere.entity.btree.BehaviorTree; import electrosphere.entity.btree.BehaviorTree;
import electrosphere.renderer.buffer.HomogenousUniformBuffer.HomogenousBufferTypes; import electrosphere.renderer.buffer.HomogenousUniformBuffer.HomogenousBufferTypes;
import electrosphere.renderer.buffer.ShaderAttribute; import electrosphere.renderer.buffer.ShaderAttribute;
import electrosphere.renderer.meshgen.TransvoxelModelGeneration.TransvoxelChunkData;
import electrosphere.server.terrain.manager.ServerTerrainChunk; import electrosphere.server.terrain.manager.ServerTerrainChunk;
import electrosphere.util.ds.octree.WorldOctTree.WorldOctTreeNode; import electrosphere.util.ds.octree.WorldOctTree.WorldOctTreeNode;
import electrosphere.util.math.GeomUtils; import electrosphere.util.math.GeomUtils;
@ -134,7 +133,7 @@ public class FoliageCell {
/** /**
* The data for generating the visuals * The data for generating the visuals
*/ */
TransvoxelChunkData chunkData; ChunkData chunkData;
/** /**
* Tracks whether the foliage cell has requested its chunk data or not * Tracks whether the foliage cell has requested its chunk data or not
@ -226,7 +225,7 @@ public class FoliageCell {
worldPos.x, worldPos.x,
worldPos.y, worldPos.y,
worldPos.z, worldPos.z,
0 ChunkData.NO_STRIDE
); );
if(currentChunk == null){ if(currentChunk == null){
success = false; success = false;
@ -238,9 +237,11 @@ public class FoliageCell {
this.setFailedGenerationAttempts(this.getFailedGenerationAttempts() + 1); this.setFailedGenerationAttempts(this.getFailedGenerationAttempts() + 1);
return; return;
} }
this.chunkData = new TransvoxelChunkData(currentChunk.getVoxelWeight(), currentChunk.getVoxelType(), 0); this.chunkData = currentChunk;
}
if(success){
this.generate();
} }
this.generate();
} }
@ -248,40 +249,41 @@ public class FoliageCell {
* Generates the foliage cell * Generates the foliage cell
*/ */
protected void generate(){ protected void generate(){
int airID = 0;
boolean shouldGenerate = false; boolean shouldGenerate = false;
ChunkData data = Globals.clientTerrainManager.getChunkDataAtWorldPoint(worldPos,ChunkData.NO_STRIDE);
if(data == null){
return;
}
//get foliage types supported //get foliage types supported
List<String> foliageTypesSupported = new LinkedList<String>(); List<String> foliageTypesSupported = new LinkedList<String>();
Map<Integer,Boolean> handledTypes = new HashMap<Integer,Boolean>();
handledTypes.put(airID,true);
boolean airAbove = true; boolean airAbove = true;
int scale = (int)Math.pow(2,lod); int scale = (int)Math.pow(2,lod);
for(int x = 0; x < scale; x++){ for(int x = 0; x < scale; x++){
for(int y = 0; y < scale; y++){ for(int y = 0; y < scale; y++){
for(int z = 0; z < scale; z++){ for(int z = 0; z < scale; z++){
int voxelType = chunkData.getType(new Vector3i(this.voxelPos).add(x,y,z));
if(handledTypes.containsKey(voxelType)){
continue;
}
if(voxelPos.y + y >= ServerTerrainChunk.CHUNK_DIMENSION){ if(voxelPos.y + y >= ServerTerrainChunk.CHUNK_DIMENSION){
continue; continue;
} }
List<String> currentList = Globals.gameConfigCurrent.getVoxelData().getTypeFromId(data.getType(new Vector3i(voxelPos).add(x,y,z))).getAmbientFoliage(); List<String> currentList = Globals.gameConfigCurrent.getVoxelData().getTypeFromId(voxelType).getAmbientFoliage();
if(currentList == null){ if(currentList == null){
handledTypes.put(voxelType,true);
continue; continue;
} }
foliageTypesSupported.addAll(currentList); foliageTypesSupported.addAll(currentList);
airAbove = data.getType(voxelPos.x + x,voxelPos.y + y + 1,voxelPos.z + z) == 0; airAbove = chunkData.getType(voxelPos.x + x,voxelPos.y + y + 1,voxelPos.z + z) == airID;
if(foliageTypesSupported != null && foliageTypesSupported.size() > 0 && airAbove){ if(foliageTypesSupported != null && foliageTypesSupported.size() > 0 && airAbove){
shouldGenerate = true; shouldGenerate = true;
break; handledTypes.put(voxelType,true);
} }
} }
if(shouldGenerate){
break;
}
}
if(shouldGenerate){
break;
} }
} }
// if(Math.abs(worldPos.x - 32767) < 5 && Math.abs(worldPos.y - 5) < 3 && Math.abs(worldPos.z - 32767) < 3 && this.chunkData.getHomogenousValue() != 0){
// System.out.println(worldPos.x + " " + worldPos.y + " " + worldPos.z + " - " + shouldGenerate);
// }
if(shouldGenerate){ if(shouldGenerate){
Entity oldEntity = this.modelEntity; Entity oldEntity = this.modelEntity;
//create entity //create entity
@ -447,16 +449,16 @@ public class FoliageCell {
/** /**
* Gets the minimum distance from a node to a point * Gets the minimum distance from a node to a point
* @param pos the position to check against * @param absVoxelPos the position to check against
* @param node the node * @param node the node
* @param distCache the lod value under which distance caches are invalidated * @param distCache the lod value under which distance caches are invalidated
* @return the distance * @return the distance
*/ */
public long getMinDistance(Vector3i worldPos, WorldOctTreeNode<FoliageCell> node, int distCache){ public long getMinDistance(Vector3i absVoxelPos, WorldOctTreeNode<FoliageCell> node, int distCache){
if(cachedMinDistance != INVALID_DIST_CACHE && distCache < lod){ if(cachedMinDistance != INVALID_DIST_CACHE && distCache < lod){
return cachedMinDistance; return cachedMinDistance;
} else { } else {
double dist = GeomUtils.approxMinDistanceAABB(worldPos, node.getMinBound(), node.getMaxBound()); double dist = GeomUtils.approxMinDistanceAABB(absVoxelPos, node.getMinBound(), node.getMaxBound());
if(Double.isFinite(dist)){ if(Double.isFinite(dist)){
this.cachedMinDistance = (long)dist; this.cachedMinDistance = (long)dist;
} else { } else {

View File

@ -8,6 +8,7 @@ import java.util.Map;
import org.joml.Vector3d; import org.joml.Vector3d;
import org.joml.Vector3i; import org.joml.Vector3i;
import electrosphere.client.terrain.cache.ChunkData;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.entity.EntityUtils; import electrosphere.entity.EntityUtils;
import electrosphere.game.data.foliage.type.FoliageType; import electrosphere.game.data.foliage.type.FoliageType;
@ -22,6 +23,11 @@ import electrosphere.util.math.GeomUtils;
*/ */
public class FoliageCellManager { public class FoliageCellManager {
/**
* If moved this many cells in 1 frame, completely bust meta cells
*/
public static final int TELEPORT_DISTANCE = 5000;
/** /**
* Number of times to try updating per frame. Lower this to reduce lag but slow down terrain mesh generation. * Number of times to try updating per frame. Lower this to reduce lag but slow down terrain mesh generation.
*/ */
@ -87,6 +93,11 @@ public class FoliageCellManager {
*/ */
public static final int ALL_RES_LOD = 5; public static final int ALL_RES_LOD = 5;
/**
* Lod value for busting up meta cells
*/
public static final int BUST_META_CELLS = 40;
/** /**
* The octree holding all the chunks to evaluate * The octree holding all the chunks to evaluate
*/ */
@ -142,6 +153,11 @@ public class FoliageCellManager {
*/ */
boolean initialized = false; boolean initialized = false;
/**
* The list of points to break at next evaluation
*/
List<Vector3i> breakPoints = new LinkedList<Vector3i>();
/** /**
* Constructor * Constructor
* @param worldDim The size of the world in chunks * @param worldDim The size of the world in chunks
@ -177,6 +193,9 @@ public class FoliageCellManager {
Vector3d playerPos = EntityUtils.getPosition(Globals.playerEntity); Vector3d playerPos = EntityUtils.getPosition(Globals.playerEntity);
Vector3i absVoxelPos = Globals.clientWorldData.convertRealToAbsoluteVoxelSpace(playerPos); Vector3i absVoxelPos = Globals.clientWorldData.convertRealToAbsoluteVoxelSpace(playerPos);
int distCache = this.getDistCache(this.lastPlayerPos, absVoxelPos); int distCache = this.getDistCache(this.lastPlayerPos, absVoxelPos);
if(absVoxelPos.distance(this.lastPlayerPos) > TELEPORT_DISTANCE){
distCache = BUST_META_CELLS;
}
this.lastPlayerPos.set(absVoxelPos); this.lastPlayerPos.set(absVoxelPos);
//the sets to iterate through //the sets to iterate through
updatedLastFrame = true; updatedLastFrame = true;
@ -190,6 +209,9 @@ public class FoliageCellManager {
if(!updatedLastFrame && !this.initialized){ if(!updatedLastFrame && !this.initialized){
this.initialized = true; this.initialized = true;
} }
if(this.breakPoints.size() > 0){
this.breakPoints.clear();
}
} }
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
} }
@ -204,19 +226,37 @@ public class FoliageCellManager {
*/ */
private boolean recursivelyUpdateCells(WorldOctTreeNode<FoliageCell> node, Vector3i absVoxelPos, Map<WorldOctTreeNode<FoliageCell>,Boolean> evaluationMap, int minLeafLod, int distCache){ private boolean recursivelyUpdateCells(WorldOctTreeNode<FoliageCell> node, Vector3i absVoxelPos, Map<WorldOctTreeNode<FoliageCell>,Boolean> evaluationMap, int minLeafLod, int distCache){
boolean updated = false; boolean updated = false;
//breakpoint handling
if(this.breakPoints.size() > 0){
for(Vector3i breakpoint : breakPoints){
if(GeomUtils.approxMinDistanceAABB(breakpoint, node.getMinBound(), node.getMaxBound()) == 0){
System.out.println("Break at " + breakpoint + " " + node.getLevel());
System.out.println(" " + node.getMinBound() + " " + node.getMaxBound());
System.out.println(" Generated: " + node.getData().hasGenerated());
System.out.println(" Homogenous: " + node.getData().isHomogenous());
System.out.println(" Leaf: " + node.isLeaf());
System.out.println(" Cached min dist: " + node.getData().cachedMinDistance);
System.out.println(" Actual min dist: " + GeomUtils.approxMinDistanceAABB(breakpoint, node.getMinBound(), node.getMaxBound()));
}
}
}
if(evaluationMap.containsKey(node)){ if(evaluationMap.containsKey(node)){
return false; return false;
} }
if(node.getData().hasGenerated() && if(
( node.getData().hasGenerated() &&
node.getData().isHomogenous() || (
this.getMinDistance(absVoxelPos, node, distCache) > SIXTEENTH_RES_DIST node.getData().isHomogenous() ||
) this.getMinDistance(absVoxelPos, node, distCache) > SIXTEENTH_RES_DIST
) &&
distCache != BUST_META_CELLS
){ ){
return false; return false;
} }
if(node.isLeaf()){ if(node.isLeaf()){
if(this.isMeta(absVoxelPos, node, distCache)){ if(distCache == BUST_META_CELLS){
node.getData().setHasGenerated(false);
} if(this.isMeta(absVoxelPos, node, distCache)){
this.flagAsMeta(node); this.flagAsMeta(node);
} else if(this.shouldSplit(absVoxelPos, node, distCache)){ } else if(this.shouldSplit(absVoxelPos, node, distCache)){
Globals.profiler.beginCpuSample("FoliageCellManager.split"); Globals.profiler.beginCpuSample("FoliageCellManager.split");
@ -321,12 +361,12 @@ public class FoliageCellManager {
/** /**
* Gets the minimum distance from a node to a point * Gets the minimum distance from a node to a point
* @param pos the position to check against * @param absVoxelPos the position to check against
* @param node the node * @param node the node
* @return the distance * @return the distance
*/ */
public long getMinDistance(Vector3i worldPos, WorldOctTreeNode<FoliageCell> node, int distCache){ public long getMinDistance(Vector3i absVoxelPos, WorldOctTreeNode<FoliageCell> node, int distCache){
return node.getData().getMinDistance(worldPos, node, distCache); return node.getData().getMinDistance(absVoxelPos, node, distCache);
} }
/** /**
@ -734,7 +774,8 @@ public class FoliageCellManager {
* @return true if all cells were successfully requested, false otherwise * @return true if all cells were successfully requested, false otherwise
*/ */
private boolean requestChunks(WorldOctTree.WorldOctTreeNode<FoliageCell> node){ private boolean requestChunks(WorldOctTree.WorldOctTreeNode<FoliageCell> node){
Vector3i worldPos = node.getMinBound(); //min bound is in absolute voxel coordinates, need to convert to world coordinates
Vector3i worldPos = Globals.clientWorldData.convertAbsoluteVoxelToWorldSpace(node.getMinBound());
if( if(
worldPos.x >= 0 && worldPos.x >= 0 &&
worldPos.x < Globals.clientWorldData.getWorldDiscreteSize() && worldPos.x < Globals.clientWorldData.getWorldDiscreteSize() &&
@ -742,11 +783,11 @@ public class FoliageCellManager {
worldPos.y < Globals.clientWorldData.getWorldDiscreteSize() && worldPos.y < Globals.clientWorldData.getWorldDiscreteSize() &&
worldPos.z >= 0 && worldPos.z >= 0 &&
worldPos.z < Globals.clientWorldData.getWorldDiscreteSize() && worldPos.z < Globals.clientWorldData.getWorldDiscreteSize() &&
!Globals.clientTerrainManager.containsChunkDataAtWorldPoint(worldPos.x, worldPos.y, worldPos.z, 0) !Globals.clientTerrainManager.containsChunkDataAtWorldPoint(worldPos.x, worldPos.y, worldPos.z, ChunkData.NO_STRIDE)
){ ){
//client should request chunk data from server for each chunk necessary to create the model //client should request chunk data from server for each chunk necessary to create the model
LoggerInterface.loggerNetworking.DEBUG("(Client) Send Request for terrain at " + worldPos); LoggerInterface.loggerNetworking.DEBUG("(Client) Send Request for terrain at " + worldPos);
if(!Globals.clientTerrainManager.requestChunk(worldPos.x, worldPos.y, worldPos.z, 0)){ if(!Globals.clientTerrainManager.requestChunk(worldPos.x, worldPos.y, worldPos.z, ChunkData.NO_STRIDE)){
return false; return false;
} }
} }
@ -756,16 +797,12 @@ public class FoliageCellManager {
/** /**
* Checks if all chunk data required to generate this foliage cell is present * Checks if all chunk data required to generate this foliage cell is present
* @param node The node * @param node The node
* @param highResFace The higher resolution face of a not-full-resolution chunk. Null if the chunk is max resolution or there is no higher resolution face for the current chunk
* @return true if all data is available, false otherwise * @return true if all data is available, false otherwise
*/ */
private boolean containsDataToGenerate(WorldOctTree.WorldOctTreeNode<FoliageCell> node){ private boolean containsDataToGenerate(WorldOctTree.WorldOctTreeNode<FoliageCell> node){
FoliageCell cell = node.getData(); FoliageCell cell = node.getData();
Vector3i worldPos = cell.getWorldPos(); Vector3i worldPos = cell.getWorldPos();
if(!Globals.clientTerrainManager.containsChunkDataAtWorldPoint(worldPos.x, worldPos.y, worldPos.z, 0)){ return Globals.clientTerrainManager.containsChunkDataAtWorldPoint(worldPos.x, worldPos.y, worldPos.z, ChunkData.NO_STRIDE);
return false;
}
return true;
} }
/** /**
@ -878,6 +915,14 @@ public class FoliageCellManager {
public int getNodeCount(){ public int getNodeCount(){
return this.chunkTree.getNodeCount(); return this.chunkTree.getNodeCount();
} }
/**
* Logs when the manager next evaluates the supplied absolute voxel position. Should be used to break at that point.
* @param absVoxelPos The absolute voxel position to break at
*/
public void addBreakPoint(Vector3i absVoxelPos){
this.breakPoints.add(absVoxelPos);
}
} }

View File

@ -1,6 +1,9 @@
package electrosphere.client.ui.menu.debug; package electrosphere.client.ui.menu.debug;
import org.joml.Vector3i;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.entity.EntityUtils;
import electrosphere.renderer.ui.imgui.ImGuiWindow; import electrosphere.renderer.ui.imgui.ImGuiWindow;
import electrosphere.renderer.ui.imgui.ImGuiWindow.ImGuiWindowCallback; import electrosphere.renderer.ui.imgui.ImGuiWindow.ImGuiWindowCallback;
import imgui.ImGui; import imgui.ImGui;
@ -47,6 +50,12 @@ public class ImGuiChunkMonitor {
if(Globals.foliageCellManager != null){ if(Globals.foliageCellManager != null){
ImGui.text("Foliage node count: " + Globals.foliageCellManager.getNodeCount()); ImGui.text("Foliage node count: " + Globals.foliageCellManager.getNodeCount());
} }
if(ImGui.button("Break at chunk")){
if(Globals.foliageCellManager != null){
Vector3i absVoxelPos = Globals.clientWorldData.convertRealToAbsoluteVoxelSpace(EntityUtils.getPosition(Globals.playerEntity));
Globals.foliageCellManager.addBreakPoint(absVoxelPos);
}
}
} }
}); });
chunkMonitorWindow.setOpen(false); chunkMonitorWindow.setOpen(false);

View File

@ -39,7 +39,7 @@ public class ServerFallTree implements BehaviorTree {
/** /**
* The minimum frames to wait before scanning if it should activate due to gravity * The minimum frames to wait before scanning if it should activate due to gravity
*/ */
public static final int MIN_FRAMES_BEFORE_ACTIVATION_SCAN = 10; public static final int MIN_FRAMES_BEFORE_ACTIVATION_SCAN = 60;
/** /**
* The minimum frames to wait before playing landing animation on fall * The minimum frames to wait before playing landing animation on fall

View File

@ -11,7 +11,7 @@ public class HillsGen implements HeightmapGenerator {
/** /**
* Offset from baseline to place the noisemap at * Offset from baseline to place the noisemap at
*/ */
static final float HEIGHT_OFFSET = 10; static final float HEIGHT_OFFSET = 100;
/** /**
* Scales the input positions * Scales the input positions
@ -21,7 +21,7 @@ public class HillsGen implements HeightmapGenerator {
/** /**
* Scales the output height * Scales the output height
*/ */
static final float VERTICAL_SCALE = 200.0f; static final float VERTICAL_SCALE = 100.0f;
/** /**
* The different scales of noise to sample from * The different scales of noise to sample from

View File

@ -127,9 +127,9 @@ public class GeomUtils {
int maxX = cubeMax.x; int maxX = cubeMax.x;
int maxY = cubeMax.y; int maxY = cubeMax.y;
int maxZ = cubeMax.z; int maxZ = cubeMax.z;
if(pos.x > minX && pos.x < maxX){ if(pos.x >= minX && pos.x <= maxX){
if(pos.y > minY && pos.y < maxY){ if(pos.y >= minY && pos.y <= maxY){
if(pos.z > minZ && pos.z < maxZ){ if(pos.z >= minZ && pos.z <= maxZ){
return 0; return 0;
} else if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){ } else if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
return pos.distance(pos.x,pos.y,minZ); return pos.distance(pos.x,pos.y,minZ);
@ -137,8 +137,8 @@ public class GeomUtils {
return pos.distance(pos.x,pos.y,maxZ); return pos.distance(pos.x,pos.y,maxZ);
} }
} else if(Math.abs(pos.y - minY) < Math.abs(pos.y - maxY)){ } else if(Math.abs(pos.y - minY) < Math.abs(pos.y - maxY)){
if(Math.abs(pos.y - maxY) > SIMPLIFICATION_CUTOFF){ if(Math.abs(pos.y - minY) > SIMPLIFICATION_CUTOFF){
return Math.abs(pos.y - maxY); return Math.abs(pos.y - minY);
} }
if(pos.z > minZ && pos.z < maxZ){ if(pos.z > minZ && pos.z < maxZ){
return pos.distance(pos.x,minY,pos.z); return pos.distance(pos.x,minY,pos.z);
@ -148,8 +148,8 @@ public class GeomUtils {
return pos.distance(pos.x,minY,maxZ); return pos.distance(pos.x,minY,maxZ);
} }
} else { } else {
if(Math.abs(pos.y - minY) > SIMPLIFICATION_CUTOFF){ if(Math.abs(pos.y - maxY) > SIMPLIFICATION_CUTOFF){
return Math.abs(pos.y - minY); return Math.abs(pos.y - maxY);
} }
if(pos.z > minZ && pos.z < maxZ){ if(pos.z > minZ && pos.z < maxZ){
return pos.distance(pos.x,maxY,pos.z); return pos.distance(pos.x,maxY,pos.z);
@ -160,8 +160,8 @@ public class GeomUtils {
} }
} }
} else if(Math.abs(pos.x - minX) < Math.abs(pos.x - maxX)){ } else if(Math.abs(pos.x - minX) < Math.abs(pos.x - maxX)){
if(Math.abs(pos.x - maxX) > SIMPLIFICATION_CUTOFF){ if(Math.abs(pos.x - minX) > SIMPLIFICATION_CUTOFF){
return Math.abs(pos.x - maxX); return Math.abs(pos.x - minX);
} }
if(pos.y > minY && pos.y < maxY){ if(pos.y > minY && pos.y < maxY){
if(pos.z > minZ && pos.z < maxZ){ if(pos.z > minZ && pos.z < maxZ){
@ -172,8 +172,8 @@ public class GeomUtils {
return pos.distance(minX,pos.y,maxZ); return pos.distance(minX,pos.y,maxZ);
} }
} else if(Math.abs(pos.y - minY) < Math.abs(pos.y - maxY)){ } else if(Math.abs(pos.y - minY) < Math.abs(pos.y - maxY)){
if(Math.abs(pos.y - maxY) > SIMPLIFICATION_CUTOFF){ if(Math.abs(pos.y - minY) > SIMPLIFICATION_CUTOFF){
return Math.abs(pos.y - maxY); return Math.abs(pos.y - minY);
} }
if(pos.z > minZ && pos.z < maxZ){ if(pos.z > minZ && pos.z < maxZ){
return pos.distance(minX,minY,pos.z); return pos.distance(minX,minY,pos.z);
@ -183,8 +183,8 @@ public class GeomUtils {
return pos.distance(minX,minY,maxZ); return pos.distance(minX,minY,maxZ);
} }
} else { } else {
if(Math.abs(pos.y - minY) > SIMPLIFICATION_CUTOFF){ if(Math.abs(pos.y - maxY) > SIMPLIFICATION_CUTOFF){
return Math.abs(pos.y - minY); return Math.abs(pos.y - maxY);
} }
if(pos.z > minZ && pos.z < maxZ){ if(pos.z > minZ && pos.z < maxZ){
return pos.distance(minX,maxY,pos.z); return pos.distance(minX,maxY,pos.z);
@ -195,7 +195,7 @@ public class GeomUtils {
} }
} }
} else { } else {
if(Math.abs(pos.x - minX) > SIMPLIFICATION_CUTOFF){ if(Math.abs(pos.x - maxX) > SIMPLIFICATION_CUTOFF){
return Math.abs(pos.x - maxX); return Math.abs(pos.x - maxX);
} }
if(pos.y > minY && pos.y < maxY){ if(pos.y > minY && pos.y < maxY){
@ -207,8 +207,8 @@ public class GeomUtils {
return pos.distance(maxX,pos.y,maxZ); return pos.distance(maxX,pos.y,maxZ);
} }
} else if(Math.abs(pos.y - minY) < Math.abs(pos.y - maxY)){ } else if(Math.abs(pos.y - minY) < Math.abs(pos.y - maxY)){
if(Math.abs(pos.y - maxY) > SIMPLIFICATION_CUTOFF){ if(Math.abs(pos.y - minY) > SIMPLIFICATION_CUTOFF){
return Math.abs(pos.y - maxY); return Math.abs(pos.y - minY);
} }
if(pos.z > minZ && pos.z < maxZ){ if(pos.z > minZ && pos.z < maxZ){
return pos.distance(maxX,minY,pos.z); return pos.distance(maxX,minY,pos.z);
@ -218,8 +218,8 @@ public class GeomUtils {
return pos.distance(maxX,minY,maxZ); return pos.distance(maxX,minY,maxZ);
} }
} else { } else {
if(Math.abs(pos.y - minY) > SIMPLIFICATION_CUTOFF){ if(Math.abs(pos.y - maxY) > SIMPLIFICATION_CUTOFF){
return Math.abs(pos.y - minY); return Math.abs(pos.y - maxY);
} }
if(pos.z > minZ && pos.z < maxZ){ if(pos.z > minZ && pos.z < maxZ){
return pos.distance(maxX,maxY,pos.z); return pos.distance(maxX,maxY,pos.z);