噪声纹理
现在学习到了“噪声”部分,感觉书上讲解地比较浅显,我对Perlin噪声的原论文比较感兴趣。下面是原文的连接:
http://freespace.virgin.net/hugo.elias/models/m_perlin.htm
由于众所周知的问题,国内无法访问这个地址。:(
于是,我又辗转找到了這篇论文。
http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf
此文的作者主要目的是介绍Perlin发明的Simplex Noise算法,同时也介绍了经典Perlin Noise算法。写得很清楚,还有代码例子。
http://weber.itn.liu.se/~stegu/simplexnoise/SimplexNoise.java
基于这个代码,我生成了简单的噪声纹理。
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
/**
* 基于SimplexNoise,生成噪音纹理。
* @author yanmaoyuan
*
*/
public class NoiseMap extends JFrame {
private static final long serialVersionUID = -5634742336049921860L;
// 图像分辨率
private int width = 192;
private int height = 192;
// 缩放系数
private double scale = 4.0;
// 图像缓冲
private BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
private JPanel panel = null;
public NoiseMap() {
// 更新噪音纹理
updateNoiseMap();
// 创建一个JPanel,用于显示噪音纹理。
panel = new JPanel() {
private static final long serialVersionUID = -5646436871841183655L;
@Override
public void update(Graphics g) {
paint(g);
}
@Override
public void paint(Graphics g) {
g.drawImage(image, 0, 0, width, height, 0, 0, width, height, null);
}
};
panel.setPreferredSize(new Dimension(width, height));
getContentPane().add(panel, BorderLayout.CENTER);
// 用于调节缩放系数。
final JSlider slider = new JSlider();
slider.setMaximum(width);
slider.setMinimum(1);
slider.setValue((int)scale);
slider.setPaintTicks(true);
slider.setMajorTickSpacing(16);
slider.setMinorTickSpacing(4);
slider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
int v = slider.getValue();
scale = v;
updateNoiseMap();
panel.repaint();
}
});
this.getContentPane().add(slider, BorderLayout.NORTH);
// 用于导出纹理贴图
JButton btn = new JButton("导出");
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
String name = String.format("noise_%d.png", (int)scale);
ImageIO.write(image, "png", new File(name));
} catch (Exception ex) {}
}
});
this.getContentPane().add(btn, BorderLayout.SOUTH);
this.pack();
this.setResizable(false);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
/**
* 重绘噪声图
*/
public void updateNoiseMap() {
Graphics g = image.getGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, width, height);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
double noise = SimplexNoise.noise(x/scale, y/scale);
int color = (int)(128 * (noise + 1));
g.setColor(new Color(color, color, color));
g.drawOval(x, y, 1, 1);
}
}
g.dispose();
}
public static void main(String[] args) throws IOException {
NoiseMap app = new NoiseMap();
app.setVisible(true);
}
}
生成不同缩放倍率的噪音纹理如下:
很多人使用噪音纹理来制作2D云。
例如**冯乐乐(aka candycat1992)**的:【Unity Shader】2D动态云彩。
文中用到了Tileable perlin noise,实现的思路很有趣。
根据这篇文章的思路,我用jME3实现了一个2D动态云彩。从技术上来说,看起来还不错。
不过目前Tileable Noise的问题还没解决,所以实际运行时会有裂缝。
很羡慕这个女孩子,92年的,上交大软件工程专业的研究生,还没工作时就已经出书了。
这几天反复阅读 The Real-time Volumetric Cloudscapes of Horizon - Zero Dawn - ARTR.pdf,总是忍不住赞叹老外的思维。以我现在的能力还无法实现文章中描述的技术,所以我想先做个笔记。等以后实力足够了,我再尝试在jME3中实现这种技术。
文中提到,他们使用Worley Noise和Perlin Noise结合,形成Worley-Perlin Nosie,用来生成花包菜状的云朵。下面是关于Worley Noise在GLSL中实现的论文:
http://weber.itn.liu.se/~stegu/GLSL-cellular/GLSL-cellular-notes.pdf