Путаница с трансформацией пространства в OpenGL
В книге 3D-графики для игрового программирования, написанной JungHyun Han, на странице 38-39 говорится, что
матрица базового преобразования из e_1, e_2, e_3 в u,v,n
Однако это противоречит тому, что я знаю по линейной алгебре. Я имею в виду, не должна ли матрица базисного преобразования быть транспонированной этой матрицей?
Обратите внимание, что автор ведет свое происхождение, но я не смог найти пропущенную точку между тем, что я знаю, и тем, что делает автор.
Код: вершинный шейдер:
#version 330
layout(location = 0) in vec4 position;
layout(location = 1) in vec4 color;
uniform vec3 cameraPosition;
uniform vec3 AT;
uniform vec3 UP;
uniform mat4 worldTrans;
vec3 ep_1 = ( cameraPosition - AT )/ length(cameraPosition - AT);
vec3 ep_2 = ( cross(UP, ep_1) )/length( cross(UP, ep_1 ));
vec3 ep_3 = cross(ep_1, ep_2);
vec4 t_ep_1 = vec4(ep_1, -1.0f);
vec4 t_ep_2 = vec4(ep_2, cameraPosition.y);
vec4 t_ep_3 = vec4(ep_3, cameraPosition.z);
mat4 viewTransform = mat4(t_ep_1, t_ep_2, t_ep_3, vec4(0.0f, 0.0f, 0.0f, 1.0f));
smooth out vec4 fragColor;
void main()
{
gl_Position = transpose(viewTransform) * position;
fragColor = color;
}
)glsl";
Входы:
GLuint transMat = glGetUniformLocation(m_Program.m_shaderProgram, "worldTrans");
GLfloat dArray[16] = {0.0};
dArray[0] = 1;
dArray[3] = 0.5;
dArray[5] = 1;
dArray[7] = 0.5;
dArray[10] = 1;
dArray[11] = 0;
dArray[15] = 1;
glUniformMatrix4fv(transMat, 1, GL_TRUE, &dArray[0]);
GLuint cameraPosId = glGetUniformLocation(m_Program.m_shaderProgram, "cameraPosition");
GLuint ATId = glGetUniformLocation(m_Program.m_shaderProgram, "AT");
GLuint UPId = glGetUniformLocation(m_Program.m_shaderProgram, "UP");
const float cameraPosition[4] = {2.0f, 0.0f, 0.0f};
const float AT[4] = {1.0f, 0.0f, 0.0f};
const float UP[4] = {0.0f, 0.0f, 1.0f};
glUniform3fv(cameraPosId, 1, cameraPosition);
glUniform3fv(ATId, 1, AT);
glUniform3fv(UPId, 1, UP);
2 ответа
По-видимому, смена базиса в векторном пространстве действительно изменяет векторы в этом векторном пространстве, и это не то, что мы хотим здесь.
Поэтому математика, которую я применял, здесь недействительна.
Чтобы понять, почему мы используем матрицу, которую я дал в этом вопросе, просмотрите этот вопрос.
Хотя верно, что вращение, масштабирование или деформация могут быть выражены матрицей 4x4 в виде
то, о чем вы читаете, это так называемая "трансформация вида"
Для достижения этой матрицы нам нужно два преобразования: сначала перевести в положение камеры, а затем повернуть камеру.
Данные для этих преобразований:
- Положение камеры
C
(Cx,Cy,Cz) - Целевая позиция
T
(Тх, Ту, Тг) - Камера нормализована
UP
(Ux, Uy, Uz)
Перевод может быть выражен
Для вращения мы определяем: F = T – C
и после нормализации мы получаем f = F / ||T-C||
также выражается f= normalize(F)
s = normalize(cross (f, UP))
u = normalize(cross(s, f))
s, u, -f
являются новой осью, выраженной в старой системе координат.
Таким образом, мы можем построить матрицу вращения для этого преобразования как
Объединяя два преобразования в единственную матрицу, мы получаем:
Обратите внимание, что система осей является той, что используется OpenGL, где -f= cross(s,u)
,
Теперь, сравнивая с вашим кодом GLSL, я вижу:
- Ваш
f
(ep_1) вектор идет в противоположном направлении. -
s
(ep_2) вектор рассчитывается какcross(UP, f)
вместоcross(f, UP)
, Это правильно, из-за 1). - То же самое для
u
(Ep_3). - Здание
V
ячейка (0,0) неверна. Он пытается установить правильное направление с помощью этого-1.0f
, - Для других ячеек (компоненты t_ep_J) используется положение камеры. Но вы забыли использовать скалярное произведение с
s,u,f
, - Инициализатор GLSL
mat4(c1,c2,c3,c4)
требует вектор-столбца в качестве параметров. Вы прошли ряды-столбцы. Но послеmain
использованиеtranspose
исправляет это.
Кстати, вы не собираетесь вычислять матрицу для каждой вершины, времени, времени и времени... верно? Лучше рассчитать его на стороне процессора и передать if (в порядке столбцов) как униформу.