Home > Articles

This chapter is from the book

This chapter is from the book

Using Matrix Math in Transformations

In the preceding section, you had to use rotation and transformation calculations to view the triangle shape. Graphics programs often perform all kinds of calculations on the vertices of an object before finally drawing that object onscreen. Translation, scaling, and rotation can all be performed on a single shape just by calling the Translate(), Scale(), and Rotate() functions with the shape's vertices. However, performing so many calculations on many vertices can be time consuming, which is why graphics programmers often use matrix math to transform shapes.

A matrix is simply a table of numbers arranged in rows and columns. Similar to arrays in programming, the size of a matrix is defined by the number of rows and columns it has. For example, this is a 4x4 matrix, which has four rows and four columns:

4 3 2 1
5 4 2 8
3 7 0 5
9 3 6 1

On the other hand, the following is a 3x4 matrix, which has three rows and four columns:

4 7 2 4
4 6 7 3
4 5 2 2

Matrices are so similar to arrays, in fact, that arrays are typically used to represent matrices in computer programs. The 3x4 matrix might be represented in a program as follows:

int matrix[3][4] =
  {4, 7, 2, 4,
   4, 6, 7, 3,
   4, 5, 2, 2};

The advantage of matrices in graphics programming is that you can represent any number of transformations with a single matrix. For example, a single matrix can contain all the values you need to simultaneously translate, scale, and rotate a shape. To do this, you fill the matrix with the appropriate values and then you multiply the matrix times all of the shape's vertices. Of course, the trick is to know what values to place in the matrix. You also need to know how to multiply matrices. You'll learn both tricks in the following sections.

Using Matrix Data Types for 2D Graphics

First, you need data types for the matrices you'll be using in your programs. Programs that deal with 2D graphics typically use two types of matrices: 1x3 and 3x3. The 1x3 matrix is a special type of matrix known as a vector. Vectors can represent a vertex in a shape, by holding the vertex's X, Y, and W values. What's W? Although Direct3D sometimes has a special use for this extra value, W is really used most often to simplify the matrix operations. In most cases, W is equal to 1, which means a vector representing a vertex in a shape has this form:

X Y 1

The data type for a vector, then, looks like this:

typedef struct vector
{
  int x, y, w;
} VECTOR;

The 3x3 matrix will hold the values needed to transform a vertex, which will be held in the VECTOR data type (which is also a matrix). The data type for the 3x3 matrix looks like this:

typedef double MATRIX3X3[3][3];

Using Transformation Matrices

The first step in using matrices to transform a shape is to load the matrix with the appropriate values. What values you use and where you place them in the matrix depend on the type of transformations you're doing. A matrix that's set up to translate a shape looks like this:

1    0    0
0    1    0
xTrans yTrans 1

Just like when you were using a formula to translate the vertices of a shape, in the preceding matrix the xTrans and yTrans variables are the number of vertical and horizontal units, respectively, that you want to translate the shape. In a program, you'd initialize this matrix like this:

MATRIX3X3 m;
m[0][0] = 1.0;   m[0][1] = 0.0;  m[0][2] = 0.0;
m[1][0] = 0.0;   m[1][1] = 1.0;  m[1][2] = 0.0;
m[2][0] = xTrans; m[2][1] = yTrans; m[2][2] = 1.0;

A matrix for scaling a shape looks like this:

xScaleFactor 0       0
0       yScaleFactor 0
0       0       1

Here, the variable xScaleFactor is how much you want to scale the shape horizontally, whereas yScaleFactor is how much to scale vertically. In a program, you'd initialize the scaling matrix like this:

MATRIX3X3 m;
m[0][0] = xScaleFactor; m[0][1] = 0.0;      m[0][2] = 0.0;
m[1][0] = 0.0;      m[1][1] = yScaleFactor; m[1][2] = 0.0;
m[2][0] = 0.0;      m[2][1] = 0.0;      m[2][2] = 1.0;

Finally, a matrix for rotating a shape looks as follows:

cos(radians)  sin(radians) 0
-sin(radians) cos(radians) 0
0       0       1

Here, the variable radians is the angle of rotation in radians. In a program, you'd initialize the rotation matrix like this:

MATRIX3X3 m;
m[0][0] = cos(radians);  m[0][1] = sin(radians); m[0][2] = 0.0;
m[1][0] = -sin(radians); m[1][1] = cos(radians); m[1][2] = 0.0;
m[2][0] = 0.0;      m[2][1] = 0.0;      m[2][2] = 1.0;

Composing Transformations

Earlier, I said that you can store in a matrix all the values you need to perform translation, scaling, and rotation simultaneously. In the previous section, you saw how each transformation looks when it's stored separately in a matrix. Now, you'll learn about composing transformations, which is the act of combining the translation, scaling, and rotation matrices into one main transformation matrix.

To compose two transformations, you multiply their matrices together, yielding a third master matrix. You can then compose another transformation by multiplying the new matrix by yet another transformation matrix. This composition of matrices can be repeated as often as necessary. Figure 3.11 illustrates an example of matrix composition. Figure 3.12 shows another way of looking at this matrix composition. In Figure 3.12, the results of each composition aren't shown.

Figure 3.11Figure 3.11 Matrix composition.

Figure 3.12Figure 3.12 Another view of matrix composition.

Now, if you only knew how to multiply matrices! A matrix can be multiplied by any other matrix as long as the first matrix has the same number of columns as the second matrix has rows. So a 1x3 matrix can be multiplied by a 3x3 matrix, which is fortunate because that's exactly what you need to do to multiply a matrix times a vector in 2D graphics programs. Also, a 3x3 matrix can be multiplied by a 3x3 matrix, something else you need to do in a 2D graphics program to compose transformations. You'll look at multiplying vectors a little later in this chapter, but Listing 3.7 is a function that multiplies two 3x3 matrices.

Listing 3.7 Multiplying 3x3 Matrices

void MultMatrix(MATRIX3X3& product,
   MATRIX3X3& matrix1, MATRIX3X3& matrix2)
{
  for (int x=0; x<3; ++x)
    for (int y=0; y<3; ++y)
    {
      double sum = 0;
      for (int z=0; z<3; ++z)
        sum += matrix1[x][z] * matrix2[z][y];
      product[x][y] = sum;
    }
}

The function's three parameters are a reference to a 3x3 matrix in which to hold the product of the multiplication and references to the two matrices that should be multiplied. Listing 3.8 is an example of how to use the function.

Listing 3.8 Using the MultMatrix() Function

MATRIX3X3 m1, m2, m3;

m1[0][0] = 1.0; m1[0][1] = 0.0; m1[0][2] = 0.0;
m1[1][0] = 0.0; m1[1][1] = 1.0; m1[1][2] = 0.0;
m1[2][0] = 0.0; m1[2][1] = 0.0; m1[2][2] = 1.0;

m2[0][0] = 9.0; m2[0][1] = 8.0; m2[0][2] = 7.0;
m2[1][0] = 6.0; m2[1][1] = 5.0; m2[1][2] = 4.0;
m2[2][0] = 3.0; m2[2][1] = 2.0; m2[2][2] = 3.0;

MultMatrix(m3, m1, m2); 

Here, the code first declares three 3x3 matrices, m1, m2, and m3. Next, m1 and m2 are initialized, after which the call to MultMatrix3X3() multiplies m1 times m2 and stores the result in m3. Can you tell what m3 will hold after the multiplication? The answer is that m3 will contain exactly the same values as m2. Why? Because the values stored in m1 are what is known as an identity matrix, which, for a 3x3 matrix, looks like this:

1 0 0
0 1 0
0 0 1

The Identity Matrix

An identity matrix is sort of the matrix equivalent of the number 1. Just as any number times 1 equals the original number (for example, 5 x 1 = 5), so also any matrix times an identity matrix equals the original matrix (for example, m1 x I = m1). An identity matrix contains all zeroes except for the line of 1s that runs diagonally from the upper-left corner to the lower-right corner.

An identity matrix is often used in graphics programming to initialize the main matrix that'll be used to compose transformations. By initializing this main matrix to the identity matrix, you know that there aren't any strange values left over in the matrix that'll foul up your matrix multiplications.

Performing the Transformation

After you compose your transformations, you have a main matrix that contains the exact values you need to simultaneously translate, scale, and rotate a shape. To perform this transformation, you only need to multiply the main transformation matrix by each of the shape's vectors. This operation requires a matrix multiplication function that can handle not only 1x3 vectors and 3x3 matrices, but also can apply the multiplication to a whole list of vectors. Listing 3.9 is a function that does just that.

Listing 3.9 Transformations with Matrices

void Transform(SHAPE& shape, MATRIX3X3& m)
{
  int transformedX, transformedY;

  for (int x=0; x<shape.numVerts; ++x)
  {
    transformedX = (int) (shape.vertices[x].x * m[0][0] +
      shape.vertices[x].y * m[1][0] + m[2][0]);
    transformedY = (int) (shape.vertices[x].x * m[0][1] +
      shape.vertices[x].y * m[1][1] + m[2][1]);
    shape.vertices[x].x = transformedX;
    shape.vertices[x].y = transformedY;
  }
}

This function takes as parameters a reference to a SHAPE structure and a reference to a MATRIX3X3 array. When this function has finished, the vertices in the SHAPE structure, shape, will have been transformed by the values in the transformation matrix, m.

Using Some Matrix Utility Functions

Now that you have some idea of how the matrix operations work, you can start using them in your programs. To do that, however, you need a couple of utility functions that make handling matrices a little easier. First, you need a function that can initialize a matrix to an identity matrix. Such a function looks like Listing 3.10.

Listing 3.10 Initializing an Identity Matrix

void InitMatrix(MATRIX3X3& m)
{
  m[0][0]=1; m[0][1]=0; m[0][2]=0; 
  m[1][0]=0; m[1][1]=1; m[1][2]=0;
  m[2][0]=0; m[2][1]=0; m[2][2]=1;
}

The InitMatrix() function takes as a parameter a reference to a MATRIX3X3 array into which the function loads the values that comprise a 3x3 identity matrix.

Another thing you'll need to do is copy a matrix. The CopyMatrix() function looks like Listing 3.11.

Listing 3.11 Copying a Matrix

void CopyMatrix(MATRIX3X3& dst, MATRIX3X3& src)
{
  for (int i=0; i<3; ++i)
   for (int j=0; j<3; ++j) 
     dst[i][j] = src[i][j];
}

This function takes as parameters references to the destination and source matrices, both of which are the type MATRIX3X3. The function copies the src matrix into the dst matrix.

Using Functions for Composing Transformations

The last task in writing functions for a 2D graphics program using matrices is to rewrite the Translate(), Scale(), and Rotate() functions so that they use the new matrix data types. The Translate() function ends up looking like Listing 3.12.

Listing 3.12 Translating with Matrices

void Translate(MATRIX3X3& m, int xTrans, int yTrans)
{
  MATRIX3X3 m1, m2;

  m1[0][0]=1;    m1[0][1]=0;    m1[0][2]=0;
  m1[1][0]=0;    m1[1][1]=1;    m1[1][2]=0;
  m1[2][0]=xTrans; m1[2][1]=yTrans; m1[2][2]=1;

  MultMatrix(m2, m1, m);
  CopyMatrix(m, m2); 
}

This function takes as parameters a reference to the matrix that holds the current state of the transformation and the X and Y translation values. First, the function loads a local matrix with the values that create a translation matrix, after which it multiplies the translation matrix times the main transformation matrix. The result of the multiplication, stored in the local matrix m2, is then copied into the transformation matrix.

Rewriting the Scale() function for use with matrices results in Listing 3.13.

Listing 3.13 Scaling with Matrices

void Scale(MATRIX3X3& m, double xScale, double yScale)
{
  MATRIX3X3 m1, m2;

  m1[0][0]=xScale; m1[0][1]=0;   m1[0][2]=0;
  m1[1][0]=0;   m1[1][1]=yScale; m1[1][2]=0;
  m1[2][0]=0;   m1[2][1]=0;   m1[2][2]=1;

  MultMatrix(m2, m1, m);
  CopyMatrix(m, m2);
}

The Scale() function takes as parameters a reference to the current transformation matrix and the X and Y scaling factors. The function first initializes the local matrix m1 to the scaling matrix. It then multiplies the scaling matrix times the current transformation matrix, storing the results in the local matrix m2. The program finally copies m2 into the transformation matrix.

The last function you need is the matrix version of Rotate(). That function looks like Listing 3.14.

Listing 3.14 Rotating with Matrices

void Rotate(MATRIX3X3& m, int degrees)
{
  MATRIX3X3 m1, m2;

  if (degrees == 0) return;

  double radians = 6.283185308 / (360.0 / degrees);
  double c = cos(radians);
  double s = sin(radians);

  m1[0][0]=c; m1[0][1]=s; m1[0][2]=0;
  m1[1][0]=-s; m1[1][1]=c; m1[1][2]=0;
  m1[2][0]=0; m1[2][1]=0; m1[2][2]=1;
  
  MultMatrix(m2, m1, m);
  CopyMatrix(m, m2); 
}

The Rotate() function takes as parameters a reference to the current transformation matrix and the number of degrees to rotate the shape. The function first checks whether degrees is zero. If it is, the function returns immediately to avoid a division-by-zero error. Then, the function converts the degrees to radians and calculates the cosine and sine of the angle. Next, Rotate() initializes the rotation matrix and multiplies that matrix times the current transformation matrix, storing the results in the local matrix m2. Finally, m2 gets copied into the transformation matrix.

Now that you have a set of matrix functions, you might want to see exactly how you would use those functions in a program to translate, scale, and rotate a shape. Listing 3.15 shows you how.

Listing 3.15 Performing Transformations with the Matrix Functions

MATRIX3X3 m;
InitMatrix(m);
Translate(m, 10, 15);
Scale(m, 0.5, 0.5);
Rotate(m, 45);
Transform(shape1, m);
DrawShape(shape1);

The code segment first declares a 3x3 transformation matrix called m. It then calls InitMatrix() to initialize m to an identity matrix. At this point, m looks like this:

1.0000000000000 0.0000000000000 0.0000000000000
0.0000000000000 1.0000000000000 0.0000000000000
0.0000000000000 0.0000000000000 1.0000000000000

The call to Translate() composes m with a translation matrix containing the values 10 and 15, which leaves m containing the translation. The transformation matrix, m, now looks like this:

1.0000000000000  0.0000000000000  0.0000000000000
0.0000000000000  1.0000000000000  0.0000000000000
10.000000000000  15.000000000000  1.0000000000000

After the call to Scale(), m contains the translation and scaling values:

0.5000000000000  0.0000000000000  0.0000000000000
0.0000000000000  0.5000000000000  0.0000000000000
10.000000000000  15.000000000000  1.0000000000000

Finally, the call to Rotate() leaves m containing the full transformation—translation, scaling, and rotation—for the shape:

0.35355339055702  0.35355339062953  0.0000000000000
-0.35355339062953  0.35355339055702  0.0000000000000
10.000000000000   15.000000000000  1.0000000000000

The call to Transform() applies the translation matrix m to all of the vertices in shape1, after which DrawShape() draws the newly transformed shape onscreen.

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020