rocky plains biome
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit

This commit is contained in:
austin 2025-04-02 13:37:25 -04:00
parent c3f372d600
commit 21c73c6672
18 changed files with 232 additions and 17 deletions

View File

@ -24,7 +24,15 @@
],
"surfaceGenerationParams": {
"surfaceGenTag": "plains",
"heightOffset": 10
"heightOffset": 10,
"floorVariants": [
{
"voxelId": 2,
"frequency": 1.0,
"dispersion": 1.0,
"priority": 1.0
}
]
}
},
{
@ -53,6 +61,12 @@
"surfaceGenTag": "hills",
"heightOffset": 10,
"floorVariants": [
{
"voxelId": 2,
"frequency": 1.0,
"dispersion": 1.0,
"priority": 1.0
}
],
"foliageDescriptions": [
]
@ -116,6 +130,53 @@
"surfaceGenTag": "empty",
"heightOffset": 0
}
},
{
"id": "plains_rock",
"displayName": "Plains (rock)",
"isAerial": false,
"isSurface": true,
"isSubterranean": false,
"regions": [
{
"frequency": 1.0,
"baseFloorVoxel": 1,
"floorVariants": [
{
"voxelId": 7,
"frequency": 0.5,
"dispersion": 0.5,
"priority": 1.0
},
{
"voxelId": 8,
"frequency": 0.5,
"dispersion": 0.5,
"priority": 1.0
}
],
"foliageDescription": [
]
}
],
"surfaceGenerationParams": {
"surfaceGenTag": "plains",
"heightOffset": 10,
"floorVariants": [
{
"voxelId": 7,
"frequency": 0.5,
"dispersion": 0.5,
"priority": 1.0
},
{
"voxelId": 8,
"frequency": 0.5,
"dispersion": 0.5,
"priority": 1.0
}
]
}
}
],
"files": [

View File

@ -35,7 +35,7 @@ out vec3 samplerIndexVec; //the indices in the atlas of textures to sample
out vec3 samplerRatioVec; //the vector of HOW MUCH to pull from each texture in the atlas
float map(float value, float min1, float max1, float min2, float max2);
void main() {
//normalize posiiton and normal
@ -48,6 +48,9 @@ void main() {
ViewFragPos = vec3(view * model * FinalVertex);
Normal = mat3(transpose(inverse(model))) * aNormal;
// //clamp the aPos vector to just shy of its surrounding values
// //this prevents sampling across into the next texture
// vec3 clampedPos = vec3(map(aPos.x,0,1,0.02,0.98), map(aPos.y,0,1,0.02,0.98), map(aPos.z,0,1,0.02,0.98));
//reference https://catlikecoding.com/unity/tutorials/advanced-rendering/triplanar-mapping/
texPlane1 = aPos.zy * TEXTURE_MAP_SCALE;
texPlane2 = aPos.xz * TEXTURE_MAP_SCALE;
@ -71,3 +74,9 @@ void main() {
//set final position with opengl space
gl_Position = projection * view * model * FinalVertex;
}
float map(float value, float min1, float max1, float min2, float max2) {
return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 402 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 108 KiB

View File

@ -1,3 +1,3 @@
#maven.buildNumber.plugin properties file
#Tue Apr 01 15:25:00 EDT 2025
buildNumber=616
#Wed Apr 02 13:31:25 EDT 2025
buildNumber=617

View File

@ -1411,6 +1411,10 @@ World creation options work
(04/02/2025)
Homogenous worlds actually generate-able
Two EXCELLENT rock textures
Fix rock2 texture
biome floor elements controlling noise generator's voxel selection
Plains (rock) biome

View File

@ -107,5 +107,5 @@ public class BiomeData {
public BiomeSurfaceGenerationParams getSurfaceGenerationParams(){
return surfaceGenerationParams;
}
}

View File

@ -1,9 +1,11 @@
package electrosphere.game.data.biome;
import electrosphere.util.noise.NoiseMapperElement;
/**
* Describes how a given voxel type may be used to populate the floor of the biome
*/
public class BiomeFloorElement {
public class BiomeFloorElement implements NoiseMapperElement {
/**
* The id of the voxel type for this element in particular
@ -25,4 +27,17 @@ public class BiomeFloorElement {
*/
Double priority;
/**
* Gets the voxel id of this floor element
* @return The voxel id
*/
public int getVoxelId(){
return voxelId;
}
@Override
public float getFrequency() {
return (float)(double)this.frequency;
}
}

View File

@ -4,6 +4,9 @@ import java.util.List;
import org.graalvm.polyglot.HostAccess.Export;
import electrosphere.util.annotation.Exclude;
import electrosphere.util.noise.NoiseMapper;
/**
* Params for the surface generation algorithm
*/
@ -32,6 +35,19 @@ public class BiomeSurfaceGenerationParams {
@Export
List<BiomeFoliageDescription> foliageDescriptions;
/**
* Used to map gradients into floor variants (ie to distribute the floor variants spatially)
*/
@Exclude
NoiseMapper<BiomeFloorElement> floorVariantMapper;
/**
* Precomputes the surface voxel distribution
*/
protected void precomputeSurfaceDistribution(){
this.floorVariantMapper = new NoiseMapper<BiomeFloorElement>(floorVariants);
}
/**
* Gets the tag for the generation algorithm for generating the surface
* @return The tag for the generation algorithm for generating the surface
@ -64,6 +80,13 @@ public class BiomeSurfaceGenerationParams {
return foliageDescriptions;
}
/**
* Gets a floor variant based on a gradient value
* @param gradientValue The gradient value
* @return The floor element
*/
public BiomeFloorElement getFloorVariant(float gradientValue){
return this.floorVariantMapper.lookup(gradientValue);
}
}

View File

@ -54,6 +54,7 @@ public class BiomeTypeMap {
idBiomeMap.put(id,biome);
if(biome.isSurface()){
this.surfaceBiomes.add(biome);
biome.getSurfaceGenerationParams().precomputeSurfaceDistribution();
}
if(biome.isAerial()){
this.skyBiomes.add(biome);
@ -61,8 +62,9 @@ public class BiomeTypeMap {
if(biome.isSubterranean()){
this.subterraneanBiomes.add(biome);
}
indexBiomeMap.put(indexBiomeMap.size(),biome);
biomeIndexMap.put(biome,indexBiomeMap.size());
int index = indexBiomeMap.size();
indexBiomeMap.put(index,biome);
biomeIndexMap.put(biome,index);
}
/**

View File

@ -183,6 +183,7 @@ public class TestGenerationChunkGenerator implements ChunkGenerator {
double surfaceHeight = heightfield[x][z];
double gradient = gradientField[x][z];
BiomeData surfaceBiome = surfaceBiomeMap[x][z];
BiomeSurfaceGenerationParams surfaceParams = surfaceBiome.getSurfaceGenerationParams();
for(int y = 0; y < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; y++){
int finalWorldY = worldY + ((y * strideValue) / ServerTerrainChunk.CHUNK_DIMENSION);
@ -196,7 +197,7 @@ public class TestGenerationChunkGenerator implements ChunkGenerator {
realX, realY, realZ,
stride,
surfaceHeight, gradient,
surfaceBiome,
surfaceBiome, surfaceParams,
generationContext
);
if(voxel != null){

View File

@ -2,6 +2,7 @@ package electrosphere.server.terrain.generation.voxelphase;
import electrosphere.engine.Globals;
import electrosphere.game.data.biome.BiomeData;
import electrosphere.game.data.biome.BiomeSurfaceGenerationParams;
import electrosphere.server.terrain.generation.interfaces.GeneratedVoxel;
import electrosphere.server.terrain.generation.interfaces.GenerationContext;
import io.github.studiorailgun.MathUtils;
@ -79,7 +80,7 @@ public class AnimeMountainsGen implements VoxelGenerator {
int chunkX, int chunkY, int chunkZ,
double realX, double realY, double realZ,
int stride, double surfaceHeight, double surfaceGradient,
BiomeData surfaceBiome,
BiomeData surfaceBiome, BiomeSurfaceGenerationParams surfaceParams,
GenerationContext generationContext
) {
Globals.profiler.beginAggregateCpuSample("AnimeMountainsGen.getVoxel");

View File

@ -2,6 +2,7 @@ package electrosphere.server.terrain.generation.voxelphase;
import electrosphere.engine.Globals;
import electrosphere.game.data.biome.BiomeData;
import electrosphere.game.data.biome.BiomeSurfaceGenerationParams;
import electrosphere.server.terrain.generation.interfaces.GeneratedVoxel;
import electrosphere.server.terrain.generation.interfaces.GenerationContext;
@ -39,7 +40,7 @@ public class HillsVoxelGen implements VoxelGenerator {
double realX, double realY, double realZ,
int stride,
double surfaceHeight, double surfaceGradient,
BiomeData surfaceBiome,
BiomeData surfaceBiome, BiomeSurfaceGenerationParams surfaceParams,
GenerationContext generationContext
){
Globals.profiler.beginAggregateCpuSample("HillsVoxelGen.getVoxel");

View File

@ -2,6 +2,7 @@ package electrosphere.server.terrain.generation.voxelphase;
import electrosphere.engine.Globals;
import electrosphere.game.data.biome.BiomeData;
import electrosphere.game.data.biome.BiomeSurfaceGenerationParams;
import electrosphere.server.terrain.generation.interfaces.GeneratedVoxel;
import electrosphere.server.terrain.generation.interfaces.GenerationContext;
@ -45,7 +46,7 @@ public class MountainVoxelGen implements VoxelGenerator {
double realX, double realY, double realZ,
int stride,
double surfaceHeight, double surfaceGradient,
BiomeData surfaceBiome,
BiomeData surfaceBiome, BiomeSurfaceGenerationParams surfaceParams,
GenerationContext generationContext
){
Globals.profiler.beginAggregateCpuSample("HillsVoxelGen.getVoxel");

View File

@ -1,6 +1,8 @@
package electrosphere.server.terrain.generation.voxelphase;
import electrosphere.game.data.biome.BiomeData;
import electrosphere.game.data.biome.BiomeFloorElement;
import electrosphere.game.data.biome.BiomeSurfaceGenerationParams;
import electrosphere.game.data.voxel.sampler.SamplerFile;
import electrosphere.server.terrain.generation.interfaces.GeneratedVoxel;
import electrosphere.server.terrain.generation.interfaces.GenerationContext;
@ -62,7 +64,8 @@ public class NoiseVoxelGen implements VoxelGenerator {
int chunkX, int chunkY, int chunkZ,
double realX, double realY, double realZ,
int stride, double surfaceHeight, double surfaceGradient,
BiomeData surfaceBiome, GenerationContext generationContext
BiomeData surfaceBiome, BiomeSurfaceGenerationParams surfaceParams,
GenerationContext generationContext
) {
//floor handling
@ -91,11 +94,13 @@ public class NoiseVoxelGen implements VoxelGenerator {
voxel.weight = -1.0f;
voxel.type = 0;
} else if(heightDiff < -strideMultiplier){
BiomeFloorElement floorEl = surfaceParams.getFloorVariant((float)surfaceGradient);
//generate full-size surface-type voxel
double finalHeight = sample;
voxel.weight = (float)finalHeight;
voxel.type = 2;
voxel.type = floorEl.getVoxelId();
} else {
BiomeFloorElement floorEl = surfaceParams.getFloorVariant((float)surfaceGradient);
//surface
double surfacePercent = -heightDiff / strideMultiplier;
if(surfacePercent > 1.0 || surfacePercent < 0){
@ -103,7 +108,7 @@ public class NoiseVoxelGen implements VoxelGenerator {
}
double finalHeight = sample * surfacePercent * 2 - 1;
voxel.weight = (float)(finalHeight * sample);
voxel.type = 2;
voxel.type = floorEl.getVoxelId();
}
}

View File

@ -1,6 +1,7 @@
package electrosphere.server.terrain.generation.voxelphase;
import electrosphere.game.data.biome.BiomeData;
import electrosphere.game.data.biome.BiomeSurfaceGenerationParams;
import electrosphere.server.terrain.generation.interfaces.GeneratedVoxel;
import electrosphere.server.terrain.generation.interfaces.GenerationContext;
@ -37,6 +38,7 @@ public interface VoxelGenerator {
* @param surfaceHeight The height of the surface at x,z
* @param surfaceGradient The rate of change in the surface at this point
* @param surfaceBiome The surface biome of the chunk
* @param surfaceGenPArams Extra parameters for generating surface voxel values
* @param generationContext The generation context
*/
public void getVoxel(
@ -46,7 +48,7 @@ public interface VoxelGenerator {
double realX, double realY, double realZ,
int stride,
double surfaceHeight, double surfaceGradient,
BiomeData surfaceBiome,
BiomeData surfaceBiome, BiomeSurfaceGenerationParams surfaceGenParams,
GenerationContext generationContext
);

View File

@ -0,0 +1,76 @@
package electrosphere.util.noise;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* Maps objects to a frequency, then allows normalized noise values to index into the frequency range
*/
public class NoiseMapper<T> {
/**
* The objects in the buckets
*/
List<T> objects;
/**
* The frequencies
*/
float[] frequencies;
public NoiseMapper(List<T> objects){
Map<NoiseMapperElement,T> typeMap = new HashMap<NoiseMapperElement,T>();
//convert types
List<NoiseMapperElement> elements = objects.stream().map(object -> {
if(object instanceof NoiseMapperElement){
NoiseMapperElement casted = (NoiseMapperElement)object;
typeMap.put(casted,object);
return casted;
} else {
throw new Error("Supplied a class that does not extend NoiseMapper! " + object.getClass());
}
}).collect(Collectors.toList());
//set frequencies
float frequencySum = 0;
for(NoiseMapperElement el : elements){
frequencySum = frequencySum + el.getFrequency();
}
this.frequencies = new float[elements.size()];
this.objects = new ArrayList<T>();
int i = 0;
float accumulator = 0;
for(NoiseMapperElement el : elements){
this.frequencies[i] = el.getFrequency() / frequencySum + accumulator;
this.objects.add(typeMap.get(el));
accumulator = accumulator + this.frequencies[i];
i++;
}
}
/**
* Looks up a value's corresponding object
* @param value The value
* @return The object
*/
public T lookup(float value){
if(value < 0){
throw new Error("Supplied value less than 0! " + value);
} else if(value > 1){
throw new Error("Supplied value greater than 1! " + value);
}
int searchIndex = 0;
float prevFreq = 0;
while(searchIndex < frequencies.length){
if(value >= prevFreq && value <= frequencies[searchIndex]){
return objects.get(searchIndex);
}
prevFreq = frequencies[searchIndex];
searchIndex++;
}
throw new Error("Failed to mape value " + value + " into object! " + frequencies + " " + objects);
}
}

View File

@ -0,0 +1,14 @@
package electrosphere.util.noise;
/**
* An element that can be supplied to a noise mapper
*/
public interface NoiseMapperElement {
/**
* Gets the frequency of this element
* @return The frequency
*/
public float getFrequency();
}