最近,我一直在尝试扩大线性代数领域的知识。无论如何,在我的游戏引擎中,我当前正在创建一个正交摄影机。在这次学习冒险中,我选择实现自己的矩阵/向量库。因此,我以为一切正常,但是我意识到我的物体围绕它们的中心而不是相机的中心旋转。我试图修复它,但一切都搞砸了。我把它固定到了原来的水平。但是我不知道如何使对象绕摄像机而不是中心旋转。
Matrix4.h
#ifndef Matrix4_h
#define Matrix4_h
#include "Scalar.h"
#include "Vector4.h"
namespace Apollo
{
class Matrix4
{
public:
Vector4 RowX, RowY, RowZ, RowW;
Scalar Elements[16];
Matrix4(const Vector4 &r1, const Vector4 &r2, const Vector4 &r3, const Vector4 &r4)
: RowX(r1), RowY(r2), RowZ(r3), RowW(r4) { SetArrayValues(); }
Matrix4(Scalar scalar)
: Matrix4({scalar, 0.0, 0.0, 0.0}, {0.0, scalar, 0.0, 0.0}, {0.0, 0.0, scalar, 0.0}, {0.0, 0.0, 0.0, scalar}) {}
///// Access Operations ////////////////////////////////////
inline Vector4 &operator[](int index)
{
switch (index)
{
case 0:
return RowX;
case 1:
return RowY;
case 2:
return RowZ;
case 3:
return RowW;
default:
return RowX;
}
}
inline const Scalar *GetUniformPointer() const { return &(Elements[0]); }
///// Matrix Operations ////////////////////////////////////
inline const Matrix4 Transpose() const
{
return Matrix4(Vector4(RowX.X, RowY.X, RowZ.X, RowW.X),
Vector4(RowX.Y, RowY.Y, RowZ.Y, RowW.Y),
Vector4(RowX.Z, RowY.Z, RowZ.Z, RowW.Z),
Vector4(RowX.W, RowY.W, RowZ.W, RowW.W));
}
///// Math Operations //////////////////////////////////////
inline Matrix4 Add(const Matrix4 &matrix) const { return Matrix4(RowX + matrix.RowX, RowY + matrix.RowY, RowZ + matrix.RowZ, RowW + matrix.RowW); }
inline Matrix4 operator+(const Matrix4 &matrix) const { return Add(matrix); }
inline Matrix4 Subtract(const Matrix4 &matrix) const { return Matrix4(RowX - matrix.RowX, RowY - matrix.RowY, RowZ - matrix.RowZ, RowW - matrix.RowW); }
inline Matrix4 operator-(const Matrix4 &matrix) const { return Subtract(matrix); }
inline Matrix4 Multiply(const Matrix4 &matrix) const
{
Matrix4 mat = matrix.Transpose();
return Matrix4(Vector4(RowX * mat.RowX, RowX * mat.RowY, RowX * mat.RowZ, RowX * mat.RowW),
Vector4(RowY * mat.RowX, RowY * mat.RowY, RowY * mat.RowZ, RowY * mat.RowW),
Vector4(RowZ * mat.RowX, RowZ * mat.RowY, RowZ * mat.RowZ, RowZ * mat.RowW),
Vector4(RowW * mat.RowX, RowW * mat.RowY, RowW * mat.RowZ, RowW * mat.RowW));
}
inline Matrix4 operator*(const Matrix4 &matrix) const { return Multiply(matrix); }
inline Matrix4 Scale(Scalar scalar) const { return Matrix4(RowX * scalar, RowY * scalar, RowZ * scalar, RowW * scalar); }
inline Matrix4 operator*(Scalar scalar) const { return Scale(scalar); }
private:
void SetArrayValues()
{
Elements[0] = RowX.X; // Column 1
Elements[1] = RowY.X;
Elements[2] = RowZ.X;
Elements[3] = RowW.X;
Elements[4] = RowX.Y; // Column 2
Elements[5] = RowY.Y;
Elements[6] = RowZ.Y;
Elements[7] = RowW.Y;
Elements[8] = RowX.Z; // Column 3
Elements[9] = RowY.Z;
Elements[10] = RowZ.Z;
Elements[11] = RowW.Z;
Elements[12] = RowX.W; // Column 4
Elements[13] = RowY.W;
Elements[14] = RowZ.W;
Elements[15] = RowW.W;
}
};
} // namespace Apollo
#endif /* end of include guard: Matrix4_h */
Vector4.h
#ifndef Vector4_h
#define Vector4_h
#include "Scalar.h"
namespace Apollo
{
class Vector4
{
public:
Scalar X, Y, Z, W;
Scalar Elements[4];
Vector4(float x, float y, float z, float w)
: X(x), Y(y), Z(z), W(w) { SetArrayValues(); }
Vector4(float x)
: Vector4(x, x, x, x) {}
///// Access Operations ////////////////////////////////////
inline Scalar &operator[](int index) { return Elements[index]; }
inline const Scalar *GetUniformPointer() const { return &(Elements[0]); }
///// Math Operations //////////////////////////////////////
inline const Vector4 Add(const Vector4 &vector) const { return Vector4(X + vector.X, Y + vector.Y, Z + vector.Z, W + vector.W); }
inline const Vector4 operator+(const Vector4 &vector) const { return Add(vector); }
inline const Vector4 Subtract(const Vector4 &vector) const { return Vector4(X - vector.X, Y - vector.Y, Z - vector.Z, W - vector.W); }
inline const Vector4 operator-(const Vector4 &vector) const { return Subtract(vector); }
inline const Scalar Multiply(const Vector4 &vector) const { return X * vector.X + Y * vector.Y + Z * vector.Z + W * vector.W; }
inline const Scalar operator*(const Vector4 &vector) const { return Multiply(vector); }
inline const Vector4 Scale(Scalar scalar) const { return Vector4(X * scalar, Y * scalar, Z * scalar, W * scalar); }
inline const Vector4 operator*(Scalar scalar) const { return Scale(scalar); }
private:
inline void SetArrayValues()
{
Elements[0] = X;
Elements[1] = Y;
Elements[2] = Z;
Elements[3] = W;
}
};
} // namespace Apollo
#endif /* end of include guard: Vector4_h */
Camera.cpp
#include "Camera.h"
#include <cmath>
namespace Apollo
{
OrthographicCamera::OrthographicCamera(float left, float right, float bottom, float top)
: m_Projection(1.0), m_View(1.0), m_ProjectionView(1.0), m_Position(0.0)
{
m_Projection = Matrix4(Vector4(2 / (right - left), 0, 0, -((right + left) / (right - left))),
Vector4(0, 2 / (top - bottom), 0, -((top + bottom) / (top - bottom))),
Vector4(0, 0, 1, 0),
Vector4(0, 0, 0, 1));
CalculateProjectionView();
}
OrthographicCamera::~OrthographicCamera()
{
}
void OrthographicCamera::SetBounds(float left, float right, float bottom, float top)
{
m_Projection = Matrix4(Vector4(2 / (right - left), 0, 0, -((right + left) / (right - left))),
Vector4(0, 2 / (top - bottom), 0, -((top + bottom) / (top - bottom))),
Vector4(0, 0, 1, 0),
Vector4(0, 0, 0, 1));
CalculateProjectionView();
}
void OrthographicCamera::CalculateProjectionView()
{
Matrix4 translation = Matrix4(Vector4(1, 0, 0, 0),
Vector4(0, 1, 0, 0),
Vector4(0, 0, 1, 0),
Vector4(0.5, 0.5, 0.5, 1));
Matrix4 rotation = Matrix4(Vector4(cos(m_Rotation / 180 * M_PI), -sin(m_Rotation / 180 * M_PI), 0, 0),
Vector4(sin(m_Rotation / 180 * M_PI), cos(m_Rotation / 180 * M_PI), 0, 0),
Vector4(0, 0, 1, 0),
Vector4(0, 0, 0, 1));
m_View = rotation * translation;
m_ProjectionView = m_View * m_Projection;
}
} // namespace Apollo
其他说明 标量只是float的typedef。每次相机更新时都会调用CalculateProjectionView。然后由渲染器将其上载到着色器。另外,可以在Github上获得完整的源代码,网址为https://github.com/James51332/Apollo,谢谢!