组合矩阵变换

Combine matrix transformations

我想将两个矩阵的变换合并为一个。我有一个包含不同形状的场景——矩形、圆形……它有自己的矩阵,其中包含所有变换:旋转、缩放、平移。当我对场景应用变换时,场景内的所有元素都将得到该变换。使用此 code from this repository that is used to apply transformation using finger gestures. Those image and shapes are generated with OpenGL GLES2 using this library 效果很好。我没有提供完整的源代码,因为问题来自下面讨论的矩阵顺序。

但我希望某些形状具有单独的矩阵和变换,形状从它们的特定矩阵和场景的变换中获得变换。这意味着我需要结合两个矩阵的变换并将其用于该形状。

假设场景有矩阵m1,图像(狮子图像)有矩阵m2,那么我需要结合这两个矩阵的变换。我已经尝试使用 preConcat,并首先应用场景中的变换,然后将它们应用于形状。

var m = Matrix()
m.preConcat(m1)
m.preConcat(m2)

然后将矩阵 m 的变换应用于形状,这样它就可以接收来自两个矩阵的组合变换。当场景的转换发生变化时,这很有效。因此,当我缩放、旋转、平移整个场景时,所有形状都会成功地接收到来自两个矩阵的变换。

更改应用于所有形状的整个场景的变换(工作!)


但是当我尝试使用相同的代码仅更改该特定形状的转换时,问题就来了。当我尝试转换时遇到问题,并且旋转和缩放的轴心点更改为屏幕中心,而不是它应该如何并且轴心点应与两个手指之间的中心匹配。三角形内的圆与屏幕的中间相匹配,因此一旦图像的中心与屏幕的中心相匹配,它就会在该点旋转。重要的是要说图像的开始被认为是该图像的中心,而不是图像的左上角。

仅更改图像的变换 (不工作!)




切换顺序

我试过切换连接矩阵的顺序,换句话说,我首先对形状矩阵应用变换 m2 和然后那些来自整个场景的矩阵保持变换 m1.

var m = Matrix()
m.preConcat(m2)
m.preConcat(m1)

但现在情况正好相反,它在更改形状的变换时开始正常工作,但在更改整个场景的变换时不起作用。

正在更改应用于所有形状的整个场景的变换 (不起作用!)

仅更改图像的变换 (有效!)




根据我们要更改的矩阵变换使用不同的顺序

我尝试过在连接矩阵时使用不同的顺序。顺序为m1 -> m2 m2 -> m1 图片。

// use when transforming the scene
var m = Matrix()
m.preConcat(m1)
m.preConcat(m2)

// used when transforming the image
var m = Matrix()
m.preConcat(m2)
m.preConcat(m1)

现在有点用了,唯一的问题是当我切换矩阵的顺序时,我得到了一个令人讨厌的转换,因为它可以在 6-7 秒处看到。但除此之外,它还有效!

所以有几个问题:

  1. 当改变矩阵的顺序 m1m2 时,导致这种转换的原因是什么?
  2. 有没有办法解决翻译的问题?
  3. 为什么需要改变矩阵的顺序?

我想出了一个绝妙的解决方案,而不是使用 m1 作为将用于所有形状的场景的矩阵并使用 m2 作为图像(狮子图像)的矩阵,然后结合这两个矩阵的变换。

我所做的是为每一层使用单独的矩阵,所以现在 m1 成为(三角形,直线,圆圈)的矩阵,而 m2 保留用于图像。


现在,当我想一次只转换一层时,当调用 onTouch() 方法时,我们会为该特定矩阵应用转换。因此,如果我只想将变换应用于图像层,我仅通过 OpenGLMatrixGestureDetector 将它们应用于 m2 矩阵,如果我只想将它们应用于形状(三角形、线条、圆圈),然后我仅将变换设置为 m1 矩阵。


所以最好的部分是当我想将转换应用于两个图层(形状和图像)时该怎么做。好吧,当调用 onTouch() 事件时,我将转换应用于两个矩阵,就好像我们一次 select 一层,然后应用转换,然后 select 下一层并应用相同的转换。 这样我们就可以通过 OpenGLMatrixGestureDetector 对每个矩阵应用相同的变换,这样我们就可以更新两个矩阵。

很酷的是,我们可以使用 Undo/Redo 逻辑,通过在每个转换后的会话后收集矩阵值的转换。当我们需要还原它们时,只需设置之前存储的矩阵值即可。

结论: 对每一层使用单独的矩阵(OpenGLMatrixGestureDetector)。要一次将转换应用于一层,请在 onTouch() 中使用与我们要转换的特定层对应的手势检测器。要将转换应用于多个图层,请使用具有相同 onTouch() 事件的所有手势检测器。