variable density for foliage cells
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit
This commit is contained in:
parent
11d468fe14
commit
f234c6423c
@ -31,6 +31,8 @@ import electrosphere.renderer.actor.instance.TextureInstancedActor;
|
||||
import electrosphere.renderer.buffer.ShaderAttribute;
|
||||
import electrosphere.renderer.buffer.HomogenousUniformBuffer.HomogenousBufferTypes;
|
||||
import electrosphere.renderer.texture.Texture;
|
||||
import electrosphere.util.ds.Octree;
|
||||
import electrosphere.util.ds.Octree.OctreeNode;
|
||||
|
||||
/**
|
||||
* Manages ambient foliage (grass, small plants, etc) that should be shown, typically instanced
|
||||
@ -79,8 +81,14 @@ public class ClientFoliageManager {
|
||||
//The number of frames that must pass before a cell can be reevaluated for foliage placement
|
||||
static final int EVALUATION_COOLDOWN = 100;
|
||||
|
||||
float targetDensity = 1.0f;
|
||||
|
||||
|
||||
/**
|
||||
* The octree holding all the chunks to evaluate
|
||||
*/
|
||||
Octree<FoliageChunk> chunkTree;
|
||||
|
||||
|
||||
//The map of all attributes for instanced foliage
|
||||
static final Map<ShaderAttribute,HomogenousBufferTypes> attributes = new HashMap<ShaderAttribute,HomogenousBufferTypes>();
|
||||
@ -126,6 +134,7 @@ public class ClientFoliageManager {
|
||||
Globals.assetManager.addShaderToQueue(vertexPath, fragmentPath);
|
||||
}
|
||||
}
|
||||
this.chunkTree = new Octree<FoliageChunk>(new Vector3d(0), new Vector3d(1000000000l));
|
||||
ready = true;
|
||||
}
|
||||
|
||||
@ -134,13 +143,26 @@ public class ClientFoliageManager {
|
||||
*/
|
||||
public void update(){
|
||||
Globals.profiler.beginCpuSample("ClientFoliageManager.update");
|
||||
if(ready){
|
||||
if(ready && this.dependenciesAreReady()){
|
||||
Vector3d playerPosition = null;
|
||||
if(Globals.playerEntity != null){
|
||||
playerPosition = EntityUtils.getPosition(Globals.playerEntity);
|
||||
}
|
||||
Globals.profiler.beginCpuSample("ClientFoliageManager.update (talley invalid cells)");
|
||||
Vector3i worldPos = Globals.clientWorldData.convertRealToWorldSpace(playerPosition);
|
||||
if(!chunkTree.containsLeaf(new Vector3d(worldPos))){
|
||||
this.createFoliageChunk(worldPos);
|
||||
}
|
||||
|
||||
//
|
||||
//evaluate what cells should be updated
|
||||
Globals.profiler.beginCpuSample("ClientFoliageManager.update (evaluate foliage chunks)");
|
||||
this.evaluateChunks(playerPosition, this.chunkTree.getRoot());
|
||||
Globals.profiler.endCpuSample();
|
||||
|
||||
|
||||
//
|
||||
//flip through all valid cells and see if you can invalidate any
|
||||
Globals.profiler.beginCpuSample("ClientFoliageManager.update (talley invalid cells)");
|
||||
List<FoliageCell> invalidationList = new LinkedList<FoliageCell>();
|
||||
for(FoliageCell cell : activeCells){
|
||||
if(
|
||||
@ -151,6 +173,9 @@ public class ClientFoliageManager {
|
||||
}
|
||||
}
|
||||
Globals.profiler.endCpuSample();
|
||||
|
||||
//
|
||||
//actually invalidate cells
|
||||
Globals.profiler.beginCpuSample("ClientFoliageManager.update (actually invalidate cells)");
|
||||
for(FoliageCell cell : invalidationList){
|
||||
invalidateCell(cell);
|
||||
@ -164,7 +189,7 @@ public class ClientFoliageManager {
|
||||
cooldownTime--;
|
||||
if(cooldownTime <= 0){
|
||||
String split[] = key.split("_");
|
||||
Vector3i worldPos = new Vector3i(Integer.parseInt(split[0]),Integer.parseInt(split[1]),Integer.parseInt(split[2]));
|
||||
worldPos = new Vector3i(Integer.parseInt(split[0]),Integer.parseInt(split[1]),Integer.parseInt(split[2]));
|
||||
Vector3i voxelPos = new Vector3i(Integer.parseInt(split[3]),Integer.parseInt(split[4]),Integer.parseInt(split[5]));
|
||||
Vector3d realPos = Globals.clientWorldData.convertWorldToRealSpace(worldPos).add(voxelPos.x,voxelPos.y,voxelPos.z);
|
||||
ChunkData data = Globals.clientTerrainManager.getChunkDataAtWorldPoint(worldPos);
|
||||
@ -177,7 +202,7 @@ public class ClientFoliageManager {
|
||||
playerPosition.distance(realPos) < CELL_DISTANCE_MAX
|
||||
){
|
||||
//create foliage cell
|
||||
createFoliageCell(worldPos,voxelPos,1);
|
||||
createFoliageCell(worldPos,voxelPos,1,targetDensity);
|
||||
locationEvaluationCooldownMap.remove(key);
|
||||
} else {
|
||||
locationEvaluationCooldownMap.put(key, EVALUATION_COOLDOWN);
|
||||
@ -282,7 +307,7 @@ public class ClientFoliageManager {
|
||||
activeCells.size() < CELL_COUNT_MAX
|
||||
){
|
||||
//create foliage cell
|
||||
createFoliageCell(worldPos,currentPos,1);
|
||||
createFoliageCell(worldPos,currentPos,1,targetDensity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -321,7 +346,7 @@ public class ClientFoliageManager {
|
||||
activeCells.size() < CELL_COUNT_MAX
|
||||
){
|
||||
//create foliage cell
|
||||
createFoliageCell(worldPos,currentPos,1);
|
||||
createFoliageCell(worldPos,currentPos,1,targetDensity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -340,7 +365,7 @@ public class ClientFoliageManager {
|
||||
* @param worldPos The world position
|
||||
* @param voxelPos The voxel position
|
||||
*/
|
||||
private void createFoliageCell(Vector3i worldPos, Vector3i voxelPos, float initialGrowthLevel){
|
||||
private void createFoliageCell(Vector3i worldPos, Vector3i voxelPos, float initialGrowthLevel, float density){
|
||||
//get foliage types supported
|
||||
ChunkData data = Globals.clientTerrainManager.getChunkDataAtWorldPoint(worldPos);
|
||||
List<String> foliageTypesSupported = Globals.gameConfigCurrent.getVoxelData().getTypeFromId(data.getType(voxelPos)).getAmbientFoliage();
|
||||
@ -356,8 +381,9 @@ public class ClientFoliageManager {
|
||||
FoliageType foliageType = Globals.gameConfigCurrent.getFoliageMap().getFoliage(foliageTypeName);
|
||||
|
||||
//create cell and buffer
|
||||
FoliageCell cell = new FoliageCell(worldPos, voxelPos, realPos);
|
||||
ByteBuffer buffer = BufferUtils.createByteBuffer(TARGET_FOLIAGE_SPACING * TARGET_FOLIAGE_SPACING * SINGLE_FOLIAGE_DATA_SIZE_BYTES);
|
||||
FoliageCell cell = new FoliageCell(worldPos, voxelPos, realPos, density);
|
||||
int FINAL_SPACING = (int)(TARGET_FOLIAGE_SPACING * density);
|
||||
ByteBuffer buffer = BufferUtils.createByteBuffer(FINAL_SPACING * FINAL_SPACING * SINGLE_FOLIAGE_DATA_SIZE_BYTES);
|
||||
FloatBuffer floatBufferView = buffer.asFloatBuffer();
|
||||
//construct simple grid to place foliage on
|
||||
Vector3d sample_00 = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(new Vector3d(realPos).add(-0.5,SAMPLE_START_HEIGHT,-0.5), new Vector3d(0,-1,0), RAY_LENGTH);
|
||||
@ -388,13 +414,13 @@ public class ClientFoliageManager {
|
||||
if(sample_11 != null){
|
||||
//generate positions to place
|
||||
int drawCount = 0;
|
||||
for(int x = 0; x < TARGET_FOLIAGE_SPACING; x++){
|
||||
for(int z = 0; z < TARGET_FOLIAGE_SPACING; z++){
|
||||
for(int x = 0; x < FINAL_SPACING; x++){
|
||||
for(int z = 0; z < FINAL_SPACING; z++){
|
||||
//get position to place
|
||||
double rand1 = placementRandomizer.nextDouble();
|
||||
double rand2 = placementRandomizer.nextDouble();
|
||||
double relativePositionOnGridX = x / (1.0 * TARGET_FOLIAGE_SPACING) + rand1 / TARGET_FOLIAGE_SPACING;
|
||||
double relativePositionOnGridZ = z / (1.0 * TARGET_FOLIAGE_SPACING) + rand2 / TARGET_FOLIAGE_SPACING;
|
||||
double relativePositionOnGridX = x / (1.0 * FINAL_SPACING) + rand1 / FINAL_SPACING;
|
||||
double relativePositionOnGridZ = z / (1.0 * FINAL_SPACING) + rand2 / FINAL_SPACING;
|
||||
double offsetX = relativePositionOnGridX - 0.5;
|
||||
double offsetZ = relativePositionOnGridZ - 0.5;
|
||||
//determine quadrant we're placing in
|
||||
@ -473,9 +499,9 @@ public class ClientFoliageManager {
|
||||
}
|
||||
}
|
||||
buffer.position(0);
|
||||
buffer.limit(TARGET_FOLIAGE_SPACING * TARGET_FOLIAGE_SPACING * SINGLE_FOLIAGE_DATA_SIZE_BYTES);
|
||||
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,TARGET_FOLIAGE_SPACING * TARGET_FOLIAGE_SPACING);
|
||||
Texture dataTexture = new Texture(Globals.renderingEngine.getOpenGLState(),buffer,SINGLE_FOLIAGE_DATA_SIZE_BYTES / 4,FINAL_SPACING * FINAL_SPACING);
|
||||
|
||||
//create entity
|
||||
Entity grassEntity = EntityCreationUtils.createClientSpatialEntity();
|
||||
@ -495,6 +521,40 @@ public class ClientFoliageManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a foliage chunk
|
||||
* @param worldPosition The world position of the chunk
|
||||
*/
|
||||
private void createFoliageChunk(Vector3i worldPosition){
|
||||
FoliageChunk chunk = new FoliageChunk(worldPosition);
|
||||
chunkTree.addLeaf(new Vector3d(worldPosition), chunk);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates all chunk nodes
|
||||
* @param chunkNode The node to evaluate
|
||||
*/
|
||||
private void evaluateChunks(Vector3d playerPos, OctreeNode<FoliageChunk> chunkNode){
|
||||
if(chunkNode.isLeaf()){
|
||||
FoliageChunk chunk = chunkNode.getData();
|
||||
Vector3d chunkPos = Globals.clientWorldData.convertWorldToRealSpace(chunk.getWorldPos());
|
||||
} else {
|
||||
for(OctreeNode<FoliageChunk> child : chunkNode.getChildren()){
|
||||
if(child != null){
|
||||
evaluateChunks(playerPos, child);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that all dependencies of this manager are ready
|
||||
* @return true if all are ready, false otherwise
|
||||
*/
|
||||
public boolean dependenciesAreReady(){
|
||||
return Globals.clientWorldData != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the voxel type supports foliage or not
|
||||
* @param type
|
||||
|
||||
@ -35,15 +35,21 @@ public class FoliageCell {
|
||||
//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
|
||||
*/
|
||||
protected float density;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param worldPos The position of the foliage cell in world coordinates
|
||||
* @param voxelPos The position of the foliage cell in voxel coordinates
|
||||
*/
|
||||
protected FoliageCell(Vector3i worldPos, Vector3i voxelPos, Vector3d realPos){
|
||||
protected FoliageCell(Vector3i worldPos, Vector3i voxelPos, Vector3d realPos, float density){
|
||||
this.worldPosition = worldPos;
|
||||
this.voxelPosition = voxelPos;
|
||||
this.realPosition = realPos;
|
||||
this.density = density;
|
||||
this.containedEntities = new HashSet<Entity>();
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,40 @@
|
||||
package electrosphere.client.foliagemanager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.joml.Vector3i;
|
||||
|
||||
/**
|
||||
* A whole chunk of foliage
|
||||
*/
|
||||
public class FoliageChunk {
|
||||
|
||||
/**
|
||||
* The world position of this chunk
|
||||
*/
|
||||
Vector3i worldPos;
|
||||
|
||||
/**
|
||||
* A list of all cells that are currently generated
|
||||
*/
|
||||
List<Vector3i> currentlyGeneratedCellPositions;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param worldPos The world position of the chunk
|
||||
*/
|
||||
public FoliageChunk(Vector3i worldPos){
|
||||
this.worldPos = worldPos;
|
||||
this.currentlyGeneratedCellPositions = new ArrayList<Vector3i>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the world position of the chunk
|
||||
* @return The world position of the chunk
|
||||
*/
|
||||
public Vector3i getWorldPos(){
|
||||
return worldPos;
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user