Масштабирование пользовательского матричного класса по вектору

Я ужасно разбираюсь в матричной математике, но у меня есть ситуация, когда мне нужно ее масштабировать. Матрица является экземпляром пользовательского класса, определенного здесь, а мой объект масштабирования — это вектор, содержащий 3 числа с плавающей запятой (x, y, z). Мне нужен фактический код, который мне нужен, а не общее объяснение, потому что я уже пошел по этому пути и просто не понимаю задействованной математики. К счастью, то, что я пытаюсь сделать, достаточно тривиально, когда я могу масштабировать матрицу.

Чтобы уточнить, вот код, который я обновляю. Он перебирает иерархию связанных объектов с относительными преобразованиями и обновляет mat& до абсолютного преобразования:

void LocalModelPiece::GetPiecePosIter(CMatrix44f* mat) const
{
if (parent) {
    parent->GetPiecePosIter(mat);
}

if (pos.x || pos.y || pos.z) { mat->Translate(pos.x, pos.y, pos.z); }
// --> My problem is here. There is no Scale() method, I need one. <--
if (scale.x!=1.0f || scale.y!=1.0f || scale.z!=1.0f) { mat->Scale(scale.x, scale.y, scale.z); }
if (rot[1]) { mat->RotateY(-rot[1]); }
if (rot[0]) { mat->RotateX(-rot[0]); }
if (rot[2]) { mat->RotateZ(-rot[2]); }

}


person SpliFF    schedule 28.11.2010    source источник
comment
Я... просто не понимаю математики - Ну, это твоя проблема. Как вы можете начать реализовывать то, чего не понимаете?   -  person In silico    schedule 28.11.2010
comment
Я уже сделал реализацию, и она находится поверх класса, который обрабатывает математику. Это ничем не отличается от ссылок на библиотеки. Я концептуально понимаю, что масштабирование делает с моим объектом, поэтому мне не нужно знать все тонкости реализации, за исключением одного случая, когда реализация отсутствует.   -  person SpliFF    schedule 28.11.2010


Ответы (2)


Я посмотрел на предоставленную вами ссылку API и, исходя из этого, я бы реализовал метод масштабирования для матричного класса, чтобы он соответствовал существующим методам Translate() и Rotate(). То есть он выполняет правостороннее умножение с масштабирующей матрицей.

Хотя лично я нахожу это немного странным, потому что API использует матрицы в стиле OpenGL. Это означает, что правостороннее умножение применяет новое преобразование до всех других преобразований, существующих в матрице, тогда как левостороннее умножение применяет его после других преобразований. Так что я не уверен, что это то, что вы хотите здесь. Возможно, вам придется выполнить все преобразования в обратном порядке или самостоятельно выполнить левостороннее умножение.

void CMatrix44f::Scale(float scalex, float scaley, float scaley) 
{
  /* the function should be equivalent to doing this:
  CMatrix44f scalemat;
  scalemat[0] = scalex;
  scalemat[5] = scaley;
  scalemat[10] = scalez;
  *this = Mul(scalemat);
  */

  m[0] *= scalex;
  m[1] *= scalex;
  m[2] *= scalex;
  m[3] *= scalex;

  m[4] *= scaley;
  m[5] *= scaley;
  m[6] *= scaley;
  m[7] *= scaley;

  m[8] *= scalez;
  m[9] *= scalez;
  m[10] *= scalez;
  m[11] *= scalez;
}
person Timo    schedule 28.11.2010
comment
Я не смог проверить это, так как было принято решение избегать масштабирования по разным причинам производительности. Я приму это на веру, хотя, и это может быть использовано позже. Спасибо за ваш ответ. - person SpliFF; 13.12.2010

Мне непонятно, что вы хотите масштабировать. Это сама матрица или вы собираетесь использовать ее для масштабирования другого вектора?

Если вы говорите о векторе в трехмерном пространстве, я не понимаю, как матрица 4x4 может быть тем, что вы хотите. Масштабирование вектора в трехмерном пространстве с использованием матрицы означало бы размещение коэффициентов масштабирования по диагонали матрицы; внедиагональные элементы равны нулю.

Вы меня путаете, когда ссылаетесь на матрицу 4х4. Вы уверены, что это то, что вы хотите?

Я думаю, вы хотите этого:

альтернативный текст

Вот некоторый псевдокод, чтобы показать, как это делается:

for (int i = 0; i < 3; ++i)
{
    v_prime[i] = c[i]*v[i];
}

Если вы хотите масштабировать матрицу 3x3, это будет выглядеть так:

альтернативный текст

Вот некоторый псевдокод, чтобы показать, как это делается:

for (int i = 0; i < 3; ++i)
{
    for (int j = 0; j < 3; ++j)
    {
        m_prime[i][j] = c[i]*m[i][j];
    }
}

Обратите внимание, что оба эти решения следуют из вашего утверждения о том, что ваш вектор масштабирования состоит из трех компонентов. Если это не так, все ставки сняты.

person duffymo    schedule 28.11.2010
comment
Идея состоит в том, чтобы найти положение дочернего объекта, перебирая относительные матричные преобразования его предков. Текущий код переводит/вращает каждую итерацию, но полностью игнорирует масштабирование. Мне нужна матрица для учета масштаба каждого объекта в иерархии. - person SpliFF; 28.11.2010