您的位置:首页 > 其它

用GPU实现Cellular Texture (转)

2007-08-01 12:43 134 查看
 
转载请注明:来自http://blog.csdn.net/skyman_2001
一、介绍
Steven Worley在Siggraph96上发表的论文《A Cellular Texture Basis Function》提出了一种用于实现cellular texture的基函数。它们是基于分散“特征点(feature point)”到R3空间,并建立基于局部点的分布的一个标量函数。这个函数的优点是不需要预计算或表存储。
二、第n最近点基函数
在R3空间随机分布特征点。对任一位置x,定义F1(x)为x到其最近特征点的距离。当x变化时,F1平滑变化(因为x是平滑变化的)。但在特定端点,x可能会与2个特征点的距离相等。但这是没关系的。x连续变化时,F1值仍然连续,尽管F1的导数在计算距离从一特征点转到相邻特征点时会变化不连续。
F2(x)表示x与第2近的特征点的距离。同样,可定义Fn(x)为x到第n近的特征点的距离。F函数有如下有趣的特征:
      1. Fn总是连续的;
2. Fn是非减函数:0<=F1(x)<=F2(x)<=F3(x)…,通常Fn(x)<=Fn+1(x);
3. Fn的梯度为从第n最近特征点到x的单位方向向量。
三、计算Fn
为计算函数Fn,我们必须定义特征点如何在空间中分布。点的密度和分布将改变基函数的特性。我们想要点的同向性分布,以避免明显的格子状的形式。
最简单的分布是泊松分布。它指定空间中点的平均密度。每个点的位置独立于其他点。某一区域的点的竖立=点的密度×该区域的体积(可能或多或少不一样)。每个区域的点的任何数目的确切概率可用离散泊松分布函数来计算。
一种方法是:将空间分为统一的立方体的格子。在整数坐标位置处分割。空间中的每个立方体可唯一的由其整数坐标表示,并且通过简单的floor操作,我们就可以确定。比如,点(1.2,3.33,2.3)位于由(1,3,2)索引的立方体内。
空间中的每个立方体可能包含0、1或多个特征点。我们可以实时地确定,因为泊松分布的随机分布函数描述了一立方体中每个可能的特征点数目的确切概率。对每个立方体的特征点的平均密度λ,m个点在同一立方体的概率为(λ-meλm!)-1,这样我们就可以列出m=0,1,2,3…的概率,并索引一随机数到该表中来确定在该立方体中有多少特征点。
    我们用随机数生成器产生的第1个值作为不同特征点数概率表的索引来找该立方体中的特征点数。
接下来,我们计算m特征点的位置(这是随机的,但对每个立方体是固定不变的)。我们用已经初始化了的随机数生成器来计算每个特征点的XYZ位置。这些坐标相对于立方体的底,且每个坐标分量都在0~1之间。
当我们产生这些点,我们计算它与初始函数计算位置x的距离,并保持一个目前第n近距离的排序表。这样就找到最近特征点和当前立方体空间中的点的值Fn。但是,相邻立方体的特征点中很有可能包含比我们发现的点更近的特征点,因此我们必须也在边界立方体中迭代。
四、Cellular Texture的应用
1. 最简单的情形——F1(x):
       在每个特征点周围放射状增加。效果就是在每个特征点周围放置斑点。这可以用来模拟圆点花样的布料等效果;
2. F2(x)和F3(x):
两者相组合可以产生更有趣的形式。如
                     F2(x) – F1(x)
    这种组合在F1=F2时其值为0,这发生在Voronoi边界。这可以用来模拟脉络状的窗饰等效果;
3. C1F1+C2F2+C3F3+C4F4:
       这是F1~F4的线性组合。改变系数C1,C2,C3,C4的值可以产生丰富多彩的迷人效果。超过4个F函数的组合,其产生的效果的差别就不明显了。所以这种组合一般控制在4个F函数之内;
4. 不规则碎片形(fractal):
    其公式为
           


       使用Gn作为颜色的索引。
       其中,F1(x)的fractal版本是最有用的:
             


                 
五、GPU实现
       本例子是用Pixel Shader实现2D的Cellular Texture。基本思路是,由CPU计算随机数数组,然后传给GPU,GPU根据这些随机数对各个cell的中心点(也就是“特征点”)进行扰动,如下图所示,然后计算Fn。
                    


HLSL源代码如下:
[align=left]/////////////////////////////////////////////////////////[/align]
[align=left]// File: cellulareffect.txt[/align]
[align=left]// [/align]
[align=left]// Author: Skyman (http://blog.csdn.net/skyman_2001)[/align]
[align=left]//[/align]
[align=left]// System: WinXP + Pentium D 2.66GHz + GeForce 7300 [/align]
[align=left]//[/align]
[align=left]// Desc: Cellular texture shader in an effect file.[/align]
[align=left]//          [/align]
[align=left]/////////////////////////////////////////////////////////[/align]
[align=left]//[/align]
[align=left]// Macros[/align]
[align=left]//[/align]
[align=left]#define Width 256[/align]
[align=left]#define CellSize 32[/align]
[align=left] [/align]
[align=left]//[/align]
[align=left]// Globals[/align]
[align=left]//[/align]
[align=left]extern float NoiseArray[162];[/align]
[align=left] [/align]
[align=left]//[/align]
[align=left]// PS[/align]
[align=left]struct vertout[/align]
[align=left]{[/align]
[align=left]   float2 HPos : VPOS;[/align]
[align=left]};[/align]
[align=left] [/align]
[align=left]struct fragout[/align]
[align=left]{[/align]
[align=left]   float4 col    : COLOR0;[/align]
[align=left]};[/align]
[align=left] [/align]
[align=left]fragout PSMain(vertout In)[/align]
[align=left]{[/align]
[align=left]   fragout Out;[/align]
[align=left]   [/align]
[align=left]   float a,b,f1,f2,f3;[/align]
[align=left]   float2 CellCenter;[/align]
[align=left]   float dist,shortest1,shortest2,shortest3;[/align]
[align=left]   float dist2,s2;[/align]
[align=left]   shortest1=shortest2=shortest3=10000;[/align]
[align=left]   s2=10000;[/align]
   float n=0;
[align=left]   for(a=0;a<=Width;a+=CellSize)[/align]
[align=left]   {[/align]
[align=left]      for(b=0;b<=Width;b+=CellSize)[/align]
[align=left]      {[/align]
        CellCenter.x=a+NoiseArray
;
[align=left]        CellCenter.y=b+NoiseArray[n+1];[/align]
[align=left]        n+=2;[/align]
[align=left]        [/align]
[align=left]        dist=distance(CellCenter,In.HPos);[/align]
[align=left]        dist2=distance(CellCenter,In.HPos*2);[/align]
[align=left]              [/align]
[align=left]        if(dist<shortest1)[/align]
[align=left]        {[/align]
[align=left]           shortest3=shortest2=shortest1;[/align]
[align=left]           shortest1=dist;[/align]
[align=left]        }[/align]
[align=left]        else if(dist<shortest2)[/align]
[align=left]        {[/align]
[align=left]           shortest3=shortest2;[/align]
[align=left]           shortest2=dist;[/align]
[align=left]        }[/align]
[align=left]        else if(dist<shortest3)[/align]
[align=left]           shortest3=dist;[/align]
[align=left]           [/align]
[align=left]        if(dist2<s2)[/align]
[align=left]           s2=dist2;[/align]
[align=left]      }[/align]
[align=left]   }[/align]
[align=left]   f1=clamp(shortest1,0,Width)/CellSize; // F1[/align]
[align=left]   f2=clamp(shortest2,0,Width)/CellSize; // F2[/align]
[align=left]   f3=clamp(shortest3,0,Width)/CellSize; // F3[/align]
[align=left]   s2=clamp(s2,0,Width)/(Width*2);[/align]
[align=left]   float f123=f3-0.25*f2-0.5*f1; // C1F1+C2F2+C3F3[/align]
[align=left]   float f1frac=f1+0.5*s2; // F1 fractal (i=1)[/align]
[align=left]   float f12=f2-f1; // F2-F1[/align]
[align=left]   float mulf=f1*f2; // F1*F2[/align]
[align=left]   float InvMulf=1-f1*f2; // 1-F1*F2[/align]
[align=left]   float mulf2=f1*f2*f3; // F1*F2*F3[/align]
[align=left]   Out.col=float4(f1,f1,f1,1.0);                [/align]
[align=left]   return Out;   [/align]
[align=left]}                        [/align]
[align=left] [/align]
[align=left]// [/align]
[align=left]// Effect[/align]
[align=left]//[/align]
[align=left] [/align]
[align=left]technique Cellular[/align]
[align=left]{[/align]
[align=left]    pass P0[/align]
[align=left]    {       [/align]
[align=left]       pixelShader = compile ps_3_0 PSMain();[/align]
[align=left]    }[/align]
}

六、运行效果
1. F1:                                                              2. F2:        


      


3. F3:                                                             4. F3-0.25*F2-0.5*F1:


      


5. F2-F1:                                                       6. F1*F2:


      


7. 1-F1:                                                         8. 1-(F2-F1):


      


9. 1-F1*F2:                                                  10. F1*F2*F3:



  


11.F2+F1-F3:                12.(F2-F1)/F1:


  


13.0.5×F1/(F2-F1):              14.1-(F2-F1)/F1:


  


七、结束语
       Cellular Texture是一项很有用的技术,可以用于过程纹理的创建(2D和3D)。看到了吧,Cellular Texture能产生许多有趣的图案。有兴趣的同志可以自己挖掘,产生比这更加丰富多彩的纹理效果。Try it now!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息