html 生成image java makenoise,[图形学] 柏林噪声 (perlin noise)
参考论文:《An Image Synthesizer》 Ken Perlin
如果你是游戏玩家,你也许曾在游戏风景中驻足,并仔细观察草木和岩石的贴图,并感叹于它那看似杂乱而又自然的纹脉。你未必会知道,这里面的很多纹理,并不是美工一个个像素填出来的,也不是相机拍摄出来的,而是由代码自动生成的。同样,波澜起伏的地面或海洋,也不一定完全是手工制作的高度图,而同样依赖于代码的力量,也就是我们接下来要介绍的柏林噪声。
柏林噪声旨在描述自然中的随机效果,它创建的纹理可以直接运用于顶点着色器,而不是生成一张纹理图,然后用传统的纹理映射技术把贴图附加到一个三维物体上。
这也就相当于,纹理将不需要适应表面,我们只需要提供每个顶点的(x,y,z)的坐标,传入柏林噪声函数Noise(),计算得到一个随机数,然后与原颜色运算,得到新的颜色,如同直接在物体表面绘制纹理一样。
这意味着我们应用柏林噪声的代码最好采用着色器,直接把颜色运算之后传给顶点着色器。
那么,问题的关键就在于这个Noise()应该是怎样的,perlin认为,噪声函数应当满足以下性质:
1. 旋转统计不变性。(不管我们怎么旋转它的域,它都有同样的统计特性)
2. 频率带通有一定界限。(它没有明显的大或者小的特征,而是在一定范围内)
3. 平移统计不变性。(不管我们如何平移它的域,它都有同样的统计特性)
这也就意味着,我们可以在不同的视觉尺度上创建所需表面的随机特性。
噪声的生成步骤:
1.预处理:考虑x,y,z空间中所有点的集合(坐标为整数),我们称这个集合为整数格。现在我们为整数格的每个点附一个(x,y,z)上的伪随机梯度值,也就是一个向量,并且要将其 处理成单位向量。
perlin给出的计算方法如下 :
对于每个顶点先随机生成一个向量(比如调用C库中的rand()),然后将这个下标固定地映射到另外一个下标上,取另外一个下标对应的顶点向量。如果是二维或三维,这个过程就要重复2次,具体过程可以看之后的代码。
2.如果(x,y,z)处在整数格上,那么此处的噪声就是d。
3.如果(x,y,z)不在整数格上,我们计算光滑插值系数。
具体的方法如下,以二维为例,我们要找到这个点周围的四个整数点,然后我们得到四个值,横坐标为bx0 ~ bx1,纵坐标为by0 ~ by1。点到bx0在x轴上的距离为rx0,到by0在y轴上的距离为ry0。
perlin给出了一个缓和曲线使得线性插值连贯。
能使得一阶导数连续的缓和曲线函数 (最初的版本) : s_curve(t) ( t * t * (3. - 2. * t) )
能使得二阶导数连续的缓和曲线函数 (更新的版本) : s_curve(t) ( t * t * t * (6 * t * t - 15 * t + 10) )
之后分别将rx0和ry0传入缓和曲线,得到一个新的值sx和sy。
接下来做一个双线性插值,sx和sy就是第一步线性插值的系数,但是计算得到系数之后,我们还需要插值的起点和终点。他们的计算方法如下:
(1)求(rx0,ry0)与左上角点的梯度b00的点乘,得到起点u,求(rx0 + 1,ry0)与右上角点的梯度b10的点乘,得到终点v,以uv为两端,sx为插值系数,做线性插值,得到a
(2)求(rx0,ry0 + 1)与左下角点的梯度b01的点乘,得到起点u,求(rx0 + 1,ry0 + 1)与右下角点的梯度b11的点乘,得到终点v,以uv为两端,sx为插值系数,做线性插值,得到b
( 3 ) 最终,对a和b进行线性插值,插值系数为sy,得到最终的结果。
以上算法步骤中,先对x轴还是先对y轴插值其实是无所谓的。
最终得到的柏林噪声分布在 -1 ~ 1之间,我们可以把它映射到我们需要的颜色区别(比如0 ~ 255 或 0 ~ 1)得到对应的颜色。
应用
计算得到噪声之后,我们可以做一些简单的应用,比如创建一个简单的随机表面纹理:
color = white * Noise(point)
上式中的point也就是点的坐标。
这样的效果如下,这张图具有较窄的带宽,它的细节仅仅分布特定区间内,也就是说,纹理的频谱没有一些中心峰的频率。关于生成这些图的代码会在后面给出。两张图仅仅是参数不同的区别,它们都是由柏林噪声生成的。
Perlin给出的官方例程的噪声生成结果
生成以上基础柏林噪声纹理的代码会在后面给出,之后的一些变形都是在Noise()函数的基础上得到的,可以根据perlin给定的一些公式自己尝试实现这些效果。当然也可以自己试着模拟一些效果。
当然,我们还可以做点别的。比如当我们可能想要不同范围的值,映射到不同的颜色上:
color = Colorful(Noise(k*point)
我们通过乘以一个常量k,就可以得到不同尺度上的纹理,这么描述似乎有些晦涩,我们可以看一下最终的效果:
可以看到这个脉络和最简单的柏林噪声图是类似的,只不过我们把特定区间的rgb映射到了一个颜色上。(通过Colorful函数)
我们把描述Noise()在x,y,z上各自的变化率(梯度)的函数为DNoise()。
假如我们想制作一个凹凸纹理贴图,我们也可以在原有法线(normal)上加一些噪声的扰动,以做出凹凸的效果。在有了DNoise()之后,这样的行为变得非常方便:
normal = normal + Dnoise(point)
最终的效果图如下:
我们来一些更有意思的。
我们可以加入一个1/f波动,通过以下公式来模拟这个信号(把不同频率的octave叠加以得到更为真实的效果):
以上1/f频谱函数的微分是一个单调频谱的函数,因此我们可以同时在所有的octave内创建类似的法线扰动,它的伪代码如下:
f = 1
while f < pixel_freq
normal += Dnoise ( f * point )
f *= 2
这个算法在计算到像素级别后停止。以上这些算法都是逐像素独立的,也就是说计算一个像素颜色不需要依赖于其它像素,所以我们可以并行地计算每个像素,然后大幅度提升运行速度。
大理石纹理
我们注意到大理石的有着各种各样的层次,我们可以用正弦波来做一个简单的色彩滤镜:
function boring_marble(point)
x = point[1]
return marble_color(sin(x))
上式中,Point[1]是point的第一个分量(x),而marble_color()是一个样条曲线函数,它可以把一个数映射到一个色彩向量上。
想要模拟更真实的大理石,可以加一个扰动:
function marble(point)
x = point[1] + turbulence(point)
return marble_color(sin(x))
而这个扰动turbluence()函数,可以通过Noise()得到,它的具体算法如下:
function turbulence(p)
t = 0
scale = 1
while( scale > pixelsize)
t += abs(Noise(p/scale) * scale)
scale /= 2
return t
水纹理
假设我们想要模拟波浪的表面,为了简单起见,我们使用法线扰动,而不是修改表面点的值。
我们使用球面波来做这件事,对于每个波浪中心,我们将会通过一个表面到中心的圆的函数来扰动表面法线。
normal += wave ( point - center)
function wave (v)
return direction(v) * cycloid (norm (v))
我们可以使用某一集合的点的Doise()的方向,产生随机分布的单位球体,来创建多个中心。
function makewaves(n)
for i in [ 1 .. n ]
center [i] = direction (Dnoise ( i * [100 0 0] ))
return center
比如如果我们想要创建一个有20个源的波浪,我们可以这样调用:
if begin_frame
center = makewaves(20)
for c in center
normal += wave (point - c)
用20的参数做出的效果:
如果想要做出更逼真的波浪效果,可以加入一个1/f扰动。如果对每个中心加一个随机的频率f,那么这个程序的最后一行将替换为:
normal += wave ((point - c) * f ) / f
此外,我们还需要让波浪随着时间动起来:
function moving_wave (v ,Dphase)
return direction(v) * cycloid (norm(v) - frame * Dphase)
Dphase就是相变的速度,一个可以让效果比较真实的参数是f^(1/2)。
做出的波浪效果:
perlin的个人主页中给出了基本Noise()函数的代码,以下只截取了二维部分,加入绘制部分,更详细的代码可以参考以下链接,点击打开链接
#include
#include "gl/glut.h"
#include
#include
#include
#define B 0x100 //256
#define BM 0xff //255
#define N 0x1000 //4096
#define NP 12 // 2^N
#define NM 0xfff
static int p[B + B + 2];
static float g2[B + B + 2][2];
int start = 1;
static void init(void);
//#define s_curve(t) ( t * t * (3. - 2. * t) )
#define s_curve(t) ( t * t * t * (t * (t * 6. - 15.) + 10.) )
#define lerp(t, a, b) ( a + t * (b - a) )
#define setup(i,b0,b1,r0,r1)\
t = vec[i] + N; \
b0 = ((int)t) & BM; \
b1 = (b0 + 1) & BM; \
r0 = t - (int)t; \
r1 = r0 - 1.;
float noise2(float vec[2])
{
int bx0, bx1, by0, by1, b00, b10, b01, b11;
float rx0, rx1, ry0, ry1, *q, sx, sy, a, b, u, v, t;
register int i, j;
if (start){
start = 0;
init();
}
setup(0, bx0, bx1, rx0, rx1);
setup(1, by0, by1, ry0, ry1);
i = p[bx0];
j = p[bx1];
b00 = p[i + by0];
b10 = p[j + by0];
b01 = p[i + by1];
b11 = p[j + by1];
sx = s_curve(rx0);
sy = s_curve(ry0);
#define at2(rx,ry) ( rx * q[0] + ry * q[1] )
q = g2[b00]; u = at2(rx0, ry0);
q = g2[b10]; v = at2(rx1, ry0);
a = lerp(sx, u, v);
q = g2[b01]; u = at2(rx0, ry1);
q = g2[b11]; v = at2(rx1, ry1);
b = lerp(sx, u, v);
return lerp(sy, a, b);
}
static void normalize2(float v[2])
{
float s;
s = sqrt(v[0] * v[0] + v[1] * v[1]);
v[0] = v[0] / s;
v[1] = v[1] / s;
}
static void init(void)
{
int i, j, k;
for (i = 0; i < B; i++) {
p[i] = i;
for (j = 0; j < 2; j++)
g2[i][j] = (float)((rand() % (B + B)) - B) / B;
}
while (--i) {
k = p[i];
p[i] = p[j = rand() % B];
p[j] = k;
}
for (i = 0; i < B + 2; i++){
p[B + i] = p[i];
for (j = 0; j < 2; j++)
g2[B + 1][j] = g2[i][j];
}
}
void drawScene()
{
float d1 = -300.0, d2 = -300.0;
const float size = 0.1f;
for (int i = 0; i < 100; i++) {
d1 = -300;
for (int j = 0; j < 100; j++) {
float vec[2] = { d1,d2 };
float color = (noise2(vec) + 1)/4;
glColor3f(color,color,color);
glRectf(i*size, j*size, i*size + size, j*size + size);
d1 += 0.1;
}
d2 += 0.1;
}
}
void reshape(int width, int height)
{
if (height == 0)height = 1;
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);//设置矩阵模式为投影
glLoadIdentity(); //初始化矩阵为单位矩阵
glOrtho(0, 10,0,10, -100, 100); //正投影
glMatrixMode(GL_MODELVIEW); //设置矩阵模式为模型
}
void redraw()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//清除颜色和深度缓存
glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); //初始化矩阵为单位矩阵
drawScene();//绘制场景
glutSwapBuffers();//交换缓冲区
}
int main(int argc,char* argv[])
{
srand(time(nullptr));
glutInit(&argc, argv);//对glut的初始化
glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
glutInitWindowSize(400, 400);//设置窗口大小
int windowHandle = glutCreateWindow("Perlin Noise");//设置窗口标题
glutDisplayFunc(redraw); //注册绘制回调函数
glutReshapeFunc(reshape); //注册重绘回调函数
glutMainLoop(); // glut事件处理循环
}
html 生成image java makenoise,[图形学] 柏林噪声 (perlin noise)相关推荐
- [算法]柏林噪声 Perlin Noise
时间:2017/1/26 大三上学年寒假 每次寒假都挺闲的,恰好最近家里网又不太稳定,不能LOL!于是想趁这个机会,利用OpenGL,尝试着写一个仿造的<Minecraft>.但是,思来想 ...
- Unity 使用柏林噪声(Perlin Noise)生成网格地图
前言 最近在尝试制作一个基于网格地图的RPG游戏,所以想着自己生成一个网格地图. 但是网格地图的生成有很多的方式,大多数的方式都达不到我的要求,我需要一个地图可以随机生成各种地形,也可以储存一些地形数 ...
- 3D数学之柏林噪声(Perlin Noise)
好了,转入正题. 其实它的原理并不是很难,但是由于网上实现的版本太多太杂,真要实现起来竟然不知从何处下手,而且自己写的时候会遇到各种各样的问题.最终写出来了,所以很欣然. 先看下,我在网上找的一些资料 ...
- Unity 动态网格地图的生成:基于Perlin Noise创建地形
前言: 在前面的文章中,写了一个简单的网格地图生成脚本,不过是基于二维空间来完成的.为了更好的拓展该脚本,同时去了解学习大世界地图加载的一些知识,这段时间会通过一个系列的文章做一个类似于我的世界那样的 ...
- 【转载】柏林噪声算法
转载自:https://www.cnblogs.com/leoin2012/p/7218033.html 原作者:立航 柏林噪声是一个非常强大算法,经常用于程序生成随机内容,在游戏和其他像电影等多 ...
- 一篇文章搞懂柏林噪声算法,附代码讲解
本文目的是以一种通俗简单的方式介绍Ken Perlin的改进版柏林噪声算法,讲解代码采用c#编写,开源免费使用.如果你只是想看完整代码,点击这里. 柏林噪声是一个非常强大算法,经常用于程序生成随机内容 ...
- Unity中使用柏林噪声生成地图
孙广东 2017.3.27 http://blog.csdn.NET/u010019717 主要是利用Unity的 Mathf.PerlinNoise 函数(柏林噪声)的不同寻常的功能. htt ...
- unity柏林噪声生成2d随机地图
1.说下思路.柏林噪声需要两个小于1的的参数导入.然后柏林噪声会输出一个相对波动变化的值0到1之间,如果对这个值进行的区间判断,就可以决定生成地图数量.比如,if<0.6再生成地图块, 2.对传 ...
- Unity无限地形生成(基于柏林噪声的简单生成)
Unity无限地形生成(基于柏林噪声的简单生成) 要求:构建一个户外开放世界游戏,为该游戏添加天空,地形,植物,并支持场景里自由漫游.这里实现一个无限地形的产生: 实现漫游 漫游的功能由玩家移动和摄像 ...
最新文章
- IsomorphicStrings(leetcode205)
- 惠普打印信息页无法连接到服务器,惠普M400系列打印机网络连接无法打印怎么办?...
- 使用DynamoDBMapper查询DynamoDB项目
- mysql图片字符集_MySQL字符集介绍及配置
- Jetbrains 系 IDE 编辑器的代码提示功能
- linux native分区,怎么将硬盘格式分区为Linux Native格式的
- ju 单元测试_【单元测试】一年级语文上册 第二单元
- X86汇编语言从实模式到保护模式09:32位x86处理器编程架构
- 十年后,若中国基建基本完成了,还有什么能大规模拉动经济?
- Sharepoin学习笔记—架构系列--Sharepoint的网页(Page),网页解析(Parsing)与解析安全处理(Security)...
- 输入法影响JDK字体?
- OpenCL编程入门(一)
- PHP的消息队列详解
- 高效的六面体变换算法实现(一) —— 等圆柱映射 与 六面体映射
- python做动态表情包下载_用 Python 开发一个【GIF表情包制作神器】
- 七牛首席布道师:Go不是在颠覆,就是在逆袭
- Maxent模型预测
- 链表实现学生信息管理系统
- 最近点对问题(蛮力法和分治法)
- 一文告诉你游戏服务器的架构到底是什么样,各服务器的职责是什么
热门文章
- element ui 图片控件 排序_vuedraggable+element ui实现页面控件拖拽排序效果
- 牛年春节海报怎么设计?psd分层模板,给你灵感!
- python输入正整数n、求n以内能被17整除的最大正整数_求100之内自然数中最大的能被17整除的数资料...
- C++共享内存类封装
- Linux 内核中的宏定义
- windows10安装Visual Studio 2017
- ubuntu18mysql登录_Ubuntu 18 mysql数据库登陆报错“Access denied for user”
- scp 覆盖_SCP-002 - “生活”室
- ActiveXObject文件读写
- 怎么用deveco studio升级鸿蒙,华为鸿蒙DevEco studio2.0的安装和hello world运行教程