你应该如何进行矩阵变换?

How should you do matrix transformations?

我们正在渲染一个带火焰的等距网格,其中每个图块都是一个组件,但我们在 Transform2D 的源代码中找到了这条评论

The returned matrix must not be modified by the user.

  /// The total transformation matrix for the component. This matrix combines
  /// translation, rotation, reflection and scale transforms into a single
  /// entity. The matrix is cached and gets recalculated only as necessary.
  ///
  /// The returned matrix must not be modified by the user.
  Matrix4 get transformMatrix {
    if (_recalculate) {
      // The transforms below are equivalent to:
      //   _transformMatrix = Matrix4.identity()
      //       .. translate(_position.x, _position.y)
      //       .. rotateZ(_angle)
      //       .. scale(_scale.x, _scale.y, 1)
      //       .. translate(_offset.x, _offset.y);
      final m = _transformMatrix.storage;
      final cosA = math.cos(_angle);
      final sinA = math.sin(_angle);
      m[0] = cosA * _scale.x;
      m[1] = sinA * _scale.x;
      m[4] = -sinA * _scale.y;
      m[5] = cosA * _scale.y;
      m[12] = _position.x + m[0] * _offset.x + m[4] * _offset.y;
      m[13] = _position.y + m[1] * _offset.x + m[5] * _offset.y;
      _recalculate = false;
    }
    return _transformMatrix;
  }

它似乎确实有效,所有图块都是它自己的组件,其中每个组件只呈现一个彩色矩形。 (Matrix4.isometric() 是我们的扩展)。

IsometricGrid 扩展了 PositionComponent

IsometricGrid({
    this.tiles = const [],
    this.rows = 1,
    this.columns = 1,
    this.tileWidth = 1,
    this.tileHeight = 1,
  }) : super() {
    final isometricMatrix = Matrix4.isometric();
    transformMatrix.multiply(isometricMatrix);
    projectionMatrix = isometricMatrix;
    inverseProjectionMatrix = Matrix4.inverted(projectionMatrix);
  }

然后我们得到

但我们后来想用IsometricGrid.addActor

向网格添加一个演员
  addActor(PositionComponent actor) {
    actor.transform.transformMatrix.multiply(inverseProjectionMatrix);
    add(actor);
  }

广告中的角色正对着网格站着。但是一旦我们通过改变它的位置将演员移动到第 2 列第 3 行,矩阵似乎为演员重置了。

在火焰引擎中修改矩阵变换的惯用方法是什么?似乎在某些情况下矩阵只是重置。我认为发生这种情况是因为它只是在您进行旋转、位置或缩放等变换时重新计算矩阵。

我们正在使用 flutter web 构建它,我们还注意到有时当 alt tab 时矩阵会被重置。

您是正确的,Transform2D 不允许这些类型的“顶部附加变换”——主要是因为变换矩阵在任何底层 属性 发生变化时都会重新计算。但是,您可以创建派生的 class,覆盖 transformMatrix getter,以便应用其他转换。

我不确定在 Flame 中实现等距游戏的最佳方法是什么,但您可以尝试以下方法:

[World]
 +--[Ground]
 |   +--[Tile]s
 |
 +--[Overground]
     +--[Character]
     +--[Enemy]s
     +--[Structure]s
     +--...

在这里,Ground 将是一个在渲染其 children Tile 之前应用等距投影的组件(这只是常规的 PositionComponents)。因此,无需乘以变换矩阵:您只是应用了一个额外的 canvas 变换。

Overground 组件有点棘手。它有很多children,每个都是一个规则的PositionComponent,在世界坐标中给出了(x, y)的位置。 Overground 的工作是将等距投影应用于该位置,将其转​​换为屏幕坐标,然后在渲染每个组件之前相应地平移 canvas。此外,Overground 需要根据他们与相机的距离不断 re-sort children。