Форум программистов, компьютерный форум, киберфорум
OpenGL
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.58/40: Рейтинг темы: голосов - 40, средняя оценка - 4.58
97 / 11 / 1
Регистрация: 14.03.2017
Сообщений: 196

Матрица LookAt

28.11.2017, 05:38. Показов 7475. Ответов 13
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Бьюсь уже битые 2 недели, никак не получается. Хочу реализовать матрицу LookAt без glm, glu и прочей математической полезности. Рыскал по сайтам, вроде нашел код, но работать не хочет. Может кто объяснить, где ошибка?

Шейдер:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#version 330 core
 
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 color;
 
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
out vec3 Color;
 
void main()
{
    gl_Position = projectionMatrix * viewMatrix * vec4(position.x, position.y, position.z, 1.0);
    Color = color;
}
Инициализация камеры:
C++
1
2
3
4
5
6
7
8
9
10
11
Camera::Camera()
{
    cameraPos.SetVector(0, 0, 0);
    WorldUp.SetVector(0, 1, 0);
    cameraFront.SetVector(0, 0, -1);
    speed = 5;
    FoV = 45;
    viewMatrix.Identity();
    lastPos = InputGetCursorPos();
    Update();
}
Обновление камеры:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void Camera::Update()
{
    Vector2 offset;
    offset = lastPos - InputGetCursorPos();
    lastPos = InputGetCursorPos();
    Yaw += offset.x;
    Pitch += offset.y;
 
    if (Pitch > 89.0f)
        Pitch = 89.0f;
    if (Pitch < -89.0f)
        Pitch = -89.0f;
 
    Vector3 front;
    front.x = cos(ToRadians(Yaw)) * cos(ToRadians(Pitch));
    front.y = sin(ToRadians(Pitch));
    front.z = sin(ToRadians(Yaw)) * cos(ToRadians(Pitch));
    cameraFront = Normalize(front); 
    cameraRight = Normalize(Cross(cameraFront, WorldUp));  
    cameraUp = Normalize(Cross(cameraRight, cameraFront));
 
    viewMatrix.LookAt(cameraPos, cameraPos + cameraFront, cameraUp);
}
Нерабочая матрица LookAt
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void Matrix4::LookAt(Vector3 cameraPos, Vector3 cameraTarget, Vector3 cameraUp)
{
    Vector3 zaxis = Normalize(cameraTarget - cameraPos);
    Vector3 xaxis = Normalize(Cross(cameraUp,zaxis));
    Vector3 yaxis = Cross(zaxis, xaxis);    
 
    matrix[0] = xaxis.x;    matrix[1] = yaxis.x;    matrix[2] = zaxis.x;  matrix[3] = 0;
    matrix[4] = xaxis.y;    matrix[5] = yaxis.y;    matrix[6] = zaxis.y;  matrix[7] = 0;
    matrix[8] = xaxis.z;    matrix[9] = yaxis.z;    matrix[10] = zaxis.z;  matrix[11] = 0;
    matrix[12] = 0; 
    matrix[13] = 0;
    matrix[14] = 0;
    matrix[15] = 1;
}
Вектора позиции и подобное выводил, вроде работает. Однако нужная картинка не выводится.
Источники
https://msdn.microsoft.com/ru-... s.85).aspx
https://learnopengl.com/code_v... ode=camera

Добавлено через 5 часов 19 минут
Итак, вот пару интересностей. Матрица проекции и матрица вида объявлены в Camera.h со static. Через метод Update матрица вида меняется, но... Когда я распечатал матрицу в мейне, она была проиницилизирована нулями. Я думал, что переменные со статиком можно изменять везде, но...

Второе что заметил. Эту матрицу виду уже в мейне я нормализовал. Следовательно там в центре одни единицы. По логике при перемножении матрицы должна остаться такая же матрица, но ничего подобного, картинка исчезла. При простом умножении на матрицу проекции картинка выводится.
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
28.11.2017, 05:38
Ответы с готовыми решениями:

Почему фигура, к которой применена команда lookat, трансформируется?
Помогите пожалуйста! При выводе на экран та фигура, к которой применена команда lookat почему то трансформируется ...

Скорость поворота через lookAt
Сделал так, что при уничтожении игрока враги улетают за границы камеры и там просто уничтожаются. Также решил сделать так, чтобы враги...

Оптимизация плавного поворота 2d + bugfix lookAt и тд
Привет, форумчане! Я тут второй день бьюсь над задачей поворота в 2д не используя всякие атангенсы и тд У меня есть пара сотен или...

13
 Аватар для snake32
3502 / 1685 / 236
Регистрация: 26.02.2009
Сообщений: 8,376
Записей в блоге: 6
28.11.2017, 13:53
Цитата Сообщение от Diochrome Посмотреть сообщение
Нерабочая матрица LookAt
Ещё её нужно домножить на матрицу переноса glTranslatef( -cameraPos.x, -cameraPos.y, -cameraPos.z );
тогда должна быть именно та матрица gluLookAt
https://www.khronos.org/regist... LookAt.xml
PS:не все браузеры показывают адекватно поэтому прикрепил картинку
Миниатюры
Матрица LookAt  
0
97 / 11 / 1
Регистрация: 14.03.2017
Сообщений: 196
07.12.2017, 19:24  [ТС]
Раньше проблема была в нерабочем перемножении матрицы. Получалось так, что матрицы как-то теряли значения. Я исправил этот косяк и фигура, наконец, задвигалась, однако, ведет себя ну очень неестественно. Я не до конца понимаю, что я должен прописать в функции, чтобы она двигалась нормально (например, при перемещении мышки наверх сама фигура идет наверх, а не меняет проекцию). Я уже просто тыкаю наугад, пытаясь что-то изменить. Может кто помочь?

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void Matrix4::LookAt(Vector3 cameraPos, Vector3 cameraTarget, Vector3 cameraUp)
{
    Vector3 zaxis = Normalize(cameraTarget - cameraPos);
    Vector3 xaxis = Normalize(Cross(cameraUp,zaxis));
    Vector3 yaxis = Cross(zaxis, xaxis);    
 
    matrix[0] = xaxis.x;    matrix[1] = yaxis.x;    matrix[2] = zaxis.x;    matrix[3] = 0;
    matrix[4] = xaxis.y;    matrix[5] = yaxis.y;    matrix[6] = zaxis.y;    matrix[7] = 0;
    matrix[8] = xaxis.z;    matrix[9] = yaxis.z;    matrix[10] = zaxis.z;   matrix[11] = 0;
    matrix[12] = 0; 
    matrix[13] = 0;
    matrix[14] = 0;
    matrix[15] = 1;
 
    (*this).Translate({ -cameraTarget.x,-cameraTarget.y,-cameraTarget.z });
}
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void Camera::Move(Direction dir)
{
    switch (dir)
    {
    case Left:
    {
        cameraPos += cameraRight * speed;
        break;
    }
    case Right:
    {
        cameraPos -= cameraRight * speed;
        break;
    }
    case Forward:
    {
        cameraPos -= cameraFront*speed;
        break;
    }
    case Backward:
    {
        cameraPos += cameraFront*speed;
        break;
    }
    default:
        break;
    }
}
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void Camera::Update()
{
    Vector2 offset;
    offset = lastPos - InputGetCursorPos();
    offset *= 0.0001f;
    lastPos = InputGetCursorPos();
    Yaw += offset.x;
    Pitch += offset.y;
 
    if (Pitch > 89.0f)
        Pitch = 89.0f;
    if (Pitch < -89.0f)
        Pitch = -89.0f;
 
    Vector3 front;
    front.x = cos(ToRadians(Yaw)) * cos(ToRadians(Pitch));
    front.y = sin(ToRadians(Pitch));
    front.z = sin(ToRadians(Yaw)) * cos(ToRadians(Pitch));
    cameraFront = Normalize(front);
    cameraRight = Normalize(Cross(cameraFront, WorldUp));
    cameraUp = Normalize(Cross(cameraRight, cameraFront));
    viewMatrix.LookAt(cameraPos, cameraPos + cameraFront, cameraUp);
}
Добавлено через 16 минут
Если я убираю перемещение в lookAt, не работает перемещение по клавишам, если оно есть, то по клавишам работает, но ведет себя КРАЙНЕ странно.
0
97 / 11 / 1
Регистрация: 14.03.2017
Сообщений: 196
08.12.2017, 02:02  [ТС]
OGL.rar
Вот проект. Там, конечно, полный бардак, но все основные функции в "Functions", Matrix4 и в "main". Если кто поможет, буду очень благодарен.
0
1961 / 817 / 114
Регистрация: 01.10.2012
Сообщений: 4,753
Записей в блоге: 2
08.12.2017, 12:19
Возможно/вероятно Вы стали жертвой того что матрицы хранятся совсем не так как они показываются в спецификации OpenGL. Возьмите исходники либы с матрицами (напр QMatrix4x4.h, совместима с OpenGL) и сравните напр свое умножение (оператор матрица * вектор) с тамошним. Я вижу что они не совпадают.

Ну и, конечно, практичнее "использовать готовое". Прикрутить либу не так уж сложно (напр Qt или GLM), а главное - рано или поздно это делать придется, напр назреет хоть какой-то импорт который потребует "своих" матриц.
0
97 / 11 / 1
Регистрация: 14.03.2017
Сообщений: 196
08.12.2017, 21:14  [ТС]
Цитата Сообщение от Igor3D Посмотреть сообщение
Ну и, конечно, практичнее "использовать готовое". Прикрутить либу не так уж сложно (напр Qt или GLM), а главное - рано или поздно это делать придется, напр назреет хоть какой-то импорт который потребует "своих" матриц.
По сути своей целью этого проекта была работа без всяких сторонних библиотек. Самописный проект, где всё сделано "своими руками" и где всё понятно.

Цитата Сообщение от Igor3D Посмотреть сообщение
Возьмите исходники либы с матрицами (напр QMatrix4x4.h, совместима с OpenGL) и сравните напр свое умножение (оператор матрица * вектор) с тамошним. Я вижу что они не совпадают.
Там матрица представляется как массив [4][4]. Я пробовал такое представление, но постоянно упирался в подачу в uniform.
То есть изображение тупо не рисовалось пи 4 на 4, а вот где одномерный 16 все было нормально.

Мне кажется проблема или неправильной подаче аргументов в LookAt, либо неправильным построением функции lookat (Но оно каким-то чертом у сех разное! У одного просто перемножение матрицы с матрицей перемещения, у другого инвертированная матрица. Я не понимаю!). Также может быть, что при инвертизации матрицы накапливается ошибка. Но такая ошибка не должна влиять так сильно...
0
с++
1282 / 523 / 225
Регистрация: 15.07.2015
Сообщений: 2,562
08.12.2017, 21:39
где пример того что вы испытываете свою функцию, средствами opengl нарисуйте треугольник и покажите
0
97 / 11 / 1
Регистрация: 14.03.2017
Сообщений: 196
08.12.2017, 22:32  [ТС]
Снова поменял функцию на
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Matrix4 LookAt(Vector3 cameraPos, Vector3 cameraTarget, Vector3 cameraUp)
{
    Matrix4 Result;
 
    Vector3 f = Normalize(cameraTarget - cameraPos);
    Vector3 u = Normalize(cameraUp);
    Vector3 s = Normalize(Cross(f, u));
    u = Cross(s, f);
 
    Result.matrix[0] = s.x;
    Result.matrix[4] = s.y;
    Result.matrix[8] = s.z;
    Result.matrix[1] = u.x;
    Result.matrix[5] = u.y;
    Result.matrix[9] = u.z;
    Result.matrix[2] = -f.x;
    Result.matrix[6] = -f.y;
    Result.matrix[10] = -f.z;
    Result.matrix[12] = -Scalar(s, cameraPos);
    Result.matrix[13] = -Scalar(u, cameraPos);
    Result.matrix[14] = -Scalar(f, cameraPos);
    Result.matrix[15] = 0;
    return Result;
    
}
Если посмотреть внимательно, то мышка по сути работает. Да, она подлагивает, но это не критично. Что критично, так это при перемещении по клавишам отсекается фигура.

Эта матрица - последняя битва в "войне" с glm. Сделаю её и можно будет переходить к самому изображению фигур.
0
97 / 11 / 1
Регистрация: 14.03.2017
Сообщений: 196
08.12.2017, 22:36  [ТС]
Цитата Сообщение от Antikl Посмотреть сообщение
где пример того что вы испытываете свою функцию, средствами opengl нарисуйте треугольник и покажите
Показываю

"Нашел" треугольник в пространстве

Довернул мышь буквально на пару пикселей.
0
97 / 11 / 1
Регистрация: 14.03.2017
Сообщений: 196
08.12.2017, 22:39  [ТС]
Другой пример:


Опять же, треугольник непонятно где


Нажал "D" и отправился направо.
0
с++
1282 / 523 / 225
Регистрация: 15.07.2015
Сообщений: 2,562
08.12.2017, 22:41
Лучший ответ Сообщение было отмечено Diochrome как решение

Решение

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Matrix4 lookAt(Vector3& eye, Vector3& target, Vector3& upDir) 
{ 
    // compute the forward vector from target to eye 
    Vector3 forward = eye - target; 
    forward.normalize();                 // make unit length 
 
    // compute the left vector 
    Vector3 left = upDir.cross(forward); // cross product 
    left.normalize(); 
 
    // recompute the orthonormal up vector 
    Vector3 up = forward.cross(left);    // cross product 
 
    // init 4x4 matrix 
    Matrix4 matrix; 
    matrix.identity(); 
 
    // set rotation part, inverse rotation matrix: M^-1 = M^T for Euclidean transform 
    matrix[0] = left.x; 
    matrix[4] = left.y; 
    matrix[8] = left.z; 
    matrix[1] = up.x; 
    matrix[5] = up.y; 
    matrix[9] = up.z; 
    matrix[2] = forward.x; 
    matrix[6] = forward.y; 
    matrix[10]= forward.z; 
 
    // set translation part 
    matrix[12]= -left.x * eye.x - left.y * eye.y - left.z * eye.z; 
    matrix[13]= -up.x * eye.x - up.y * eye.y - up.z * eye.z; 
    matrix[14]= -forward.x * eye.x - forward.y * eye.y - forward.z * eye.z; 
 
    return matrix; 
}
2
97 / 11 / 1
Регистрация: 14.03.2017
Сообщений: 196
08.12.2017, 22:52  [ТС]
Antikl, Мышка стала вести себя ПОЛНОСТЬЮ корректно. Теперь разворачиваться стала даже приятно. Клавиатура так и не "починилась". Видимо проблема ещё и там. По крайней мере вы вдохнули в меня надежду. Огромное спасибо!
0
с++
1282 / 523 / 225
Регистрация: 15.07.2015
Сообщений: 2,562
08.12.2017, 23:00
Цитата Сообщение от Diochrome Посмотреть сообщение
Огромное спасибо!
ок

Добавлено через 3 минуты
если решите проблему отпишите, мне интересно ведь
0
1961 / 817 / 114
Регистрация: 01.10.2012
Сообщений: 4,753
Записей в блоге: 2
10.12.2017, 14:42
Цитата Сообщение от Diochrome Посмотреть сообщение
Там матрица представляется как массив [4][4]. Я пробовал такое представление, но постоянно упирался в подачу в uniform. То есть изображение тупо не рисовалось пи 4 на 4, а вот где одномерный 16 все было нормально.
И Вы решили перетерпеть с одномерным? Так делать нельзя, Вас все время будут находить и бить (вот lookAt уже нашла - и это только начало ).

Цитата Сообщение от Diochrome Посмотреть сообщение
Мне кажется проблема или неправильной подаче аргументов в LookAt, либо неправильным построением функции lookat (Но оно каким-то чертом у сех разное! У одного просто перемножение матрицы с матрицей перемещения, у другого инвертированная матрица. Я не понимаю!). Также может быть, что при инвертизации матрицы накапливается ошибка. Но такая ошибка не должна влиять так сильно...
Причем тут инверсия? LookAt получает на вход 2 вектора и строит из них 3 взаимо-перпендикулярных вектора (локальную СК). Эти вектора записываются в матрицу по столбцам (таковы соглашения по хранению матриц). Как я понял, это Вы преодолели. Теперь со смещением

Матрицв LookAt переводит из исходной СК в локальную СК заданную векторами. На входе смещение (eyePos) задается в исходной СК, а в матрице должно быть записано в координатах локальной СК. Поэтому (после того как прописали вращение)
C++
1
2
3
4
offset = matrix * (-eyePos);
matrix[12] = offset.x;
matrix[13] = offset.y;
matrix[14] = offset.z;
То же самое сделает ф-ция Translate (если она у Вас работает верно)

Добавлено через 1 час 15 минут
C++
1
2
3
4
    // set translation part 
    matrix[12]= -left.x * eye.x - left.y * eye.y - left.z * eye.z; 
    matrix[13]= -up.x * eye.x - up.y * eye.y - up.z * eye.z; 
    matrix[14]= -forward.x * eye.x - forward.y * eye.y - forward.z * eye.z;
Это записано то же самое (offset = matrix * (-eye)), только зачем-то руками

Не по теме:

C++
1
void Matrix4::LookAt(Vector3 cameraPos, Vector3 cameraTarget, Vector3 cameraUp)
Увидев этот текст, программист немедленно решит типа "а, ну все ясно, этот в плюсах без году неделя" :) И будет прав

0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
10.12.2017, 14:42
Помогаю со студенческими работами здесь

Вращение другой оси объекта для LookAt возможно?
1) Нужно повернуть объект, предположим капсулу, ее верхушкой в сторону клика мышкой на плоскости. Можно ли это как-то сделать с помощью...

Дана квадратная матрица А порядка n. Проверьте, является ли матрица единичной
Дана квадратная матрица А порядка n. Проверьте, является ли матрица единичной. Описать с помощью функций и процедур. Ввод-вывод в текстовый...

Дана квадратная матрица А порядка n. Проверить, является ли матрица единичной.
Ребят,помогите решить задачу &quot;Дана квадратная матрица А порядка n. Проверить, является ли матрица единичной&quot;

Как доказать то, что матрица и транспонированная ей матрица имеют одинаковые собственные числа?
Как доказать то, что матрица и транспонированная ей матрица имеют одинаковые собственные числа с одинаковой кратностью? Добавлено...

Матрица:Даны натуральное число n, действительная матрица размера n х 9. Найти среднее арифметическое: каждого
Даны натуральное число n, действительная матрица размера n х 9. Найти среднее арифметическое: каждого из столбцов.


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
14
Ответ Создать тему
Новые блоги и статьи
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
Фото: Daniel Greenwood
kumehtar 13.11.2025
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru