Я категорически настаиваю на закреплении этой темы в важном из-за ссылок в первых постах.
void Perlin(int size, int grain){
srand(grain);
int resolution=1<<size;
//создание структуры данных
float **m1[size];
for(int i=0;i<size;i++){
m1[i]=new float*[resolution];
for(int j=0;j<resolution;j++){m1[i][j]=new float[resolution];}}
//обнуление
for(int i=0;i<size;i++){for(int j=0;j<resolution;j++){for(int k=0;k<resolution;k++){m1[i][j][k]=0;}}}
//создание исходного шума
float length=0;
for(int i=0;i<size;i++){
int width=1<<(i+1);
//kof коэффициент веса октавы
float detsize=2.0f;
float kof=(size-i);
if(i==0){kof=detsize*16;}
if(i==1){kof=detsize*32;}
if(i==2){kof=detsize*64;}
if(i==3){kof=detsize*64;}
if(i==4){kof=detsize*4;}
if(i==5){kof=detsize*8;}
if(i>5){kof=detsize*4;}
for(int j=0;j<width;j++){for(int k=0;k<width;k++){m1[i][j<<(size-i-1)][k<<(size-i-1)]=kof*(1-2*(float)rand()/(float)RAND_MAX);}}
//cуммируется вес октав это будет максимально возможный перепад высот
length=length+kof;}
//что бы коегде заменить все деления умножением
float len=(0.5/length);
//тут градиентный шум считается
for(int k=0;k<size-1;k++){
int step=resolution>>1;
while(step>0){
for(int i=step;i<resolution-step;i=i+2*step){
for(int j=step;j<resolution-step;j=j+2*step){
//данные в углах текущей клетки
float val00=m1[k][i-step][j-step];
float val01=m1[k][i-step][j+step];
float val10=m1[k][i+step][j-step];
float val11=m1[k][i+step][j+step];
//если текущая клетка пуста, то пишется в клетку крест значений
if(m1[k][i][j]==0){
m1[k][i][j]=0.25*(val00+val01+val10+val11);
m1[k][i-step][j]=0.5*(val00+val01);
m1[k][i+step][j]=0.5*(val10+val11);
m1[k][i][j-step]=0.5*(val00+val10);
m1[k][i][j+step]=0.5*(val01+val11);}
}}
step=step>>1;}}
//суммирование в последний массив
for(int i=0;i<resolution;i++){for(int j=0;j<resolution;j++){for(int k=0;k<size-1;k++){m1[size-1][i][j]=m1[size-1][i][j]+m1[k][i][j];}}}