Как использовать функцию шума Перлина? - Java

Формулировка задачи:

Доброго времени суток. Пытаюсь понять как использовать шум Перлина. После прочтения этой статьи https://habrahabr.ru/post/265775/ я перевел функцию шума Перлина этой статьи на Java:
import java.util.Random;
 
public class Perlin2D {
 
    private Random random;
 
    public Perlin2D(long seed) {
    random = new Random(seed);
    }
 
    public float getNoise(float x, float y) {
    int left = (int)x;
    int top = (int)y;
 
    float localX = x - left;
    float localY = y - top;
 
        // извлекаем градиентные векторы для всех вершин квадрата:
        Vector topLeftGradient     = getPseudoRandomGradientVector(left,   top  );
        Vector topRightGradient    = getPseudoRandomGradientVector(left+1, top  );
        Vector bottomLeftGradient  = getPseudoRandomGradientVector(left,   top+1);
        Vector bottomRightGradient = getPseudoRandomGradientVector(left+1, top+1);
 
     // вектора от вершин квадрата до точки внутри квадрата:
        Vector distanceToTopLeft     = new Vector(localX,   localY);
        Vector distanceToTopRight    = new Vector(localX-1, localY);
        Vector distanceToBottomLeft  = new Vector(localX,   localY-1);
        Vector distanceToBottomRight = new Vector(localX-1, localY-1);
 
    // считаем скалярные произведения между которыми будем интерполировать
        float tx1 = dot(distanceToTopLeft,     topLeftGradient);
        float tx2 = dot(distanceToTopRight,    topRightGradient);
        float bx1 = dot(distanceToBottomLeft,  bottomLeftGradient);
        float bx2 = dot(distanceToBottomRight, bottomRightGradient);
 
        // собственно, интерполяция:
        float tx = lerp(tx1, tx2, localX);
        float bx = lerp(bx1, bx2, localX);
        float tb = lerp(tx, bx, localY);
 
    return tb;
    }
 
    private float lerp(float a, float b, float t) {
    return a + (b - a) * t;
    }
 
    private float dot(Vector a, Vector b) {
    return a.x * b.x + a.y * b.y;
    }
 
    private Vector getPseudoRandomGradientVector(int x, int y) {
    // псевдо-случайное число от 0 до 3 которое всегда неизменно при данных x и y
        int v = random.nextInt(4);
 
        switch (v)
        {
            case 0:  return new Vector(1, 0);
            case 1:  return new Vector(-1, 0);
            case 2:  return new Vector(0, 1);
            default: return new Vector(0,-1);
        }
    }
 
 
 
    private static class Vector {
    
    float x;
    float y;
 
    Vector(float x, float y) {
        this.x = x;
        this.y = y;
    }
 
    }
 
}
однако остался ряд следующих вопросов: что передовать в качестве аргумента методу getNoise(float x, float y)? Координаты точки? Допустим у меня есть некий массив хранящий карту высот, где каждый элемент - тайл или пиксель определенного цвета (от белого, до черного). Я хочу заполнить его используя шум Перлина, чтобы затем использовать для вывода изображения. Я делаю это следующим образом:
import java.awt.*;
import java.awt.geom.Rectangle2D;
import javax.swing.*;
 
public class Map {
 
    private JFrame frame;
 
    public static void main(String[] args) {
    new Map();
    }
 
    private Map() {
    createFrame(500, 500);
    }
 
    private void createFrame(int width, int height) {
    frame = new JFrame("Perlin noise 2D");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setResizable(false);
    frame.getContentPane().add(new MyMap(width, height, 1));
    frame.pack();
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
    }
 
    
 
    private class MyMap extends JPanel {
    private float[][] map;
    private int widthInCell;
    private int heightInCell;
    private int cellSize;
 
    MyMap(int width, int height, int cellSize) {
        setLayout(null);
        setPreferredSize(new Dimension(width, height));
    
        widthInCell = width / cellSize;
        heightInCell = height / cellSize;
        this.cellSize = cellSize;
 
        map = new float[widthInCell][heightInCell];
 
        Perlin2D perlin = new Perlin2D(1000);
        for(int x = 0; x < widthInCell; x++) {
        for(int y = 0; y < heightInCell; y++) {
            float value = perlin.getNoise(x * 0.1f, y * 0.1f);
            map[x][y] = (int)(value * 255) & 255;
        }
        }
 
        }
 
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        
        Graphics2D g2d = (Graphics2D)g;
 
        for(int x = 0; x < widthInCell; ++x) {
        for(int y = 0; y < heightInCell; ++y) {
            Rectangle2D cell = new Rectangle2D.Float(x * cellSize, y * cellSize,
                                 cellSize, cellSize);
            g2d.setColor(new Color((int)map[x][y], (int)map[x][y], (int)map[x][y]));
            g2d.fill(cell);
        }
        }       
    }
 
    }
 
}
и ожидаю получить нечто похожее на туман, облака. Но получаю это: А вот как выглядит это безобразие, если размер клетки 1 пиксель: Скажите пожалуйста, что я не так делаю и каковы основные принципы его использования?

Код к задаче: «Как использовать функцию шума Перлина? - Java»

textual
float value = perlin.getNoise(x / 100f, y / 100f, 8, 0.2f) + .5f;

7   голосов, оценка 4.143 из 5


СОХРАНИТЬ ССЫЛКУ