微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在浏览器中求解显式 Euler 方法的最快方法

如何解决在浏览器中求解显式 Euler 方法的最快方法

我想使用每帧/顶点最少操作的方法在网络浏览器中进行简单的布料模拟,我认为这是显式欧拉。这是一个使用 vanilla JS 的非常基本的初稿,布料是 4D 的,但这不会对算法产生影响:

class Phase {
  constructor(r,bf,ns) {
    this.r = r;
    this.bf = bf;
    this.ns = ns;
    this.s = math.random([4],2 * math.pi);
    this.o = math.multiply(this.r,math.sin(this.s));
  }
  tck() {
    this.s = math.mod(
      math.add(this.s,this.bf,math.random([4],this.ns)),2 * math.pi
    );
    this.o = math.multiply(this.r,math.sin(this.s));
  }
}
class Cloth {
  constructor(n,d,e) {
    this.n = n;
    this.d = d;
    this.e = e;
    this.dt = [];
    for (let i = 0; i < this.n; i++) {
      this.dt[i] = [];
      for (let j = 0; j < this.n; j++) {
        this.dt[i][j] = {
          p: [i / n,j / n,0],v: [0,0]
        };
      }
    }
  }
  tck() {
    for (let i = 0; i < this.n; i++) {
      for (let j = 0; j < this.n; j++) {
        if ((i == 0 || i == this.n - 1) && (j == 0 || j == this.n - 1)) {
          continue;
        }
        let nbh = [];
        if (0 < i) {
          nbh.push(this.dt[i - 1][j]);
        }
        if (0 < j) {
          nbh.push(this.dt[i][j - 1]);
        }
        if (j < this.n - 1) {
          nbh.push(this.dt[i][j + 1]);
        }
        if (i < this.n - 1) {
          nbh.push(this.dt[i + 1][j]);
        }
        this.dt[i][j].v = math.multiply(this.d,this.dt[i][j].v);
        for (let nb of nbh) {
          this.dt[i][j].v = math.add(
            this.dt[i][j].v,math.multiply(
              this.e,math.distance(nb.p,this.dt[i][j].p) - 1 / this.n,math.subtract(nb.p,this.dt[i][j].p)
            )
          );
        }
      }
    }
    for (let i = 0; i < this.n; i++) {
      for (let j = 0; j < this.n; j++) {
        if ((i == 0 || i == this.n - 1) && (j == 0 || j == this.n - 1)) {
          continue;
        }
        this.dt[i][j].p = math.add(this.dt[i][j].p,this.dt[i][j].v);
      }
    }
  }
  drw(ctx,bs,ds) {
    ctx.beginPath();
    for (let i = 0; i < this.n; i++) {
      for (let j = 0; j < this.n; j++) {
        if (i < this.n - 1) {
          ctx.moveto(
            bs + ds * this.dt[i][j].p[0],bs + ds * this.dt[i][j].p[1]
          );
          ctx.lineto(
            bs + ds * this.dt[i + 1][j].p[0],bs + ds * this.dt[i + 1][j].p[1]
          );
          ctx.stroke();
        }
        if (j < this.n - 1) {
          ctx.beginPath();
          ctx.moveto(
            bs + ds * this.dt[i][j].p[0],bs + ds * this.dt[i][j].p[1]
          );
          ctx.lineto(
            bs + ds * this.dt[i][j + 1].p[0],bs + ds * this.dt[i][j + 1].p[1]
          );
          ctx.stroke();
        }
      }
    }
  }
}
cloth = new Cloth(20,0.99,5);
phase = [...Array(4)].map(() => new Phase(0.02,0.2,0.001));
cntxt = document.createElement("canvas").getContext("2d");
cntxt.canvas.width = 500;
cntxt.canvas.height = 500;
document.body.append(cntxt.canvas);
(function f() {
  cloth.dt[0][0].p = phase[0].o;
  cloth.dt[0][cloth.n - 1].p = math.add([0,1,phase[1].o);
  cloth.dt[cloth.n - 1][0].p = math.add([1,phase[2].o);
  cloth.dt[cloth.n - 1][cloth.n - 1].p = math.add([1,phase[3].o);
  cntxt.clearRect(0,500,500);
  cloth.drw(cntxt,50,400);
  cloth.tck();
  for (ph of phase) {
    ph.tck();
  }
  window.requestAnimationFrame(f);
})()
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/9.3.0/math.js"></script>

快速度的两个明显途径是 WASM 和 WebGL(例如通过 GPU.js)。我从未尝试过 WASM 并且在 WebGL 方面有一些经验,但不是用于通用计算。因此,在我尝试其中之一之前,最终哪个会让我获得最快的结果?

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。