![]() |
Матрица статей Список статей Всячина Контакты | ||||||||||||
|
Фрактальные поверхности
Для получения фрактальных поверхностей можно использовать алгоритм срединного смещения. Заключается он в следующем (существуют различные вариации). Возьмём квадрат. Значение высоты в углах сгенерируем случайным образом и выполним основной шаг алгоритма, который состоит в следующем. Значение высоты на сторонах квадрата вычисляется как полусумма значений высот вершин, которые соединяет эта сторона. Значение высоты же в центре квадрата вычисляется как среднее арифметическое значений в углах плюс некторое случайное число, лежащее в некоторых пределах, которые зависят от размера квадрата. Далее квадрат делится на четыре квадратика, для которых выполняется основной шаг алгоритма.
package ru.xaoc.fractalworld.plasma;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main {
static float[][] x;
static void calc(int a, int b, int c, int d) {
if (a + 1 == c || b + 1 == d) {
return;
}
float r = (c - a) + (d - b);
int e = (a + c) / 2;
int f = (b + d) / 2;
x[e][f] =
(x[a][b] + x[a][d] + x[c][b] + x[c][d]) / 4 +
r * (float)(Math.random() - .5);
x[e][b] = (x[a][b] + x[c][b]) / 2;
x[e][d] = (x[a][d] + x[c][d]) / 2;
x[a][f] = (x[a][b] + x[a][d]) / 2;
x[c][f] = (x[c][b] + x[c][d]) / 2;
calc(a, b, e, f);
calc(a, f, e, d);
calc(e, b, c, f);
calc(e, f, c, d);
}
static Color floatToColor(float x) {
if (x <= 0) {
return new Color(1f, 0f, 0f);
}
if (x <= 1f/6) {
return new Color(1f, x * 6f, 0f);
}
if (x <= 2f/6) {
return new Color(1f - (x - 1f/6) * 6f, 1f, 0f);
}
if (x <= 3f/6) {
return new Color(0f, 1f, (x - 2f/6f) * 6f);
}
if (x <= 4f/6) {
return new Color(0f, 1f - (x - 3f/6f) * 6f, 1f);
}
if (x <= 5f/6) {
return new Color((x - 4f/6) * 6f, 0f, 1f);
}
if (x < 1f) {
return new Color(1f, 0f, 1f - (x - 5f/6f) * 6f);
}
return new Color(1f, 0f, 0f);
}
static BufferedImage createPlasma(int countLevels) {
int size = (int)Math.round(Math.pow(2, countLevels));
BufferedImage image = new BufferedImage(size + 1, size + 1,
BufferedImage.TYPE_INT_RGB);
x = new float[size + 1][size + 1];
x[0][0] = (float)Math.random() * size / 2 - size / 4;
x[0][size] = (float)Math.random() * size / 2 - size / 4;
x[size][0] = (float)Math.random() * size / 2 - size / 4;
x[size][size] = (float)Math.random() * size / 2 - size / 4;
calc(0, 0, size, size);
float min = Float.MAX_VALUE;
float max = Float.MIN_VALUE;
for (int i = 0; i <= size; ++i) {
for (int j = 0; j <= size; ++j) {
if (x[i][j] < min) {
min = x[i][j];
}
if (x[i][j] > max) {
max = x[i][j];
}
}
}
for (int i = 0; i <= size; ++i) {
for (int j = 0; j <= size; ++j) {
image.setRGB(j, i,
floatToColor((x[i][j] - min) / (max - min)).getRGB());
}
}
return image;
}
static Image image;
public static void main(String[] args) {
image = createPlasma(9);
JFrame frame = new JFrame();
frame.addNotify();
frame.setSize(frame.getInsets().left
+ frame.getInsets().right + image.getWidth(null),
frame.getInsets().top
+ frame.getInsets().bottom + image.getHeight(null));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JPanel() {
@Override
public void paintComponent(Graphics g) {
Graphics2D G = (Graphics2D) g;
if (image != null) {
G.drawImage(image, 0, 0, null);
}
}
});
frame.setVisible(true);
}
}
Теперь перейдём в 3D. Для этого я воспользовался набором классов, которые были написаны для сдачи зачёта по машинной графике несколько лет назад.
package ru.xaoc.fractalworld.land;
import ru.xaoc.fractalworld.base3d.*;
import ru.xaoc.fractalworld.plasma.Plasma;
public class Land extends Solid
{
public Land(int countLevels) {
Colorer landColorer = new LandColorer();
Colorer waterColorer = new WaterColorer();
Plasma plasma = new Plasma(countLevels, 0, 0, 0, 0);
double t = plasma.getSize() / 2;
double r = plasma.getValue(0, 0);
double s = 1.0 / plasma.getSize();
for (int i = 0; i < plasma.getSize(); ++i) {
for (int j = 0; j < plasma.getSize(); ++j) {
double n = (plasma.getValue(i, j) - r) * s;
double m = (plasma.getValue(i + 1, j + 1) - r) * s;
double p = (plasma.getValue(i, j + 1) - r) * s;
double q = (plasma.getValue(i + 1, j) - r) * s;
Vector a = new Vector((i - t) * s, (j - t) * s,
n > 0 ? n : 0);
Vector b = new Vector((i + 1 - t) * s, (j + 1 - t) * s,
m > 0 ? m : 0);
Vector c = new Vector((i - t) * s, (j + 1 - t) * s,
p > 0 ? p : 0);
Vector d = new Vector((i + 1 - t) * s, (j - t) * s,
q > 0 ? q : 0);
add(new Triangle(new Vector[] {a, b, c},
(n > 0 || m > 0 || p > 0) ? landColorer : waterColorer));
add(new Triangle(new Vector[] {a, d, b},
(n > 0 || q > 0 || m > 0) ? landColorer : waterColorer));
}
}
}
}
Вы можете скачать весь исходный код.
Ссылки:
|