Я новичок в 3D-графике, поэтому полагаю, что сделал что-то в корне неправильно. Я построил 4 матрицы для обработки моих объектов в трехмерном пространстве: матрицу масштабирования, матрицу перевода, матрицу перспективы и матрицу вращения.
Матрица вращения и масштабирования работают нормально, однако мои матрицы перспективы и перевода ведут себя не так, как ожидалось, из того, что я понимаю, матрицы перевода и перспективы выглядят так:
Translation Perspective
[1, 0, 0, x] [1, 0, 0 , 0]
[0, 1, 0, y] [0, 1, 0 , 1]
[0, 0, 1, z] [0, 0, 1 , 0]
[0, 0, 0, 1] [0, 0, 1/D, 1]
Чтобы понять, как все работает за кулисами, я пишу свою собственную библиотеку Math - для создания определенных выше матриц у меня есть следующие методы:
public static ASMATRIX4 CreatePerspectiveMatrix(double focalLength)
{
// Create matrix as an identity matrix
var m = new ASMATRIX4();
// Set the perspective matrix
m.Matrix[3].Points[2] = 1 / focalLength;
m.Matrix[1].Points[3] = 1;
return m;
}
public static ASMATRIX4 CreateTranslationMatrix(double x, double y, double z)
{
// reset to identity matrix
var m = new ASMATRIX4();
// Set the translation matrix
m.Matrix[0].Points[3] = x;
m.Matrix[1].Points[3] = y;
m.Matrix[2].Points[3] = z;
return m;
}
Ничего особенного, но когда я умножаю свои матрицы вместе, ничего не происходит - я могу вращаться вокруг любой оси, но не могу переводить. Также обратите внимание, что new ASMATRIX4()
инициализирует новую матрицу 4x4 как единичную матрицу.
Чтобы перемножить свои матрицы, я делаю следующее:
m_scaling = ASMATRIX4.CreateScalingMatrix(s, s, s);
m_translation = ASMATRIX4.CreateTranslationMatrix(tX, tY, tZ);
m_perspective = ASMATRIX4.CreatePerspectiveMatrix(f);
m_rotation = ASMATRIX4.RotateByDegrees(rX, rY, rZ);
var transformationMatrix = m_scaling*m_translation*m_perspective*m_rotation;
Я также написал перегрузку оператора для совместной обработки умножаемых матриц:
public static ASMATRIX4 operator *(ASMATRIX4 mA, ASMATRIX4 mB)
{
// Creates a new identity matrix
var m = new ASMATRIX4();
// Multiply the two matrixes together and return the output matrix
for (var i = 0; i < 4; i++)
{
for (var j = 0; j < 4; j++)
{
m.Matrix[i].Points[j] =
(mB.Matrix[i].Points[0]*mA.Matrix[0].Points[j]) +
(mB.Matrix[i].Points[1]*mA.Matrix[1].Points[j]) +
(mB.Matrix[i].Points[2]*mA.Matrix[2].Points[j]) +
(mB.Matrix[i].Points[3]*mA.Matrix[3].Points[j])
}
}
return m;
}
Наконец, чтобы действительно преобразовать мою сетку, у меня есть массив Faces, которые я рисую в контексте 2D-рендеринга, метод ниже преобразует каждое лицо с помощью матрицы преобразования, определенной выше.
private void TransformMesh()
{
var transformationMatrix = m_scaling*m_translation*m_perspective*m_rotation;
for (var i = 0; i < m_numFaces; i++)
{
m_meshData[i] = m_meshData[i].TransformFace(transformationMatrix);
}
}
Метод TransformFace
выглядит так, как описано ниже:
public ASFace TransformFace(ASMATRIX4 matrix)
{
var transformedFace = new ASFace();
for (var i = 0; i < 3; i++)
{
transformedFace.m_points[i] = m_points[i].TransformVector(matrix);
transformedFace.m_points[i] = transformedFace.m_points[i].Rescale();
}
return transformedFace;
}
Этот первый метод в цикле преобразует однородную точку с помощью входной матрицы, а затем вызывается метод масштабирования для нормализации вектора.
Я не понимаю, что я сделал не так? Я думаю, что порядок операций по умножению матриц может быть неправильным, но я не слишком уверен, любые предложения будут приняты с благодарностью.