Я пытаюсь написать симулятор физики на c ++ с opengl, и мне нужно иметь возможность масштабировать объекты (в основном кубы) вдоль оси, с которой сталкивается камера.
Я могу отлично рисовать объекты, используя это в качестве моей модели матрицы:
mat4 Model = Translate(cube.Position - float3(gl.Position.x, gl.Position.y, -gl.Position.z)) * Rotate(cube.Rotation) * Scale(cube.Scale);
Где gl.Position — позиция камеры, float3 — класс, похожий на vec3, который я написал, и т. Д.
Поэтому я попытался изменить эту строку, чтобы она включала коэффициент масштабирования раньше всего (где сначала применяется материал в конце):
mat4 Model = Translate(cube.Position - float3(gl.Position.x, gl.Position.y, -gl.Position.z)) * Rotate(cube.Rotation) * Scale(cube.Scale) * (Rotate(float3(gl.Rotation.x, gl.Rotation.y, gl.Rotation.z)) * Scale(float3(1.0f, 1.0f, sqrt(1 - (velocity * velocity)))) * Rotate(float3(tau - gl.Rotation.x, tau - gl.Rotation.y, tau - gl.Rotation.z)));
Это последняя часть, которая важна, где я вращаю объект, масштабирую его, а затем поворачиваю его назад .. sqrt (1 — (скорость * скорость)) — это физическая часть (сжатие Лоренца), а gl.Rotation — это vec3, где каждая ось содержит шаг, рыскание и крен в радианах кулачка. Мои функции перевода, поворота и т. Д. Работают правильно, но мне нужна помощь в теории создания матрицы для масштабирования.
Матрицы масштабирования имеют вид:
{{s_x, 0, 0, 0},
{0, s_y, 0, 0},
{0, 0, s_z, 0},
{0, 0, 0, 1}}
Предполагая однородные координаты.
Чтобы применить их, вам нужно масштабировать, затем вращать, а затем переводить. Я рекомендую использовать функции GL, чтобы сделать это. Предположим, вы хотите, чтобы ваш объект находился в положении x, y, z, а его вращение находится в кватернионе {theta, r_x, r_y, r_z}. Масштабирование и вращение должны происходить в координатной рамке модели. GL применяет преобразования в соответствующем порядке, поэтому его код будет выглядеть следующим образом:
glTranslatef(x, y, z);
glRotatef(theta, r_x, r_y, r_z);
glScalef(s_x, s_y, s_z);
//draw my model
Я решил это, написав эту функцию, основанную на решении pippin1289
mat4 ScaleOnAxis(float3 a)
{
a = Norm3f(a);
if(a == x || (a.x == -1.0f && a.y == 0.0f && a.z == 0.0f))
return Scale(0.2f, 1.0f, 1.0f);
float3 axis = Cross(a, x);
float theta = acos(Dot(a, x));
if(theta > pi / 2)
{
axis = axis * -1.0f;
theta = pi - theta;
}
Quaternion ToRotation(axis.x, axis.y, axis.z, theta);
Quaternion FromRotation(axis.x, axis.y, axis.z, tau - theta);
return mat4(FromRotation) * (Scale(float3(0.2f, 1.0f, 1.0f)) * mat4(ToRotation));
}
Возвращает матрицу, которая будет масштабироваться на 0,2 по оси