守望者--AIR技术交流

标题: 多相流体力学模拟特效 [打印本页]

作者: 破晓    时间: 2015-7-15 16:01
标题: 多相流体力学模拟特效
http://swf.wonderfl.net/swf/usercode/b/b9/b973/b9736d12dd7747868c3ac794128a931dd6f248ad.swf?t=1436946973791


  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. }
复制代码



[attach]1232[/attach]

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

作者: songxp03    时间: 2015-10-24 16:18
效果真不错啊
作者: songxp03    时间: 2015-10-24 16:18
效果真不错啊




欢迎光临 守望者--AIR技术交流 (http://www.airmyth.com/)