Всем привет. При изучении 3D в программировании мы пользуемся математикой — линейная алгебра, матрицы, векторы, кватернионы и т.д. В какой-то момент становится интересно как устроено пространство 3D, какие принципы и основы заложены в фундамент отображения моделей. Так же, просто на отображении 3D не возможно остановиться — хочется добавить свет, тень, как минимум. Для расчета света нам надо отправить в шейдер матрицу модели рисуемого объекта — текущего, нормали плоскостей (например на триангулированный объект на каждый треугольник по нормали выходит).
Так же по расчету света необходимо добавить эту же текущую модель, в виде обратной матрицы и транспонированную.
В этой статье покажу как я решил такую задачу — комплексное решение приводящее к обратной матрице (размер 3х3).
Рабочее пространство
Все расчеты буду вести в среде Линукс, 14.2 gcc.
Давайте посмотрим, как можно это решить
Так же подготовим ориентиры которыми будем пользоваться
Так же будем пользоваться транспонированием результирующей матрицы.
Когда мы посчитаем матрицу Minor и применим знаки матрицы Cofactor и применим матрицу Транспонирования — это можно назвать матрицей Сопряжения(Ajoint или она же где-то может называться Ajugate).
Примерно перед применением Транспонирования мы можем проверить определитель (Determinant, Det), определитель нужно проверить на не ноль далее ниже мы рассмотрим случаи 0 и не 0.
Определитель является важной составляющей при расчете обратной матрицы, так как при нахождении обратной матрицы на определитель надо поделить.
Перейдём к реализации
Скрытый текст
#pragma GCC optimize ("Ofast,unroll-loops,-ffast-math") #pragma GCC target ("sse,sse4.2") #include <xmmintrin.h> #include <smmintrin.h> #include <stdlib.h> #include <string.h> #include <stdio.h> #include <math.h> #include <assert.h> #include <stdio.h> #include <stdlib.h> #include <stdbool.h> //обозначим необходимый минимум по структурам typedef float f32; struct vec3_t { f32 x; f32 y; f32 z; }; typedef struct vec3_t vec3; struct mat3_t { f32 v[9]; }; typedef struct mat3_t mat3; //функция печати матрицы void printMatrix(const mat3 m) { printf("%f %f %f\n%f %f %f\n%f %f %f\n\n", m.v[0],m.v[1],m.v[2], m.v[3],m.v[4],m.v[5], m.v[6],m.v[7],m.v[8] ); } //установка матрицы через 3 вектора const mat3 setMatrix(const vec3 v,const vec3 v1,const vec3 v2) { return (mat3) { v.x,v.y,v.z, v1.x,v1.y,v1.z, v2.x,v2.y,v2.z, }; } //матрица транспонирования const mat3 Transposedm3(const mat3 m) { return (mat3) { m.v[0], m.v[3],m.v[6], m.v[1], m.v[4],m.v[7], m.v[2], m.v[5],m.v[8] }; } //матрица минора mat3 Minorm3(mat3 m) { return (mat3) { (m.v[4]*m.v[8]-m.v[5]*m.v[7]), (m.v[3]*m.v[8]-m.v[5]*m.v[6]), (m.v[3]*m.v[7]-m.v[4]*m.v[6]), (m.v[1]*m.v[8]-m.v[2]*m.v[7]), (m.v[0]*m.v[8]-m.v[2]*m.v[6]), (m.v[0]*m.v[7]-m.v[1]*m.v[6]), (m.v[1]*m.v[5]-m.v[2]*m.v[4]), (m.v[0]*m.v[5]-m.v[2]*m.v[3]), (m.v[0]*m.v[4]-m.v[1]*m.v[3]), }; } //применение знаковой матрицы mat3 Cofactorm3(mat3 m) { return (mat3) { m.v[0],-m.v[1],m.v[2], -m.v[3], m.v[4],-m.v[5], m.v[6],-m.v[7],m.v[8] }; } //результирующая функция Инверсной матрицы const mat3 Inversem3(mat3 m) { mat3 as; as=Minorm3(m); as=Cofactorm3(as); float DetA=(m.v[0]*as.v[0])+(m.v[1]*as.v[1])+(m.v[2]*as.v[2]); printf("Det %f\n\n",DetA); //проверка !0 DetA=1/DetA; as=Transposedm3(as); return (mat3) { as.v[0]*DetA,as.v[1]*DetA,as.v[2]*DetA, as.v[3]*DetA,as.v[4]*DetA,as.v[5]*DetA, as.v[6]*DetA,as.v[7]*DetA,as.v[8]*DetA }; } int main() { //printf("Chapter: Find Inverse Matrix!\nExample Matrix for start calculate:\n\n"); mat3 matA; matA=setMatrix( (vec3){1,2,3}, (vec3){4,5,6}, (vec3){7,8,9} ); printMatrix(matA); mat3 as; as=Inversem3(matA); printf("Inverse Result: \n"); printMatrix(as); printf("\n\n"); return 0; }
скомпилируем
gcc -Ofast -ffast-math -o test main.c -lm
результат
теперь мы умеем находить Обратную матрицу.
Ресурсы
https://www.mathsisfun.com/algebra/matrix-calculator.html
https://www.geeksforgeeks.org/inverse-of-3×3-matrix/
ссылка на оригинал статьи https://habr.com/ru/articles/865192/
Добавить комментарий