守望者--AIR技术交流

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

搜索
热搜: ANE FlasCC 炼金术
查看: 1145|回复: 2

[华丽特效] 多相流体力学模拟特效

[复制链接]
  • TA的每日心情
    擦汗
    2018-4-10 15:18
  • 签到天数: 447 天

    [LV.9]以坛为家II

    1742

    主题

    2094

    帖子

    13万

    积分

    超级版主

    Rank: 18Rank: 18Rank: 18Rank: 18Rank: 18

    威望
    562
    贡献
    29
    金币
    52623
    钢镚
    1422

    开源英雄守望者

    发表于 2015-7-15 16:01:33 | 显示全部楼层 |阅读模式



    1. /*
    2. * 混相流 / Multiphase flow
    3. *
    4. * いくつかの種類の液体のシミュレーションです。
    5. * クリックで注ぎます。
    6. * Click:Pouring
    7. */
    8. package {
    9.     import flash.utils.*;
    10.     import flash.text.*;
    11.     import flash.filters.*;
    12.     import flash.geom.*;
    13.     import flash.events.*;
    14.     import flash.display.*;
    15.     import net.hires.debug.Stats;
    16.     [SWF(frameRate = "60")]
    17.     public class Fluid extends Sprite {
    18.         public static const GRAVITY:Number = 0.05;//重力
    19.         public static const RANGE:Number = 16;//影響半径
    20.         public static const RANGE2:Number = RANGE * RANGE;//影響半径の二乗
    21.         public static const DENSITY:Number = 2.5;//流体の基準(安定する)密度
    22.         public static const PRESSURE:Number = 1;//圧力係数
    23.         public static const PRESSURE_NEAR:Number = 1;//近距離圧力係数
    24.         public static const VISCOSITY:Number = 0.1;//粘性係数
    25.         public static const NUM_GRIDS:int = 29;//グリッド数(≒ 465 / RANGE)
    26.         public static const INV_GRID_SIZE:Number = 1 / (465 / NUM_GRIDS);//グリッドサイズの逆数(≒ 1 / RANGE)
    27.         private var particles:Vector.<Particle>;
    28.         private var numParticles:uint;
    29.         private var neighbors:Vector.<Neighbor>;
    30.         private var numNeighbors:uint;
    31.         private var count:int;
    32.         private var press:Boolean;
    33.         private var bitmap:BitmapData;
    34.         private var grids:Vector.<Vector.<Grid>>;
    35.         private const COLOR_TRANSFORM:ColorTransform = new ColorTransform(0.5, 0.5, 0.5);

    36.         public function Fluid() {
    37.             initialize();
    38.         }

    39.         private function initialize():void {
    40.             particles = new Vector.<Particle>();
    41.             numParticles = 0;
    42.             neighbors = new Vector.<Neighbor>();
    43.             numNeighbors = 0;
    44.             grids = new Vector.<Vector.<Grid>>(NUM_GRIDS, true);
    45.             for(var i:int = 0; i < NUM_GRIDS; i++) {
    46.                 grids[i] = new Vector.<Grid>(NUM_GRIDS, true);
    47.                 for(var j:int = 0; j < NUM_GRIDS; j++)
    48.                     grids[i][j] = new Grid();
    49.             }
    50.             count = 0;
    51.             bitmap = new BitmapData(465, 465, false, 0);
    52.             addChild(new Bitmap(bitmap));
    53.             // var s:Stats = new Stats();
    54.             // s.alpha = 0.8;
    55.             // addChild(s);
    56.             addEventListener(Event.ENTER_FRAME, frame);
    57.             stage.addEventListener(MouseEvent.MOUSE_DOWN, function(e:MouseEvent):void {press = true;});
    58.             stage.addEventListener(MouseEvent.MOUSE_UP, function(e:MouseEvent):void {press = false;});
    59.         }

    60.         private function frame(e:Event):void {
    61.             if(press)
    62.                 pour();
    63.             move();
    64.         }

    65.         private function pour():void {
    66.             for(var i:int = -4; i <= 4; i++) {
    67.                  particles[numParticles++] = new Particle(mouseX + i * 10, mouseY,
    68.                      count / 10 % 5);
    69.                  particles[numParticles - 1].vy = 5;
    70.             }
    71.         }

    72.         private function move():void {
    73.             count++;
    74.             updateGrids();
    75.             findNeighbors();
    76.             calcForce();
    77.             bitmap.lock();
    78.             bitmap.colorTransform(bitmap.rect, COLOR_TRANSFORM);
    79.             for(var i:uint = 0; i < numParticles; i++) {
    80.                 const p:Particle = particles[i];
    81.                 p.move();
    82.                 bitmap.fillRect(new Rectangle(p.x - 1, p.y - 1, 3, 3), p.color);
    83.             }
    84.             bitmap.unlock();
    85.         }

    86.         private function updateGrids():void {
    87.             var i:uint;
    88.             var j:uint;
    89.             for(i = 0; i < NUM_GRIDS; i++)
    90.                 for(j = 0; j < NUM_GRIDS; j++)
    91.                     grids[i][j].numParticles = 0;
    92.             for(i = 0; i < numParticles; i++) {
    93.                 const p:Particle = particles[i];
    94.                 p.fx = p.fy = p.density = p.densityNear = 0;
    95.                 p.gx = p.x * INV_GRID_SIZE; // グリッドのどこにいるか計算
    96.                 p.gy = p.y * INV_GRID_SIZE;
    97.                 if(p.gx < 0) // グリッドから外れてたら一番近いとこに入ってることにする
    98.                     p.gx = 0;
    99.                 if(p.gy < 0)
    100.                     p.gy = 0;
    101.                 if(p.gx > NUM_GRIDS - 1)
    102.                     p.gx = NUM_GRIDS - 1;
    103.                 if(p.gy > NUM_GRIDS - 1)
    104.                     p.gy = NUM_GRIDS - 1;
    105.             }
    106.         }

    107.         private function findNeighbors():void { // 空間分割で近接粒子を計算
    108.             numNeighbors = 0;
    109.             for(var i:uint = 0; i < numParticles; i++) {
    110.                 const p:Particle = particles[i];
    111.                 const xMin:Boolean = p.gx != 0;
    112.                 const xMax:Boolean = p.gx != NUM_GRIDS - 1;
    113.                 const yMin:Boolean = p.gy != 0;
    114.                 const yMax:Boolean = p.gy != NUM_GRIDS - 1;
    115.                 findNeighborsInGrid(p, grids[p.gx][p.gy]);
    116.                 if(xMin) findNeighborsInGrid(p, grids[p.gx - 1][p.gy]);
    117.                 if(xMax) findNeighborsInGrid(p, grids[p.gx + 1][p.gy]);
    118.                 if(yMin) findNeighborsInGrid(p, grids[p.gx][p.gy - 1]);
    119.                 if(yMax) findNeighborsInGrid(p, grids[p.gx][p.gy + 1]);
    120.                 if(xMin && yMin) findNeighborsInGrid(p, grids[p.gx - 1][p.gy - 1]);
    121.                 if(xMin && yMax) findNeighborsInGrid(p, grids[p.gx - 1][p.gy + 1]);
    122.                 if(xMax && yMin) findNeighborsInGrid(p, grids[p.gx + 1][p.gy - 1]);
    123.                 if(xMax && yMax) findNeighborsInGrid(p, grids[p.gx + 1][p.gy + 1]);
    124.                 grids[p.gx][p.gy].add(p);
    125.             }
    126.         }

    127.         private function findNeighborsInGrid(pi:Particle, g:Grid):void {
    128.             for(var j:uint = 0; j < g.numParticles; j++) {
    129.                 var pj:Particle = g.particles[j];
    130.                 const distance:Number = (pi.x - pj.x) * (pi.x - pj.x) + (pi.y - pj.y) * (pi.y - pj.y);
    131.                 if(distance < RANGE2) {
    132.                     if(neighbors.length == numNeighbors)
    133.                         neighbors[numNeighbors] = new Neighbor();
    134.                     neighbors[numNeighbors++].setParticle(pi, pj);
    135.                 }
    136.             }
    137.         }

    138.         private function calcForce():void {
    139.             for(var i:uint = 0; i < numNeighbors; i++)
    140.                 neighbors[i].calcForce();
    141.         }
    142.     }
    143. }

    144. class Particle {
    145.     public var x:Number;
    146.     public var y:Number;
    147.     public var gx:int;
    148.     public var gy:int;
    149.     public var vx:Number;
    150.     public var vy:Number;
    151.     public var fx:Number;
    152.     public var fy:Number;
    153.     public var density:Number;
    154.     public var densityNear:Number;
    155.     public var color:int;
    156.     public var type:int;
    157.     public const GRAVITY:Number = Fluid.GRAVITY;
    158.     public function Particle(x:Number, y:Number, type:int) {
    159.         this.x = x;
    160.         this.y = y
    161.         this.type = type;
    162.         vx = vy = fx = fy = 0;
    163.         switch(type) {
    164.         case 0:
    165.             color = 0x6060ff;
    166.             break;
    167.         case 1:
    168.             color = 0xff6000;
    169.             break;
    170.         case 2:
    171.             color = 0xff0060;
    172.             break;
    173.         case 3:
    174.             color = 0x00d060;
    175.             break;
    176.         case 4:
    177.             color = 0xd0d000;
    178.             break;
    179.         }
    180.     }

    181.     public function move():void {
    182.         vy += GRAVITY;
    183.         if(density > 0) {
    184.             vx += fx / (density * 0.9 + 0.1); // 本当は密度で割る計算だけど0に近かった時に
    185.             vy += fy / (density * 0.9 + 0.1); //     粒子が飛び出すから微調整
    186.         }
    187.         x += vx;
    188.         y += vy;
    189.         if(x < 5) // 壁境界
    190.             vx += (5 - x) * 0.5 - vx * 0.5;
    191.         if(x > 460)
    192.             vx += (460 - x) * 0.5 - vx * 0.5;
    193.         if(y < 5)
    194.             vy += (5 - y) * 0.5 - vy * 0.5;
    195.         if(y > 460)
    196.             vy += (460 - y) * 0.5 - vy * 0.5;
    197.     }
    198. }

    199. class Neighbor {
    200.     public var p1:Particle;
    201.     public var p2:Particle;
    202.     public var distance:Number;
    203.     public var nx:Number;
    204.     public var ny:Number;
    205.     public var weight:Number;
    206.     public const RANGE:Number = Fluid.RANGE;
    207.     public const PRESSURE:Number = Fluid.PRESSURE;
    208.     public const PRESSURE_NEAR:Number = Fluid.PRESSURE_NEAR;
    209.     public const DENSITY:Number = Fluid.DENSITY;
    210.     public const VISCOSITY:Number = Fluid.VISCOSITY;
    211.     public function Neighbor() {
    212.     }

    213.     public function setParticle(p1:Particle, p2:Particle):void { // 使いまわし
    214.         this.distance = distance;
    215.         this.p1 = p1;
    216.         this.p2 = p2;
    217.         nx = p1.x - p2.x;
    218.         ny = p1.y - p2.y;
    219.         distance = Math.sqrt(nx * nx + ny * ny);
    220.         weight = 1 - distance / RANGE;
    221.         var density:Number = weight * weight; // 普通の圧力カーネルは距離の二乗
    222.         p1.density += density;
    223.         p2.density += density;
    224.         density *= weight * PRESSURE_NEAR; // 粒子が近づきすぎないよう近距離用のカーネルを計算
    225.         p1.densityNear += density;
    226.         p2.densityNear += density;
    227.         const invDistance:Number = 1 / distance;
    228.         nx *= invDistance;
    229.         ny *= invDistance;
    230.     }

    231.     public function calcForce():void {
    232.         var p:Number;
    233.         if(p1.type != p2.type) // 違うタイプの粒子なら安定する密度をちょっと減らす
    234.             p = (p1.density + p2.density - DENSITY * 1.5) * PRESSURE;
    235.         else // 同じタイプなら普通に計算
    236.             p = (p1.density + p2.density - DENSITY * 2) * PRESSURE;
    237.         const pn:Number = (p1.densityNear + p2.densityNear) * PRESSURE_NEAR; // 基準密度に関係なく近づきすぎたら跳ね返す!
    238.         var pressureWeight:Number = weight * (p + weight * pn); // 結果としてかかる圧力
    239.         var viscosityWeight:Number = weight * VISCOSITY;
    240.         var fx:Number = nx * pressureWeight;
    241.         var fy:Number = ny * pressureWeight;
    242.         fx += (p2.vx - p1.vx) * viscosityWeight; // 単純に粘性項を解く
    243.         fy += (p2.vy - p1.vy) * viscosityWeight;
    244.         p1.fx += fx;
    245.         p1.fy += fy;
    246.         p2.fx -= fx;
    247.         p2.fy -= fy;
    248.     }
    249. }

    250. class Grid {
    251.     public var particles:Vector.<Particle>;
    252.     public var numParticles:uint;
    253.     public function Grid() {
    254.         particles = new Vector.<Particle>;
    255.     }

    256.     public function add(p:Particle):void {
    257.         particles[numParticles++] = p;
    258.     }
    259. }
    复制代码





    本文来自:http://wonderfl.net/c/qszD

    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    守望者AIR技术交流社区(www.airmyth.com)
    回复

    使用道具 举报

    该用户从未签到

    0

    主题

    5

    帖子

    78

    积分

    列兵

    Rank: 2

    威望
    0
    贡献
    0
    金币
    51
    钢镚
    0
    发表于 2015-10-24 16:18:28 | 显示全部楼层
    效果真不错啊
    守望者AIR技术交流社区(www.airmyth.com)
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    0

    主题

    5

    帖子

    78

    积分

    列兵

    Rank: 2

    威望
    0
    贡献
    0
    金币
    51
    钢镚
    0
    发表于 2015-10-24 16:18:45 | 显示全部楼层
    效果真不错啊
    守望者AIR技术交流社区(www.airmyth.com)
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    
    关闭

    站长推荐上一条 /4 下一条

    QQ|手机版|Archiver|网站地图|小黑屋|守望者 ( 京ICP备14061876号

    GMT+8, 2024-3-29 19:33 , Processed in 0.052149 second(s), 36 queries .

    守望者AIR

    守望者AIR技术交流社区

    本站成立于 2014年12月31日

    快速回复 返回顶部 返回列表