Эксперименты с матрицей Вида
Загрузить архив с примерами ЗДЕСЬ.
Я вынес в отдельный проект расчет матрицы Вида и теперь мы можем немного поэкспериментировать, что бы наглядно показать, что матрица Вида делает с вершиной. Пусть у нас есть вершина:
vector3 vert = { 0.0f, 0.0f, 2.0f };
Так же пусть у нас есть позиция камеры на сцене, правый вектор vRight и вектор взгляда vLook (см.функцию Get_View_Matrix()):
vector3 vPos = { 0.0f, 5.0f, -15.0f }; vector3 vRight = { 1.0f, 0.0f, 0.0f }; vector3 vLook = { 0, 0, 1.0f};
То есть мы разместили камеру на -15.0f по оси Z. Теперь поставим точку останова строке кода в функции main():
//тут ставим точку останова return 0;
И запускаем проект на выполнение. После того как отладчик остановится на строке return 0; мы можем посмотреть что значение v равно:
//результат работы программы v.z = 17.0f v = { 0.0f, -5.0f, 17.0f };
Как видим v.z = 17.0f при исходных данных vPos.z = -15, vector3 vRight = { 1.0f, 0.0f, 0.0f }; и vLook = { 0.0f, 0.0f, 1.0f };.
Теперь давайт поменяем исходные данные и размесим камеру на +15 по оси Z:
vector3 vPos = { 0.0f, 5.0f, 15.0f }; //инвертируем vRight так как камера смотрит Z = -1 vector3 vRight = { -1.0f, 0.0f, 0.0f }; vector3 vLook = { 0.0f, 0.0f, -1.0f };
В результате мы получим v.z:
//результат работы программы v.z = 13.0f; v.z = { 0.0f, 5.0f, 13.0f };
Как мы можем видеть у нас точка в позиции Z = 2.0f, в первом случае камера была в позиции Z = -15.0f и в результате мы получили значение вектора Z = 17.0f. Во втором случаем камера была в позиции Z = 15.0f и в результате мы получили значение вектора Z = 13.0f. О чем это говорит? Что после умножения на матрицу Вида исходная вершина переходит в новую систему координат, видовую координатную систему. Все что видит камера перед собой - имеет положительную координату. Все что находится за камерой - имеет отрицательную координату, мы этих объектов не видим. Центр новой координатной системы находится в том месте где расположена камера. Но игрок может перемещать камеру в процессе игры при помощи клавишь клавиатуры, тогда центр сцены смещается вместе в камерой и центр сцены находится в месте где расположена камера в данный момент.
Давайте посчитаем отдельно компоненту Z вектора при умножении на матрицу Вида. Пусть есть такие исходные данные:
//пример 1 vert.z = 2.0f; vPos.z = -15.0f; vLook.z = 1.0f; //пример 2 vert.z = 2.0f; vPos.z = 15.0f; vLook.z = -1.0f;
Тогда мы получим такой расчет согласно тому как вектор умножается на матрицу Вида, но мы будем расчитывать только компоненту Z:
//пример 1 исходные данные vert.z = 2.0f; vPos.z = -15.0f vLook.z = 1.0f; float zp = - Vec3_Dot(vPos, vLook); zp = -(vPos.z * vLook.z) = 15.0f; //результат v.z Z = vert.z * vLook.z + vPos.z = 2.0f * 1.0f + 15.0f = 17.0f; //пример 2 исходные данные vert.z = 2.0f; vPos.z = 15.0f vLook.z = -1.0f; float zp = - Vec3_Dot(vPos, vLook); zp = -(vPos.z * vLook.z) = 15.0f; //результат v.z Z = vert.z * vLook.z + vPos.z = 2.0f * (-1.0f) + 15.0f = 13.0f;
Так же предположим вершина у нас имеет y = 0 в мировом пространстве. А камера у нас расположена на y = +5 в мировом пространстве. Тогда после умножения на матрицу вида вершина в видовом пространстве будет иметь координату y = -5, потому что камера возвышается над вершиной (при условии что vector3 vLook = { 0, 0, 1.0f}; и vRight = { 1.0f, 0.0f, 0.0f };). Попробуйте сами поэкспериментировать с кодом примера. Но только помните если вы меняете направление камеры vLook.z = -1 то надо менять правый вектор vRight = { -1.0f, 0.0f, 0.0f };
Загрузить проект /src/01.001-soft_rend_main/mxView_Experiments_1.
Второй пример показывает как меняется матрица Вида при повороте VecRight, VecUp, VecLook на 90 градусов. Загрузить проект /src/01.001-soft_rend_main/mxView_Experiments_2.
Код первого примера mxView_Experiments_1 ниже.
#include <windows.h> #include <math.h> struct vector3 { float x,y,z; }; typedef float matrix4x4[4][4]; float Vec3_Dot(vector3 v1, vector3 v2) { return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; } //нормализация вектора- приведение к единичной длинне vector3 Vec3_Normalize(vector3 v) { float len = sqrtf((v.x * v.x) + (v.y * v.y) + (v.z * v.z)); vector3 t = { v.x / len, v.y / len, v.z / len }; return t; } //векторное произведение векторов vector3 Vec3_Cross(vector3 v1, vector3 v2) { vector3 t = { v1.y * v2.z - v1.z * v2.y, v1.z * v2.x - v1.x * v2.z, v1.x * v2.y - v1.y * v2.x }; return t; } void Get_View_Matrix(matrix4x4 * mxView) { vector3 vPos = { 0.0f, 5.0f, -15.0f }; vector3 vUp = { 0.0f, 1.0f, 0.0f }; vector3 vLook = { 0, 0, 1.0f}; vector3 vRight; if(vLook.z > 0) { vRight.x = 1.0f; vRight.y = 0.0f; vRight.z = 0.0f; } if(vLook.z < 0) { vRight.x = -1.0f; vRight.y = 0.0f; vRight.z = 0.0f; } vLook = Vec3_Normalize(vLook); vUp = Vec3_Cross(vLook, vRight); vUp = Vec3_Normalize(vUp); vRight = Vec3_Cross(vUp, vLook); vRight = Vec3_Normalize(vRight); float xp = - Vec3_Dot(vPos, vRight); float yp = - Vec3_Dot(vPos, vUp); float zp = - Vec3_Dot(vPos, vLook); matrix4x4 mView = { vRight.x, vUp.x, vLook.x, 0.0, vRight.y, vUp.y, vLook.y, 0.0, vRight.z, vUp.z, vLook.z, 0.0, xp, yp, zp, 1.0 }; memcpy(mxView, &mView, sizeof(matrix4x4)); } vector3 Vec3_Mat4x4_Mul(vector3 v, matrix4x4 m) { vector3 out; out.x = v.x * m[0][0] + v.y * m[1][0] + v.z * m[2][0] + m[3][0]; out.y = v.x * m[0][1] + v.y * m[1][1] + v.z * m[2][1] + m[3][1]; out.z = v.x * m[0][2] + v.y * m[1][2] + v.z * m[2][2] + m[3][2]; return out; } int main(void) { vector3 vert = { 0.0f, 0.0f, 2.0f }; matrix4x4 mxView; Get_View_Matrix(&mxView); vector3 v = Vec3_Mat4x4_Mul(vert, mxView); return 0; }