【问题标题】:Multiplying css matrices causes animation to accelerate将css矩阵相乘会导致动画加速
【发布时间】:2016-07-06 01:24:06
【问题描述】:

我有两个 css 3d 矩阵,我在每一帧上相乘,将结果存储在一个新数组中,并使用该新数组更新我的 div 的 css3 矩阵变换。它现在终于起作用了,但不幸的是我得到了一些意想不到的行为。由于将它们相乘,它实际上在每一帧上都加速了。因此,最后一次矩阵乘法的乘积再次与另一个矩阵相乘,依此类推。

我能做些什么来解决这个问题?

https://jsfiddle.net/testopia/qjfz17g3/15/

var elem = document.getElementsByTagName("div")[0];
var inc = 0;

var matrix = [3, 0, 0, 0,
                            0, 3, 0, 0,
              0, 0, 3, 0,
              0, 0, 0, 1];

var matrixLength = matrix.length;
var request = null;
var product = [];

function rotateX() {
  let deg = inc * (180 / Math.PI);

  let cos = Math.cos(inc);
  let sin = Math.sin(inc);

    let x = [1, 0, 0, 0,
           0, cos, -sin, 0,
           0, sin, cos, 0,
           0, 0, 0, 1];

  dot(x, matrix);
    applyTransform();
    updateMatrix();
  product = [];
}

function updateMatrix() {
  var str = elem.style.transform,
      stripped = str.substring(str.indexOf("(") + 1, str.length - 1);

  matrix = stripped.split(", ");

  for (let i = 0; i < matrixLength; i++) {
    matrix[i] = parseFloat(matrix[i]);
  }
}

function applyTransform() {
        elem.style.transform = `matrix3d(${product[0]}, ${product[1]}, ${product[2]}, ${product[3]}, ${product[4]}, ${product[5]}, ${product[6]}, ${product[7]}, ${product[8]}, ${product[9]}, ${product[10]}, ${product[11]}, ${product[12]}, ${product[13]}, ${product[14]}, ${product[15]})`;
}

function init() {
        rotateX();
    inc += 0.01;
    requestAnimationFrame(init);
}
init();

function dot(rows, columns) {
  product.push((rows[0] * columns[0]) + (rows[1] * columns[4]) + (rows[2] * columns[8]) + (rows[3] * columns[12]))
  product.push((rows[0] * columns[1]) + (rows[1] * columns[5]) + (rows[2] * columns[9]) + (rows[3] * columns[13]))
  product.push((rows[0] * columns[2]) + (rows[1] * columns[6]) + (rows[2] * columns[10]) + (rows[3] * columns[14]))
  product.push((rows[0] * columns[3]) + (rows[1] * columns[7]) + (rows[2] * columns[11]) + (rows[3] * columns[15]))

  product.push((rows[4] * columns[0]) + (rows[5] * columns[4]) + (rows[6] * columns[8]) + (rows[7] * columns[12]))
  product.push((rows[4] * columns[1]) + (rows[5] * columns[5]) + (rows[6] * columns[9]) + (rows[7] * columns[13]))
  product.push((rows[4] * columns[2]) + (rows[5] * columns[6]) + (rows[6] * columns[10]) + (rows[7] * columns[14]))
  product.push((rows[4] * columns[3]) + (rows[5] * columns[7]) + (rows[6] * columns[11]) + (rows[7] * columns[15]))

  product.push((rows[8] * columns[0]) + (rows[9] * columns[4]) + (rows[10] * columns[8]) + (rows[11] * columns[12]))
  product.push((rows[8] * columns[1]) + (rows[9] * columns[5]) + (rows[10] * columns[9]) + (rows[11] * columns[13]))
  product.push((rows[8] * columns[2]) + (rows[9] * columns[6]) + (rows[10] * columns[10]) + (rows[11] * columns[14]))
  product.push((rows[8] * columns[3]) + (rows[9] * columns[7]) + (rows[10] * columns[11]) + (rows[11] * columns[15]))

  product.push((rows[12] * columns[0]) + (rows[13] * columns[4]) + (rows[14] * columns[8]) + (rows[15] * columns[12]))
  product.push((rows[12] * columns[1]) + (rows[13] * columns[5]) + (rows[14] * columns[9]) + (rows[15] * columns[13]))
  product.push((rows[12] * columns[2]) + (rows[13] * columns[6]) + (rows[14] * columns[10]) + (rows[15] * columns[14]))
  product.push((rows[12] * columns[3]) + (rows[13] * columns[7]) + (rows[14] * columns[11]) + (rows[15] * columns[15]))
}

【问题讨论】:

    标签: javascript matrix 3d css-transforms


    【解决方案1】:

    这是因为每一帧您都在增加 init 函数内的 inc 变量,所以每一帧您都在增加每帧旋转的旋转量。在每一帧上,您都从 style 属性中获取当前矩阵,该属性已经包含了先前的旋转,然后您正在递增 inc,因此您在矩阵中存储了一个增量,并且您也在将增量存储在inc 中,因此您可以有效地将每帧的增量加倍。

    相反,您可以保持inc 不变,不要增加它,这样就可以了。

    例如,这是一个 JSBin:http://jsbin.com/doyadakado/edit?html,css,js,output

    【讨论】:

    • 请问,如果我想要多个转换怎么办? jsfiddle.net/testopia/qjfz17g3/28
    • 如果你想应用多个东西(例如两个轴上的旋转)也许更容易进行一次变换,那么只需首先计算两个旋转,然后将两者应用到单个矩阵。这是我作为 DOMMatrix polyfill 的一部分编写的函数:github.com/trusktr/geometry-interfaces/blob/master/src/…。前三个参数用于定义向量的方向,第四个参数是您希望围绕该向量应用的旋转。
    • 我正在使用如下函数对每个轴应用旋转:github.com/infamous/infamous/blob/master/src/motor/… 基本上,您会看到我为每个轴应用旋转。它被应用于单个矩阵。作为参考,您可以查看我用来实现 polyfill 的几何接口规范版本 1(需要更新到最新的编辑草稿)。因此,在您的情况下,我建议将旋转应用于单个矩阵。
    • 啊,看来您正在尝试将结果应用于单个矩阵,并在product 数组中累积。但是,我想我看到了一个错误:您将结果推送到 product 数组,所以您最终得到一个长度为 32 的数组。前 16 个值来自第一个 dot() 调用,接下来的 16 个值是从第二个dot().
    • 给你,对dot()函数及其用法进行小修改,现在可以使用:jsfiddle.net/qjfz17g3/33
    【解决方案2】:

    一般而言,您不应该使用矩阵来存储对象状态并逐帧相乘,因为您会遇到浮点精度问题,并且您的矩阵可能会在多次乘法后中断。正交轴将不再正交,它们的长度可能会改变。

    只需将缩放和旋转存储为浮点数,每帧修改这些浮点数,然后每帧从它们构建最终矩阵。

    这可能无法解决您的确切问题,但我相信从长远来看它会对您有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-24
      • 2016-12-11
      • 1970-01-01
      • 2022-06-30
      • 2021-12-04
      相关资源
      最近更新 更多