scaled foliage cell generation
This commit is contained in:
parent
8430439509
commit
5e06dbe786
1
.gitignore
vendored
1
.gitignore
vendored
@ -14,6 +14,7 @@
|
|||||||
/NetArranger-*.jar
|
/NetArranger-*.jar
|
||||||
/lwjglx-debug-*.jar
|
/lwjglx-debug-*.jar
|
||||||
/hs_err_pid*
|
/hs_err_pid*
|
||||||
|
/replay_pid*
|
||||||
/trace.log
|
/trace.log
|
||||||
|
|
||||||
.classpath
|
.classpath
|
||||||
|
|||||||
@ -128,7 +128,10 @@ public class ClientFoliageManager {
|
|||||||
* @return true if all are ready, false otherwise
|
* @return true if all are ready, false otherwise
|
||||||
*/
|
*/
|
||||||
public boolean dependenciesAreReady(){
|
public boolean dependenciesAreReady(){
|
||||||
return Globals.clientWorldData != null;
|
return
|
||||||
|
Globals.clientWorldData != null &&
|
||||||
|
Globals.drawCellManager != null
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -122,22 +122,30 @@ public class FoliageCell {
|
|||||||
*/
|
*/
|
||||||
int scale;
|
int scale;
|
||||||
|
|
||||||
//position of the foliage cell in world coordinates
|
/**
|
||||||
|
* Position of the foliage cell in world coordinates
|
||||||
|
*/
|
||||||
protected Vector3i worldPosition;
|
protected Vector3i worldPosition;
|
||||||
//position of the foliage cell in local coordinates
|
|
||||||
|
/**
|
||||||
|
* Position of the foliage cell in local coordinates
|
||||||
|
*/
|
||||||
protected Vector3i voxelPosition;
|
protected Vector3i voxelPosition;
|
||||||
//the real position of this cell, stored so we don't constantly have to recalculate
|
|
||||||
|
/**
|
||||||
|
* The real position of this cell, stored so we don't constantly have to recalculate
|
||||||
|
*/
|
||||||
protected Vector3d realPosition;
|
protected Vector3d realPosition;
|
||||||
//constituent entities
|
|
||||||
|
/**
|
||||||
|
* Constituent entities
|
||||||
|
*/
|
||||||
protected Set<Entity> containedEntities;
|
protected Set<Entity> containedEntities;
|
||||||
|
|
||||||
//template bounding shere used for checking frustum for this cell
|
|
||||||
static Sphered boundingSphere = new Sphered(0.5,0.5,0.5,2);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The density of the cell
|
* Template bounding shere used for checking frustum for this cell
|
||||||
*/
|
*/
|
||||||
protected float density;
|
static Sphered boundingSphere = new Sphered(0.5,0.5,0.5,2);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inits the foliage cell data
|
* Inits the foliage cell data
|
||||||
@ -157,12 +165,11 @@ public class FoliageCell {
|
|||||||
* @param worldPos The position of the foliage cell in world coordinates
|
* @param worldPos The position of the foliage cell in world coordinates
|
||||||
* @param voxelPos The position of the foliage cell in voxel coordinates
|
* @param voxelPos The position of the foliage cell in voxel coordinates
|
||||||
*/
|
*/
|
||||||
protected FoliageCell(Vector3i worldPos, Vector3i voxelPos, Vector3d realPos, int scale, float density){
|
protected FoliageCell(Vector3i worldPos, Vector3i voxelPos, Vector3d realPos, int scale){
|
||||||
this.worldPosition = worldPos;
|
this.worldPosition = worldPos;
|
||||||
this.voxelPosition = voxelPos;
|
this.voxelPosition = voxelPos;
|
||||||
this.realPosition = realPos;
|
this.realPosition = realPos;
|
||||||
this.scale = scale;
|
this.scale = scale;
|
||||||
this.density = density;
|
|
||||||
this.containedEntities = new HashSet<Entity>();
|
this.containedEntities = new HashSet<Entity>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,34 +205,94 @@ public class FoliageCell {
|
|||||||
boolean shouldGenerate = false;
|
boolean shouldGenerate = false;
|
||||||
//get foliage types supported
|
//get foliage types supported
|
||||||
ChunkData data = Globals.clientTerrainManager.getChunkDataAtWorldPoint(worldPosition);
|
ChunkData data = Globals.clientTerrainManager.getChunkDataAtWorldPoint(worldPosition);
|
||||||
List<String> foliageTypesSupported = null;
|
if(data == null){
|
||||||
if(data != null && voxelPosition.y + 1 < ServerTerrainChunk.CHUNK_DIMENSION){
|
return;
|
||||||
foliageTypesSupported = Globals.gameConfigCurrent.getVoxelData().getTypeFromId(data.getType(voxelPosition)).getAmbientFoliage();
|
}
|
||||||
boolean airAbove = data.getType(voxelPosition.x,voxelPosition.y+1,voxelPosition.z) == 0;
|
if(voxelPosition.y + 1 >= ServerTerrainChunk.CHUNK_DIMENSION){
|
||||||
if(foliageTypesSupported != null && airAbove && scale < 2){
|
return;
|
||||||
shouldGenerate = true;
|
}
|
||||||
}
|
if(!Globals.drawCellManager.generatedPhysics(worldPosition)){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<String> foliageTypesSupported = Globals.gameConfigCurrent.getVoxelData().getTypeFromId(data.getType(voxelPosition)).getAmbientFoliage();
|
||||||
|
boolean airAbove = data.getType(voxelPosition.x,voxelPosition.y+1,voxelPosition.z) == 0;
|
||||||
|
if(foliageTypesSupported != null && airAbove && scale < 3){
|
||||||
|
shouldGenerate = true;
|
||||||
}
|
}
|
||||||
if(shouldGenerate){
|
if(shouldGenerate){
|
||||||
|
|
||||||
//get type
|
//get type
|
||||||
String foliageTypeName = foliageTypesSupported.get(placementRandomizer.nextInt() % foliageTypesSupported.size());
|
String foliageTypeName = foliageTypesSupported.get(placementRandomizer.nextInt() % foliageTypesSupported.size());
|
||||||
FoliageType foliageType = Globals.gameConfigCurrent.getFoliageMap().getFoliage(foliageTypeName);
|
FoliageType foliageType = Globals.gameConfigCurrent.getFoliageMap().getFoliage(foliageTypeName);
|
||||||
|
|
||||||
//create cell and buffer
|
//create cell and buffer
|
||||||
int FINAL_SPACING = (int)(TARGET_FOLIAGE_SPACING * density);
|
ByteBuffer buffer = BufferUtils.createByteBuffer(TARGET_FOLIAGE_PER_CELL * SINGLE_FOLIAGE_DATA_SIZE_BYTES);
|
||||||
ByteBuffer buffer = BufferUtils.createByteBuffer(FINAL_SPACING * FINAL_SPACING * SINGLE_FOLIAGE_DATA_SIZE_BYTES);
|
|
||||||
FloatBuffer floatBufferView = buffer.asFloatBuffer();
|
FloatBuffer floatBufferView = buffer.asFloatBuffer();
|
||||||
|
int drawCount = 0;
|
||||||
|
for(int x = 0; x < scale; x++){
|
||||||
|
for(int y = 0; y < scale; y++){
|
||||||
|
for(int z = 0; z < scale; z++){
|
||||||
|
drawCount = drawCount + insertBlades(x, y, z, floatBufferView, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// drawCount = drawCount + this.insertBlades(0, 0, 0, floatBufferView, data);
|
||||||
|
if(drawCount > 0){
|
||||||
|
buffer.position(0);
|
||||||
|
buffer.limit(TARGET_FOLIAGE_PER_CELL * SINGLE_FOLIAGE_DATA_SIZE_BYTES);
|
||||||
|
//construct data texture
|
||||||
|
Texture dataTexture = new Texture(Globals.renderingEngine.getOpenGLState(),buffer,SINGLE_FOLIAGE_DATA_SIZE_BYTES / 4,TARGET_FOLIAGE_PER_CELL);
|
||||||
|
|
||||||
|
//create entity
|
||||||
|
Entity grassEntity = EntityCreationUtils.createClientSpatialEntity();
|
||||||
|
|
||||||
|
TextureInstancedActor.attachTextureInstancedActor(grassEntity, foliageType.getModelPath(), vertexPath, fragmentPath, dataTexture, drawCount);
|
||||||
|
EntityUtils.getPosition(grassEntity).set(realPosition);
|
||||||
|
EntityUtils.getRotation(grassEntity).set(0,0,0,1);
|
||||||
|
EntityUtils.getScale(grassEntity).set(1,1,1);
|
||||||
|
//add ambient foliage behavior tree
|
||||||
|
AmbientFoliage.attachAmbientFoliageTree(grassEntity, 1.0f, foliageType.getGrowthModel().getGrowthRate());
|
||||||
|
this.addEntity(grassEntity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert blades of grass into the entity
|
||||||
|
* @param vX the x offset of the voxel
|
||||||
|
* @param vY the y offset of the voxel
|
||||||
|
* @param vZ the z offset of the voxel
|
||||||
|
* @param floatBufferView the gpu data buffer
|
||||||
|
* @param chunkData the chunk data
|
||||||
|
* @return the number of blades of grass added
|
||||||
|
*/
|
||||||
|
protected int insertBlades(int vX, int vY, int vZ, FloatBuffer floatBufferView, ChunkData chunkData){
|
||||||
|
int rVal = 0;
|
||||||
|
|
||||||
|
//get positions offset
|
||||||
|
Vector3d voxelRealPos = new Vector3d(realPosition).add(vX,vY,vZ);
|
||||||
|
Vector3i currVoxelPos = new Vector3i(voxelPosition).add(vY,vY,vZ);
|
||||||
|
|
||||||
|
//check that the current voxel even supports foliage
|
||||||
|
boolean shouldGenerate = false;
|
||||||
|
List<String> foliageTypesSupported = null;
|
||||||
|
if(chunkData != null && currVoxelPos.y + 1 < ServerTerrainChunk.CHUNK_DIMENSION){
|
||||||
|
foliageTypesSupported = Globals.gameConfigCurrent.getVoxelData().getTypeFromId(chunkData.getType(currVoxelPos)).getAmbientFoliage();
|
||||||
|
boolean airAbove = chunkData.getType(currVoxelPos.x,currVoxelPos.y+1,currVoxelPos.z) == 0;
|
||||||
|
if(foliageTypesSupported != null && airAbove){
|
||||||
|
shouldGenerate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(shouldGenerate){
|
||||||
//construct simple grid to place foliage on
|
//construct simple grid to place foliage on
|
||||||
Vector3d sample_00 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(realPosition).add(-0.5,SAMPLE_START_HEIGHT,-0.5), new Vector3d(0,-1,0), RAY_LENGTH);
|
Vector3d sample_00 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(voxelRealPos).add(-0.5,SAMPLE_START_HEIGHT,-0.5), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||||
Vector3d sample_01 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(realPosition).add(-0.5,SAMPLE_START_HEIGHT, 0), new Vector3d(0,-1,0), RAY_LENGTH);
|
Vector3d sample_01 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(voxelRealPos).add(-0.5,SAMPLE_START_HEIGHT, 0), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||||
Vector3d sample_02 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(realPosition).add(-0.5,SAMPLE_START_HEIGHT, 0.5), new Vector3d(0,-1,0), RAY_LENGTH);
|
Vector3d sample_02 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(voxelRealPos).add(-0.5,SAMPLE_START_HEIGHT, 0.5), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||||
Vector3d sample_10 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(realPosition).add( 0,SAMPLE_START_HEIGHT,-0.5), new Vector3d(0,-1,0), RAY_LENGTH);
|
Vector3d sample_10 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(voxelRealPos).add( 0,SAMPLE_START_HEIGHT,-0.5), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||||
Vector3d sample_11 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(realPosition).add( 0,SAMPLE_START_HEIGHT, 0), new Vector3d(0,-1,0), RAY_LENGTH);
|
Vector3d sample_11 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(voxelRealPos).add( 0,SAMPLE_START_HEIGHT, 0), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||||
Vector3d sample_12 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(realPosition).add( 0,SAMPLE_START_HEIGHT, 0.5), new Vector3d(0,-1,0), RAY_LENGTH);
|
Vector3d sample_12 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(voxelRealPos).add( 0,SAMPLE_START_HEIGHT, 0.5), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||||
Vector3d sample_20 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(realPosition).add( 0.5,SAMPLE_START_HEIGHT,-0.5), new Vector3d(0,-1,0), RAY_LENGTH);
|
Vector3d sample_20 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(voxelRealPos).add( 0.5,SAMPLE_START_HEIGHT,-0.5), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||||
Vector3d sample_21 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(realPosition).add( 0.5,SAMPLE_START_HEIGHT, 0), new Vector3d(0,-1,0), RAY_LENGTH);
|
Vector3d sample_21 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(voxelRealPos).add( 0.5,SAMPLE_START_HEIGHT, 0), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||||
Vector3d sample_22 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(realPosition).add( 0.5,SAMPLE_START_HEIGHT, 0.5), new Vector3d(0,-1,0), RAY_LENGTH);
|
Vector3d sample_22 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(voxelRealPos).add( 0.5,SAMPLE_START_HEIGHT, 0.5), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||||
//get the heights of each sample
|
//get the heights of each sample
|
||||||
float height_11 = (float)(sample_11 != null ? sample_11.y : 0);
|
float height_11 = (float)(sample_11 != null ? sample_11.y : 0);
|
||||||
float height_00 = (float)(sample_00 != null ? sample_00.y : height_11);
|
float height_00 = (float)(sample_00 != null ? sample_00.y : height_11);
|
||||||
@ -244,14 +311,13 @@ public class FoliageCell {
|
|||||||
//if we don't find data for the center sample, can't place grass so don't create entity
|
//if we don't find data for the center sample, can't place grass so don't create entity
|
||||||
if(sample_11 != null){
|
if(sample_11 != null){
|
||||||
//generate positions to place
|
//generate positions to place
|
||||||
int drawCount = 0;
|
for(int x = 0; x < TARGET_FOLIAGE_SPACING; x=x+scale){
|
||||||
for(int x = 0; x < FINAL_SPACING; x++){
|
for(int z = 0; z < TARGET_FOLIAGE_SPACING; z=z+scale){
|
||||||
for(int z = 0; z < FINAL_SPACING; z++){
|
|
||||||
//get position to place
|
//get position to place
|
||||||
double rand1 = placementRandomizer.nextDouble();
|
double rand1 = placementRandomizer.nextDouble();
|
||||||
double rand2 = placementRandomizer.nextDouble();
|
double rand2 = placementRandomizer.nextDouble();
|
||||||
double relativePositionOnGridX = x / (1.0 * FINAL_SPACING) + rand1 / FINAL_SPACING;
|
double relativePositionOnGridX = x / (1.0 * TARGET_FOLIAGE_SPACING) + rand1 / TARGET_FOLIAGE_SPACING;
|
||||||
double relativePositionOnGridZ = z / (1.0 * FINAL_SPACING) + rand2 / FINAL_SPACING;
|
double relativePositionOnGridZ = z / (1.0 * TARGET_FOLIAGE_SPACING) + rand2 / TARGET_FOLIAGE_SPACING;
|
||||||
double offsetX = relativePositionOnGridX - 0.5;
|
double offsetX = relativePositionOnGridX - 0.5;
|
||||||
double offsetZ = relativePositionOnGridZ - 0.5;
|
double offsetZ = relativePositionOnGridZ - 0.5;
|
||||||
//determine quadrant we're placing in
|
//determine quadrant we're placing in
|
||||||
@ -320,32 +386,18 @@ public class FoliageCell {
|
|||||||
offsetY = offsetY - realPosition.y;
|
offsetY = offsetY - realPosition.y;
|
||||||
double rotVar = placementRandomizer.nextDouble() * Math.PI * 2;
|
double rotVar = placementRandomizer.nextDouble() * Math.PI * 2;
|
||||||
double rotVar2 = placementRandomizer.nextDouble();
|
double rotVar2 = placementRandomizer.nextDouble();
|
||||||
floatBufferView.put((float)offsetX);
|
floatBufferView.put((float)offsetX + vX);
|
||||||
floatBufferView.put((float)offsetY);
|
floatBufferView.put((float)offsetY + vY);
|
||||||
floatBufferView.put((float)offsetZ);
|
floatBufferView.put((float)offsetZ + vZ);
|
||||||
floatBufferView.put((float)rotVar);
|
floatBufferView.put((float)rotVar);
|
||||||
floatBufferView.put((float)rotVar2);
|
floatBufferView.put((float)rotVar2);
|
||||||
drawCount++;
|
rVal++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buffer.position(0);
|
|
||||||
buffer.limit(FINAL_SPACING * FINAL_SPACING * SINGLE_FOLIAGE_DATA_SIZE_BYTES);
|
|
||||||
//construct data texture
|
|
||||||
Texture dataTexture = new Texture(Globals.renderingEngine.getOpenGLState(),buffer,SINGLE_FOLIAGE_DATA_SIZE_BYTES / 4,FINAL_SPACING * FINAL_SPACING);
|
|
||||||
|
|
||||||
//create entity
|
|
||||||
Entity grassEntity = EntityCreationUtils.createClientSpatialEntity();
|
|
||||||
|
|
||||||
TextureInstancedActor.attachTextureInstancedActor(grassEntity, foliageType.getModelPath(), vertexPath, fragmentPath, dataTexture, drawCount);
|
|
||||||
EntityUtils.getPosition(grassEntity).set(realPosition);
|
|
||||||
EntityUtils.getRotation(grassEntity).set(0,0,0,1);
|
|
||||||
EntityUtils.getScale(grassEntity).set(1,1,1);
|
|
||||||
//add ambient foliage behavior tree
|
|
||||||
AmbientFoliage.attachAmbientFoliageTree(grassEntity, 1.0f, foliageType.getGrowthModel().getGrowthRate());
|
|
||||||
this.addEntity(grassEntity);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -396,7 +448,6 @@ public class FoliageCell {
|
|||||||
|
|
||||||
|
|
||||||
modelMatrix = modelMatrix.identity();
|
modelMatrix = modelMatrix.identity();
|
||||||
// cameraModifiedPosition = new Vector3f((float)grassPosition.x,(float)grassPosition.y,(float)grassPosition.z).sub(cameraCenter);
|
|
||||||
modelMatrix.translate(cameraModifiedPosition);
|
modelMatrix.translate(cameraModifiedPosition);
|
||||||
modelMatrix.rotate(new Quaterniond(grassRotation));
|
modelMatrix.rotate(new Quaterniond(grassRotation));
|
||||||
modelMatrix.scale(new Vector3d(EntityUtils.getScale(entity)));
|
modelMatrix.scale(new Vector3d(EntityUtils.getScale(entity)));
|
||||||
@ -500,16 +551,4 @@ public class FoliageCell {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets whether the voxel type supports foliage or not
|
|
||||||
* @param type
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private boolean typeSupportsFoliage(int type){
|
|
||||||
if(Globals.gameConfigCurrent.getVoxelData().getTypeFromId(type) != null){
|
|
||||||
return Globals.gameConfigCurrent.getVoxelData().getTypeFromId(type).getAmbientFoliage() != null;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package electrosphere.client.foliagemanager;
|
package electrosphere.client.foliagemanager;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
|
||||||
import org.joml.Vector3d;
|
import org.joml.Vector3d;
|
||||||
@ -10,6 +11,7 @@ import electrosphere.engine.Globals;
|
|||||||
import electrosphere.entity.EntityUtils;
|
import electrosphere.entity.EntityUtils;
|
||||||
import electrosphere.util.ds.octree.ChunkTree;
|
import electrosphere.util.ds.octree.ChunkTree;
|
||||||
import electrosphere.util.ds.octree.ChunkTree.ChunkTreeNode;
|
import electrosphere.util.ds.octree.ChunkTree.ChunkTreeNode;
|
||||||
|
import electrosphere.util.math.GeomUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A whole chunk of foliage
|
* A whole chunk of foliage
|
||||||
@ -25,7 +27,12 @@ public class FoliageChunk {
|
|||||||
/**
|
/**
|
||||||
* The distance to draw at full resolution
|
* The distance to draw at full resolution
|
||||||
*/
|
*/
|
||||||
static final double FULL_RES_DIST = 15;
|
static final double FULL_RES_DIST = 20;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The distance for half resolution
|
||||||
|
*/
|
||||||
|
static final double HALF_RES_DIST = 40;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The octree holding all the chunks to evaluate
|
* The octree holding all the chunks to evaluate
|
||||||
@ -68,6 +75,7 @@ public class FoliageChunk {
|
|||||||
this.currentChunkData = Globals.clientTerrainManager.getChunkDataAtWorldPoint(worldPos);
|
this.currentChunkData = Globals.clientTerrainManager.getChunkDataAtWorldPoint(worldPos);
|
||||||
// //evaluate top cells if chunk above this one exists
|
// //evaluate top cells if chunk above this one exists
|
||||||
this.aboveChunkData = Globals.clientTerrainManager.getChunkDataAtWorldPoint(new Vector3i(worldPos).add(0,1,0));
|
this.aboveChunkData = Globals.clientTerrainManager.getChunkDataAtWorldPoint(new Vector3i(worldPos).add(0,1,0));
|
||||||
|
this.updateCells();
|
||||||
Globals.profiler.endCpuSample();
|
Globals.profiler.endCpuSample();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,47 +86,13 @@ public class FoliageChunk {
|
|||||||
Globals.profiler.beginCpuSample("FoliageChunk.updateCells");
|
Globals.profiler.beginCpuSample("FoliageChunk.updateCells");
|
||||||
Vector3d playerPos = EntityUtils.getPosition(Globals.playerEntity);
|
Vector3d playerPos = EntityUtils.getPosition(Globals.playerEntity);
|
||||||
//the sets to iterate through
|
//the sets to iterate through
|
||||||
ChunkTreeNode<FoliageCell> rootNode = this.chunkTree.getRoot();
|
boolean updated = true;
|
||||||
this.recursivelyUpdateCells(rootNode, playerPos);
|
int attempts = 0;
|
||||||
//split into nodes
|
while(updated && attempts < 3){
|
||||||
// Globals.profiler.beginCpuSample("FoliageChunk.updateCells - evaluate split/join");
|
ChunkTreeNode<FoliageCell> rootNode = this.chunkTree.getRoot();
|
||||||
// while(openSet.size() > 0){
|
updated = this.recursivelyUpdateCells(rootNode, playerPos);
|
||||||
// ChunkTreeNode<FoliageCell> current = openSet.remove(0);
|
attempts++;
|
||||||
|
}
|
||||||
// if(this.shouldSplit(playerPos, current)){
|
|
||||||
// //add children for this one
|
|
||||||
// ChunkTreeNode<FoliageCell> container = chunkTree.split(current);
|
|
||||||
// toInit.addAll(container.getChildren());
|
|
||||||
// toCleanup.add(current);
|
|
||||||
// } else if(this.shouldJoin(playerPos, current)) {
|
|
||||||
// //add children for this one
|
|
||||||
// ChunkTreeNode<FoliageCell> newLeaf = chunkTree.join(current);
|
|
||||||
// toCleanup.addAll(current.getChildren());
|
|
||||||
// toCleanup.add(current);
|
|
||||||
// toInit.add(newLeaf);
|
|
||||||
// } else if(!current.isLeaf()){
|
|
||||||
// openSet.addAll(current.getChildren());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// Globals.profiler.endCpuSample();
|
|
||||||
// Globals.profiler.beginCpuSample("FoliageChunk.updateCells - generate");
|
|
||||||
// //init end-nodes as leaves
|
|
||||||
// for(ChunkTreeNode<FoliageCell> current : toInit){
|
|
||||||
// Vector3d realPos = Globals.clientWorldData.convertWorldToRealSpace(worldPos).add(new Vector3d(current.getMinBound()));
|
|
||||||
// current.convertToLeaf(new FoliageCell(worldPos, current.getMinBound(), realPos, 5 - current.getLevel(), 1.0f));
|
|
||||||
// if(this.shouldGenerate(playerPos,current)){
|
|
||||||
// current.getData().generate();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// Globals.profiler.endCpuSample();
|
|
||||||
// Globals.profiler.beginCpuSample("FoliageChunk.updateCells - destroy");
|
|
||||||
// //destroy orphan nodes
|
|
||||||
// for(ChunkTreeNode<FoliageCell> current : toCleanup){
|
|
||||||
// if(current.getData() != null){
|
|
||||||
// current.getData().destroy();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// Globals.profiler.endCpuSample();
|
|
||||||
Globals.profiler.endCpuSample();
|
Globals.profiler.endCpuSample();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +101,8 @@ public class FoliageChunk {
|
|||||||
* @param node The root node
|
* @param node The root node
|
||||||
* @param playerPos The player's position
|
* @param playerPos The player's position
|
||||||
*/
|
*/
|
||||||
private void recursivelyUpdateCells(ChunkTreeNode<FoliageCell> node, Vector3d playerPos){
|
private boolean recursivelyUpdateCells(ChunkTreeNode<FoliageCell> node, Vector3d playerPos){
|
||||||
|
boolean updated = false;
|
||||||
if(this.shouldSplit(playerPos, node)){
|
if(this.shouldSplit(playerPos, node)){
|
||||||
//perform op
|
//perform op
|
||||||
ChunkTreeNode<FoliageCell> container = chunkTree.split(node);
|
ChunkTreeNode<FoliageCell> container = chunkTree.split(node);
|
||||||
@ -142,8 +117,9 @@ public class FoliageChunk {
|
|||||||
worldPos.y * ChunkData.CHUNK_SIZE + child.getMinBound().y,
|
worldPos.y * ChunkData.CHUNK_SIZE + child.getMinBound().y,
|
||||||
worldPos.z * ChunkData.CHUNK_SIZE + child.getMinBound().z
|
worldPos.z * ChunkData.CHUNK_SIZE + child.getMinBound().z
|
||||||
);
|
);
|
||||||
child.convertToLeaf(new FoliageCell(worldPos, child.getMinBound(), realPos, 5 - child.getLevel(), 1.0f));
|
child.convertToLeaf(new FoliageCell(worldPos, child.getMinBound(), realPos, 5 - child.getLevel()));
|
||||||
});
|
});
|
||||||
|
updated = true;
|
||||||
} else if(this.shouldJoin(playerPos, node)) {
|
} else if(this.shouldJoin(playerPos, node)) {
|
||||||
//perform op
|
//perform op
|
||||||
ChunkTreeNode<FoliageCell> newLeaf = chunkTree.join(node);
|
ChunkTreeNode<FoliageCell> newLeaf = chunkTree.join(node);
|
||||||
@ -152,12 +128,19 @@ public class FoliageChunk {
|
|||||||
this.recursivelyDestroy(node);
|
this.recursivelyDestroy(node);
|
||||||
|
|
||||||
//do creations
|
//do creations
|
||||||
newLeaf.convertToLeaf(new FoliageCell(worldPos, newLeaf.getMinBound(), realPos, 5 - newLeaf.getLevel(), 1.0f));
|
newLeaf.convertToLeaf(new FoliageCell(worldPos, newLeaf.getMinBound(), realPos, 5 - newLeaf.getLevel()));
|
||||||
|
updated = true;
|
||||||
} else if(shouldGenerate(playerPos, node)){
|
} else if(shouldGenerate(playerPos, node)){
|
||||||
node.getData().generate();
|
node.getData().generate();
|
||||||
|
updated = true;
|
||||||
} else if(!node.isLeaf()){
|
} else if(!node.isLeaf()){
|
||||||
new LinkedList<>(node.getChildren()).forEach(child -> recursivelyUpdateCells(child, playerPos));
|
List<ChunkTreeNode<FoliageCell>> children = new LinkedList<ChunkTreeNode<FoliageCell>>(node.getChildren());
|
||||||
|
for(ChunkTreeNode<FoliageCell> child : children){
|
||||||
|
boolean childUpdate = recursivelyUpdateCells(child, playerPos);
|
||||||
|
updated = childUpdate || updated;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return updated;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -169,41 +152,15 @@ public class FoliageChunk {
|
|||||||
public double getMinDistance(Vector3d pos, ChunkTreeNode<FoliageCell> node){
|
public double getMinDistance(Vector3d pos, ChunkTreeNode<FoliageCell> node){
|
||||||
Vector3i min = node.getMinBound();
|
Vector3i min = node.getMinBound();
|
||||||
Vector3i max = node.getMaxBound();
|
Vector3i max = node.getMaxBound();
|
||||||
|
|
||||||
double minX = min.x + realPos.x;
|
double minX = min.x + realPos.x;
|
||||||
double minY = min.y + realPos.y;
|
double minY = min.y + realPos.y;
|
||||||
double minZ = min.z + realPos.z;
|
double minZ = min.z + realPos.z;
|
||||||
|
|
||||||
double maxX = max.x + realPos.x;
|
double maxX = max.x + realPos.x;
|
||||||
double maxY = max.y + realPos.y;
|
double maxY = max.y + realPos.y;
|
||||||
double maxZ = max.z + realPos.z;
|
double maxZ = max.z + realPos.z;
|
||||||
if(Math.abs(pos.x - minX) < Math.abs(pos.x - maxX)){
|
return GeomUtils.getMinDistanceAABB(pos, new Vector3d(minX,minY,minZ), new Vector3d(maxX,maxY,maxZ));
|
||||||
if(Math.abs(pos.y - minY) < Math.abs(pos.y - maxY)){
|
|
||||||
if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
|
|
||||||
return pos.distance(minX,minY,minZ);
|
|
||||||
} else {
|
|
||||||
return pos.distance(minX,minY,maxZ);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
|
|
||||||
return pos.distance(minX,maxY,minZ);
|
|
||||||
} else {
|
|
||||||
return pos.distance(minX,maxY,maxZ);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(Math.abs(pos.y - minY) < Math.abs(pos.y - maxY)){
|
|
||||||
if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
|
|
||||||
return pos.distance(maxX,minY,minZ);
|
|
||||||
} else {
|
|
||||||
return pos.distance(maxX,minY,maxZ);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
|
|
||||||
return pos.distance(maxX,maxY,minZ);
|
|
||||||
} else {
|
|
||||||
return pos.distance(maxX,maxY,maxZ);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -217,9 +174,18 @@ public class FoliageChunk {
|
|||||||
//to combine fullres nodes into larger nodes to conserve on draw calls
|
//to combine fullres nodes into larger nodes to conserve on draw calls
|
||||||
return
|
return
|
||||||
node.isLeaf() &&
|
node.isLeaf() &&
|
||||||
node.getLevel() < ChunkTree.MAX_LEVEL &&
|
|
||||||
node.canSplit() &&
|
node.canSplit() &&
|
||||||
this.getMinDistance(pos, node) <= FULL_RES_DIST
|
(
|
||||||
|
(
|
||||||
|
node.getLevel() < ChunkTree.MAX_LEVEL - 1 &&
|
||||||
|
this.getMinDistance(pos, node) <= HALF_RES_DIST
|
||||||
|
)
|
||||||
|
||
|
||||||
|
(
|
||||||
|
node.getLevel() < ChunkTree.MAX_LEVEL &&
|
||||||
|
this.getMinDistance(pos, node) <= FULL_RES_DIST
|
||||||
|
)
|
||||||
|
)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,7 +201,16 @@ public class FoliageChunk {
|
|||||||
return
|
return
|
||||||
node.getLevel() > 0 &&
|
node.getLevel() > 0 &&
|
||||||
!node.isLeaf() &&
|
!node.isLeaf() &&
|
||||||
this.getMinDistance(pos, node) > FULL_RES_DIST
|
(
|
||||||
|
(
|
||||||
|
node.getLevel() == ChunkTree.MAX_LEVEL &&
|
||||||
|
this.getMinDistance(pos, node) > FULL_RES_DIST
|
||||||
|
)
|
||||||
|
||
|
||||||
|
(
|
||||||
|
this.getMinDistance(pos, node) > HALF_RES_DIST
|
||||||
|
)
|
||||||
|
)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,11 +222,23 @@ public class FoliageChunk {
|
|||||||
*/
|
*/
|
||||||
public boolean shouldGenerate(Vector3d pos, ChunkTreeNode<FoliageCell> node){
|
public boolean shouldGenerate(Vector3d pos, ChunkTreeNode<FoliageCell> node){
|
||||||
return
|
return
|
||||||
node.getLevel() == ChunkTree.MAX_LEVEL &&
|
|
||||||
node.isLeaf() &&
|
node.isLeaf() &&
|
||||||
node.getData() != null &&
|
node.getData() != null &&
|
||||||
node.getData().containedEntities.size() < 1 &&
|
node.getData().containedEntities.size() < 1 &&
|
||||||
this.getMinDistance(pos, node) <= FULL_RES_DIST;
|
(
|
||||||
|
(
|
||||||
|
node.getLevel() == ChunkTree.MAX_LEVEL
|
||||||
|
// &&
|
||||||
|
// this.getMinDistance(pos, node) <= FULL_RES_DIST
|
||||||
|
)
|
||||||
|
||
|
||||||
|
(
|
||||||
|
node.getLevel() == ChunkTree.MAX_LEVEL - 1
|
||||||
|
&&
|
||||||
|
this.getMinDistance(pos, node) <= HALF_RES_DIST
|
||||||
|
)
|
||||||
|
)
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -262,7 +249,8 @@ public class FoliageChunk {
|
|||||||
public boolean shouldDestroy(ChunkTreeNode<FoliageCell> node){
|
public boolean shouldDestroy(ChunkTreeNode<FoliageCell> node){
|
||||||
return
|
return
|
||||||
node.getData() != null &&
|
node.getData() != null &&
|
||||||
node.getData().containedEntities.size() > 0;
|
node.getData().containedEntities.size() > 0
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -3,7 +3,6 @@ package electrosphere.client.terrain.cells;
|
|||||||
import org.joml.Quaterniond;
|
import org.joml.Quaterniond;
|
||||||
import org.joml.Vector3d;
|
import org.joml.Vector3d;
|
||||||
import org.joml.Vector3i;
|
import org.joml.Vector3i;
|
||||||
import org.ode4j.ode.DBody;
|
|
||||||
|
|
||||||
import electrosphere.client.terrain.cache.ChunkData;
|
import electrosphere.client.terrain.cache.ChunkData;
|
||||||
import electrosphere.collision.CollisionEngine;
|
import electrosphere.collision.CollisionEngine;
|
||||||
@ -36,9 +35,6 @@ public class DrawCell {
|
|||||||
|
|
||||||
//the main entity for the cell
|
//the main entity for the cell
|
||||||
Entity modelEntity;
|
Entity modelEntity;
|
||||||
|
|
||||||
//the physics mesh
|
|
||||||
DBody physicsObject;
|
|
||||||
|
|
||||||
//Allocated once instead of continuously, used to generate the visual/physics models
|
//Allocated once instead of continuously, used to generate the visual/physics models
|
||||||
float[][][] weights = new float[ChunkData.CHUNK_DATA_GENERATOR_SIZE][ChunkData.CHUNK_DATA_GENERATOR_SIZE][ChunkData.CHUNK_DATA_GENERATOR_SIZE];
|
float[][][] weights = new float[ChunkData.CHUNK_DATA_GENERATOR_SIZE][ChunkData.CHUNK_DATA_GENERATOR_SIZE][ChunkData.CHUNK_DATA_GENERATOR_SIZE];
|
||||||
|
|||||||
@ -490,6 +490,20 @@ public class DrawCellManager {
|
|||||||
atlas = voxelTextureAtlas;
|
atlas = voxelTextureAtlas;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the draw cell at the given world position has generated physics
|
||||||
|
* @param worldPos The world position
|
||||||
|
* @return true if has generated physics, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean generatedPhysics(Vector3i worldPos){
|
||||||
|
String key = this.getCellKey(worldPos.x, worldPos.y, worldPos.z);
|
||||||
|
if(!keyCellMap.containsKey(key)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
DrawCell cell = this.keyCellMap.get(key);
|
||||||
|
return cell.modelEntity != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
transvoxel algorithm spacing management
|
transvoxel algorithm spacing management
|
||||||
|
|||||||
105
src/main/java/electrosphere/util/math/GeomUtils.java
Normal file
105
src/main/java/electrosphere/util/math/GeomUtils.java
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
package electrosphere.util.math;
|
||||||
|
|
||||||
|
import org.joml.Vector3d;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utilities for dealing with geometry
|
||||||
|
*/
|
||||||
|
public class GeomUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the minimum distance from a point to an axis aligned cube
|
||||||
|
* @param pos the position to check against
|
||||||
|
* @param cubeMin The min position of the cube
|
||||||
|
* @param cubeMax The max position of the cube
|
||||||
|
* @return the distance
|
||||||
|
*/
|
||||||
|
public static double getMinDistanceAABB(Vector3d pos, Vector3d cubeMin, Vector3d cubeMax){
|
||||||
|
double minX = cubeMin.x;
|
||||||
|
double minY = cubeMin.y;
|
||||||
|
double minZ = cubeMin.z;
|
||||||
|
double maxX = cubeMax.x;
|
||||||
|
double maxY = cubeMax.y;
|
||||||
|
double maxZ = cubeMax.z;
|
||||||
|
if(pos.x > minX && pos.x < maxX){
|
||||||
|
if(pos.y > minY && pos.y < maxY){
|
||||||
|
if(pos.z > minZ && pos.z < maxZ){
|
||||||
|
return 0;
|
||||||
|
} else if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
|
||||||
|
return pos.distance(pos.x,pos.y,minZ);
|
||||||
|
} else {
|
||||||
|
return pos.distance(pos.x,pos.y,maxZ);
|
||||||
|
}
|
||||||
|
} else if(Math.abs(pos.y - minY) < Math.abs(pos.y - maxY)){
|
||||||
|
if(pos.z > minZ && pos.z < maxZ){
|
||||||
|
return pos.distance(pos.x,minY,pos.z);
|
||||||
|
} else if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
|
||||||
|
return pos.distance(pos.x,minY,minZ);
|
||||||
|
} else {
|
||||||
|
return pos.distance(pos.x,minY,maxZ);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(pos.z > minZ && pos.z < maxZ){
|
||||||
|
return pos.distance(pos.x,maxY,pos.z);
|
||||||
|
} else if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
|
||||||
|
return pos.distance(pos.x,maxY,minZ);
|
||||||
|
} else {
|
||||||
|
return pos.distance(pos.x,maxY,maxZ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(Math.abs(pos.x - minX) < Math.abs(pos.x - maxX)){
|
||||||
|
if(pos.y > minY && pos.y < maxY){
|
||||||
|
if(pos.z > minZ && pos.z < maxZ){
|
||||||
|
return pos.distance(minX,pos.y,pos.z);
|
||||||
|
} else if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
|
||||||
|
return pos.distance(minX,pos.y,minZ);
|
||||||
|
} else {
|
||||||
|
return pos.distance(minX,pos.y,maxZ);
|
||||||
|
}
|
||||||
|
} else if(Math.abs(pos.y - minY) < Math.abs(pos.y - maxY)){
|
||||||
|
if(pos.z > minZ && pos.z < maxZ){
|
||||||
|
return pos.distance(minX,minY,pos.z);
|
||||||
|
} else if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
|
||||||
|
return pos.distance(minX,minY,minZ);
|
||||||
|
} else {
|
||||||
|
return pos.distance(minX,minY,maxZ);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(pos.z > minZ && pos.z < maxZ){
|
||||||
|
return pos.distance(minX,maxY,pos.z);
|
||||||
|
} else if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
|
||||||
|
return pos.distance(minX,maxY,minZ);
|
||||||
|
} else {
|
||||||
|
return pos.distance(minX,maxY,maxZ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(pos.y > minY && pos.y < maxY){
|
||||||
|
if(pos.z > minZ && pos.z < maxZ){
|
||||||
|
return pos.distance(maxX,pos.y,pos.z);
|
||||||
|
} else if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
|
||||||
|
return pos.distance(maxX,pos.y,minZ);
|
||||||
|
} else {
|
||||||
|
return pos.distance(maxX,pos.y,maxZ);
|
||||||
|
}
|
||||||
|
} else if(Math.abs(pos.y - minY) < Math.abs(pos.y - maxY)){
|
||||||
|
if(pos.z > minZ && pos.z < maxZ){
|
||||||
|
return pos.distance(maxX,minY,pos.z);
|
||||||
|
} else if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
|
||||||
|
return pos.distance(maxX,minY,minZ);
|
||||||
|
} else {
|
||||||
|
return pos.distance(maxX,minY,maxZ);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(pos.z > minZ && pos.z < maxZ){
|
||||||
|
return pos.distance(maxX,maxY,pos.z);
|
||||||
|
} else if(Math.abs(pos.z - minZ) < Math.abs(pos.z - maxZ)){
|
||||||
|
return pos.distance(maxX,maxY,minZ);
|
||||||
|
} else {
|
||||||
|
return pos.distance(maxX,maxY,maxZ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
44
src/test/java/electrosphere/util/math/GeomUtilsTests.java
Normal file
44
src/test/java/electrosphere/util/math/GeomUtilsTests.java
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package electrosphere.util.math;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
import org.joml.Vector3d;
|
||||||
|
|
||||||
|
import electrosphere.test.annotations.UnitTest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for geometry utils
|
||||||
|
*/
|
||||||
|
public class GeomUtilsTests {
|
||||||
|
|
||||||
|
@UnitTest
|
||||||
|
public void test_getMinDistanceAABB_center_0(){
|
||||||
|
assertEquals(0, GeomUtils.getMinDistanceAABB(new Vector3d(1,1,1), new Vector3d(0,0,0), new Vector3d(2,2,2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@UnitTest
|
||||||
|
public void test_getMinDistanceAABB_xSide_1(){
|
||||||
|
assertEquals(1, GeomUtils.getMinDistanceAABB(new Vector3d(3,0,0), new Vector3d(0,0,0), new Vector3d(2,2,2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@UnitTest
|
||||||
|
public void test_getMinDistanceAABB_ySide_1(){
|
||||||
|
assertEquals(1, GeomUtils.getMinDistanceAABB(new Vector3d(0,3,0), new Vector3d(0,0,0), new Vector3d(2,2,2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@UnitTest
|
||||||
|
public void test_getMinDistanceAABB_zSide_1(){
|
||||||
|
assertEquals(1, GeomUtils.getMinDistanceAABB(new Vector3d(0,0,3), new Vector3d(0,0,0), new Vector3d(2,2,2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@UnitTest
|
||||||
|
public void test_getMinDistanceAABB_angle_1(){
|
||||||
|
assertEquals(Math.sqrt(2), GeomUtils.getMinDistanceAABB(new Vector3d(3,3,1), new Vector3d(0,0,0), new Vector3d(2,2,2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@UnitTest
|
||||||
|
public void test_getMinDistanceAABB_angle_2(){
|
||||||
|
assertEquals(Math.sqrt(3), GeomUtils.getMinDistanceAABB(new Vector3d(3,3,3), new Vector3d(0,0,0), new Vector3d(2,2,2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user