fixes + generator work
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
d06d5d4506
commit
a32f6200cc
@ -125,6 +125,12 @@
|
||||
"path" : "Models/items/weapons/katana1alt.glb"
|
||||
}
|
||||
},
|
||||
"boneGroups" : [
|
||||
{
|
||||
"id" : "torso",
|
||||
"boneNamesThirdPerson" : []
|
||||
}
|
||||
],
|
||||
"collidable": {
|
||||
"type" : "CUBE",
|
||||
"dimension1" : 0.04,
|
||||
|
||||
@ -102,16 +102,13 @@ export const TestGen: ChunkGenerator = {
|
||||
engine: Engine
|
||||
): VoxelFunction => {
|
||||
const rVal = (
|
||||
voxel: GeneratedVoxel,
|
||||
worldX: number, worldY: number, worldZ: number,
|
||||
chunkX: number, chunkY: number, chunkZ: number,
|
||||
stride: number,
|
||||
surfaceHeight: number,
|
||||
surfaceBiome: BiomeData
|
||||
): GeneratedVoxel => {
|
||||
let rVal: GeneratedVoxel = {
|
||||
type: 0,
|
||||
weight: -1,
|
||||
}
|
||||
): void => {
|
||||
|
||||
const realX = voxelToReal(chunkX,worldX)
|
||||
const realY = voxelToReal(chunkY,worldY)
|
||||
@ -122,8 +119,8 @@ export const TestGen: ChunkGenerator = {
|
||||
const surfacePercent = (surfaceHeight - realY) / strideMultiplier
|
||||
|
||||
if(heightDiff < -strideMultiplier){
|
||||
return getSubsurfaceVoxel(
|
||||
rVal,
|
||||
getSubsurfaceVoxel(
|
||||
voxel,
|
||||
worldX, worldY, worldZ,
|
||||
chunkX, chunkY, chunkZ,
|
||||
realX, realY, realZ,
|
||||
@ -132,8 +129,8 @@ export const TestGen: ChunkGenerator = {
|
||||
surfaceBiome
|
||||
);
|
||||
} else if(heightDiff > 0) {
|
||||
return getOverSurfaceVoxel(
|
||||
rVal,
|
||||
getOverSurfaceVoxel(
|
||||
voxel,
|
||||
worldX, worldY, worldZ,
|
||||
chunkX, chunkY, chunkZ,
|
||||
realX, realY, realZ,-
|
||||
@ -142,8 +139,8 @@ export const TestGen: ChunkGenerator = {
|
||||
surfaceBiome
|
||||
);
|
||||
} else {
|
||||
return getSurfaceVoxel(
|
||||
rVal,
|
||||
getSurfaceVoxel(
|
||||
voxel,
|
||||
worldX, worldY, worldZ,
|
||||
chunkX, chunkY, chunkZ,
|
||||
realX, realY, realZ,
|
||||
|
||||
@ -25,6 +25,7 @@ export interface GeneratedVoxel {
|
||||
|
||||
/**
|
||||
* Gets a voxel for a given position
|
||||
* @param voxel The voxel to fill with values
|
||||
* @param worldX The world x coordinate of the chunk
|
||||
* @param worldY The world y coordinate of the chunk
|
||||
* @param worldZ The world z coordinate of the chunk
|
||||
@ -38,12 +39,13 @@ export interface GeneratedVoxel {
|
||||
* @returns The voxel at the provided position
|
||||
*/
|
||||
export type VoxelFunction = (
|
||||
voxel: GeneratedVoxel,
|
||||
worldX: number, worldY: number, worldZ: number,
|
||||
chunkX: number, chunkY: number, chunkZ: number,
|
||||
stride: number,
|
||||
surfaceHeight: number,
|
||||
surfaceBiome: BiomeData
|
||||
) => GeneratedVoxel;
|
||||
) => void;
|
||||
|
||||
|
||||
|
||||
|
||||
@ -130,7 +130,7 @@ void main(){
|
||||
vec3 textureColor = getColor(texPlane1, texPlane2, texPlane3, norm, samplerIndexVec, samplerRatioVec, material);
|
||||
|
||||
//shadow
|
||||
float shadow = ShadowCalculation(FragPosLightSpace, normalize(-directLight.direction), norm);
|
||||
float shadow = ShadowCalculation(FragPosLightSpace, normalize(-directLight.direction), -norm);
|
||||
|
||||
//
|
||||
//point light calculations
|
||||
@ -350,5 +350,5 @@ float ShadowCalculation(vec4 fragPosLightSpace, vec3 lightDir, vec3 normal){
|
||||
|
||||
// shadow = currentDepth;
|
||||
|
||||
return shadow;
|
||||
return clamp(1.0 - shadow, 0.0, 0.7);
|
||||
}
|
||||
@ -1,3 +1,3 @@
|
||||
#maven.buildNumber.plugin properties file
|
||||
#Sun Nov 10 17:05:45 EST 2024
|
||||
buildNumber=378
|
||||
#Wed Nov 13 13:33:32 EST 2024
|
||||
buildNumber=381
|
||||
|
||||
@ -10,4 +10,13 @@ Different cases to consider when working on a biome generation system
|
||||
- Superstructure biomes (World tree, massive mountains, etc)
|
||||
- Oceans
|
||||
- Lakes
|
||||
- Rivers
|
||||
- Rivers
|
||||
- Large scale overhangs
|
||||
|
||||
|
||||
Operations we might want to do
|
||||
- Placing things on the surface
|
||||
- Solve navgation at the macro scale
|
||||
|
||||
|
||||
|
||||
|
||||
@ -60,3 +60,14 @@ store fire pixels as "good for fire civilization"
|
||||
|
||||
|
||||
when a pixel changes biome, must evict it from all these structures and recalculate which ones it should be within (except maybe zone)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Solve for the heightmap at a given x-z for the surface
|
||||
Then, have "cells" placed above the surface based on the base height offset of the biome
|
||||
These cells can be populated with larger structures
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1001,6 +1001,18 @@ Passing chunk data between nodes
|
||||
Fix homogenous value propagating from chunk gen to client cache
|
||||
Fix homogenous value joining on client
|
||||
|
||||
(11/12/2024)
|
||||
Work to optimize javascript chunk generators
|
||||
Solve curve SDF
|
||||
|
||||
(11/13/2024)
|
||||
Fix shadows on terrain
|
||||
Work on an anime-style mountain generator
|
||||
Work on making chunk reloading less obvious
|
||||
Fix default chunk generator
|
||||
Fix unit test
|
||||
Fix missing data on katana item
|
||||
|
||||
|
||||
|
||||
# TODO
|
||||
|
||||
@ -51,6 +51,11 @@
|
||||
"data" : [
|
||||
"data"
|
||||
]
|
||||
},
|
||||
{
|
||||
"messageName" : "EditorSwap",
|
||||
"description" : "Swaps between the editor entity and the non-editor entity",
|
||||
"data" : []
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
2
pom.xml
2
pom.xml
@ -305,7 +305,7 @@
|
||||
<dependency>
|
||||
<groupId>io.github.studiorailgun</groupId>
|
||||
<artifactId>MathUtils</artifactId>
|
||||
<version>1.1.0</version>
|
||||
<version>1.3.0</version>
|
||||
</dependency>
|
||||
|
||||
<!--DataStructures-->
|
||||
|
||||
@ -184,31 +184,6 @@ public class ClientDrawCellManager {
|
||||
if(!updatedLastFrame && !this.initialized){
|
||||
this.initialized = true;
|
||||
}
|
||||
// if(!updatedLastFrame){
|
||||
// Globals.profiler.beginCpuSample("ClientDrawCellManager.update - half res cells");
|
||||
// updatedLastFrame = this.recursivelyUpdateCells(rootNode, playerWorldPos, evaluationMap, HALF_RES_LOD, distCache);
|
||||
// Globals.profiler.endCpuSample();
|
||||
// }
|
||||
// if(!updatedLastFrame){
|
||||
// Globals.profiler.beginCpuSample("ClientDrawCellManager.update - half res cells");
|
||||
// updatedLastFrame = this.recursivelyUpdateCells(rootNode, playerWorldPos, evaluationMap, QUARTER_RES_LOD, distCache);
|
||||
// Globals.profiler.endCpuSample();
|
||||
// }
|
||||
// if(!updatedLastFrame){
|
||||
// Globals.profiler.beginCpuSample("ClientDrawCellManager.update - quarter res cells");
|
||||
// updatedLastFrame = this.recursivelyUpdateCells(rootNode, playerWorldPos, evaluationMap, EIGHTH_RES_LOD, distCache);
|
||||
// Globals.profiler.endCpuSample();
|
||||
// }
|
||||
// if(!updatedLastFrame){
|
||||
// Globals.profiler.beginCpuSample("ClientDrawCellManager.update - eighth res cells");
|
||||
// updatedLastFrame = this.recursivelyUpdateCells(rootNode, playerWorldPos, evaluationMap, SIXTEENTH_RES_LOD, distCache);
|
||||
// Globals.profiler.endCpuSample();
|
||||
// }
|
||||
// if(!updatedLastFrame){
|
||||
// Globals.profiler.beginCpuSample("ClientDrawCellManager.update - all res cells");
|
||||
// updatedLastFrame = this.recursivelyUpdateCells(rootNode, playerPos, evaluationMap, ALL_RES_LOD);
|
||||
// Globals.profiler.endCpuSample();
|
||||
// }
|
||||
}
|
||||
Globals.profiler.endCpuSample();
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@ import electrosphere.collision.CollisionEngine;
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.entity.ClientEntityUtils;
|
||||
import electrosphere.entity.Entity;
|
||||
import electrosphere.entity.btree.BehaviorTree;
|
||||
import electrosphere.entity.types.terrain.TerrainChunk;
|
||||
import electrosphere.renderer.meshgen.TransvoxelModelGeneration;
|
||||
import electrosphere.renderer.meshgen.TransvoxelModelGeneration.TransvoxelChunkData;
|
||||
@ -23,6 +24,11 @@ import electrosphere.util.math.GeomUtils;
|
||||
*/
|
||||
public class DrawCell {
|
||||
|
||||
/**
|
||||
* Number of frames to wait before destroying the chunk entity
|
||||
*/
|
||||
public static final int FRAMES_TO_WAIT_BEFORE_DESTRUCTION = 15;
|
||||
|
||||
/**
|
||||
* Enum for the different faces of a draw cell -- used when filling in data for higher LOD faces
|
||||
*/
|
||||
@ -188,9 +194,19 @@ public class DrawCell {
|
||||
*/
|
||||
public void destroy(){
|
||||
if(modelEntity != null){
|
||||
CollisionEngine collisionEngine = Globals.clientSceneWrapper.getCollisionEngine();
|
||||
collisionEngine.destroyPhysics(modelEntity);
|
||||
ClientEntityUtils.destroyEntity(modelEntity);
|
||||
Globals.clientScene.registerBehaviorTree(new BehaviorTree(){
|
||||
int framesSimulated = 0;
|
||||
public void simulate(float deltaTime) {
|
||||
if(framesSimulated < FRAMES_TO_WAIT_BEFORE_DESTRUCTION){
|
||||
framesSimulated++;
|
||||
} else {
|
||||
CollisionEngine collisionEngine = Globals.clientSceneWrapper.getCollisionEngine();
|
||||
collisionEngine.destroyPhysics(modelEntity);
|
||||
ClientEntityUtils.destroyEntity(modelEntity);
|
||||
Globals.clientScene.deregisterBehaviorTree(this);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -57,6 +57,9 @@ public class ClientEntityUtils {
|
||||
if(Globals.clientSceneWrapper != null){
|
||||
Globals.clientSceneWrapper.getScene().deregisterEntity(entity);
|
||||
Globals.clientSceneWrapper.deregisterTranslationMapping(entity);
|
||||
if(Globals.clientSceneWrapper.getCollisionEngine() != null){
|
||||
Globals.clientSceneWrapper.getCollisionEngine().destroyPhysics(entity);
|
||||
}
|
||||
}
|
||||
if(Globals.clientScene != null){
|
||||
Globals.clientScene.deregisterEntity(entity);
|
||||
|
||||
@ -11,7 +11,6 @@ import electrosphere.entity.Entity;
|
||||
import electrosphere.entity.EntityDataStrings;
|
||||
import electrosphere.entity.EntityUtils;
|
||||
import electrosphere.entity.btree.BehaviorTree;
|
||||
import electrosphere.logger.LoggerInterface;
|
||||
import electrosphere.net.parser.net.message.EntityMessage;
|
||||
import electrosphere.server.datacell.utils.DataCellSearchUtils;
|
||||
import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils;
|
||||
@ -46,7 +45,6 @@ public class ServerPhysicsSyncTree implements BehaviorTree {
|
||||
Quaterniond rotation = EntityUtils.getRotation(parent);
|
||||
DBody body = PhysicsEntityUtils.getDBody(parent);
|
||||
if(body == null){
|
||||
LoggerInterface.loggerEngine.ERROR(new IllegalStateException("Running physics sync tree on entity that does not have a physics body!"));
|
||||
} else {
|
||||
//velocities
|
||||
Vector3d linearVel = PhysicsUtils.odeVecToJomlVec(body.getLinearVel());
|
||||
|
||||
@ -63,7 +63,7 @@ public class TerrainChunk {
|
||||
}
|
||||
rVal.putData(EntityDataStrings.HAS_UNIQUE_MODEL, true);
|
||||
} else {
|
||||
LoggerInterface.loggerEngine.WARNING("Finished generating terrain polygons; however, entity has already been deleted.");
|
||||
LoggerInterface.loggerEngine.DEBUG("Finished generating terrain polygons; however, entity has already been deleted.");
|
||||
}
|
||||
} catch (Error e){
|
||||
LoggerInterface.loggerEngine.ERROR(e);
|
||||
|
||||
@ -251,7 +251,11 @@ public class Actor {
|
||||
}
|
||||
}
|
||||
} else if(this.boneGroups == null){
|
||||
LoggerInterface.loggerRenderer.WARNING("Trying to play animation on pose actor that uses bone groups, but the actor's bone group isn't defined!");
|
||||
LoggerInterface.loggerRenderer.WARNING(
|
||||
"Trying to play animation on Actor that uses bone groups, but the Actor's bone group isn't defined!\n" +
|
||||
"Model path: " + modelPath + "\n" +
|
||||
"Animation name: " + animationName + "\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -31,17 +31,22 @@ public class ShadowMapPipeline implements RenderPipeline {
|
||||
/**
|
||||
* The eye of the camera that is used to render the shadow map
|
||||
*/
|
||||
Vector3d cameraEye = new Vector3d(-1,10,-5.5);
|
||||
Vector3d cameraEye = new Vector3d(-1,20,-5.5);
|
||||
|
||||
/**
|
||||
* The near plane distance
|
||||
*/
|
||||
float nearPlane = 0.1f;
|
||||
float nearPlane = 1f;
|
||||
|
||||
/**
|
||||
* The far plane
|
||||
*/
|
||||
float farPlane = 25f;
|
||||
float farPlane = 40f;
|
||||
|
||||
/**
|
||||
* Sides of the orthagonal box
|
||||
*/
|
||||
float sideLength = 50f;
|
||||
|
||||
/**
|
||||
* Sets whether the far plane should update based on camera location or not
|
||||
@ -68,9 +73,10 @@ public class ShadowMapPipeline implements RenderPipeline {
|
||||
float eyeX = (float)cameraEye.x;
|
||||
float eyeY = (float)cameraEye.y;
|
||||
float eyeZ = (float)cameraEye.z;
|
||||
float eyeDist = (float)cameraEye.length();
|
||||
// float eyeDist = (float)cameraEye.length();
|
||||
// float farPlane = eyeDist + 10.0f;
|
||||
float sidesMagnitude = (float)Math.sqrt(eyeDist);
|
||||
// float sidesMagnitude = (float)Math.sqrt(eyeDist);
|
||||
float sidesMagnitude = sideLength;
|
||||
//set matrices for light render
|
||||
Matrix4f lightProjection = new Matrix4f().setOrtho(-sidesMagnitude, sidesMagnitude, -sidesMagnitude, sidesMagnitude, nearPlane, farPlane);//glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, near_plane, far_plane);
|
||||
Matrix4f lightView = new Matrix4f().setLookAt(
|
||||
|
||||
@ -48,11 +48,11 @@ public class ServerContentGenerator {
|
||||
);
|
||||
}
|
||||
|
||||
//setup
|
||||
Random random = new Random(randomizer);
|
||||
// //setup
|
||||
// Random random = new Random(randomizer);
|
||||
|
||||
|
||||
//generate foliage
|
||||
// //generate foliage
|
||||
// BiomeData biome = null;
|
||||
// if(realm.getServerWorldData() != null && realm.getServerWorldData().getServerTerrainManager() != null && realm.getServerWorldData().getServerTerrainManager().getModel() != null){
|
||||
// biome = realm.getServerWorldData().getServerTerrainManager().getModel().getSurfaceBiome(worldPos.x, worldPos.z);
|
||||
|
||||
@ -224,7 +224,11 @@ public class PoseActor {
|
||||
}
|
||||
}
|
||||
} else if(this.boneGroups == null){
|
||||
LoggerInterface.loggerRenderer.WARNING("Trying to play animation on pose actor that uses bone groups, but the actor's bone group isn't defined!");
|
||||
LoggerInterface.loggerRenderer.WARNING(
|
||||
"Trying to play animation on PoseActor that uses bone groups, but the PoseActor's bone group isn't defined!\n" +
|
||||
"Model path: " + modelPath + "\n" +
|
||||
"Animation name: " + animationName + "\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -26,19 +26,19 @@ public class DefaultChunkGenerator implements ChunkGenerator {
|
||||
public ServerTerrainChunk generateChunk(int worldX, int worldY, int worldZ, int stride) {
|
||||
//Each chunk also needs custody of the next chunk's first values so that they can perfectly overlap.
|
||||
//Hence, width should actually be chunk dimension + 1
|
||||
float[][][] weights = new float[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION];
|
||||
int[][][] values = new int[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION];
|
||||
for(int inc = 0; inc < ServerTerrainChunk.CHUNK_DIMENSION; inc++){
|
||||
for(int weightX = 0; weightX < ServerTerrainChunk.CHUNK_DIMENSION; weightX++){
|
||||
for(int weightZ = 0; weightZ < ServerTerrainChunk.CHUNK_DIMENSION; weightZ++){
|
||||
float[][][] weights = new float[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE];
|
||||
int[][][] values = new int[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE];
|
||||
for(int inc = 0; inc < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; inc++){
|
||||
for(int weightX = 0; weightX < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; weightX++){
|
||||
for(int weightZ = 0; weightZ < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; weightZ++){
|
||||
weights[weightX][inc][weightZ] = -1;
|
||||
values[weightX][inc][weightZ] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(worldY < 1){
|
||||
for(int weightX = 0; weightX < ServerTerrainChunk.CHUNK_DIMENSION; weightX++){
|
||||
for(int weightZ = 0; weightZ < ServerTerrainChunk.CHUNK_DIMENSION; weightZ++){
|
||||
for(int weightX = 0; weightX < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; weightX++){
|
||||
for(int weightZ = 0; weightZ < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; weightZ++){
|
||||
weights[weightX][0][weightZ] = 0.1f;
|
||||
values[weightX][0][weightZ] = baseVoxelId;
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@ import java.util.Map;
|
||||
|
||||
import electrosphere.client.terrain.cache.ChunkData;
|
||||
|
||||
// import org.graalvm.polyglot.Value;
|
||||
import org.graalvm.polyglot.Value;
|
||||
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.game.data.biome.BiomeData;
|
||||
@ -17,6 +17,10 @@ import electrosphere.server.terrain.generation.heightmap.HillsGen;
|
||||
import electrosphere.server.terrain.generation.heightmap.PlainsGen;
|
||||
import electrosphere.server.terrain.generation.interfaces.ChunkGenerator;
|
||||
import electrosphere.server.terrain.generation.interfaces.GeneratedVoxel;
|
||||
import electrosphere.server.terrain.generation.interfaces.GenerationContext;
|
||||
import electrosphere.server.terrain.generation.voxelphase.AnimeMountainsGen;
|
||||
import electrosphere.server.terrain.generation.voxelphase.HillsVoxelGen;
|
||||
import electrosphere.server.terrain.generation.voxelphase.VoxelGenerator;
|
||||
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
||||
import electrosphere.server.terrain.models.TerrainModel;
|
||||
|
||||
@ -61,9 +65,14 @@ public class TestGenerationChunkGenerator implements ChunkGenerator {
|
||||
ServerWorldData serverWorldData;
|
||||
|
||||
/**
|
||||
* Map of generator tag to the generator
|
||||
* The map of generator tag to the heightmap generator
|
||||
*/
|
||||
Map<String,HeightmapGenerator> tagGeneratorMap = new HashMap<String,HeightmapGenerator>();
|
||||
Map<String,HeightmapGenerator> tagHeightmapMap = new HashMap<String,HeightmapGenerator>();
|
||||
|
||||
/**
|
||||
* The map of generator tag to voxel generator
|
||||
*/
|
||||
Map<String,VoxelGenerator> tagVoxelMap = new HashMap<String,VoxelGenerator>();
|
||||
|
||||
/**
|
||||
* Tracks whether to use javascript generation or not
|
||||
@ -75,9 +84,11 @@ public class TestGenerationChunkGenerator implements ChunkGenerator {
|
||||
*/
|
||||
public TestGenerationChunkGenerator(ServerWorldData serverWorldData, boolean useJavascript){
|
||||
this.serverWorldData = serverWorldData;
|
||||
registerGenerator(new EmptySkyGen());
|
||||
registerGenerator(new HillsGen());
|
||||
registerGenerator(new PlainsGen());
|
||||
registerHeightmapGenerator(new EmptySkyGen());
|
||||
registerHeightmapGenerator(new HillsGen());
|
||||
registerHeightmapGenerator(new PlainsGen());
|
||||
registerVoxelGenerator(new HillsVoxelGen());
|
||||
registerVoxelGenerator(new AnimeMountainsGen());
|
||||
this.useJavascript = useJavascript;
|
||||
}
|
||||
|
||||
@ -85,27 +96,31 @@ public class TestGenerationChunkGenerator implements ChunkGenerator {
|
||||
* Registers a heightmap generator
|
||||
* @param generator The heightmap generator
|
||||
*/
|
||||
private void registerGenerator(HeightmapGenerator generator){
|
||||
tagGeneratorMap.put(generator.getTag(),generator);
|
||||
private void registerHeightmapGenerator(HeightmapGenerator generator){
|
||||
tagHeightmapMap.put(generator.getTag(),generator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a voxel generator
|
||||
* @param generator The voxel generator
|
||||
*/
|
||||
private void registerVoxelGenerator(VoxelGenerator generator){
|
||||
tagVoxelMap.put(generator.getTag(),generator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerTerrainChunk generateChunk(int worldX, int worldY, int worldZ, int stride) {
|
||||
Globals.profiler.beginAggregateCpuSample("TestGenerationChunkGenerator.generateChunk");
|
||||
ServerTerrainChunk rVal = null;
|
||||
ServerTerrainChunk rVal = new ServerTerrainChunk(worldX, worldY, worldZ);
|
||||
float[][][] weights = new float[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE];;
|
||||
int[][][] values = new int[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE];
|
||||
|
||||
int firstType = -2;
|
||||
boolean homogenous = true;
|
||||
try {
|
||||
//actual generation algo
|
||||
|
||||
//biome of the current chunk
|
||||
BiomeData surfaceBiome = this.terrainModel.getSurfaceBiome(worldX, worldZ);
|
||||
|
||||
BiomeSurfaceGenerationParams surfaceParams = surfaceBiome.getSurfaceGenerationParams();
|
||||
HeightmapGenerator heightmapGen = this.tagGeneratorMap.get(surfaceParams.getSurfaceGenTag());
|
||||
HeightmapGenerator heightmapGen = this.tagHeightmapMap.get(surfaceParams.getSurfaceGenTag());
|
||||
if(heightmapGen == null){
|
||||
throw new Error("Undefined heightmap generator in biome! " + surfaceBiome.getId() + " " + surfaceBiome.getDisplayName() + " " + surfaceParams.getSurfaceGenTag());
|
||||
}
|
||||
@ -129,39 +144,58 @@ public class TestGenerationChunkGenerator implements ChunkGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
VoxelGenerator voxelGenerator = this.tagVoxelMap.get("hills");
|
||||
|
||||
if(this.useJavascript){
|
||||
// Globals.scriptEngine.executeSynchronously(() -> {
|
||||
// Value getVoxelFunc = Globals.scriptEngine.invokeEngineMember("chunkGeneratorManager", "getVoxelFunction", SCRIPT_GEN_TEST_TAG);
|
||||
// for(int x = 0; x < ServerTerrainChunk.CHUNK_DIMENSION; x++){
|
||||
// Globals.profiler.beginAggregateCpuSample("TestGenerationChunkGenerator - Generate slice");
|
||||
// for(int y = 0; y < ServerTerrainChunk.CHUNK_DIMENSION; y++){
|
||||
// for(int z = 0; z < ServerTerrainChunk.CHUNK_DIMENSION; z++){
|
||||
// int finalWorldX = worldX + ((x * strideValue) / ServerTerrainChunk.CHUNK_DIMENSION);
|
||||
// int finalWorldY = worldY + ((y * strideValue) / ServerTerrainChunk.CHUNK_DIMENSION);
|
||||
// int finalWorldZ = worldZ + ((z * strideValue) / ServerTerrainChunk.CHUNK_DIMENSION);
|
||||
// int finalChunkX = (x * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION;
|
||||
// int finalChunkY = (y * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION;
|
||||
// int finalChunkZ = (z * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION;
|
||||
// Value result = getVoxelFunc.execute(
|
||||
// finalWorldX, finalWorldY, finalWorldZ,
|
||||
// finalChunkX, finalChunkY, finalChunkZ,
|
||||
// stride,
|
||||
// heightfield[x][z],
|
||||
// surfaceBiome
|
||||
// );
|
||||
// if(result != null){
|
||||
// weights[x][y][z] = result.getMember("weight").asFloat();
|
||||
// values[x][y][z] = result.getMember("type").asInt();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// Globals.profiler.endCpuSample();
|
||||
// }
|
||||
// });
|
||||
Globals.scriptEngine.executeSynchronously(() -> {
|
||||
int firstType = -2;
|
||||
boolean homogenous = true;
|
||||
GeneratedVoxel voxel = new GeneratedVoxel();
|
||||
Value getVoxelFunc = Globals.scriptEngine.invokeEngineMember("chunkGeneratorManager", "getVoxelFunction", SCRIPT_GEN_TEST_TAG);
|
||||
for(int x = 0; x < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; x++){
|
||||
Globals.profiler.beginAggregateCpuSample("TestGenerationChunkGenerator - Generate slice");
|
||||
for(int y = 0; y < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; y++){
|
||||
for(int z = 0; z < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; z++){
|
||||
int finalWorldX = worldX + ((x * strideValue) / ServerTerrainChunk.CHUNK_DIMENSION);
|
||||
int finalWorldY = worldY + ((y * strideValue) / ServerTerrainChunk.CHUNK_DIMENSION);
|
||||
int finalWorldZ = worldZ + ((z * strideValue) / ServerTerrainChunk.CHUNK_DIMENSION);
|
||||
int finalChunkX = (x * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION;
|
||||
int finalChunkY = (y * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION;
|
||||
int finalChunkZ = (z * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION;
|
||||
getVoxelFunc.execute(
|
||||
voxel,
|
||||
finalWorldX, finalWorldY, finalWorldZ,
|
||||
finalChunkX, finalChunkY, finalChunkZ,
|
||||
stride,
|
||||
heightfield[x][z],
|
||||
surfaceBiome
|
||||
);
|
||||
weights[x][y][z] = voxel.weight;
|
||||
values[x][y][z] = voxel.type;
|
||||
if(firstType == -2){
|
||||
firstType = values[x][y][z];
|
||||
} else if(homogenous && firstType != values[x][y][z]){
|
||||
homogenous = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Globals.profiler.endCpuSample();
|
||||
}
|
||||
if(homogenous){
|
||||
rVal.setHomogenousValue(firstType);
|
||||
} else {
|
||||
rVal.setHomogenousValue(ChunkData.NOT_HOMOGENOUS);
|
||||
}
|
||||
rVal.setWeights(weights);
|
||||
rVal.setValues(values);
|
||||
});
|
||||
} else {
|
||||
int firstType = -2;
|
||||
boolean homogenous = true;
|
||||
GeneratedVoxel voxel = new GeneratedVoxel();
|
||||
GenerationContext generationContext = new GenerationContext();
|
||||
generationContext.setServerWorldData(serverWorldData);
|
||||
for(int x = 0; x < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; x++){
|
||||
Globals.profiler.beginAggregateCpuSample("TestGenerationChunkGenerator - Generate slice");
|
||||
for(int y = 0; y < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; y++){
|
||||
for(int z = 0; z < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; z++){
|
||||
int finalWorldX = worldX + ((x * strideValue) / ServerTerrainChunk.CHUNK_DIMENSION);
|
||||
@ -170,13 +204,14 @@ public class TestGenerationChunkGenerator implements ChunkGenerator {
|
||||
int finalChunkX = (x * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION;
|
||||
int finalChunkY = (y * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION;
|
||||
int finalChunkZ = (z * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION;
|
||||
this.getVoxel(
|
||||
voxelGenerator.getVoxel(
|
||||
voxel,
|
||||
finalWorldX, finalWorldY, finalWorldZ,
|
||||
finalChunkX, finalChunkY, finalChunkZ,
|
||||
stride,
|
||||
heightfield[x][z],
|
||||
surfaceBiome
|
||||
surfaceBiome,
|
||||
generationContext
|
||||
);
|
||||
if(voxel != null){
|
||||
weights[x][y][z] = voxel.weight;
|
||||
@ -189,13 +224,18 @@ public class TestGenerationChunkGenerator implements ChunkGenerator {
|
||||
}
|
||||
}
|
||||
}
|
||||
Globals.profiler.endCpuSample();
|
||||
}
|
||||
if(homogenous){
|
||||
rVal.setHomogenousValue(firstType);
|
||||
} else {
|
||||
rVal.setHomogenousValue(ChunkData.NOT_HOMOGENOUS);
|
||||
}
|
||||
rVal.setWeights(weights);
|
||||
rVal.setValues(values);
|
||||
}
|
||||
} catch(Exception ex){
|
||||
ex.printStackTrace();
|
||||
}
|
||||
rVal = new ServerTerrainChunk(worldX, worldY, worldZ, homogenous ? firstType : ChunkData.NOT_HOMOGENOUS, weights, values);
|
||||
Globals.profiler.endCpuSample();
|
||||
return rVal;
|
||||
}
|
||||
@ -205,7 +245,7 @@ public class TestGenerationChunkGenerator implements ChunkGenerator {
|
||||
BiomeData surfaceBiome = this.terrainModel.getSurfaceBiome(worldX, worldZ);
|
||||
|
||||
BiomeSurfaceGenerationParams surfaceParams = surfaceBiome.getSurfaceGenerationParams();
|
||||
HeightmapGenerator heightmapGen = this.tagGeneratorMap.get(surfaceParams.getSurfaceGenTag());
|
||||
HeightmapGenerator heightmapGen = this.tagHeightmapMap.get(surfaceParams.getSurfaceGenTag());
|
||||
if(heightmapGen == null){
|
||||
throw new Error("Undefined heightmap generator in biome! " + surfaceBiome.getId() + " " + surfaceBiome.getDisplayName() + " " + surfaceParams.getSurfaceGenTag());
|
||||
}
|
||||
@ -222,140 +262,4 @@ public class TestGenerationChunkGenerator implements ChunkGenerator {
|
||||
this.terrainModel = model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value for a chunk
|
||||
* @param voxel The voxel to fill
|
||||
* @param worldX The world x pos
|
||||
* @param worldY The world y pos
|
||||
* @param worldZ The world z pos
|
||||
* @param chunkX The chunk x pos
|
||||
* @param chunkY The chunk y pos
|
||||
* @param chunkZ The chunk z pos
|
||||
* @param stride The stride of the data
|
||||
* @param surfaceHeight The height of the surface at x,z
|
||||
* @param surfaceBiome The surface biome of the chunk
|
||||
*/
|
||||
private void getVoxel(
|
||||
GeneratedVoxel voxel,
|
||||
int worldX, int worldY, int worldZ,
|
||||
int chunkX, int chunkY, int chunkZ,
|
||||
int stride,
|
||||
float surfaceHeight,
|
||||
BiomeData surfaceBiome
|
||||
){
|
||||
Globals.profiler.beginAggregateCpuSample("TestGenerationChunkGenerator.getChunkValue");
|
||||
BiomeSurfaceGenerationParams surfaceParams = surfaceBiome.getSurfaceGenerationParams();
|
||||
HeightmapGenerator heightmapGen = this.tagGeneratorMap.get(surfaceParams.getSurfaceGenTag());
|
||||
if(heightmapGen == null){
|
||||
throw new Error("Undefined heightmap generator in biome! " + surfaceBiome.getId() + " " + surfaceBiome.getDisplayName() + " " + surfaceParams.getSurfaceGenTag());
|
||||
}
|
||||
|
||||
double realX = this.serverWorldData.convertVoxelToRealSpace(chunkX,worldX);
|
||||
double realY = this.serverWorldData.convertVoxelToRealSpace(chunkY,worldY);
|
||||
double realZ = this.serverWorldData.convertVoxelToRealSpace(chunkZ,worldZ);
|
||||
|
||||
double strideMultiplier = Math.pow(2,stride);
|
||||
double heightDiff = realY - surfaceHeight;
|
||||
double surfacePercent = TestGenerationChunkGenerator.getSurfaceWeight(surfaceHeight,realY,strideMultiplier);
|
||||
Globals.profiler.endCpuSample();
|
||||
if(heightDiff < -strideMultiplier * SURFACE_VOXEL_WIDTH){
|
||||
getSubsurfaceVoxel(
|
||||
voxel,
|
||||
worldX, worldY, worldZ,
|
||||
chunkX, chunkY, chunkZ,
|
||||
realX, realY, realZ,
|
||||
surfacePercent,
|
||||
surfaceHeight,
|
||||
surfaceBiome
|
||||
);
|
||||
} else if(heightDiff > 0) {
|
||||
getOverSurfaceVoxel(
|
||||
voxel,
|
||||
worldX, worldY, worldZ,
|
||||
chunkX, chunkY, chunkZ,
|
||||
realX, realY, realZ,-
|
||||
surfacePercent,
|
||||
surfaceHeight,
|
||||
surfaceBiome
|
||||
);
|
||||
} else {
|
||||
getSurfaceVoxel(
|
||||
voxel,
|
||||
worldX, worldY, worldZ,
|
||||
chunkX, chunkY, chunkZ,
|
||||
realX, realY, realZ,
|
||||
surfacePercent,
|
||||
surfaceHeight,
|
||||
surfaceBiome
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the voxel on the surface
|
||||
* @return The voxel
|
||||
*/
|
||||
private void getSurfaceVoxel(
|
||||
GeneratedVoxel voxel,
|
||||
int worldX, int worldY, int worldZ,
|
||||
int chunkX, int chunkY, int chunkZ,
|
||||
double realX, double realY, double realZ,
|
||||
double surfacePercent,
|
||||
float surfaceHeight,
|
||||
BiomeData surfaceBiome
|
||||
){
|
||||
voxel.weight = (float)surfacePercent * 2 - 1;
|
||||
voxel.type = 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the voxel below the surface
|
||||
* @return The voxel
|
||||
*/
|
||||
private void getSubsurfaceVoxel(
|
||||
GeneratedVoxel voxel,
|
||||
int worldX, int worldY, int worldZ,
|
||||
int chunkX, int chunkY, int chunkZ,
|
||||
double realX, double realY, double realZ,
|
||||
double surfacePercent,
|
||||
float surfaceHeight,
|
||||
BiomeData surfaceBiome
|
||||
){
|
||||
if(realY < surfaceHeight - 5){
|
||||
voxel.weight = 1;
|
||||
voxel.type = 6;
|
||||
} else {
|
||||
voxel.weight = 1;
|
||||
voxel.type = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the voxel above the service
|
||||
* @return The voxel
|
||||
*/
|
||||
private void getOverSurfaceVoxel(
|
||||
GeneratedVoxel voxel,
|
||||
int worldX, int worldY, int worldZ,
|
||||
int chunkX, int chunkY, int chunkZ,
|
||||
double realX, double realY, double realZ,
|
||||
double surfacePercent,
|
||||
float surfaceHeight,
|
||||
BiomeData surfaceBiome
|
||||
){
|
||||
voxel.weight = -1;
|
||||
voxel.type = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the weight of a voxel on the surface based on the surface height, the position of the voxel, and the stride multiplier
|
||||
* @param surfaceHeight The surface height
|
||||
* @param realPosY The position of the voxel
|
||||
* @param strideMultiplier The stride multiplier
|
||||
* @return The weight of the voxel
|
||||
*/
|
||||
protected static double getSurfaceWeight(double surfaceHeight, double realPosY, double strideMultiplier){
|
||||
return ((surfaceHeight - realPosY) / strideMultiplier);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -52,7 +52,7 @@ public class HillsGen implements HeightmapGenerator {
|
||||
Globals.profiler.beginAggregateCpuSample("HillsGen.getHeight");
|
||||
double scaledX = x * POSITION_SCALE;
|
||||
double scaledY = y * POSITION_SCALE;
|
||||
float rVal = gradientHeight(SEED, scaledX, scaledY) * VERTICAL_SCALE + HEIGHT_OFFSET;
|
||||
float rVal = HillsGen.gradientHeight(SEED, scaledX, scaledY) * VERTICAL_SCALE + HEIGHT_OFFSET;
|
||||
Globals.profiler.endCpuSample();
|
||||
return rVal;
|
||||
}
|
||||
|
||||
@ -0,0 +1,26 @@
|
||||
package electrosphere.server.terrain.generation.heightmap;
|
||||
|
||||
import electrosphere.util.noise.OpenSimplex2S;
|
||||
|
||||
/**
|
||||
* Generates a mild plain that would look like a seafloor
|
||||
*/
|
||||
public class SeaFloorGen implements HeightmapGenerator {
|
||||
|
||||
/**
|
||||
* The scale of the noise
|
||||
*/
|
||||
float noiseScale = 0.01f;
|
||||
|
||||
@Override
|
||||
public float getHeight(long SEED, double x, double y) {
|
||||
float noise = (float)OpenSimplex2S.noise2_ImproveX(SEED, x * noiseScale, y * noiseScale);
|
||||
return noise;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTag() {
|
||||
return "seafloor";
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
package electrosphere.server.terrain.generation.interfaces;
|
||||
|
||||
import electrosphere.game.server.world.ServerWorldData;
|
||||
|
||||
/**
|
||||
* The context the generation is happening in. Stores things like biomes to interpolate between.
|
||||
*/
|
||||
public class GenerationContext {
|
||||
|
||||
/**
|
||||
* The world data for the realm we're generating for
|
||||
*/
|
||||
ServerWorldData serverWorldData;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public GenerationContext(){
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the world data for the server
|
||||
* @return The world data
|
||||
*/
|
||||
public ServerWorldData getServerWorldData(){
|
||||
return serverWorldData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the world data for the context
|
||||
* @param serverWorldData The world data
|
||||
*/
|
||||
public void setServerWorldData(ServerWorldData serverWorldData){
|
||||
this.serverWorldData = serverWorldData;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,259 @@
|
||||
package electrosphere.server.terrain.generation.voxelphase;
|
||||
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.game.data.biome.BiomeData;
|
||||
import electrosphere.server.terrain.generation.interfaces.GeneratedVoxel;
|
||||
import electrosphere.server.terrain.generation.interfaces.GenerationContext;
|
||||
import io.github.studiorailgun.MathUtils;
|
||||
import io.github.studiorailgun.RandUtils;
|
||||
|
||||
/**
|
||||
* Generates anime-style mountains
|
||||
*/
|
||||
public class AnimeMountainsGen implements VoxelGenerator {
|
||||
|
||||
/**
|
||||
* The width of the surface in number of voxels
|
||||
*/
|
||||
public static final int SURFACE_VOXEL_WIDTH = 2;
|
||||
|
||||
/**
|
||||
* Size of the large cells that generate mountains
|
||||
*/
|
||||
public static final int LARGE_CELL_SIZE = 1024;
|
||||
|
||||
/**
|
||||
* How much to sink the cell into the surface
|
||||
*/
|
||||
public static final int CELL_VERTICAL_OFFSET = - (int)((LARGE_CELL_SIZE) * 2.5 / 5.0);
|
||||
|
||||
/**
|
||||
* The variance in scale of mountains
|
||||
*/
|
||||
public static final double MOUNTAIN_SCALE_VARIANCE = 0.2;
|
||||
|
||||
/**
|
||||
* The width of the mountain
|
||||
*/
|
||||
public static final double MOUNTAIN_WIDTH = 0.4;
|
||||
|
||||
/**
|
||||
* The center x point of the cell
|
||||
*/
|
||||
public static final double CELL_CENTER_X = 0.5;
|
||||
|
||||
/**
|
||||
* The center y point of the cell
|
||||
*/
|
||||
public static final double CELL_CENTER_Y = 0.5;
|
||||
|
||||
/**
|
||||
* The center z point of the cell
|
||||
*/
|
||||
public static final double CELL_CENTER_Z = 0.5;
|
||||
|
||||
/**
|
||||
* Amount the vertical rotation offset can vary
|
||||
*/
|
||||
public static final double VERTICAL_ROTATION_OFFSET_VARIANCE = 0.2;
|
||||
|
||||
@Override
|
||||
public String getTag() {
|
||||
return "animeMountain";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getVoxel(
|
||||
GeneratedVoxel voxel,
|
||||
int worldX, int worldY, int worldZ,
|
||||
int chunkX, int chunkY, int chunkZ,
|
||||
int stride, float surfaceHeight,
|
||||
BiomeData surfaceBiome,
|
||||
GenerationContext generationContext
|
||||
) {
|
||||
Globals.profiler.beginAggregateCpuSample("AnimeMountainsGen.getVoxel");
|
||||
|
||||
double realX = generationContext.getServerWorldData().convertVoxelToRealSpace(chunkX,worldX);
|
||||
double realY = generationContext.getServerWorldData().convertVoxelToRealSpace(chunkY,worldY);
|
||||
double realZ = generationContext.getServerWorldData().convertVoxelToRealSpace(chunkZ,worldZ);
|
||||
|
||||
double strideMultiplier = Math.pow(2,stride);
|
||||
double heightDiff = realY - surfaceHeight;
|
||||
double surfacePercent = AnimeMountainsGen.getSurfaceWeight(surfaceHeight,realY,strideMultiplier);
|
||||
Globals.profiler.endCpuSample();
|
||||
if(heightDiff < -strideMultiplier * SURFACE_VOXEL_WIDTH){
|
||||
this.getSubsurfaceVoxel(
|
||||
voxel,
|
||||
worldX, worldY, worldZ,
|
||||
chunkX, chunkY, chunkZ,
|
||||
realX, realY, realZ,
|
||||
surfacePercent,
|
||||
surfaceHeight,
|
||||
surfaceBiome
|
||||
);
|
||||
} else if(heightDiff > 0) {
|
||||
this.getOverSurfaceVoxel(
|
||||
voxel,
|
||||
worldX, worldY, worldZ,
|
||||
chunkX, chunkY, chunkZ,
|
||||
realX, realY, realZ,-
|
||||
surfacePercent,
|
||||
surfaceHeight,
|
||||
surfaceBiome
|
||||
);
|
||||
} else {
|
||||
this.getSurfaceVoxel(
|
||||
voxel,
|
||||
worldX, worldY, worldZ,
|
||||
chunkX, chunkY, chunkZ,
|
||||
realX, realY, realZ,
|
||||
surfacePercent,
|
||||
surfaceHeight,
|
||||
surfaceBiome
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the voxel on the surface
|
||||
* @return The voxel
|
||||
*/
|
||||
private void getSurfaceVoxel(
|
||||
GeneratedVoxel voxel,
|
||||
int worldX, int worldY, int worldZ,
|
||||
int chunkX, int chunkY, int chunkZ,
|
||||
double realX, double realY, double realZ,
|
||||
double surfacePercent,
|
||||
float surfaceHeight,
|
||||
BiomeData surfaceBiome
|
||||
){
|
||||
voxel.weight = (float)surfacePercent * 2 - 1;
|
||||
voxel.type = 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the voxel below the surface
|
||||
* @return The voxel
|
||||
*/
|
||||
private void getSubsurfaceVoxel(
|
||||
GeneratedVoxel voxel,
|
||||
int worldX, int worldY, int worldZ,
|
||||
int chunkX, int chunkY, int chunkZ,
|
||||
double realX, double realY, double realZ,
|
||||
double surfacePercent,
|
||||
float surfaceHeight,
|
||||
BiomeData surfaceBiome
|
||||
){
|
||||
if(realY < surfaceHeight - 5){
|
||||
voxel.weight = 1;
|
||||
voxel.type = 6;
|
||||
} else {
|
||||
voxel.weight = 1;
|
||||
voxel.type = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the voxel above the service
|
||||
* @return The voxel
|
||||
*/
|
||||
private void getOverSurfaceVoxel(
|
||||
GeneratedVoxel voxel,
|
||||
int worldX, int worldY, int worldZ,
|
||||
int chunkX, int chunkY, int chunkZ,
|
||||
double realX, double realY, double realZ,
|
||||
double surfacePercent,
|
||||
float surfaceHeight,
|
||||
BiomeData surfaceBiome
|
||||
){
|
||||
//default voxel value
|
||||
voxel.weight = -1;
|
||||
voxel.type = 0;
|
||||
|
||||
//get the height above the surface
|
||||
double heightAboveBaseSurface = realY - surfaceBiome.getSurfaceGenerationParams().getHeightOffset();
|
||||
double offsetHeight = heightAboveBaseSurface - CELL_VERTICAL_OFFSET;
|
||||
|
||||
//calculated floored values
|
||||
double x_i = Math.floor(realX / LARGE_CELL_SIZE);
|
||||
double y_i = Math.floor(offsetHeight / LARGE_CELL_SIZE);
|
||||
double z_i = Math.floor(realZ / LARGE_CELL_SIZE);
|
||||
|
||||
//only generate if you're on the first cell from the surface
|
||||
if(y_i < 1){
|
||||
//calculate values from which cell we're in
|
||||
double rotationTheta = RandUtils.rand(x_i, z_i, 0) * Math.PI * 2;
|
||||
// double mountainScale = MathUtils.rand(x_i, z_i, 1) * MOUNTAIN_SCALE_VARIANCE + (1.0 - (MOUNTAIN_SCALE_VARIANCE / 2.0));
|
||||
// double verticalRotationOffset = MathUtils.rand(x_i, z_i, 2) * VERTICAL_ROTATION_OFFSET_VARIANCE;
|
||||
|
||||
//remainders of the point coordinates
|
||||
double x_r = (realX / LARGE_CELL_SIZE) - x_i;
|
||||
double y_r = (offsetHeight / LARGE_CELL_SIZE) - y_i;
|
||||
double z_r = (realZ / LARGE_CELL_SIZE) - z_i;
|
||||
|
||||
//get the center of the cell
|
||||
double cellCenterX = CELL_CENTER_X;
|
||||
double cellCenterY = CELL_CENTER_Y;
|
||||
double cellCenterZ = CELL_CENTER_Z;
|
||||
|
||||
//delta positions
|
||||
double deltaX = (x_r - cellCenterX);
|
||||
double deltaY = (y_r - cellCenterY);
|
||||
double deltaZ = (z_r - cellCenterZ);
|
||||
|
||||
//rotate around the center
|
||||
double rotX = deltaX * Math.cos(rotationTheta) + deltaZ * Math.sin(rotationTheta);
|
||||
double rotY = deltaY;
|
||||
double rotZ = - deltaX * Math.sin(rotationTheta) + deltaZ * Math.cos(rotationTheta);
|
||||
|
||||
//roation along the arctre
|
||||
//ranged [0,2PI]
|
||||
double rotationAlongArc = Math.atan2(rotY,rotX);
|
||||
//ranges [0,1]
|
||||
// double rotationPercent = rotationAlongArc / (Math.PI * 2.0);
|
||||
|
||||
|
||||
//calculate values from where we are WITHIN the cell
|
||||
// double voxelGamma = Math.atan2(
|
||||
// x_r - cellCenterX,
|
||||
// z_r - cellCenterZ
|
||||
// ) + Math.PI * 2.0;
|
||||
// double voxelTheta = Math.atan2(y_r - cellCenterY, MathUtils.dist(x_r,z_r,cellCenterX,cellCenterZ));
|
||||
double distanceFromCenter = MathUtils.dist(rotX,rotY,0,0);
|
||||
double distanceFromArcCenter = Math.sqrt(rotZ*rotZ);
|
||||
|
||||
//target distance from center
|
||||
double targetDistanceFromArcCenter = Math.sin(rotationAlongArc) * 0.3;
|
||||
double targetArcRadius = 0.6;
|
||||
double targetArcRadiusWidth = Math.sin(rotationAlongArc) * 0.03;
|
||||
|
||||
|
||||
if(
|
||||
// voxelTheta > 0 &&
|
||||
// (voxelGamma - Math.PI/2) < Math.PI &&
|
||||
// voxelTheta > Math.max(Math.sin(voxelGamma),0) &&
|
||||
// voxelTheta > 0.4 * Math.max(Math.sin(voxelGamma),0) &&
|
||||
distanceFromCenter > targetArcRadius - targetArcRadiusWidth &&
|
||||
distanceFromCenter < targetArcRadius + targetArcRadiusWidth &&
|
||||
distanceFromArcCenter < targetDistanceFromArcCenter
|
||||
){
|
||||
voxel.weight = 1.0f;
|
||||
voxel.type = 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the weight of a voxel on the surface based on the surface height, the position of the voxel, and the stride multiplier
|
||||
* @param surfaceHeight The surface height
|
||||
* @param realPosY The position of the voxel
|
||||
* @param strideMultiplier The stride multiplier
|
||||
* @return The weight of the voxel
|
||||
*/
|
||||
private static double getSurfaceWeight(double surfaceHeight, double realPosY, double strideMultiplier){
|
||||
return ((surfaceHeight - realPosY) / strideMultiplier);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,146 @@
|
||||
package electrosphere.server.terrain.generation.voxelphase;
|
||||
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.game.data.biome.BiomeData;
|
||||
import electrosphere.server.terrain.generation.interfaces.GeneratedVoxel;
|
||||
import electrosphere.server.terrain.generation.interfaces.GenerationContext;
|
||||
|
||||
/**
|
||||
* Generates voxels for a hill
|
||||
*/
|
||||
public class HillsVoxelGen implements VoxelGenerator {
|
||||
|
||||
/**
|
||||
* The width of the surface in number of voxels
|
||||
*/
|
||||
public static final int SURFACE_VOXEL_WIDTH = 2;
|
||||
|
||||
|
||||
@Override
|
||||
public String getTag(){
|
||||
return "hills";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getVoxel(
|
||||
GeneratedVoxel voxel,
|
||||
int worldX, int worldY, int worldZ,
|
||||
int chunkX, int chunkY, int chunkZ,
|
||||
int stride,
|
||||
float surfaceHeight,
|
||||
BiomeData surfaceBiome,
|
||||
GenerationContext generationContext
|
||||
){
|
||||
Globals.profiler.beginAggregateCpuSample("HillsVoxelGen.getVoxel");
|
||||
|
||||
double realX = generationContext.getServerWorldData().convertVoxelToRealSpace(chunkX,worldX);
|
||||
double realY = generationContext.getServerWorldData().convertVoxelToRealSpace(chunkY,worldY);
|
||||
double realZ = generationContext.getServerWorldData().convertVoxelToRealSpace(chunkZ,worldZ);
|
||||
|
||||
double strideMultiplier = Math.pow(2,stride);
|
||||
double heightDiff = realY - surfaceHeight;
|
||||
double surfacePercent = HillsVoxelGen.getSurfaceWeight(surfaceHeight,realY,strideMultiplier);
|
||||
Globals.profiler.endCpuSample();
|
||||
if(heightDiff < -strideMultiplier * SURFACE_VOXEL_WIDTH){
|
||||
this.getSubsurfaceVoxel(
|
||||
voxel,
|
||||
worldX, worldY, worldZ,
|
||||
chunkX, chunkY, chunkZ,
|
||||
realX, realY, realZ,
|
||||
surfacePercent,
|
||||
surfaceHeight,
|
||||
surfaceBiome
|
||||
);
|
||||
} else if(heightDiff > 0) {
|
||||
this.getOverSurfaceVoxel(
|
||||
voxel,
|
||||
worldX, worldY, worldZ,
|
||||
chunkX, chunkY, chunkZ,
|
||||
realX, realY, realZ,-
|
||||
surfacePercent,
|
||||
surfaceHeight,
|
||||
surfaceBiome
|
||||
);
|
||||
} else {
|
||||
this.getSurfaceVoxel(
|
||||
voxel,
|
||||
worldX, worldY, worldZ,
|
||||
chunkX, chunkY, chunkZ,
|
||||
realX, realY, realZ,
|
||||
surfacePercent,
|
||||
surfaceHeight,
|
||||
surfaceBiome
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the voxel on the surface
|
||||
* @return The voxel
|
||||
*/
|
||||
private void getSurfaceVoxel(
|
||||
GeneratedVoxel voxel,
|
||||
int worldX, int worldY, int worldZ,
|
||||
int chunkX, int chunkY, int chunkZ,
|
||||
double realX, double realY, double realZ,
|
||||
double surfacePercent,
|
||||
float surfaceHeight,
|
||||
BiomeData surfaceBiome
|
||||
){
|
||||
voxel.weight = (float)surfacePercent * 2 - 1;
|
||||
voxel.type = 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the voxel below the surface
|
||||
* @return The voxel
|
||||
*/
|
||||
private void getSubsurfaceVoxel(
|
||||
GeneratedVoxel voxel,
|
||||
int worldX, int worldY, int worldZ,
|
||||
int chunkX, int chunkY, int chunkZ,
|
||||
double realX, double realY, double realZ,
|
||||
double surfacePercent,
|
||||
float surfaceHeight,
|
||||
BiomeData surfaceBiome
|
||||
){
|
||||
if(realY < surfaceHeight - 5){
|
||||
voxel.weight = 1;
|
||||
voxel.type = 6;
|
||||
} else {
|
||||
voxel.weight = 1;
|
||||
voxel.type = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the voxel above the service
|
||||
* @return The voxel
|
||||
*/
|
||||
private void getOverSurfaceVoxel(
|
||||
GeneratedVoxel voxel,
|
||||
int worldX, int worldY, int worldZ,
|
||||
int chunkX, int chunkY, int chunkZ,
|
||||
double realX, double realY, double realZ,
|
||||
double surfacePercent,
|
||||
float surfaceHeight,
|
||||
BiomeData surfaceBiome
|
||||
){
|
||||
voxel.weight = -1;
|
||||
voxel.type = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the weight of a voxel on the surface based on the surface height, the position of the voxel, and the stride multiplier
|
||||
* @param surfaceHeight The surface height
|
||||
* @param realPosY The position of the voxel
|
||||
* @param strideMultiplier The stride multiplier
|
||||
* @return The weight of the voxel
|
||||
*/
|
||||
protected static double getSurfaceWeight(double surfaceHeight, double realPosY, double strideMultiplier){
|
||||
return ((surfaceHeight - realPosY) / strideMultiplier);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
package electrosphere.server.terrain.generation.voxelphase;
|
||||
|
||||
import electrosphere.game.data.biome.BiomeData;
|
||||
import electrosphere.server.terrain.generation.interfaces.GeneratedVoxel;
|
||||
import electrosphere.server.terrain.generation.interfaces.GenerationContext;
|
||||
|
||||
|
||||
/**
|
||||
* Used for generating voxels
|
||||
*/
|
||||
public interface VoxelGenerator {
|
||||
|
||||
|
||||
/**
|
||||
* Gets the tag of the generator
|
||||
* @return The tag
|
||||
*/
|
||||
public String getTag();
|
||||
|
||||
|
||||
/**
|
||||
* Gets the value for a chunk
|
||||
* @param voxel The voxel to fill
|
||||
* @param worldX The world x pos
|
||||
* @param worldY The world y pos
|
||||
* @param worldZ The world z pos
|
||||
* @param chunkX The chunk x pos
|
||||
* @param chunkY The chunk y pos
|
||||
* @param chunkZ The chunk z pos
|
||||
* @param stride The stride of the data
|
||||
* @param surfaceHeight The height of the surface at x,z
|
||||
* @param surfaceBiome The surface biome of the chunk
|
||||
* @param generationContext The generation context
|
||||
*/
|
||||
public void getVoxel(
|
||||
GeneratedVoxel voxel,
|
||||
int worldX, int worldY, int worldZ,
|
||||
int chunkX, int chunkY, int chunkZ,
|
||||
int stride,
|
||||
float surfaceHeight,
|
||||
BiomeData surfaceBiome,
|
||||
GenerationContext generationContext
|
||||
);
|
||||
|
||||
}
|
||||
@ -80,6 +80,18 @@ public class ServerTerrainChunk {
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param worldX The world position x coordinate
|
||||
* @param worldY The world position y coordinate
|
||||
* @param worldZ The world position z coordinate
|
||||
*/
|
||||
public ServerTerrainChunk(int worldX, int worldY, int worldZ){
|
||||
this.worldX = worldX;
|
||||
this.worldY = worldY;
|
||||
this.worldZ = worldZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the world position x coordinate
|
||||
* @return The x coordinate
|
||||
@ -201,5 +213,31 @@ public class ServerTerrainChunk {
|
||||
public int getHomogenousValue(){
|
||||
return homogenousValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the weights of the chunk
|
||||
* @param weights The weights
|
||||
*/
|
||||
public void setWeights(float[][][] weights) {
|
||||
this.weights = weights;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the values of the chunk
|
||||
* @param values The values
|
||||
*/
|
||||
public void setValues(int[][][] values) {
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the homogenous value
|
||||
* @param homogenousValue The homogenous value
|
||||
*/
|
||||
public void setHomogenousValue(int homogenousValue) {
|
||||
this.homogenousValue = homogenousValue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -40,9 +40,11 @@ public class ClientDrawCellManagerTests {
|
||||
Vector3i playerPos = new Vector3i(0,0,0);
|
||||
WorldOctTreeNode<DrawCell> node = WorldOctTreeNode.constructorForTests(manager.chunkTree, 1, new Vector3i(16,0,0), new Vector3i(32,16,16));
|
||||
node.setLeaf(true);
|
||||
node.setData(DrawCell.generateTerrainCell(new Vector3i(0,0,0),3));
|
||||
node.setData(DrawCell.generateTerrainCell(new Vector3i(16,0,0),3));
|
||||
|
||||
assertTrue(manager.shouldSplit(playerPos, node, 0));
|
||||
boolean shouldBeTrue = node.getParent() != null;
|
||||
|
||||
assertEquals(shouldBeTrue,manager.shouldSplit(playerPos, node, 0));
|
||||
|
||||
//cleanup
|
||||
Main.shutdown();
|
||||
|
||||
@ -1,22 +0,0 @@
|
||||
package electrosphere.server.terrain.generation;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import electrosphere.test.annotations.FastTest;
|
||||
import electrosphere.test.annotations.UnitTest;
|
||||
|
||||
/**
|
||||
* Unit tests for the test generation chunk generator
|
||||
*/
|
||||
public class TestGenerationChunkGeneratorTests {
|
||||
|
||||
@UnitTest
|
||||
@FastTest
|
||||
public void getSurfaceWeight_ValueTests(){
|
||||
assertEquals(0.5,TestGenerationChunkGenerator.getSurfaceWeight(0.5, 0, 1));
|
||||
assertEquals(0.1,TestGenerationChunkGenerator.getSurfaceWeight(0.1, 0, 1));
|
||||
assertEquals(0.9,TestGenerationChunkGenerator.getSurfaceWeight(0.9, 0, 1));
|
||||
assertEquals(0.95,TestGenerationChunkGenerator.getSurfaceWeight(1.9, 0, 2));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
package electrosphere.server.terrain.generation.voxelphase;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import electrosphere.test.annotations.FastTest;
|
||||
import electrosphere.test.annotations.UnitTest;
|
||||
|
||||
/**
|
||||
* Unit tests for the test generation chunk generator
|
||||
*/
|
||||
public class HillsVoxelGenTests {
|
||||
|
||||
@UnitTest
|
||||
@FastTest
|
||||
public void getSurfaceWeight_ValueTests(){
|
||||
assertEquals(0.5,HillsVoxelGen.getSurfaceWeight(0.5, 0, 1));
|
||||
assertEquals(0.1,HillsVoxelGen.getSurfaceWeight(0.1, 0, 1));
|
||||
assertEquals(0.9,HillsVoxelGen.getSurfaceWeight(0.9, 0, 1));
|
||||
assertEquals(0.95,HillsVoxelGen.getSurfaceWeight(1.9, 0, 2));
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user