柏林噪声产生火焰等纹理

简介: 柏林噪声产生火焰等纹理

柏林噪声是一种特殊的随机噪声,即对于每个给定的值产生的随机数是唯一的,但是不同的


值产生不同的随机数。关于柏林噪声更详细的解释可以参考这里:


http://freespace.virgin.net/hugo.elias/models/m_perlin.htm



本文主要是探讨如何使用柏林噪声产生火焰效果与乌云效果的纹理,在解释实现代码之前,


首先来看一下影响柏林噪声效果的两个参数音度(Octave) 与余辉(Persistence),可以调节


纹理的大小和密度。



最终实现的火焰纹理效果

0_132793357343AE.png


最终实现的乌云纹理效果

0_1327933624Soy6.png


最终实现的草地纹理效果–怎么感觉有点魔兽中精灵族的草地啊,哈哈

0_1327933666oTwQ.png


代码解释


首先产生随机空白噪声,使用随机空白噪声产生柏林噪声,最后将柏林噪声映射为RGB值


输出到指定大小的图像中,代码如下:


float[][] whiteNoise = GenerateWhiteNoise(rows, cols);


float[][] perlinNoise = GeneratePerlinNoise(whiteNoise, 6); //


float[][] colorData = MapGray(perlinNoise);



白噪声产生主要是利用JAVA中的系统时间作为种子,产生[0~1]之间的噪声数组


代码如下:


public float[][] GenerateWhiteNoise(int width, int height)


{


Random random = new Random(System.currentTimeMillis());    


float[][] noise = new float[width][height];


for (int i = 0; i < width; i++)


{


       for (int j = 0; j <height; j++)


       {


           noise[i][j] = (float)random.nextDouble();


       }


   }


   return noise;


}



柏林噪声的产生稍微复杂一点点,首先把上面的白噪声数据带入,利用插值公式产生平滑的噪声


数据,具体要产生几组平滑噪声数据取决于音度(Octave)参数。本程序的插值公式非常简单,


代码如下:


public float Interpolate(float x0, float x1, float alpha)


{


return x0 * (1 - alpha) + alpha * x1;


}


最后把这些组的平滑噪声加上不同的振幅混合在一起产生一个输出数组结果即为柏林噪声。


完成上面这些还不足以产生那些效果震撼的纹理,另外一个顶级秘诀在于怎么把柏林噪声


映射到你想要的RGB值。代码如下:


   float[][] MapGradient(float[][] perlinNoise)


   {


      int width =perlinNoise.length;


      int height =perlinNoise[0].length;


      float[][] image = new float[width][height];


      int ta=0, tr=0, tb=0,tg=0;


      for (int i = 0; i <width; i++)


      {


         for (int j = 0; j <height; j++)


         {


         ta = 255;


         int u = (int)(perlinNoise[i][j] * (float)angryFireColorTable.length);


         tr = (int)angryFireColorTable[u][0];


         tg = (int)angryFireColorTable[u][1];


         tb = (int)angryFireColorTable[u][2];


         image[i][j] = (ta <<24) | (tr << 16) | (tg << 8) | tb;


         }


      }


   


      return image;


   }


程序完全源代码如下:

package com.gloomyfish.perlin.noise;
 
import java.util.Random;
 
public class PerlinNoiseCreator {
  
  private int[][] angryFireColorTable = {
      {255, 255, 204},  {255, 255, 204},  {255, 255, 204},  {255, 255, 204},
      {255, 255, 204},  {255, 255, 204},  {255, 255, 204},  {255, 255, 204},  {255, 255, 204},
      {255, 255, 204},  {255, 255, 204},  {255, 255, 204},  {255, 255, 204},  {255, 255, 204},
      {255, 255, 204},  {255, 255, 204},  {255, 255, 204},  {255, 255, 204},  {255, 255, 204},
      {255, 255, 204},  {255, 255, 204},  {255, 255, 204},  {255, 255, 204},  {255, 255, 204},
      {255, 255, 204},  {255, 255, 204},  {255, 255, 204},  {255, 255, 204},  {255, 255, 204},
      {255, 255, 204},  {255, 255, 204},  {255, 255, 204},  {255, 255, 204},  {255, 255, 204},
      {255, 255, 204},  {255, 255, 204},  {255, 255, 204},  {255, 255, 204},  {255, 255, 199},  
      {255, 255, 199},  {255, 255, 197},  {255, 255, 197},  {255, 255, 193},  {255, 255, 193},
      {255, 255, 191},  {255, 255, 191},  {255, 255, 189},  {255, 255, 189},  {255, 255, 185},
      {255, 255, 185},  {255, 255, 183},  {255, 255, 183},  {255, 255, 179},  {255, 255, 179},
      {255, 255, 177},  {255, 255, 177},  {255, 255, 175},  {255, 255, 175},  {255, 255, 171},    
      {255, 255, 171},  {255, 255, 169},  {255, 255, 169},  {255, 255, 167},  {255, 255, 167},
      {255, 255, 163},  {255, 255, 161},  {255, 255, 157},  {255, 255, 155},  {255, 255, 153},
      {255, 251, 149},  {255, 249, 147},  {255, 246, 144},  {255, 244, 142},  {255, 242, 140},
      {253, 244, 205},  {248, 246, 197},  {248, 246, 187},  {248, 245, 178},  {248, 245, 168},
      {247, 245, 160},  {248, 243, 149},  {247, 244, 141},  {249, 243, 133},  {248, 243, 123},
      {249, 242, 112},  {248, 242, 102},  {248, 242, 92}, {247, 241, 81}, {248, 241, 73},
      {247, 240, 63}, {249, 239, 53}, {247, 239, 42}, {249, 238, 32}, {249, 238, 26},
      {248, 234, 21}, {248, 231, 21}, {250, 224, 25}, {248, 218, 24}, {249, 214, 26},
      {249, 209, 26}, {252, 204, 32}, {251, 198, 32}, {251, 191, 33}, {251, 186, 34},
      {250, 179, 35}, {252, 176, 38}, {252, 169, 41}, {252, 164, 41}, {254, 157, 44},
      {254, 151, 46}, {253, 145, 47}, {254, 141, 49}, {251, 136, 47}, {253, 135, 48},
      {251, 130, 47}, {250, 129, 46}, {249, 126, 46}, {247, 124, 44}, {246, 120, 43},
      {244, 118, 41}, {243, 115, 42}, {241, 113, 40}, {242, 111, 41}, {240, 109, 39},
      {239, 104, 40}, {236, 101, 37}, {234, 99, 35},  {235, 97, 34},  {232, 93, 34},
      {231, 91, 32},  {229, 88, 32},  {227, 86, 30},  {227, 83, 30},  {225, 81, 28},
      {224, 78, 27},  {222, 76, 25},  {223, 72, 27},  {221, 70, 25},  {219, 66, 24},
      {216, 63, 22},  {216, 58, 21},  {212, 54, 19},  {210, 50, 18},  {209, 45, 17},
      {206, 40, 14},  {206, 37, 14},  {203, 32, 12},  {200, 29, 9}, {200, 24, 9},
      {197, 21, 6}, {195, 17, 7}, {191, 13, 3}, {190, 7, 3},  {188, 5, 1},
      {184, 2, 0},  {180, 0, 0},  {178, 0, 0},  {174, 0, 0},  {172, 0, 0},
      {169, 1, 0},  {164, 0, 1},  {160, 0, 0},  {158, 0, 0},  {154, 0, 0},
      {150, 0, 0},  {146, 0, 0},  {144, 0, 0},  {140, 0, 1},  {136, 0, 2},
      {133, 0, 1},  {130, 0, 0},  {126, 1, 0},  {124, 0, 2},  {120, 0, 1},
      {116, 0, 0},  {112, 0, 0},  {109, 1, 1},  {104, 0, 0},  {103, 0, 1},
      {98, 0, 0}, {95, 0, 0}, {92, 1, 0}, {92, 1, 0}, {90, 0, 0},
      {89, 1, 0}, {88, 0, 0}, {86, 0, 0}, {86, 0, 0}, {84, 0, 0},
      {84, 0, 0}, {82, 1, 0}, {82, 1, 0}, {80, 0, 0}, {80, 0, 0},
      {79, 1, 1}, {78, 0, 0}, {76, 0, 0}, {76, 0, 0}, {74, 0, 0},
      {74, 0, 0}, {72, 0, 1}, {72, 0, 1}, {70, 0, 0}, {70, 0, 0},
      {69, 1, 2}, {68, 0, 1}, {66, 0, 1}, {66, 0, 1}, {64, 0, 0},
      {62, 1, 0}, {61, 1, 1}, {60, 0, 0}, {60, 0, 0}, {60, 0, 0},
      {58, 0, 0}, {58, 0, 0}, {56, 0, 1}, {56, 0, 1}, {54, 0, 0},
      {54, 0, 0}, {52, 1, 0}, {51, 0, 0}, {50, 0, 1}, {50, 0, 1},
      {49, 1, 1}, {48, 0, 0}, {46, 0, 0}, {46, 0, 0}, {44, 0, 1},
      {42, 0, 1}, {42, 0, 1}, {40, 0, 0}, {40, 0, 0}, {39, 0, 0},
      {38, 0, 0}, {38, 0, 0}, {36, 0, 0}, {35, 0, 0}, {34, 0, 0},
      {34, 0, 0}, {32, 0, 1}, {30, 0, 0}, {30, 0, 0}, {29, 1, 0},
      {28, 0, 0}, {28, 0, 0}, {26, 0, 1}, {24, 0, 0}, {22, 1, 0},
      {22, 1, 0}, {21, 1, 0}, {20, 0, 0}, {19, 1, 1}, {19, 1, 1},
      {16, 0, 0}, {16, 0, 0}, {16, 0, 0}, {14, 0, 0}, {12, 0, 0},
      {12, 0, 0}, {11, 1, 0}, {10, 0, 0}, {9, 1, 0},  {8, 0, 0},
      {6, 0, 0},  {6, 0, 0},  {5, 1, 0},  {4, 0, 0},  {2, 1, 0},
      {2, 1, 0},  {1, 1, 1},  {0, 0, 0},  {0, 0, 0},  {0, 0, 0},
    };
 
  
  public void generateNoise(int[] noiseData, int rows, int cols) {
 
    float[][] whiteNoise = GenerateWhiteNoise(rows, cols);
    float[][] perlinNoise = GeneratePerlinNoise(whiteNoise, 6); // default value is 6
    //float[][] colorData = MapGradient(perlinNoise);
    float[][] colorData = MapGray(perlinNoise);
    int index = 0;
    for(int row = 0; row<rows; row++) {
      for(int col=0; col<cols; col++) {
        index = row * cols + col;
        noiseData[index] = (int)colorData[row][col];
      }
    }
  }
  
  public float[][] GenerateWhiteNoise(int width, int height)
  {
      Random random = new Random(System.currentTimeMillis()); //Seed to 0 for testing
      float[][] noise = new float[width][height];
   
      for (int i = 0; i < width; i++)
      {
          for (int j = 0; j < height; j++)
          {
              noise[i][j] = (float)random.nextDouble();
          }
      }
   
      return noise;
  }
  
  public float[][] GenerateSmoothNoise(float[][] baseNoise, int octave)
  {
     int width = baseNoise.length;
     int height = baseNoise[0].length;
   
     float[][] smoothNoise = new float[width][height];
   
     int samplePeriod = 1 << octave; // calculates 2 ^ k
     float sampleFrequency = 1.0f / samplePeriod;
   
     for (int i = 0; i < width; i++)
     {
        //calculate the horizontal sampling indices
        int sample_i0 = (i / samplePeriod) * samplePeriod;
        int sample_i1 = (sample_i0 + samplePeriod) % width; //wrap around
        float horizontal_blend = (i - sample_i0) * sampleFrequency;
   
        for (int j = 0; j < height; j++)
        {
           //calculate the vertical sampling indices
           int sample_j0 = (j / samplePeriod) * samplePeriod;
           int sample_j1 = (sample_j0 + samplePeriod) % height; //wrap around
           float vertical_blend = (j - sample_j0) * sampleFrequency;
   
           //blend the top two corners
           float top = Interpolate(baseNoise[sample_i0][sample_j0],
              baseNoise[sample_i1][sample_j0], horizontal_blend);
   
           //blend the bottom two corners
           float bottom = Interpolate(baseNoise[sample_i0][sample_j1],
              baseNoise[sample_i1][sample_j1], horizontal_blend);
   
           //final blend
           smoothNoise[i][j] = Interpolate(top, bottom, vertical_blend);
        }
     }
   
     return smoothNoise;
  }
  
  public float Interpolate(float x0, float x1, float alpha)
  {
     return x0 * (1 - alpha) + alpha * x1;
  }
  
  public float[][] GeneratePerlinNoise(float[][] baseNoise, int octaveCount)
  {
     int width = baseNoise.length;
     int height = baseNoise[0].length;
   
     float[][][] smoothNoise = new float[octaveCount][][]; //an array of 2D arrays containing
   
     float persistance = 0.5f; // default value is 0.5f
   
     //generate smooth noise
     for (int i = 0; i < octaveCount; i++)
     {
         smoothNoise[i] = GenerateSmoothNoise(baseNoise, i);
     }
   
      float[][] perlinNoise = new float[width][height];
      float amplitude = 1.0f;
      float totalAmplitude = 0.0f;
   
      //blend noise together
      for (int octave = octaveCount - 1; octave >= 0; octave--)
      {
         amplitude *= persistance;
         totalAmplitude += amplitude;
   
         for (int i = 0; i < width; i++)
         {
            for (int j = 0; j < height; j++)
            {
               perlinNoise[i][j] += smoothNoise[octave][i][j] * amplitude;
            }
         }
      }
   
     //normalization
     for (int i = 0; i < width; i++)
     {
        for (int j = 0; j < height; j++)
        {
           perlinNoise[i][j] /= totalAmplitude;
        }
     }
   
     return perlinNoise;
  }
  
  float[][] MapGray(float[][] perlinNoise)
  {
     int width = perlinNoise.length;
     int height = perlinNoise[0].length;
     float[][] image = new float[width][height];
     int ta=0, tr=0, tb=0, tg=0;
     for (int i = 0; i < width; i++)
     {
        for (int j = 0; j < height; j++)
        {
          ta = 255;
          int u = (int)(perlinNoise[i][j] * (float)80.0);
          tr = u+100;
          tg = u+100;
          tb = u+100;
          //ta = (int)(255.0f * perlinNoise[i][j]);
          image[i][j] = (ta << 24) | (tr << 16) | (tg << 8) | tb;
          
        }
     }
     
     return image;
  }
  
  float[][] MapGradient(float[][] perlinNoise)
  {
     int width = perlinNoise.length;
     int height = perlinNoise[0].length;
     float[][] image = new float[width][height];
     int ta=0, tr=0, tb=0, tg=0;
     for (int i = 0; i < width; i++)
     {
        for (int j = 0; j < height; j++)
        {
          ta = 255;
          int u = (int)(perlinNoise[i][j] * (float)angryFireColorTable.length);
          tr = (int)angryFireColorTable[u][0];
          tg = (int)angryFireColorTable[u][1];
          tb = (int)angryFireColorTable[u][2];
          image[i][j] = (ta << 24) | (tr << 16) | (tg << 8) | tb;
        }
     }
     
     return image;
  }
 
}
相关文章
|
24天前
|
算法 API 计算机视觉
图像处理之角点检测与亚像素角点定位
图像处理之角点检测与亚像素角点定位
16 1
|
10月前
|
机器学习/深度学习 传感器 算法
球体同胚表面准各向同性采样附matlab代码
球体同胚表面准各向同性采样附matlab代码
|
12月前
遥感原理与应用:常用波段及其特性、太阳辐射衰减原因、大气窗口及其分布是什么?
遥感原理与应用:常用波段及其特性、太阳辐射衰减原因、大气窗口及其分布是什么?
284 0
遥感原理与应用:常用波段及其特性、太阳辐射衰减原因、大气窗口及其分布是什么?
|
11月前
【基于矢量射线的衍射积分 (VRBDI)】基于矢量射线的衍射积分 (VRBDI) 和仿真工具(Matlab代码实现)
【基于矢量射线的衍射积分 (VRBDI)】基于矢量射线的衍射积分 (VRBDI) 和仿真工具(Matlab代码实现)
|
11月前
|
机器学习/深度学习 传感器 算法
基于视差传播进行相机阵列的视差估计附matlab代码
基于视差传播进行相机阵列的视差估计附matlab代码
|
算法
大气湍流自适应光学校正算法matlab仿真,包括涡旋光束,大气湍流影响,不同轨道角动量OAM态之间的串扰,校正等
大气湍流自适应光学校正算法matlab仿真,包括涡旋光束,大气湍流影响,不同轨道角动量OAM态之间的串扰,校正等
505 0
大气湍流自适应光学校正算法matlab仿真,包括涡旋光束,大气湍流影响,不同轨道角动量OAM态之间的串扰,校正等
|
传感器 算法 定位技术
Google Earth Engine ——MODIS表面反射率产品提供了在没有大气散射或吸收的情况下在地面测量的表面光谱反射率的估计。低层数据经过了大气气体和气溶胶的校正
Google Earth Engine ——MODIS表面反射率产品提供了在没有大气散射或吸收的情况下在地面测量的表面光谱反射率的估计。低层数据经过了大气气体和气溶胶的校正
151 0
Google Earth Engine ——MODIS表面反射率产品提供了在没有大气散射或吸收的情况下在地面测量的表面光谱反射率的估计。低层数据经过了大气气体和气溶胶的校正
|
存储 编解码
Google Earth Engine ——MODIS/006/MYD09GQ表面反射率产品提供了在没有大气散射或吸收的情况下在地面测量的表面光谱反射率的估计。低层数据经过大气气体和气溶胶的校正。
Google Earth Engine ——MODIS/006/MYD09GQ表面反射率产品提供了在没有大气散射或吸收的情况下在地面测量的表面光谱反射率的估计。低层数据经过大气气体和气溶胶的校正。
231 0
Google Earth Engine ——MODIS/006/MYD09GQ表面反射率产品提供了在没有大气散射或吸收的情况下在地面测量的表面光谱反射率的估计。低层数据经过大气气体和气溶胶的校正。
|
存储 编解码 算法
Google Earth Engine ——MODIS表面反射率产品提供了在没有大气散射或吸收的情况下在地面测量的表面光谱反射率的估计,250米的分辨率提供波段1和2数据集
Google Earth Engine ——MODIS表面反射率产品提供了在没有大气散射或吸收的情况下在地面测量的表面光谱反射率的估计,250米的分辨率提供波段1和2数据集
437 0
Google Earth Engine ——MODIS表面反射率产品提供了在没有大气散射或吸收的情况下在地面测量的表面光谱反射率的估计,250米的分辨率提供波段1和2数据集
|
编解码 算法 ice
Google Earth Engine ——MOD09A1 V6产品提供了Terra MODIS 1-7带500米分辨率的表面光谱反射率的估计,并对大气条件如气体、气溶胶和瑞利散射进行了校正!
Google Earth Engine ——MOD09A1 V6产品提供了Terra MODIS 1-7带500米分辨率的表面光谱反射率的估计,并对大气条件如气体、气溶胶和瑞利散射进行了校正!
356 0
Google Earth Engine ——MOD09A1 V6产品提供了Terra MODIS 1-7带500米分辨率的表面光谱反射率的估计,并对大气条件如气体、气溶胶和瑞利散射进行了校正!