Как использовать функцию шума Перлина? - 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;
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д