Catmull Rom Spline

https://en.wikipedia.org/wiki/Centripetal_Catmull%E2%80%93Rom_spline


// Loop around the total time if necessary
if (elapsedTime >= endTime) {
    if (loop) {
        while (elapsedTime > endTime)
            elapsedTime -= endTime;
    }
    else {
        position = frames[frames.size() - 1].position;
        return;
    }
}

int i = 0;
// Find the index of the current frame
while (frames[i+1].time < elapsedTime) i++;
	
// Find the time since the beginning of this frame
elapsedTime -= frames[i].time;

// Find how far we are between the current and next frame (0 to 1)
float fraction = (float)(elapsedTime / (frames[i + 1].time - frames[i].time));

// Interpolate position and rotation values between frames
position = glm::catmullRom (
                   frames[wrap(i - 1, frames.size() - 1)].position,
                   frames[wrap(i, frames.size() - 1)].position,
                   frames[wrap(i + 1, frames.size() - 1)].position,
                   frames[wrap(i + 2, frames.size() - 1)].position,
                   fraction);
template<typename genType> 
GLM_FUNC_QUALIFIER genType catmullRom(
		genType const& v1,
		genType const& v2,
		genType const& v3,
		genType const& v4,
		typename genType::value_type const& s
	) {
    typename genType::value_type s2 = pow2(s);
    typename genType::value_type s3 = pow3(s);

    typename genType::value_type f1 = -s3 + typename genType::value_type(2) * s2 - s;
    typename genType::value_type f2 = typename genType::value_type(3) * s3 - typename genType::value_type(5) * s2 + typename genType::value_type(2);
    typename genType::value_type f3 = typename genType::value_type(-3) * s3 + typename genType::value_type(4) * s2 + s;
    typename genType::value_type f4 = s3 - s2;

    return (f1 * v1 + f2 * v2 + f3 * v3 + f4 * v4) / typename genType::value_type(2);
}

http://www.lighthouse3d.com/tutorials/maths/catmull-rom-spline/

f(x) = [1, x, x^2, x^3] * M * [v1, v2, v3, v4]

/* Coefficients for Matrix M */
#define M11	 0.0
#define M12	 1.0
#define M13	 0.0
#define M14	 0.0
#define M21	-0.5
#define M22	 0.0
#define M23	 0.5
#define M24	 0.0
#define M31	 1.0
#define M32	-2.5
#define M33	 2.0
#define M34	-0.5
#define M41	-0.5
#define M42	 1.5
#define M43	-1.5
#define M44	 0.5

double catmullRomSpline(float x, float v1,float v2, float v3,float v4) {
	double c1,c2,c3,c4;

	c1 =  	      M12*v2;
	c2 = M21*v1          + M23*v3;
	c3 = M31*v1 + M32*v2 + M33*v3 + M34*v4;
	c4 = M41*v1 + M42*v2 + M43*v3 + M44*v4;

	return(((c4*x + c3)*x +c2)*x + c1);
}

lab6

lab6-GeometryPositionColorSimpleCar-src

SimpleCar::SimpleCar()
{
angle = 0.0f; // 0~360
direction = 1.0f; // +/-1
position = glm::vec3(-3.0f, 0.0f, 0.0f);

init();
}

void SimpleCar::init()
{
body = Parallelepiped(glm::vec3(-1.0f, 0.0f, -1.0f), glm::vec3(2.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 2.0f), glm::vec3(0.0f, 1.0f, 0.0f));
body.setColor(glm::vec3(0.0f, 1.0f, 0.0f));
wheel[0] = Torus(glm::vec3(0.0f, 0.0f, .0f), 0.3f, 0.1f, 32, 16);
wheel[0].setColor(glm::vec3(1.0f, 0.0f, 0.0f));
wheel[1] = Torus(glm::vec3(0.0f, 0.0f, .0f), 0.3f, 0.1f, 32, 16);
wheel[1].setColor(glm::vec3(0.0f, 0.0f, 1.0f));

bodyTransform = glm::translate(glm::mat4(1.0f), position); // RHS x+ right
wheelTransform[0] = glm::translate(glm::mat4(1.0f), glm::vec3(-0.5f, 0.0f, -0.5f)) * glm::rotate(glm::mat4(1.0f), angle, glm::vec3(0.0f, 0.0f, 1.0f));
wheelTransform[1] = glm::translate(glm::mat4(1.0f), glm::vec3(-0.5f, 0.0f, 0.5f)) * glm::rotate(glm::mat4(1.0f), angle, glm::vec3(0.0f, 0.0f, 1.0f));
wheelTransform[2] = glm::translate(glm::mat4(1.0f), glm::vec3(0.5f, 0.0f, -0.5f)) * glm::rotate(glm::mat4(1.0f), angle, glm::vec3(0.0f, 0.0f, 1.0f));
wheelTransform[3] = glm::translate(glm::mat4(1.0f), glm::vec3(0.5f, 0.0f, 0.5f)) * glm::rotate(glm::mat4(1.0f), angle, glm::vec3(0.0f, 0.0f, 1.0f));
}

void SimpleCar::draw(Program* p, glm::mat4& projection, glm::mat4& view, glm::mat4& model)
{
p->useProgram();
p->setUniform(“gProjection”, projection);
p->setUniform(“gView”, view);

glm::mat4 carMatrix = model * bodyTransform;
p->setUniform(“gModel”, carMatrix);
body.draw();

glm::mat4 wheelMatrix = model * bodyTransform * wheelTransform[0];
p->setUniform(“gModel”, wheelMatrix);
wheel[0].draw();

wheelMatrix = model * bodyTransform * wheelTransform[1];
p->setUniform(“gModel”, wheelMatrix);
wheel[0].draw();

wheelMatrix = model * bodyTransform * wheelTransform[2];
p->setUniform(“gModel”, wheelMatrix);
wheel[1].draw();

wheelMatrix = model * bodyTransform * wheelTransform[3];
p->setUniform(“gModel”, wheelMatrix);
wheel[1].draw();
}

bool SimpleCar::update(float deltaTime)
{
angle = angle – 180.0f * (float) (deltaTime) * 0.001f * direction;
position[0] = position[0] + (float) (deltaTime) * 0.001f * direction;

//std::cout << “position[0]=” << position[0] << std::endl;
if (position[0] * direction > 3)
direction = -direction;

bodyTransform = glm::translate(glm::mat4(1.0f), position); // RHS x+ right
wheelTransform[0] = glm::translate(glm::mat4(1.0f), glm::vec3(-0.5f, 0.0f, -0.5f)) * glm::rotate(glm::mat4(1.0f), angle, glm::vec3(0.0f, 0.0f, 1.0f));
wheelTransform[1] = glm::translate(glm::mat4(1.0f), glm::vec3(-0.5f, 0.0f, 0.5f)) * glm::rotate(glm::mat4(1.0f), angle, glm::vec3(0.0f, 0.0f, 1.0f));
wheelTransform[2] = glm::translate(glm::mat4(1.0f), glm::vec3( 0.5f, 0.0f, -0.5f)) * glm::rotate(glm::mat4(1.0f), angle, glm::vec3(0.0f, 0.0f, 1.0f));
wheelTransform[3] = glm::translate(glm::mat4(1.0f), glm::vec3( 0.5f, 0.0f, 0.5f)) * glm::rotate(glm::mat4(1.0f), angle, glm::vec3(0.0f, 0.0f, 1.0f));

return true;
}

 

lab5

lab5-GeometryPositionColorComposeTransformation-src

// MVP matrix
Projection = glm::perspective(g_fovy, g_aspect, g_zNear, g_zFar);
View = glm::lookAt(g_eye, g_at, g_up);
spMain.useProgram();
spMain.setUniform(“gProjection”, Projection);
spMain.setUniform(“gView”, View);

// p’ = M3 * M2 * M1 * p (OpenGL uses Column-Major Order)
glm::mat4 Tx = glm::translate(glm::mat4(1.0f), glm::vec3(3.0f, 0.0f, 0.0f)); // RHS x+ right
glm::mat4 Rz = glm::rotate(glm::mat4(1.0f), 45.0f, glm::vec3(0.0f, 0.0f, 1.0f)); // RHS z+ (X->Y rotation)
glm::mat4 S = glm::scale(glm::mat4(1.0f), glm::vec3(2.0f, 2.0f, 2.0f)); // RHS

World = glm::mat4(1.0f);
spMain.setUniform(“gModel”, World);
cube1->draw();

// p’= R T p (red) => translate, and then rotate
glm::mat4 RT = Rz * Tx;
World = RT;
spMain.setUniform(“gModel”, World);
cube2->draw();

// p’= T R p (green) => rotate, and then translate
glm::mat4 TR = Tx * Rz;
World = TR;
spMain.setUniform(“gModel”, World);
cube3->draw();

// p’= T R S p (blue) => scale, and then rotate, and then translate
glm::mat4 TRS = Tx * Rz * S;
World = TRS;
spMain.setUniform(“gModel”, World);
cube4->draw();

// p’= S R T p (cyan) => translate, and then rotate, and then scale
glm::mat4 SRT = S * Rz * Tx;
World = SRT;
spMain.setUniform(“gModel”, World);
cube5->draw();

// p’= Ra p (yellow green) => rotate by arbitrary axis
glm::mat4 Ra = glm::rotate(glm::mat4(1.0f), 45.0f, glm::vec3(1.0f, 1.0f, 1.0f)));
World = Ra;
spMain.setUniform(“gModel”, World);
cube6->draw();

OPENGL/GLM TRANSFORMATION (COLUMN-MAJOR ORDER)

glm::mat4 A(1.0f, 0.0f, 0.0f, 0.0f, // column1
0.0f, 2.0f, 0.0f, 0.0f, // column2
0.0f, 0.0f, 4.0f, 0.0f, // column3
1.0f, 2.0f, 3.0f, 1.0f); // column4
// A =
// 1 0 0 1
// 0 2 0 2
// 0 0 4 3
// 0 0 0 1

 

glm::mat4 B(1.0f, 0.0f, 0.0f, 0.0f, // column1
0.0f, 1.0f, 0.0f, 0.0f,
// column2
0.0f, 0.0f, 1.0f, 0.0f,
// column3
2.0f, 2.0f, 2.0f, 1.0f); // column4
// B =
// 1 0 0 2
// 0 1 0 2
// 0 0 1 2
// 0 0 0 1

 

glm::mat4 C = A*B;
// C = A*B =
// 1 0 0 3
// 0 2 0 6
// 0 0 4 11
// 0 0 0 1

 

glm::mat4 D = B*A;
// D = B*A =
// 1 0 0 3
// 0 2 0 4
// 0 0 4 5
// 0 0 0 1

 

glm::mat4 E = glm::inverse(A); // inverse
// E = inverse(A) =
// 1 0 0 -1
// 0 0.5 0 -1
// 0 0 0.25 -0.75
// 0 0 0 1

 

glm::mat4 I = A * E; // I = A * A-1
// I = A*E =
// 1 0 0 0
// 0 1 0 0
// 0 0 1 0
// 0 0 0 1

 

// p’ = M * p (OpenGL/GLM uses Column-Major Order)
glm::vec4 p = glm::vec4(1.0f, 0.0f, 0.0f, 1.0f);
// p = (1, 0, 0)

glm::vec4 q = A * p;
// q = A * p = (2, 2, 3)

glm::vec4 r = B * p;
// r = B * p = (3, 2, 2)

glm::vec4 s = C * p;
// s = A * B * p = (4, 6, 11)

glm::vec4 t = D * p;
// t = B * A * p = (4, 4, 5)

 

glm::mat4 Tx,Ty,Tz;
Tx = glm::translate(glm::mat4(1.0f), glm::vec3(2.0f, 0.0f, 0.0f)); // RHS x+ right
Ty = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 2.0f, 0.0f)); // RHS y+ up
Tz = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, 2.0f)); // RHS z+ front
// Tx =
// 1 0 0 2
// 0 1 0 0
// 0 0 1 0
// 0 0 0 1

// Ty =
// 1 0 0 0
// 0 1 0 2
// 0 0 1 0
// 0 0 0 1

// Tz =
// 1 0 0 0
// 0 1 0 0
// 0 0 1 2
// 0 0 0 1

glm::mat4 Rx,Ry,Rz,Ra;
Rx = glm::rotate(glm::mat4(1.0f), 30.0f, glm::vec3(1.0f, 0.0f, 0.0f)); // RHS x+ (Y->Z rotation)
Ry = glm::rotate(glm::mat4(1.0f), 60.0f, glm::vec3(0.0f, 1.0f, 0.0f)); // RHS y+ (Z->X rotation)
Rz = glm::rotate(glm::mat4(1.0f), 45.0f, glm::vec3(0.0f, 0.0f, 1.0f)); // RHS z+ (X->Y rotation)
Ra = glm::rotate(glm::mat4(1.0f), 45.0f, glm::vec3(1.0f, 1.0f, 1.0f)); // RHS (arbitrary axis)
// Rx =
// 1 0 0 0
// 0 0.999958 -0.0091384 0
// 0 0.0091384 0.999958 0
// 0 0 0 1

 

// Ry =
// 0.999833 0 0.018276 0
// 0 1 0 0
// -0.018276 0 0.999833 0
// 0 0 0 1

 

// Rz =
// 0.999906 -0.0137074 0 0
// 0.0137074 0.999906 0 0
// 0 0 1 0
// 0 0 0 1

 

// Ra =
// 0.999937 -0.00788263 0.00794526 0
// 0.00794526 0.999937 -0.00788263 0
// -0.00788263 0.00794526 0.999937 0
// 0 0 0 1

 

glm::mat4 Sx,Sy,Sz;
Sx = glm::scale(glm::mat4(1.0f), glm::vec3(2, 1, 1)); // RHS
Sy = glm::scale(glm::mat4(1.0f), glm::vec3(1, 2, 1)); // RHS
Sz = glm::scale(glm::mat4(1.0f), glm::vec3(1, 1, 2)); // RHS
// Sy =
// 1 0 0 0
// 0 2 0 0
// 0 0 1 0
// 0 0 0 1

 

// p’ = M3 * M2 * M1 * p (OpenGL uses Column-Major Order)
glm::mat4 TR = Tx * Rz; // Rotate Z, and then Translate X
glm::mat4 RT = Rz * Tx; // Translate X, and then Rotate Z
glm::mat4 TRS = Tx * Rz * Sy; // Scale Y, and then Rotate Z, and then Translate X
glm::mat4 SRT = Sy * Rz * Tx; // Translate X, and then Rotate Z, and then Scale Y
// Tx*Rz =
// 0.707107 -0.707107 0 2
// 0.707107 0.707107 0 0
// 0 0 1 0
// 0 0 0 1

 

// Rz*Tx =
// 0.707107 -0.707107 0 1.41421
// 0.707107 0.707107 0 1.41421
// 0 0 1 0
// 0 0 0 1

 

// Tx*Rz*Sy =
// 0.707107 -1.41421 0 2
// 0.707107 1.41421 0 0
// 0 0 1 0
// 0 0 0 1

 

// Sy*Rz*Tx =
// 0.707107 -0.707107 0 1.41421
// 1.41421 1.41421 0 2.82843
// 0 0 1 0
// 0 0 0 1

OPENGL TRANSFORMATION MATRIX TUTORIAL

http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices/

Homogeneous coordinates

Until then, we only considered 3D vertices as a (x,y,z) triplet. Let’s introduce w. We will now have (x,y,z,w) vectors.

This will be more clear soon, but for now, just remember this :

  • If w == 1, then the vector (x,y,z,1) is a position in space.
  • If w == 0, then the vector (x,y,z,0) is a direction.

(In fact, remember this forever.)
What difference does this make ? Well, for a rotation, it doesn’t change anything. When you rotate a point or a direction, you get the same result. However, for a translation (when you move the point in a certain direction), things are different. What could mean “translate a direction” ? Not much.Homogeneous coordinates allow us to use a single mathematical formula to deal with these two cases.

Transformation matrices

In 3D graphics we will mostly use 4×4 matrices. They will allow us to transform our (x,y,z,w) vertices. This is done by multiplying the vertex with the matrix :

Matrix x Vertex (in this order !!) = TransformedVertex

In C++, with GLM:

glm::mat4 myMatrix;
glm::vec4 myVector;
// fill myMatrix and myVector somehow
glm::vec4 transformedVector = myMatrix * myVector; // Again, in this order ! this is important.

In GLSL :

mat4 myMatrix;
vec4 myVector;
// fill myMatrix and myVector somehow
vec4 transformedVector = myMatrix * myVector; // Yeah, it's pretty much the same than GLM

Translation matrices

These are the most simple tranformation matrices to understand. A translation matrix look like this :

where X,Y,Z are the values that you want to add to your position.

So if we want to translate the vector (10,10,10,1) of 10 units in the X direction, we get :

Scaling matrices

Scaling matrices are quite easy too :

So if you want to scale a vector (position or direction, it doesn’t matter) by 2.0 in all directions :

Rotation matrices

These are quite complicated.

Cumulating transformations

So now we know how to rotate, translate, and scale our vectors. It would be great to combine these transformations. This is done by multiplying the matrices together, for instance :

TransformedVector = TranslationMatrix * RotationMatrix * ScaleMatrix * OriginalVector;