Android: Matrix -> в чем разница между preconcat и postconcat? - PullRequest
44 голосов
/ 04 октября 2010

Я использую Матрица для масштабирования и поворота растровых изображений. Теперь мне интересно, в чем разница между preconcat и postconcat, а точнее разница между:

Из того, что я мог выяснить до сих пор, setRotate всегда перезаписывает всю матрицу, в то время как с помощью preRotate и postRotate я могу применить к матрице несколько изменений (например, масштабирование + вращение). Однако использование postRotate или preRotate не привело к каким-либо другим результатам для случаев, в которых я их использовал.

Ответы [ 2 ]

129 голосов
/ 26 февраля 2011

Ответ на ваш вопрос не совсем специфичен для Android;это графика и математический вопрос.В этом ответе много теории - вас предупредили!Для поверхностного ответа на ваш вопрос, перейдите к основанию.Кроме того, поскольку это такая многословная тирада, у меня может быть опечатка или две, которые неясно.Заранее извиняюсь, если это так.

В компьютерной графике мы можем представлять пиксели (или в 3D, вершины) как векторы.Если ваш экран имеет размер 640x480, вот двухмерный вектор для точки в середине экрана (простите за мою дрянную разметку):

[320]
[240]
[  1]

Я объясню, почему 1 важна позже.Преобразования часто представлены с использованием матриц , потому что тогда очень просто (и очень эффективно) связать их вместе, как вы упомянули.Чтобы увеличить вышеупомянутую точку с коэффициентом 1,5, вы можете умножить ее влево на следующую матрицу:

[1.5   0   0]
[  0 1.5   0]
[  0   0   1]

Вы получите эту новую точку:

[480]
[360]
[  1]

Который представляет исходную точку, масштабированную на 1,5 относительно угла вашего экрана (0, 0).Это важно: масштабирование всегда выполняется с учетом происхождения.Если вы хотите масштабировать с какой-то другой точкой в ​​качестве вашего центра (например, серединой спрайта), вам нужно «обернуть» шкалу в переводах в и из начала координат.Вот матрица для перевода нашей исходной точки в начало координат:

[1  0  -320]
[0  1  -240]
[0  0     1]

, что приводит к:

[320*1 + 1*-320]   [0]
[240*1 + 1*-240] = [0]
[     1*1      ]   [1]

Вы узнаете вышеуказанное как матрицу identity скоординаты смещения хлопали в правом верхнем углу.Вот почему 1 («однородная координата») необходима: чтобы освободить место для этих координат, что позволило бы выполнить перевод с использованием умножения.В противном случае это должно было бы быть представлено сложением матриц, которое является более интуитивным для человека, но сделало бы видеокарты еще более сложными, чем они уже есть.

Теперь умножение матриц в целом не является коммутативным , поэтому при «добавлении» преобразования (путем умножения вашей матрицы) вам необходимо указать, умножаете ли вы влево или умножаете вправо.Разница заключается в том, в каком порядке преобразуются цепочки ваших преобразований. Умножая вправо матрицу (используя preRotate()), вы указываете, что шаг поворота должен произойти за до всех остальных преобразований, которые вы используете.только что попросил.Это может быть то, что вы хотите, но обычно это не так.

Часто это не имеет значения.Например, если у вас есть только одно преобразование, это никогда не имеет значения :) Иногда ваши преобразования могут происходить в любом порядке с одинаковым эффектом, таким как масштабирование и вращение - моя линейная алгебра ржавая, но я считаю, что в этом случаеУмножение матриц на самом деле является коммутативным, потому что масштабная матрица симметрична , то есть она отражает себя по диагонали.Но на самом деле, просто подумайте: если я поверну какое-нибудь изображение на 10 градусов по часовой стрелке, а затем масштабирую его до 200%, оно будет выглядеть так же, как если бы я сначала масштабировало его, а затем повернуло его.более странные сложные преобразования, вы начнете замечать расхождения.Мой совет: придерживайтесь postRotate().

4 голосов
/ 18 сентября 2012

Я ответил на вопрос вчера ,, но сегодня я чувствую что-то не так, поэтому я исправляю ответ здесь:

matrix:  float[] values ={1.2f,0.5f,30,0.5f,1.2f,30,0,0,1};

//as we all know, the basic value in matrix,means no transformation added
matrix2:  float[] values2 ={1f,0,0,0,1f,0,0,0,1};

Let's say our matrix values are the values above.

1 、, когда мы выполняем преобразование, как показано ниже:

matrix.preTranslate(-50, -50);

is equals to do sequence transformation to matrix2 above like below:

matrix2.postTranslate(-50, -50);
matrix2.postSkew(0.5f/1.2f,0.5f/1.2f);// note here
matrix2.postScale(1.2f, 1.2f);
matrix2.postTranslate(30, 30);

2 、 когда мы делаем преобразование, как показано ниже:

matrix.preRotate(50);

is equals to do sequence transformation to matrix2 like below:

matrix2.postRotate(50);
matrix2.postSkew(0.5f/1.2f,0.5f/1.2f);
matrix2.postScale(1.2f, 1.2f);
matrix2.postTranslate(30, 30);

3 、, когда мы делаем преобразование, как показано ниже:

matrix.preScale(1.3f,1.3f);

is equals to do sequence transformation to matrix2 like below:

matrix2.postScale(1.3f,1.3f);
matrix2.postSkew(0.5f/1.2f,0.5f/1.2f);
matrix2.postScale(1.2f, 1.2f);
matrix2.postTranslate(30, 30);

4 、, когда мы выполняем преобразование, как показано ниже:

 matrix.preSkew(0.4f,0.4f);

равно преобразованию последовательности в matrix2, как показано ниже:

 matrix2.postSkew(0.4f,0.4f);
 matrix2.postSkew(0.5f/1.2f,0.5f/1.2f);
 matrix2.postScale(1.2f, 1.2f);
 matrix2.postTranslate(30, 30);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...