Foundations of Game Engine Development Volume 1 Mathematics

Posted revoid

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Foundations of Game Engine Development Volume 1 Mathematics相关的知识,希望对你有一定的参考价值。

http://www.foundationsofgameenginedev.com/

Chapter1 Vectors and Matrices (已看)

Chapter2 Transforms

Chapter3 Geometry

Chapter4 Adavanced Algebra

 

Chapter1 Vectors and Matrices

  1.1 Vector Fundamentals

A scalar is a quantity such as distance,mass,or time that can be fully described using a single numerical value representing its size,or its magnitude.

A vector is a quantity that carries enough information to represent a direction in space in addition to a magnitude

An n-dimensional vector v can be written as   v = (v0, v1, ..., vn - 1);

Zero-based indices are a much better fit for the way in which computers access individual fields in data structures.

The meaning of a vector‘s components depends on the coordinate system in which those components are expressed.  v = (vx, vy, vz)

  1.2 Basic Vecotr Operations

技术图片
struct Vector3D {
    float x, y, z;

    Vector3D() = default;

    Vector3D(float a, float b, float c) {
        x = a;
        y = b;
        z = c;
    }

    float & operator [](int i) {
        return ((&x)[i]);
    }

    const float & operator [](int i) const {
        return ((&x)[i]);
    }
};
View Code

A vector can be used to represent a point that does have a location in space by thinking of the vector as a relative offset from a given origin.    

    1.2.1 Magnitude and Scalar Multiplication

The magnitude of an n-dimensional vector is calculated with the formula 技术图片

The vector whose components are all zero called the zero vector, and it is the only vector for which the magnitude is zero.

The magnitude of a vector can be changed by multiplying it by a scalar value.  tv = (tv0, tv1, ..., tvn-1)  技术图片

A vector that has a magnitude of one is called a unit vector.Unit vector are particularly imortant because they are able to provide directional information without a magnitude when a meaningful size of some kind is not necessary.技术图片

The process of setting a vector‘s magnitude to one is called normalization, and a unit vector that has been produced by this process is often referred to as normalized.

技术图片
struct Vector3D {
    float x, y, z;

private:
    Vector3D() = default;
public:
    Vector3D(float a, float b, float c) {
        x = a;
        y = b;
        z = c;
    }

    float & operator[](int i) {
        return ((&x)[i]);
    }

    const float & operator[](int i) const {
        return ((&x)[i]);
    }

    Vector3D & operator*=(float s) {
        x *= s;
        y *= s;
        z *= s;
        return (*this);
    }

    Vector3D & operator/=(float s) {
        s = 1.0f / s;
        x *= s;
        y *= s;
        z *= s;
        return (*this);
    }
};

inline Vector3D operator*(const Vector3D & v, float s) {
    return (Vector3D(v.x * s, v.y * s, v.z * s));
}

inline Vector3D operator/(const Vector3D & v, float s) {
    s = 1.0f / s;
    return (Vector3D(v.x * s, v.y * s, v.z  * s));
}

inline Vector3D operator-(const Vector3D & v) {
    return (Vector3D(-v.x, -v.y, -v.z));
}

inline float Magnitude(const Vector3D & v) {
    return (sqrt(v.x * v.x + v.y * v.y + v.z * v.z));
}

inline Vector3D Normalize(const Vector3D & v) {
    return (v / Magnitude(v));
}
View Code

    1.2.2 Addtion and Subtraction

Vectors can be added and subtracted by applying these operations componentwise. That is, for two n-dimensional vectors a and b, we have 技术图片 and 技术图片

技术图片

技术图片
#ifndef VECTOR3D_H_
#define VECTOR3D_H_

struct Vector3D {
    float x, y, z;

private:
    Vector3D() = default;
public:
    Vector3D(float a, float b, float c) {
        x = a;
        y = b;
        z = c;
    }

    float & operator[](int i) {
        return ((&x)[i]);
    }

    const float & operator[](int i) const {
        return ((&x)[i]);
    }

    Vector3D & operator*=(float s) {
        x *= s;
        y *= s;
        z *= s;
        return (*this);
    }

    Vector3D & operator/=(float s) {
        s = 1.0f / s;
        x *= s;
        y *= s;
        z *= s;
        return (*this);
    }

    Vector3D & operator+=(const Vector3D & v) {
        x += v.x;
        y += v.y;
        z += v.z;
        return (*this);
    }

    Vector3D & operator-=(const Vector3D & v) {
        x -= v.x;
        y -= v.y;
        z -= v.z;
        return (*this);
    }
};

inline Vector3D operator*(const Vector3D & v, float s) {
    return (Vector3D(v.x * s, v.y * s, v.z * s));
}

inline Vector3D operator/(const Vector3D & v, float s) {
    s = 1.0f / s;
    return (Vector3D(v.x * s, v.y * s, v.z  * s));
}

inline Vector3D operator-(const Vector3D & v) {
    return (Vector3D(-v.x, -v.y, -v.z));
}

inline float Magnitude(const Vector3D & v) {
    return (sqrt(v.x * v.x + v.y * v.y + v.z * v.z));
}

inline Vector3D Normalize(const Vector3D & v) {
    return (v / Magnitude(v));
}

inline Vector3D operator+(const Vector3D & a, const Vector3D & b) {
    return (Vector3D(a.x + b.x, a.y + b.y, a.z + b.z));
}

inline Vector3D operator-(const Vector3D & a, const Vector3D & b) {
    return (Vector3D(a.x - b.x, a.y - b.y, a.z - b.z));
}

#endif
View Code

  1.3 Matrix Fundamentals

A matrix is a mathematical object composed of a set of numerical quantities arranged in a two-dimensional array of rows and columns. When a matrix has n rows and m columns, we say that its size is n x m,which is read "n by m". If it‘s the case that n = m,

then we say the matrix is "square matrix". The numbers that make up a matrix M are called its entries.

The symbol Mij means the entry apearing int he i-th row and j-th column.Sometimes, a comma may be inserted between the indices for clarity.Using this notation, an n x m matrix M can be written as 技术图片

The entries Mij , where the row index and the column index are equal to each other, are called the diagonal entries of the matrix M, and they are said to reside on the main diagonal of the matrix.

The main diagonal starts with the upper-left entry and continues downward and to the right.

The entries Mij  for which i != j are called the off-diagonal entries of the matrix M.

Any matrix for which all of the off-diagonal entries are zero is called a diagnoal matrix. Note that some or all of the entries on the main diagonal itself could be zero,and the matrix would still be considered to be a diagonal matrix.技术图片

The transpose of a matrix M is the matrix denoted by MT whose rows are equal to the columns of M, or equivalently, whose columns are equal to the rows of M.

If the matrix M has size n x m, then the matrix MT has size m x n, and its entries are given by MijT = Mji.

The transpose of a matrix can be thought of as the reflection of its entries across the main diagonal.

If a matrix M is equal to its transpose MT, meaning that it‘s always the case that Mij = Mji, then it is called a symmetric matrix because all of the entries above and right of the main diagonal are the same as the entries below and left of the main diagonal, 

with the row and column indices reversed.技术图片

A matrix must be square in order to be symmetric, and every diagoal matrix is automatically symmetric.

If the entries of a transpose MT are equal to the negations of the same entries in the matrix M,meaning that it‘s always the case that MijT = -Mij , then the matrix M is called an antisymmetric matrix(反对称矩阵) or a skew-symmetric matrix(斜对称矩阵).

Note that for this to be the case, all of the entries on the main diagonal must be zero as in the example.技术图片

An n-dimensional vector can be regarded as an n x 1 matrix or as 1 x n matrix,and as such, is called a column vector or a row vector, respectively.

A comma-spearated list of n components is equivalent to an n x 1 matrix containing the same numbers in the same order.技术图片

If we apply the transpose operation to v, then we get the row vector 技术图片 which despite its horizontal layout, is different from the comma-separated list of components.

It is frequently useful to treat a matrix as an array of column vectors or row vectors.For example,suppose that a,b, and c are column vectors. Then we can construct 3 x 3 matrix M by making those vectors the columns of the matrix and writing it as 技术图片

技术图片
#ifndef MATRIX3D_H_
#define MATRIX3D_H_

#include "Vector3D.h"

struct Matrix3D {
private:
    float n[3][3];
    Matrix3D() = default;
public:
    // column major order
    Matrix3D(float n00, float n01, float n02,
        float n10, float n11, float n12,
        float n20, float n21, float n22) {
        n[0][0] = n00; n[0][1] = n10; n[0][2] = n20;
        n[1][0] = n01; n[1][1] = n11; n[1][2] = n21;
        n[2][0] = n02; n[2][1] = n12; n[2][2] = n22;
    }

    Matrix3D(const Vector3D & a, const Vector3D & b, const Vector3D & c) {
        n[0][0] = a.x; n[0][1] = a.y; n[0][2] = a.z;
        n[1][0] = b.x; n[1][1] = b.y; n[1][2] = b.z;
        n[2][0] = c.x; n[2][1] = c.y; n[2][2] = c.z;
    }

    float & operator()(int i, int j) {
        return (n[j][i]);
    }

    const float & operator()(int i, int j) const {
        return (n[j][i]);
    }

    Vector3D & operator[](int j) {
        return (*reinterpret_cast<Vector3D *>(n[j]));
    }

    const Vector3D & operator[](int j) const {
        return (*reinterpret_cast<const Vector3D *>(n[j]));
    }
};

#endif
View Code

  1.4 Basic Matrix Operations

    1.4.1 Addition,Subtraction,and Scalar Multiplication

Two matrices of the same size can be added or subtracted by simply adding or subtracting corresponding entries.技术图片技术图片

A matrix M is multiplied by a scalar t by applying the multiplication to every entry of the matrix.技术图片

    1.4.2 Matrix Multiplication

Two matrices can be multiplied together if and only if the number of columns in the first matrix is equal to the number of rows in the second matrix.

The result is a new matrix having the same number of rows as the first matrix and the same number of columns as the second matrix.

When an n x p matrix A is multiplied by a p x m matrix B, the (i,j) entry of the matrix product AB is given by the formula技术图片

技术图片
#ifndef MATRIX3D_H_
#define MATRIX3D_H_

#include "Vector3D.h"

struct Matrix3D {
private:
    float n[3][3];
    Matrix3D() = default;
public:
    // column major order
    Matrix3D(float n00, float n01, float n02,
        float n10, float n11, float n12,
        float n20, float n21, float n22) {
        n[0][0] = n00; n[0][1] = n10; n[0][2] = n20;
        n[1][0] = n01; n[1][1] = n11; n[1][2] = n21;
        n[2][0] = n02; n[2][1] = n12; n[2][2] = n22;
    }

    Matrix3D(const Vector3D & a, const Vector3D & b, const Vector3D & c) {
        n[0][0] = a.x; n[0][1] = a.y; n[0][2] = a.z;
        n[1][0] = b.x; n[1][1] = b.y; n[1][2] = b.z;
        n[2][0] = c.x; n[2][1] = c.y; n[2][2] = c.z;
    }

    float & operator()(int i, int j) {
        return (n[j][i]);
    }

    const float & operator()(int i, int j) const {
        return (n[j][i]);
    }

    Vector3D & operator[](int j) {
        return (*reinterpret_cast<Vector3D *>(n[j]));
    }

    const Vector3D & operator[](int j) const {
        return (*reinterpret_cast<const Vector3D *>(n[j]));
    }
};

Matrix3D operator*(const Matrix3D & A, const Matrix3D & B) {
    return (Matrix3D(
        A(0, 0) * B(0, 0) + A(0, 1) * B(1, 0) + A(0, 2) * B(2, 0),
        A(0, 0) * B(0, 1) + A(0, 1) * B(1, 1) + A(0, 2) * B(2, 1),
        A(0, 0) * B(0, 2) + A(0, 1) * B(1, 2) + A(0, 2) * B(2, 2),

        A(1, 0) * B(0, 0) + A(1, 1) * B(1, 0) + A(1, 2) * B(2, 0),
        A(1, 0) * B(0, 1) + A(1, 1) * B(1, 1) + A(1, 2) * B(2, 1),
        A(1, 0) * B(0, 2) + A(1, 1) * B(1, 2) + A(1, 2) * B(2, 2),

        A(2, 0) * B(0, 0) + A(2, 1) * B(1, 0) + A(2, 2) * B(2, 0),
        A(2, 0) * B(0, 1) + A(2, 1) * B(1, 1) + A(2, 2) * B(2, 1),
        A(2, 0) * B(0, 2) + A(2, 1) * B(1, 2) + A(2, 2) * B(2, 2)
    ));
}

Vector3D operator*(const Matrix3D & M, const Vector3D & v) {
    return (Vector3D(
        M(0, 0) * v.x + M(0, 1) * v.y + M(0, 2) * v.z,
        M(1, 0) * v.x + M(1, 1) * v.y + M(1, 2) * v.z,
        M(2, 0) * v.x + M(2, 1) * v.y + M(2, 2) * v.z
    ));

}

#endif
View Code

技术图片

 技术图片

  1.5 Vector Multiplication

    1.5.1 Dot Product

The dot product between two n-dimensional vectors a and b is a scalar quantity given by the formula 技术图片

If the vectors a and b are regarded as column matrices, then the dot product be also be expressed as 技术图片which produces a 1 x 1 matrix having a single entry.

技术图片

Although not at all obvious from its definition, the dot product between two vectors a and b statisfies the equality 技术图片 where θ is the planar angle between the directions of a and b if the were to be drawn as arrows starting at the same location

This equality represent the main application of the dot product, and it provides a computationally cheap way to determine how much two vectors are parallel to each other or perpendicular to each other.

If a and b are both unit vectors,then a · b is always in the range [-1,1] because in this case a · b = cosθ, and the range of the cosine function is [-1, 1]

Assuming the magnitude of a and b remain the same, the dot product a · b attains its largest positive value when a and b are parallel and point in the same direction.

When a and b are parallel and point in opposite directions, a · b attains its largest negative value. If a and b are perpendicular, then a · b is zero no matter what the magnitudes of a and b are.

In general, the dot product is positive when the angle between the vectors is less then 90 degrees and negative when the angle is greater than 90 degrees.Loosely speaking, the dot product provides a measure of how much one vector is like another.

When a · b = 0, the vectors a and b are said to be orthogonal, and this term is used even if one of the vectors being multiplied together is the zero vector.

Orthogonality is a concept that includes the geometric state of two vectors being perpendicular to each other, but it also has a more abstract meaning in different settings that are not explored in this book

技术图片

    1.5.2 Cross Product

技术图片
#ifndef VECTOR3D_H_
#define VECTOR3D_H_

struct Vector3D {
    float x, y, z;

private:
    Vector3D() = default;
public:
    Vector3D(float a, float b, float c) {
        x = a;
        y = b;
        z = c;
    }

    float & operator[](int i) {
        return ((&x)[i]);
    }

    const float & operator[](int i) const {
        return ((&x)[i]);
    }

    Vector3D & operator*=(float s) {
        x *= s;
        y *= s;
        z *= s;
        return (*this);
    }

    Vector3D & operator/=(float s) {
        s = 1.0f / s;
        x *= s;
        y *= s;
        z *= s;
        return (*this);
    }

    Vector3D & operator+=(const Vector3D & v) {
        x += v.x;
        y += v.y;
        z += v.z;
        return (*this);
    }

    Vector3D & operator-=(const Vector3D & v) {
        x -= v.x;
        y -= v.y;
        z -= v.z;
        return (*this);
    }
};

inline Vector3D operator*(const Vector3D & v, float s) {
    return (Vector3D(v.x * s, v.y * s, v.z * s));
}

inline Vector3D operator/(const Vector3D & v, float s) {
    s = 1.0f / s;
    return (Vector3D(v.x * s, v.y * s, v.z  * s));
}

inline Vector3D operator-(const Vector3D & v) {
    return (Vector3D(-v.x, -v.y, -v.z));
}

inline float Magnitude(const Vector3D & v) {
    return (sqrt(v.x * v.x + v.y * v.y + v.z * v.z));
}

inline Vector3D Normalize(const Vector3D & v) {
    return (v / Magnitude(v));
}

inline Vector3D operator+(const Vector3D & a, const Vector3D & b) {
    return (Vector3D(a.x + b.x, a.y + b.y, a.z + b.z));
}

inline Vector3D operator-(const Vector3D & a, const Vector3D & b) {
    return (Vector3D(a.x - b.x, a.y - b.y, a.z - b.z));
}

inline float Dot(const Vector3D & a, const Vector3D & b) {
    return (a.x * b.x + a.y * b.y + a.z * b.z);
}

inline Vector3D Cross(const Vector3D & a, const Vector3D & b) {
    return (Vector3D(
        a.y * b.z - a.z * b.y,
        a.z * b.x - a.x * b.z,
        a.x * b.y - a.y * b.x
    ));
}

#endif
View Code

The cross product between two 3D vectors a and b is another 3D vector given by the formula 技术图片

The cross product can also be expressed as a matrix product by forming a special 3 x 3 antisymmetric matrix denoted by [a]x and multiplying by the column vector b. The matrix [a]x is defined as 技术图片

and when multiplied by b, it gives us 技术图片

It‘s important to emphasize that the cross product is defined only for three dimensions, whereas the dot product is defined for all numbers of dimensions.

This limitation is a consequence of the fact that the cross product is actually a subtle misinterpretation of a more general and more algebraically sound operation called the wedge product(楔积)

If two vectors a and b are parallel, either because they point the same direction or they point in opposite directions,then the cross product a x bis zero no matter what the magnitudes of a and b are. 

Because the are parallel, one of the vectors can be written as a scalar multiple of the other, so we can say that b = ta for some scalar t.

The fact that the cross product is zero then becomes obvious when b is replaced by ta in the definition to get 技术图片

When two vectors a and b are not parallel, the cross product a x b is a new vector that is perpendicular to both a and b.This is evident if we calculate the dot products a · (a x b) and b · (a x b) because both of them are always zero技术图片

The vectors a and b, not being parallel, establish a plane to which the cross product a x b is perpendicular, and we have two choices as to what direction the vector a x b actually points.

If we are looking at the plane from a position not lying in the plane itself, then a x b could point toward us, or it could point away from us.

The correct direction is determined by the handeness of the coordinates system.

技术图片技术图片

The magnitude of the cross product between two vectors a and b satisfies the equality 技术图片 where θ is the planar angle between the directions of a and b if they were to be drawn as arrows starting at the same location.

技术图片技术图片

    1.5.3 Scalar Triple Product

The scalar triple product of three vectors a,b and c is the scalar quantity produced by multiplying two of the vectors together using the cross product and then multiplying by the third vector using the dot product, as in (a x b) · c.

It turns out that it doesn‘t matter where the cross product goes and where the dot product gose, and the scalar triple product gives the same result as long as the vector multiplied together in the same order with wraparound.

As such, the special notation [a, b, c], without any specific multiplication symbols, is often used to represent the scalar triple product, and we can write 技术图片

If the order of the input vectors is reversed, then the scalr tripple product is negated to give us 技术图片

This accounts for all six possible permutation of the vectors a, b and c.

技术图片

技术图片

  1.6 Vector Projection

Given a particular vector, we might want to find two or more other vectors with specific alignments that add up to our original vector. This is a process called decomposing a vector into its separate components.

The most straightforward decomposition invovles breaking a vector into pieces that are aligned to the coordinates axes.

The letters i, j and k are commonly used to represent unit vector aligned to the positive x,y and z axes,and they are thus defined as 技术图片

If we wanted to decompose a 3D vector v into components parallel to the coordinate axes, then we could write 技术图片技术图片

技术图片

In general, we can use the dot product to project any vector a onto any other nonzero vector b using the formula 技术图片

The notation a||b indicates the component of the vector a that is parallel to the vector b,and equation gives us the projection of a onto b(The alternative notation projba is sometimes used in other texts for the projection of a onto b)

The projection of a onto b can be expressed as the matrix product技术图片

The product bbT yields a symmetric matrix that can be multiplied by the vector a to perform the projection. In three dimensions, we have 技术图片

The matrix in this equation is an example of an outer product. Ingeneral, the outer product between two vectors u and v is written as 技术图片, and it produces a matrix for which the (i,j) entry is equal to uivj as in 技术图片

The perpendicular part of the decomposition is called the rejection of a from b and is written技术图片

技术图片

技术图片
#ifndef VECTOR3D_H_
#define VECTOR3D_H_

struct Vector3D {
    float x, y, z;

private:
    Vector3D() = default;
public:
    Vector3D(float a, float b, float c) {
        x = a;
        y = b;
        z = c;
    }

    float & operator[](int i) {
        return ((&x)[i]);
    }

    const float & operator[](int i) const {
        return ((&x)[i]);
    }

    Vector3D & operator*=(float s) {
        x *= s;
        y *= s;
        z *= s;
        return (*this);
    }

    Vector3D & operator/=(float s) {
        s = 1.0f / s;
        x *= s;
        y *= s;
        z *= s;
        return (*this);
    }

    Vector3D & operator+=(const Vector3D & v) {
        x += v.x;
        y += v.y;
        z += v.z;
        return (*this);
    }

    Vector3D & operator-=(const Vector3D & v) {
        x -= v.x;
        y -= v.y;
        z -= v.z;
        return (*this);
    }
};

inline Vector3D operator*(const Vector3D & v, float s) {
    return (Vector3D(v.x * s, v.y * s, v.z * s));
}

inline Vector3D operator/(const Vector3D & v, float s) {
    s = 1.0f / s;
    return (Vector3D(v.x * s, v.y * s, v.z  * s));
}

inline Vector3D operator-(const Vector3D & v) {
    return (Vector3D(-v.x, -v.y, -v.z));
}

inline float Magnitude(const Vector3D & v) {
    return (sqrt(v.x * v.x + v.y * v.y + v.z * v.z));
}

inline Vector3D Normalize(const Vector3D & v) {
    return (v / Magnitude(v));
}

inline Vector3D operator+(const Vector3D & a, const Vector3D & b) {
    return (Vector3D(a.x + b.x, a.y + b.y, a.z + b.z));
}

inline Vector3D operator-(const Vector3D & a, const Vector3D & b) {
    return (Vector3D(a.x - b.x, a.y - b.y, a.z - b.z));
}

inline float Dot(const Vector3D & a, const Vector3D & b) {
    return (a.x * b.x + a.y * b.y + a.z * b.z);
}

inline Vector3D Cross(const Vector3D & a, const Vector3D & b) {
    return (Vector3D(
        a.y * b.z - a.z * b.y,
        a.z * b.x - a.x * b.z,
        a.x * b.y - a.y * b.x
    ));
}

inline Vector3D Project(const Vector3D & a, const Vector3D & b) {
    return (b * (Dot(a, b) / Dot(b, b)));
}

inline Vector3D Reject(const Vector3D & a, const Vector3D & b) {
    return (a - b * (Dot(a, b) / Dot(b, b)));
}

#endif
View Code

  1.7 Matrix Inversion

One of the main reasons that matrices appear so frequently in game engines is because they represent coordinate system transformations.

That is, a matrix M describes how a vector, point, line, plane, or even another transformation can be moved from a coordinate system A with its own origin and set of axes to another coordinate system B with a different origin and set of axes.

It is often necessary to be able to perform the reverse transformation from coordinate system B back to coordinate system A, and to accomplish this, we must be able to find a matrix M-1, called  the inverse of M, that undoes the transformation performed by the matrix M

    1.7.1 Identity Matrices

The identity matrix In is the n x nmatrix whose entries on the main diagonal are all ones and whose entries everywhere else are all zero, which can be written as 技术图片

Inverse are defined onlly for square matrices, and the inverse of an n x n matrix M is a matrix denoted by M-1 having the property that MM-1 = In and M-1M = In. An inverse does not always exist.

    1.7.2 Determinants

The determinant of an n x n matrix M is a scalar value that can be thought of as a sort of magnitude M.It is written as det(M) or |M|.

A matrix has an inverse if and only if its determinant is non zero

The calculation of the determinant for an n x n matrix M requires that we sum over n! terms corresponding to all of the possible permutations of the sequence {0, 1, 2, ..., n - 1}

The determinant of  3 x 3 matrix M is given by 技术图片

The determinant of a 1 x 1 matrix is simply the value of its single entry.

The determinant of a 2 x 2 matrix 技术图片

技术图片
#ifndef MATRIX3D_H_
#define MATRIX3D_H_

#include "Vector3D.h"

struct Matrix3D {
private:
    float n[3][3];
    Matrix3D() = default;
public:
    // column major order
    Matrix3D(float n00, float n01, float n02,
        float n10, float n11, float n12,
        float n20, float n21, float n22) {
        n[0][0] = n00; n[0][1] = n10; n[0][2] = n20;
        n[1][0] = n01; n[1][1] = n11; n[1][2] = n21;
        n[2][0] = n02; n[2][1] = n12; n[2][2] = n22;
    }

    Matrix3D(const Vector3D & a, const Vector3D & b, const Vector3D & c) {
        n[0][0] = a.x; n[0][1] = a.y; n[0][2] = a.z;
        n[1][0] = b.x; n[1][1] = b.y; n[1][2] = b.z;
        n[2][0] = c.x; n[2][1] = c.y; n[2][2] = c.z;
    }

    float & operator()(int i, int j) {
        return (n[j][i]);
    }

    const float & operator()(int i, int j) const {
        return (n[j][i]);
    }

    Vector3D & operator[](int j) {
        return (*reinterpret_cast<Vector3D *>(n[j]));
    }

    const Vector3D & operator[](int j) const {
        return (*reinterpret_cast<const Vector3D *>(n[j]));
    }
};

Matrix3D operator*(const Matrix3D & A, const Matrix3D & B) {
    return (Matrix3D(
        A(0, 0) * B(0, 0) + A(0, 1) * B(1, 0) + A(0, 2) * B(2, 0),
        A(0, 0) * B(0, 1) + A(0, 1) * B(1, 1) + A(0, 2) * B(2, 1),
        A(0, 0) * B(0, 2) + A(0, 1) * B(1, 2) + A(0, 2) * B(2, 2),

        A(1, 0) * B(0, 0) + A(1, 1) * B(1, 0) + A(1, 2) * B(2, 0),
        A(1, 0) * B(0, 1) + A(1, 1) * B(1, 1) + A(1, 2) * B(2, 1),
        A(1, 0) * B(0, 2) + A(1, 1) * B(1, 2) + A(1, 2) * B(2, 2),

        A(2, 0) * B(0, 0) + A(2, 1) * B(1, 0) + A(2, 2) * B(2, 0),
        A(2, 0) * B(0, 1) + A(2, 1) * B(1, 1) + A(2, 2) * B(2, 1),
        A(2, 0) * B(0, 2) + A(2, 1) * B(1, 2) + A(2, 2) * B(2, 2)
    ));
}

Vector3D operator*(const Matrix3D & M, const Vector3D & v) {
    return (Vector3D(
        M(0, 0) * v.x + M(0, 1) * v.y + M(0, 2) * v.z,
        M(1, 0) * v.x + M(1, 1) * v.y + M(1, 2) * v.z,
        M(2, 0) * v.x + M(2, 1) * v.y + M(2, 2) * v.z
    ));

}

float Determinant(const Matrix3D & M) {
    return (
        M(0, 0) * M(1, 1) * M(2, 2) - M(0, 2) * M(1, 1) * M(2, 0) +
        M(0, 1) * M(1, 2) * M(2, 0) - M(0, 1) * M(1, 0) * M(2, 2) +
        M(0, 2) * M(1, 0) * M(2, 1) - M(0, 0) * M(1, 2) * M(2, 1));
}

#endif
View Code

The determinant of any n xn matrix M can be expressed as 技术图片

Using expansion by minors, the determinant  of an n x n matrix M is given by 技术图片

    1.7.3 Elementary Matrices 

The inverse of a matrix M can be found by systematically performing a sequence of basic operations on M until it has been transformed into the identity matrix.

Each of these basic operations can be represented by an elementary matrix(初等矩阵), and the product of all the elementary matrices corresponding to all the basic operations used to transform M into the identity provides us with the inverse of M

There are three elementary row operations(初等行运算), named as such because they each affect one or two entiere rows of a matrix, and the particular types perform the following modifications to a matrix M.

  (a) Multiply one row of M by a nonzero scalar value

  (b) Exchange two rows of M

  (c) Add a scalar multiple of one row of M to another row of M

    1.7.4 Inverse Calculation

    1.7.5 Inverse of Small Matrices

技术图片
#ifndef MATRIX3D_H_
#define MATRIX3D_H_

#include "Vector3D.h"

struct Matrix3D {
private:
    float n[3][3];
    Matrix3D() = default;
public:
    // column major order
    Matrix3D(float n00, float n01, float n02,
        float n10, float n11, float n12,
        float n20, float n21, float n22) {
        n[0][0] = n00; n[0][1] = n10; n[0][2] = n20;
        n[1][0] = n01; n[1][1] = n11; n[1][2] = n21;
        n[2][0] = n02; n[2][1] = n12; n[2][2] = n22;
    }

    Matrix3D(const Vector3D & a, const Vector3D & b, const Vector3D & c) {
        n[0][0] = a.x; n[0][1] = a.y; n[0][2] = a.z;
        n[1][0] = b.x; n[1][1] = b.y; n[1][2] = b.z;
        n[2][0] = c.x; n[2][1] = c.y; n[2][2] = c.z;
    }

    float & operator()(int i, int j) {
        return (n[j][i]);
    }

    const float & operator()(int i, int j) const {
        return (n[j][i]);
    }

    Vector3D & operator[](int j) {
        return (*reinterpret_cast<Vector3D *>(n[j]));
    }

    const Vector3D & operator[](int j) const {
        return (*reinterpret_cast<const Vector3D *>(n[j]));
    }
};

Matrix3D operator*(const Matrix3D & A, const Matrix3D & B) {
    return (Matrix3D(
        A(0, 0) * B(0, 0) + A(0, 1) * B(1, 0) + A(0, 2) * B(2, 0),
        A(0, 0) * B(0, 1) + A(0, 1) * B(1, 1) + A(0, 2) * B(2, 1),
        A(0, 0) * B(0, 2) + A(0, 1) * B(1, 2) + A(0, 2) * B(2, 2),

        A(1, 0) * B(0, 0) + A(1, 1) * B(1, 0) + A(1, 2) * B(2, 0),
        A(1, 0) * B(0, 1) + A(1, 1) * B(1, 1) + A(1, 2) * B(2, 1),
        A(1, 0) * B(0, 2) + A(1, 1) * B(1, 2) + A(1, 2) * B(2, 2),

        A(2, 0) * B(0, 0) + A(2, 1) * B(1, 0) + A(2, 2) * B(2, 0),
        A(2, 0) * B(0, 1) + A(2, 1) * B(1, 1) + A(2, 2) * B(2, 1),
        A(2, 0) * B(0, 2) + A(2, 1) * B(1, 2) + A(2, 2) * B(2, 2)
    ));
}

Vector3D operator*(const Matrix3D & M, const Vector3D & v) {
    return (Vector3D(
        M(0, 0) * v.x + M(0, 1) * v.y + M(0, 2) * v.z,
        M(1, 0) * v.x + M(1, 1) * v.y + M(1, 2) * v.z,
        M(2, 0) * v.x + M(2, 1) * v.y + M(2, 2) * v.z
    ));

}

float Determinant(const Matrix3D & M) {
    return (
        M(0, 0) * M(1, 1) * M(2, 2) - M(0, 2) * M(1, 1) * M(2, 0) +
        M(0, 1) * M(1, 2) * M(2, 0) - M(0, 1) * M(1, 0) * M(2, 2) +
        M(0, 2) * M(1, 0) * M(2, 1) - M(0, 0) * M(1, 2) * M(2, 1));
}

Matrix3D Inverse(const Matrix3D & M) {
    const Vector3D & a = M[0];
    const Vector3D & b = M[1];
    const Vector3D & c = M[2];

    Vector3D r0 = Cross(b, c);
    Vector3D r1 = Cross(c, a);
    Vector3D r2 = Cross(a, b);

    float invDet = 1.0f / Dot(r2, c);
    return (Matrix3D(
        r0.x * invDet, r0.y * invDet, r0.z * invDet,
        r1.x * invDet, r1.y * invDet, r1.z * invDet,
        r2.x * invDet, r2.y * invDet, r2.z * invDet
    ));
}



#endif
View Code

  Exercises for Chapter1

Chapter2 Transforms

A dynamic object in a game may need to move from one point to another, and it may need to rotate itself to different orientations.

A model may be composed of a collection of objects arranged in a tree structure,and each part may move in a manner that is relative to another part above it in the hierarchy.

It may be necessary to express positions and orientations in may different local coordinate systems used by various components of a rendering system.

All of these are examples of cases that require the application of transforms.

  2.1 Coordinate Spaces

It is typical for a game engine to define a number of different coordinate systems.

There is usually a coordinate system called world space or global space that serves as a fixed background relative to which other coordinate systems can be established.]

Various objects in a game, which can include things like models, light sources, and cameras, often have their own independent coordinate systems called object space or local space.

When an interaction occurs between two objects using different coordinate systems, either one object need to be transformed into the coordinate system used by the other object

or both objects need to be transformed into some other common coordinate system.

    2.1.1 Transformation Matrices

The transformation from a position PA in coordinate system A to the position PB in coordinate system B can be expressed as技术图片 

where M is a 3 x 3 martrix that reorients the coordinate axes, and t is a 3D translation vector that moves the origin of the coordinate system.

The transformation is called an affine transformation

Assuming that M is invertible, we can solve this equation for PA to obtain the inverse transformation from coordinate system B to coordinate system A as 技术图片

 

    2.1.2 Orthogonal Transforms

    2.1.3 Transform Composition

  2.2 Rotations

    2.2.1 Rotation About a Coordinate Axis

    2.2.2 Rotation About an Arbitrary Axis

  2.3 Reflections

  2.4 Scales

  2.5 Skews

  2.6 Homogeneous Coordinates

  2.7 Quaternions

    2.7.1 Quaternion Fundamentals

    2.7.2 Rotations With Quaternions

  Exercises for Chapter2

Chapter3 Geometry

  3.1 Triangle Meshes

  3.2 Normal Vectors

    3.2.1 Calculating Normal Vectors

    3.2.2 Transforming Normal Vectors

  3.3 Lines and Rays

    3.3.1 Parametric Lines

    3.3.2 Distance Between a Point and a Line

    3.3.3 Distance Between Two Lines

  3.4 Planes

    3.4.1 Implicit Planes

    3.4.2 Distance Between a Point and a Plane

    3.4.3 Reflection Through a Plane

    3.4.4 Intersection of a Line and a Plane

    3.4.5 Intersection of Three Planes

    3.4.6 Intersection of Two Planes

    3.4.7 Transforming Planes

  3.5 Plucker Coordinates

    3.5.1 Implicit Lines

    3.5.2 Homogeneous Formulas

    3.5.3 Transforming Lines

  Exercises for Chapter3

Chapter4 Adavanced Algebra

  4.1 Grassmann Algebra

    4.1.1 Wedge Product

    4.1.2 Bivectors

    4.1.3 Trivectors

    4.1.4 Algebraic Structure

    4.1.5 Complements

    4.1.6 Antivectors

    4.1.7 Antiwedge Product

  4.2 Projective Geometry

    4.2.1 Lines

    4.2.2 Planes

    4.2.3 Join and Meet

    4.2.4 Line Crossing

    4.2.5 Plane Distance

    4.2.6 Summary and Implementation

  4.3 Matrix Inverses

  4.4 Geometric Algebra

    4.4.1 Geometric Product

    4.4.2 Vector Division

    4.4.3 Rotors

  4.5 Conclusion

  Exercises for Chapter4

以上是关于Foundations of Game Engine Development Volume 1 Mathematics的主要内容,如果未能解决你的问题,请参考以下文章

Python socket 基础(Server) - Foundations of Python Socket

Foundations of streaming SQL

Conway's Game of Life

289. Game of Life

Game of Connections

289. Game of Life