2013-08-11 1 views
1

Я пытаюсь написать физический симулятор в C++ с opengl, и мне нужно иметь возможность масштабировать объекты (в основном кубы прямо сейчас) вдоль оси, в которой находится камера облицовка.Как масштабировать объект вдоль любой оси (в 3D-пространстве)

я могу рисовать объекты прекрасно использовать это как моя модель Matrix:

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, где каждая ось содержит шаг, рыскание и рулон в радианах кулачка. Мои функции перевода, поворота и т. Д. Работают правильно, но мне нужна помощь в теории создания матрицы для масштабирования.

+0

Далее обсуждается это на https://www.gamedev.net/topic/541643-scaling-along-arbitrary-axis/. – fuzzyTew

ответ

0

Я решил, написав эту функцию, основанную от решения 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 на оси

1

Скейлинговые матрицы имеют вид:

{{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 
+0

Возможно, вы не поняли мою проблему, посмотрите, что матрица шкалы будет масштабироваться только по осям x, y и z независимо (например, превращая куб в прямоугольную призму), но она не сможет масштабировать вдоль вектора (0,5, 0, 0,5), создающего 3d-параллелограмм (что мне и нужно) – ryco117

+0

Почему glScale (0,5, 0, 0,5) не даст эффекта, который вы хотите? или обеспечения 0,5 для любой требуемой величины масштабирования. – pippin1289

+0

, потому что glScale будет половиной его длины, равна нулю, а половина - ширине (создавая небольшой квадрат), в отличие от масштабирования его вдоль вектора (0,5, 0, 0,5) (создавая форму, которая больше не имеет только 90 deg углы) – ryco117

Смежные вопросы