Умножение с плавающей запятой не так точно, как вы думаете, и каждый раз, когда вы умножаете два числа с плавающей запятой, вы теряете точность - довольно быстро, как вы обнаружили.
Как правило, вы хотите сохранитьваши преобразования не как матрица результатов, а как шаги, необходимые для получения этой матрицы;Например, если вы выполняете только одноосное преобразование, вы сохраняете свое преобразование как угол и каждый раз пересчитываете матрицу.Однако, если задействовано несколько осей, это очень сложно очень быстро.
Другой подход заключается в использовании базового представления преобразования, которое само может быть преобразовано точно. Кватернионы очень популярны для этого (согласно ответу Майкла Кензеля ), но другой подход, который может быть проще визуализировать, - это использовать пару векторов, которые представляют преобразование таким образом, что выможно восстановить нормализованную матрицу.Например, вы можете думать о своем вращении как о паре векторов forward
и up
.Из этого вы можете вычислить вашу матрицу преобразования, например:
z_axis = normalize(forward);
x_axis = normalize(cross(up, forward));
y_axis = normalize(cross(forward, x_axis));
, а затем вы построите свою матрицу преобразования из этих векторов;с учетом этих осей и pos
для вашей позиции (основная колонка) матрица OpenGL будет:
{ x_axis.x, x_axis.y, x_axis.z, 0,
y_axis.x, y_axis.y, y_axis.z, 0,
z_axis.x, z_axis.y, z_axis.z, 0,
pos.x, pos.y, pos.z, 1 }
Аналогично, вы можете перенормировать матрицу преобразования, извлекая векторы Z и Y из вашей матрицы какdirection
и up
, соответственно, и восстановление из них новой матрицы.
Это требует гораздо большей вычислительной сложности, чем использование кватернионов, но я считаю, что гораздо проще обернуть голову.