zoukankan      html  css  js  c++  java
  • Houdini 中 Gray Scott Reaction-Diffusion算法的实现

    这篇文章是吧很久以前学的一个神奇算法归一下档,在公交车上突然想起来了,觉得还是很有必要再仔细梳理一遍,对以后也许有用。

    先看图再说话:

    Gray Scott Reaction-Diffusion算法, 在模拟微观细胞的运动或者类似的效果是非常神奇。

    理论链接:http://www.karlsims.com/rd.html

    原理:模拟两种物质之间在平面(暂时是平面)上的相互作用,动作分为反应与扩散。

    公式:

    右手边第一项为扩散,第二项为反应,第三项是供给,DA与DB为分散率,▽2A或B为相邻位置扩散阵列(下图),f和k是两个非常重要的外参数,分别叫做feed和kill。可以简单理解成A是环境中的实物,两个B和一个A就能变成三个B,过程中feed会变出更多的A,k也会去掉一些B。非常想现实的生长环境。

    |0.05| 0.2 |0.05|

    | 0.2 | -1  | 0.2 | 

    |0.05| 0.2 |0.05|    

    上面是拉普拉斯方程用到的阵列,因为外围总和等于中间数的反数,所以参数化后便可以随便调

    在houdini里面,使用sop solver来迭代A和B的物质变化,在进入solver前,先定义好A和B的值,一般是A在整个平面是1.0,B随机散布开,这样出来的效果也好,如下图是我做的B随机散布示意图:

    同时用noise方法随机分布feed和kill的值,你当然可以使用固定的f和k,不过有随机变化的话会让生长更加自然有趣。下面是detail面板里面的简单示意:

    值得注意的是feed和kill的值是非常敏感的,我自己测试时,也就几个非常窄的区间内会有生长效果,要不然cb会非常快的全死掉。

    在solver里面给preframe 加一个新的vex node,代码如下:

    #pragma label resx "Res X"
    #pragma label resy "Res Y"
    
    #pragma label diff_a "Diffusion A"
    #pragma label diff_b "Diffusion B"
    
    #pragma label weight "Weight"
    #pragma range weight 0.125 0.25
    
    #pragma label feed "Feed"
    #pragma range feed 0 1
    #pragma label kill "Kill"
    #pragma range kill 0 1
    #pragma label time_step "Sub Step"
    #pragma range time_step 0 20
    
    #pragma hint ca invisible
    #pragma hint cb invisible
    
    
    //this fuction will diffuse 
    float laplacian(int ptnum; int resx; int resy; string attrib; float weight){
    
            // | w_s  | w | w_s  |
            //-----------------------
            // | w    |-1 | w    |
            //-----------------------
            // | w_s  | w | w_s  |         weight
    
            // | pt+w-1  | pt+w | pt+w+1  |
            //-----------------------------
            // | pt-1    |  pt  | pt+1    |
            //-----------------------------
            // | pt-w-1  | pt-w | pt-w+1  |   location
    
            int vb = resx*2, hb = 1;
    
            // detects boundaries
            if((ptnum % resx) == 0 || (ptnum % resx) == (resx - 1)){
                    hb *= -1;  // horizon
            }
    
            if(ptnum < resx || ptnum > (resy-1)*resx){
                    vb *= -1;  // vetical
            }
    
    
    
            float n[];
            resize(n,9);
    
            float weight_second = 0.25 - weight;
    
            n[0] = point(0, attrib, ptnum - vb - 1) * weight_second;  // left bottom
            n[1] = point(0, attrib, ptnum - vb    ) * weight;         // bottom
            n[2] = point(0, attrib, ptnum - vb + 1) * weight_second;  // right bottom
            n[3] = point(0, attrib, ptnum      - 1) * weight;         // left
            n[4] = point(0, attrib, ptnum         ) * (-1.0);           // center
            n[5] = point(0, attrib, ptnum      + 1) * weight;         // right
            n[6] = point(0, attrib, ptnum + vb - 1) * weight_second;  // left top
            n[7] = point(0, attrib, ptnum + vb    ) * weight;         // top
            n[8] = point(0, attrib, ptnum + vb + 1) * weight_second;  // right top
    
            float sum=0.0;
            foreach(float i; n){
                    sum += i;
            }
    
            return sum;
    }
    
    sop
    gray_scott(
            int resx = 512;
            int resy = 512;
            float diff_a = 1.0;
            float diff_b = 1.0;
            float weight = 0.15;
            export float feed = 0.05;
            export float kill = 0.05;
            float time_step = 1.0;
            export float ca = 0.0;
            export float cb = 0.0;
            )
    {
                    float react_rate = ca * pow(cb,2);
                    float feed_set = feed * (1.0 - ca);
                    float kill_set = (kill + feed) * cb;
                    //float substep = 1.0/(float)time_step;
    
            ca += (diff_a * laplacian(ptnum, resx, resy, "ca", weight) - react_rate + feed_set) * time_step;
            cb += (diff_b * laplacian(ptnum, resx, resy, "cb", weight) + react_rate - kill_set) * time_step;
    }
    

     最后看一看不同的feed和kill值产生的不同效果:

     feed = 0.051  kill = 0.062

     feed = 0.0367 kill = 0.069

     feed = 0.0561 kill = 0.0636

  • 相关阅读:
    字符串倒序
    字符串反转问题
    linux系统性能分析
    操作系统基础知识
    两个数组a[N],b[N],其中A[N]的各个元素值已知,现给b[i]赋值,b[i] = a[0]*a[1]*a[2]…*a[N-1]/a[i];
    用加法模拟乘法
    2015年最新中国知网CNKI免费账号直接入口
    nginx模块开发(18)—日志分析
    nginx基本配置
    三层架构和MVC
  • 原文地址:https://www.cnblogs.com/simonxia/p/4282569.html
Copyright © 2011-2022 走看看