0

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

class Phase {
  constructor(r, bf, ns) {
    this.r = r;
    this.bf = bf;
    this.ns = ns;
    this.s = math.random([4], 0, 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], 0, 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, 0],
          v: [0, 0, 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, 0, 0], phase[1].o);
  cloth.dt[cloth.n - 1][0].p = math.add([1, 0, 0, 0], phase[2].o);
  cloth.dt[cloth.n - 1][cloth.n - 1].p = math.add([1, 1, 0, 0], phase[3].o);
  cntxt.clearRect(0, 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 方面有一些经验,但不适用于通用计算。所以在我开始研究其中之一之前,最终哪一个能让我获得最快的结果?

4

0 回答 0