// Grain 使用PBD算法,說白了就是先更新位置,再更新速度,Houddini Masterclass Grain 中的案例有一些簡單的實現(最基本的原理)
比如跟新位置(這里為了簡化Jeff 把粒子的pscale大小都看成一樣),如果粒子有重合, 直接更改位置
int n[] = pcfind(0, 'P', @P, @pscale*2, 100); vector change = 0; float weight = 0; foreach (int npt; n) { if (npt == @ptnum) continue; vector op = point(0, 'P', npt); float d = length(op - @P); if (d < @pscale*2) { change += normalize(@P-op) * (@pscale*2-d)/2; weight += 1; } } @P += change / weight;
如果考慮質量的話,大概的算法:
int n[] = pcfind(0, 'P', @P, @pscale*2, 100); vector change = 0; float weight = 0; foreach (int npt; n) { if (npt == @ptnum) continue; vector op = point(0, 'P', npt); float d = length(op - @P); if (d < @pscale*2) { float omass = point(0, 'mass', npt); float ratio = omass / (@mass + omass); change += normalize(@P-op) * (@pscale*2-d) * ratio; weight += 1; } } @P += change / weight;
然后再根據位置的變化更新速度
if (i@has_pprevious) @v = (@P - v@pprevious) / @TimeInc;
注意POP Grain 節點會在粒子上添加一個屬性 ispbd 值為1 , 這樣POP Solver 就 不會更新P (位置) ,只在POP Grain 節點中更新
// Grain 中mass為0時的 特殊意義
如果粒子的屬性mass值為0(特殊值),代表的意義是粒子質量無窮大,這樣根據上面的算式
float ratio = omass / (@mass + omass); change += normalize(@P-op) * (@pscale*2-d) * ratio;
omass 是搜到的附近的粒子的質量,@mass 是粒子自身的質量,@mass無窮大, ratio無窮接近0
在試驗中,在grainsource節點后選中上面的粒子,建組zero_mass
然后在popnet 中,popwrangle,
第一句 float @mass = 1 必不可少啊(Bug ), 他的作用是為所有的粒子聲明創建一個屬性,初始值為1,看起來只給zero_mass組里面的操作,實際不是:(
下面一句才是只是對zero_mass組里的粒子操作,mass值為0
這樣,上面的粒子靜止,下面的粒子由於重力散開, 圖為結算第一幀和第14幀對比