1
votes

I'm trying to write a physics simulator in c++ with opengl and I need to be able to scale objects (mostly cubes right now) along the axis that the camera is facing.

I can draw objects perfectly fine using this as my Model Matrix:

mat4 Model = Translate(cube.Position - float3(gl.Position.x, gl.Position.y, -gl.Position.z)) * Rotate(cube.Rotation) * Scale(cube.Scale);

Where gl.Position is the cam's position, float3 is a vec3 like class I wrote, etc...

So i tried to modify that line to include a scaling factor before all else (where stuff at the end is applied first):

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)));

It's the last part that is important, where I rotate the object, scale it, then rotate it back.. the sqrt(1 - (velocity * velocity)) is the physics part (Lorentz contraction) and gl.Rotation is a vec3 where each axis holds the pitch, yaw, and roll in radians of the cam. My translate, rotate, etc. functions work properly, but I need help with the theory of creating a matrix to scale.

2
There's further discussion of this at gamedev.net/topic/541643-scaling-along-arbitrary-axis . - fuzzyTew

2 Answers

1
votes

Scaling matrices are of the form:

{{s_x, 0, 0, 0},
 {0, s_y, 0, 0},
 {0, 0, s_z, 0},
 {0,  0,  0, 1}}

Assuming uniform coordinates.

To apply them, you need to scale, then rotate, then translate. I recommend using gl functions to do this. Assume you want your object at position x, y, z, and its rotation is in a quaternion {theta, r_x, r_y, r_z}. Scaling and rotation need to occur in the model coordinate frame. GL applies the transformations in an appropriate order, so its code would look like this:

glTranslatef(x, y, z);
glRotatef(theta, r_x, r_y, r_z);
glScalef(s_x, s_y, s_z);

//draw my model
1
votes

I solved it by writing this function that is based off of pippin1289's solution

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));
}

It returns a matrix that will scale by 0.2 on a axis