【互动媒体创意编程0】柏林噪声生成的随机地形

【互动媒体创意编程0】柏林噪声生成的随机地形

前言

重接从结课以来陆陆续续一边学一边写的大作业。
这大概是最近时间里写得最舒服的一科作业了。除了偶尔有的bug,整体来说难度都不高,并且写出来真的非常好看也非常有意思。
《代码本色》是我从大一的时候就知道的一本书,但知道最近才真正仔仔细细去看一遍。现在我将前面五章内容的作业写到一个文档中,因为它们之间彼此有一些联系,也可以从相互之间得到一些启发。
我在构思的前期花费了很多时间。相关的想法网上有很多,但是都不是很有趣。因此我花费了很多时间在油管上找了一些实例,参考了一些,也仿写了一些。(有一些想法真的是很妙呀。)

第0章:随机游走和泊林噪声

这是模仿youtube上的一个代码挑战编写的程序。先来看效果:

在这里插入图片描述
比较显而易见的是,这样的地形很显然是由一块平整地形进行局部节点拔高形成的。
在二维平面中,我们很容易能够将整块画布切分为一定密度的网格,只需要计算它的行和列,并连接成线即可。
不过,我们如果想要一块可以动的地形,那么就必然不可能通过画线来实现这样的网格,除非我们计算每一个节点的位置,然而这样的做法很显然是没有必要的。
processing为用户定义了绘制特定图形的方法,即beginShape()、vertex()以及endShape()。通过这三个函数,我们将能够利用计算好的节点位置批量生成图形。在这里,这个方法显现出了巨大的优势。
在这里插入图片描述

代码也很简单:

int cols,rows;  
int density =20; 
color currentColor;
int scl = 20;

void setup(){
  size(900,600,P3D);  
  int w = 900;
  int h = 600;
  cols = w/scl;
  rows = h/ scl;
}  


void draw()  {         
  background(0);     
  stroke(255);     
  noFill();        

  for(int y=0;y < rows;y++){      
    beginShape(TRIANGLE_STRIP);            
    for(int x=0; x<cols; x++){
      vertex(x*scl,y*scl);        
      vertex(x*scl,(y+1)*scl);      
    }      
    endShape();    
  }
}

那么现在我们要做的就是把这块平面变成三维的地形,并且为某些顶点添加噪声值。
我们需要首先创建一块地形。

  terrain=new float[cols][rows];  

然后我们定义一个起伏值jump。这个jump将作为类似time一样的变量,来控制noise函数所取得的值。这个值将在draw()函数中每一帧发生一些变化来动态地在泊林噪声函数上取值。一般情况下,我们见到的都是以0.1甚至是0.01为度量进行增加的,因为这将使得我们取到的噪声更加光滑。
地形突起的量需要由二维变量生成。故我们最好是要利用jump来首先计算出x和y方向上每一帧相应的增量,用它来作为生成噪声的参数。又由于我们只需要地形在平面上凸起而不需要它在水平方向上扭曲,所以简单来说只需要改变y方向的噪声值就可以了。
因此,我们首先在draw()函数中的进行如下的更新:

  jump -= 0.1;    
  float yoff=jump;    
  for(int y=0;y<rows;y++)    
  {      
    float xoff=0;      
    for(int x=0;x<cols;x++)      
    {        
      terrain[x][y]=map(noise(xoff,yoff),0,1,-100,100);        
      xoff += 0.2;      
    }      
    yoff += 0.2;    
  } 

泊林噪声是一个可以由一维参数定义的也可以是由一个二维参数定义的连续随机值。这个随机值介于(0,1)之间,经过插值可以变成平滑的曲线。一般情况下,我们在生成噪声图的时候将会取一个不断随时间变化的值,并将它乘上一个数来进行插值,就能够生成一些平滑的噪点。

同时,需要改变地形绘制的方式:

    beginShape(TRIANGLE_STRIP);            
    for(int x=0;x<cols;x++){
      vertex(x*density,y*density,terrain[x][y]);        
      vertex(x*density,(y+1)*density,terrain[x][y+1]);      
    }      
    endShape();    

这样,基本上就完成了。我们来看一下效果:
在这里插入图片描述
看起来还挺像水面的,不过我们需要看到它更像是一块地形而不是俯视的平面。processing有非常好用的方法,即rotate()函数。
只需要一行

  rotateX(PI/3);  

就可以旋转绘图区(看上去就是把视角往上抬起了一些了)。
原先应该还有一张错误截图,但是不想再截一张了,直接放最终结果好了。这张错误结果的原因在我们前面说过的jump上。我们如果定义jump每一帧-0.1,那么我们看到的结果就会是这块地形在向后跑,而不是我们预期的向我们的方向滚动。因此,我们再调整这行代码为jump -= 0.01。
最终效果:
在这里插入图片描述
我非常喜欢胡子大哥的创意。能够运用噪声来实现这样的效果实属玄妙。我暂时想不出把它呈现地更好的方法了,因此就直接学习它吧。

礼貌性地贴上完整代码:

int cols,rows;  
int density =20;  
int w=2000;  
int h=1600;  
float[][] terrain;  
float jump=0;  
color currentColor;

void setup(){
  size(900,600,P3D);    
  cols=w/density;    
  rows=h/density;    
  terrain=new float[cols][rows];  
}  


void draw()  {         
  jump += 0.1;    
  float yoff=jump;    
  for(int y=0;y<rows;y++)    
  {      
    float xoff=0;      
    for(int x=0;x<cols;x++)      
    {        
      terrain[x][y]=map(noise(xoff,yoff),0,1,-100,100);        
      xoff += 0.2;      
    }      
    yoff += 0.2;    
  }     
  
  background(0);     
  stroke(255);     
  noFill();        
  translate(width/2,height/2+50);     
  rotateX(PI/3);     
  translate(-w/2,-h/2);    
  
  for(int y=0;y<rows-1;y++){      
    beginShape(TRIANGLE_STRIP);            
    for(int x=0;x<cols;x++){
      vertex(x*density,y*density,terrain[x][y]);        
      vertex(x*density,(y+1)*density,terrain[x][y+1]);      
    }      
    endShape();    
  }
}

【互动媒体创意编程1&2】万千星河都涌向你:向量、速度、力与加速度
【互动媒体创意编程3】小球弹跳:震荡
【互动媒体创意编程4】processing中用粒子系统实现的烟花

发布了153 篇原创文章 · 获赞 184 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/Ha1f_Awake/article/details/103835992