官术网_书友最值得收藏!

Vector matrix multiplication

We have now implemented translation, scaling, and rotation in terms of matrices. These matrices become useful when we can apply their transformations to vectors. How do we apply a matrix transformation to a vector? The same way we do to a matrix: using matrix multiplication!

To multiply a vector and a matrix, we need to think of a vector as a matrix that has only one row or column. This leaves us with an important question, is a vec3 a matrix with one column and three rows, or three columns and one row?

If the vector is on the left side of the matrix, it's a 1 X 3 Row Vector. With a row vector, we use Pre Multiplication.

If the vector is on the right side of the matrix, it's a 3 X 1 Column Vector. With column vectors we use Post Multiplication.

The naming is intuitive, with pre multiplication the vector is placed before the matrix, with post multiplication the vector is placed after the matrix. This convention must be followed because the inner dimensions of matrices being multiplied have to match.

We have to decide if our vectors are row or column vectors. This decision comes down to whether we want to use pre or post multiplication. Multiplying two matrices using our row major library is already left to right. By using row vectors we can multiply vectors and matrices left to right as well. This should help make vector matrix multiplication feel more intuitive.

This takes care of 3 X 3 matrices, but what about a 4 X 4 matrix? We can't multiply a vec3 by a mat4, the inner dimensions for matrix multiplication must match! We actually need to use a data type we don't have, a vec4. This is where the W component we briefly discussed in Chapter 1, Vectors, becomes important. In our final physics engine, a vector will represent one of two things, a point in space, or a direction and a magnitude.

What's the difference? Multiplying a point in space by a matrix will change its position. Multiplying a vector can't change its position, it has none! Only the direction and magnitude of the vector can change.

  • A vector is a 1 X 4 matrix with a W component of 0.
  • A point is a 1 X 4 matrix with a W component of anything other than 0.

Getting ready

Because a vec3 could potentially represent a point or a vector, we're not going to overload the multiplication operator. Instead, we are going to make two new functions, MultiplyPoint and MultiplyVector. There are two ways we can implement these functions.

We could create a temp float array with four elements; filling the first three with the X, Y, and Z components of the vector and the W component with 0 or 1, depending on whether we have a point or a vector. Then, we could use the generic Multiply function on this array.

The other option is to hard-code the dot product between row i of the vector and column j of the matrix. This way, we can hard-code the W component within the dot product to 0 or 1. We're going to implement both the MultiplyPoint and MultiplyVector functions in this manner.

How to do it…

Follow these steps to multiply vectors and matrices:

  1. Add the MultiplyPoint and MultiplyVector declarations to matrices.h:
    vec3 MultiplyPoint(const vec3& vec, const mat4& mat);
    vec3 MultiplyVector(const vec3& vec, const mat4& mat);
    vec3 MultiplyVector(const vec3& vec, const mat3& mat);
  2. Implement the MultiplyPoint function in matrices.cpp. Hard-code 1 where the W component would be:
    vec3 MultiplyPoint(const vec3& vec, const mat4& mat) {
       vec3 result;
       result.x = vec.x * mat._11 + vec.y * mat._21 + 
                  vec.z * mat._31 + 1.0f  * mat._41;
       result.y = vec.x * mat._12 + vec.y * mat._22 + 
                  vec.z * mat._32 + 1.0f  * mat._42;
       result.z = vec.x * mat._13 + vec.y * mat._23 + 
                  vec.z * mat._33 + 1.0f  * mat._43;
       return result;
    }
  3. Implement the MultiplyVector in matrices.cpp. Hard code 0 where the W component should be:
    vec3 MultiplyVector(const vec3& vec, const mat4& mat) {
       vec3 result;
       result.x = vec.x * mat._11 + vec.y * mat._21 + 
                  vec.z * mat._31 + 0.0f  * mat._41;
       result.y = vec.x * mat._12 + vec.y * mat._22 + 
                  vec.z * mat._32 + 0.0f  * mat._42;
       result.z = vec.x * mat._13 + vec.y * mat._23 + 
                  vec.z * mat._33 + 0.0f  * mat._43;
       return result;
    }
  4. Implement the mat3 version of MultiplyVector in matrices.cpp. In this function, we actually use the dot product, instead of hand-coding the whole thing.
    vec3 MultiplyVector(const vec3& vec, const mat3& mat) {
       vec3 result;
       result.x = Dot(vec, vec3(mat._11, mat._21, mat._31));
       result.y = Dot(vec, vec3(mat._12, mat._22, mat._32));
       result.z = Dot(vec, vec3(mat._13, mat._23, mat._33));
       return result;
    }

How it works…

We have to choose between row or column vectors because we can only multiply matrices together if their inner dimensions match. Let's explore why a W component of 1 will turn a vector into a point.

Translation is stored in elements 41, 42, and 43 of a matrix. When we take the dot product of a four-component vector and the column of a 4 X 4 matrix, the elements in the translation row of the matrix get multiplied by the W component. A W of 1 means the translation remains untouched. A W of 0 cancels out the translation.

主站蜘蛛池模板: 乌鲁木齐县| 泰州市| 都安| 阳山县| 阳城县| 田东县| 峨眉山市| 邯郸县| 扎赉特旗| 万宁市| 伊金霍洛旗| 昌吉市| 原阳县| 洪江市| 盐边县| 克山县| 太保市| 元谋县| 淳安县| 建昌县| 灯塔市| 韩城市| 青冈县| 莆田市| 桦甸市| 三门县| 米泉市| 饶平县| 盱眙县| 浮山县| 乌拉特前旗| 沁阳市| 县级市| 织金县| 云南省| 册亨县| 广灵县| 垦利县| 文山县| 巴青县| 嵊泗县|