java使用Perlin noise生成二维平铺贴图
我在网上搜索了很多关于柏林噪声的信息,但是我还是很困惑
我正在使用java和libgdx。我有一门柏林的课程要做,会产生噪音,但我不确定它给出的值是否正确。我如何检查它是否真的输出柏林噪声
如果我的实现是正确的,我不知道从那里去做随机地形。如何将柏林噪声映射到瓷砖?目前我有4个基本瓷砖;水、沙、岩石和草
package com.bracco.thrive.world;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.Texture;
public class WorldGeneration {
Perlin noise = new Perlin();
private SpriteBatch spriteBatch;
//private boolean debug = false;
private TextureRegion[] regions = new TextureRegion[4];
private Texture texture;
float x = 110;
float y = 120;
float originX = 0;
float originY = 16;
float width = 16;
float height = 16;
float scaleX = 1;
float scaleY = 1;
float rotation = 1;
@SuppressWarnings("static-access")
public void createWorld(){
spriteBatch = new SpriteBatch();
texture = new Texture(Gdx.files.internal("assets/data/textures/basictextures.png"));
regions[0] = new TextureRegion(texture,0,0,16,16); //grass
regions[1] = new TextureRegion(texture,16,0,16,16); //water
regions[2] = new TextureRegion(texture,0,17,16,16); //sand
regions[3] = new TextureRegion(texture,17,17,16,16); //rock
float[][] seed = noise.GenerateWhiteNoise(50, 50);
for (int i = 0;i < seed.length; i++){
for ( int j = 0; j < seed[i].length; j++){
System.out.println(seed[i][j] + " ");
}
}
float[][] seedE = noise.GenerateSmoothNoise( seed, 6);
for (int i = 0;i < seedE.length; i++){
for ( int j = 0; j < seedE[i].length; j++){
System.out.println(seedE[i][j] + " ");
}
}
float[][] perlinNoise = noise.GeneratePerlinNoise(seedE, 8);
for (int i = 0;i < perlinNoise.length; i++){
for ( int j = 0; j < perlinNoise[i].length; j++){
System.out.println(perlinNoise[i][j] + " ");
}
}
}
public void render(){
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
spriteBatch.begin();
//spriteBatch.draw(texture, 0, 0, 16, 16);
for (int i = 0; i < regions.length; i++){
spriteBatch.draw(regions[i],75 * (i + 1),100);
}
spriteBatch.end();
}
}
package com.bracco.thrive.world;
import java.util.Random;
public class Perlin {
public static float[][] GenerateWhiteNoise(int width,int height){
Random random = new Random((long) (Math.round(Math.random() * 100 * Math.random() * 10))); //Seed to 0 for testing
float[][] noise = new float[width][height];
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++){
noise[i][j] = (float)(Math.random() % 1);
}
}
return noise;
}
float[][] GenerateSmoothNoise(float[][] baseNoise, int octave)
{
int width = baseNoise.length;
int height = baseNoise.length;
float[][] smoothNoise = new float[width][height];
int samplePeriod = 1 << octave; // calculates 2 ^ k
float sampleFrequency = 1.0f / samplePeriod;
for (int i = 0; i < width; i++)
{
//calculate the horizontal sampling indices
int sample_i0 = (i / samplePeriod) * samplePeriod;
int sample_i1 = (sample_i0 + samplePeriod) % width; //wrap around
float horizontal_blend = (i - sample_i0) * sampleFrequency;
for (int j = 0; j < height; j++)
{
//calculate the vertical sampling indices
int sample_j0 = (j / samplePeriod) * samplePeriod;
int sample_j1 = (sample_j0 + samplePeriod) % height; //wrap around
float vertical_blend = (j - sample_j0) * sampleFrequency;
//blend the top two corners
float top = Interpolate(baseNoise[sample_i0][sample_j0],
baseNoise[sample_i1][sample_j0], horizontal_blend);
//blend the bottom two corners
float bottom = Interpolate(baseNoise[sample_i0][sample_j1],
baseNoise[sample_i1][sample_j1], horizontal_blend);
//final blend
smoothNoise[i][j] = Interpolate(top, bottom, vertical_blend);
}
}
return smoothNoise;
}
float Interpolate(float x0, float x1, float alpha)
{
return x0 * (1 - alpha) + alpha * x1;
}
float[][] GeneratePerlinNoise(float[][] baseNoise, int octaveCount)
{
int width = baseNoise.length;
int height = baseNoise[0].length;
float[][][] smoothNoise = new float[octaveCount][][]; //an array of 2D arrays containing
float persistance = 0.5f;
//generate smooth noise
for (int i = 0; i < octaveCount; i++)
{
smoothNoise[i] = GenerateSmoothNoise(baseNoise, i);
}
float[][] perlinNoise = new float[width][height];
float amplitude = 1.0f;
float totalAmplitude = 0.0f;
//blend noise together
for (int octave = octaveCount - 1; octave >= 0; octave--)
{
amplitude *= persistance;
totalAmplitude += amplitude;
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
perlinNoise[i][j] += smoothNoise[octave][i][j] * amplitude;
}
}
}
//normalisation
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
perlinNoise[i][j] /= totalAmplitude;
}
}
return perlinNoise;
}
}
# 1 楼答案
柏林噪声的正确性 关于你的柏林噪音是否“正确”;要想知道柏林噪声(或基于柏林噪声几个八度音阶的分形噪声)是否有效,最简单的方法是使用柏林噪声的值生成灰度图像,这张图片应该看起来像某种风景(起伏的山丘,或山脉,取决于你为持久性选择的参数(在较小程度上取决于八度音阶的数量)。柏林噪声的一些例子如下:
低耐用性:
或者
高耐用性:
或者
高耐用性(放大):
这些灰度图像由以下代码生成
这段代码假设每个条目都在0和1之间,但柏林噪声通常会产生-1和1之间的值,比例取决于您的实现。假设perlin noise将为任何x,y提供一个值,那么可以使用以下代码运行该程序
我的实现需要整数x和y。如果不是这样,请随意修改
映射到磁贴
这完全取决于您,您需要定义柏林噪波值的特定范围来创建特定的瓷砖。然而,请注意柏林噪声偏向于0。假设2D,通过半字面地进行景观类比,你可以得到很好的结果,低值=水,低值=沙,中值=草,高值=雪
还要注意的是,在一些实施中(如minecraft生物群落和洞穴),几个随机值被组合在一起,以创建一个整体结果。见https://softwareengineering.stackexchange.com/questions/202992/randomization-of-biomes/203040#203040
改进的想法
如果发现PrLIN噪声生成太慢,那么考虑单纯形噪声,它具有非常相似的性质,但效率更高(特别是在更高的维度)。然而,单纯形噪声在数学上要复杂得多