Как использовать функцию шума Перлина? - Java
Формулировка задачи:
Доброго времени суток.
Пытаюсь понять как использовать шум Перлина. После прочтения этой статьи https://habrahabr.ru/post/265775/ я перевел функцию шума Перлина этой статьи на Java:
однако остался ряд следующих вопросов: что передовать в качестве аргумента методу getNoise(float x, float y)? Координаты точки?
Допустим у меня есть некий массив хранящий карту высот, где каждый элемент - тайл или пиксель определенного цвета (от белого, до черного). Я хочу заполнить его используя шум Перлина, чтобы затем использовать для вывода изображения. Я делаю это следующим образом:
и ожидаю получить нечто похожее на туман, облака. Но получаю это:
А вот как выглядит это безобразие, если размер клетки 1 пиксель:
Скажите пожалуйста, что я не так делаю и каковы основные принципы его использования?
Листинг программы
- 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;
- }
- }
- }
Листинг программы
- 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);
- }
- }
- }
- }
- }
Решение задачи: «Как использовать функцию шума Перлина?»
textual
Листинг программы
- float value = perlin.getNoise(x / 100f, y / 100f, 8, 0.2f) + .5f;
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д