gpt4 book ai didi

c++ - 在 C++ 中使用您自己的 Matrix 类进行 OpenGL 对象旋转

转载 作者:行者123 更新时间:2023-11-28 01:30:41 25 4
gpt4 key购买 nike

我正在尝试使用 OpenGL,我决定做的一件事是创建我自己的 Matrix 类,而不是使用 glm 的矩阵。Matrix 类具有平移、旋转和缩放对象的方法,如下所示:

Matrix4 Matrix4::translate(Matrix4& matrix, Vector3& translation)
{
Vector4 result(translation, 1.0f);

result.multiply(matrix);

matrix.mElements[3 * 4 + 0] = result.x;
matrix.mElements[3 * 4 + 1] = result.y;
matrix.mElements[3 * 4 + 2] = result.z;

return matrix;
}

Matrix4 Matrix4::rotate(Matrix4& matrix, float angle, Vector3& axis)
{
if (axis.x == 0 && axis.y == 0 && axis.z == 0)
return matrix;

float r = angle;
float s = sin(r);
float c = cos(r);
float omc = 1.0f - cos(r);

float x = axis.x;
float y = axis.y;
float z = axis.z;

matrix.mElements[0 + 0 * 4] = c + x * x * omc;
matrix.mElements[1 + 0 * 4] = x * y * omc - z * s;
matrix.mElements[2 + 0 * 4] = z * x * omc + y * s;

matrix.mElements[0 + 1 * 4] = x * y * omc + z * s;
matrix.mElements[1 + 1 * 4] = c + y * y * omc;
matrix.mElements[2 + 1 * 4] = z * y * omc - x * s;

matrix.mElements[0 + 2 * 4] = x * z * omc - y * s;
matrix.mElements[1 + 2 * 4] = y * z * omc + x * s;
matrix.mElements[2 + 2 * 4] = c + z * z * omc;

return matrix;
}

Matrix4 Matrix4::scale(Matrix4& matrix, Vector3& scaler)
{

matrix.mElements[0 + 0 * 4] *= scaler.x;
matrix.mElements[1 + 0 * 4] *= scaler.x;
matrix.mElements[2 + 0 * 4] *= scaler.x;

matrix.mElements[0 + 1 * 4] *= scaler.y;
matrix.mElements[1 + 1 * 4] *= scaler.y;
matrix.mElements[2 + 1 * 4] *= scaler.y;

matrix.mElements[0 + 2 * 4] *= scaler.z;
matrix.mElements[1 + 2 * 4] *= scaler.z;
matrix.mElements[2 + 2 * 4] *= scaler.z;

matrix.mElements[3 + 3 * 4] = 1;

return matrix;
}

当我在 while 循环中调用平移、旋转和缩放方法(按此特定顺序)时,它会执行我想要的操作,即平移对象,然后围绕其局部原点旋转并缩放它。但是,当我想切换顺序时,我先调用旋转然后再调用翻译,我希望它这样做:

Intended way of rotating then translating

但我的代码不会那样做。相反,它这样做:

What my code does

我该怎么做才能让我的对象只围绕屏幕中心旋转,而不是围绕它的本地原点旋转?我唯一的猜测是我在转换后的矩阵上添加旋转计算时做错了,但我仍然不知道它是什么。

编辑:我需要指出的一件事是,如果我省略了旋转方法,我只处理平移和缩放,他们会做我期望他们做的事情,首先是平移,然后是旋转,然后是先旋转,然后是平移订单。

编辑 2:这是我在 while 循环中调用这些函数的方式。

Matrix4 trans = Matrix4(1.0f);
trans = Matrix4::rotate(trans, (float)glfwGetTime(), Vector3(0.0f, 0.0f, 1.0f));
trans = Matrix4::translate(trans, Vector3(0.5f, -0.5f, 0.0f));
trans = Matrix4::scale(trans, Vector3(0.5f, 0.5f, 1.0f));

shader.setUniformMatrix4f("uTransform", trans);

最佳答案

您必须通过矩阵乘法来连接矩阵。

矩阵乘法 C = A * B 的工作原理如下:

Matrix4x4 A, B, C;

// C = A * B
for ( int k = 0; k < 4; ++ k )
for ( int j = 0; j < 4; ++ j )
C[k][j] = A[0][j] * B[k][0] + A[1][j] * B[k][1] + A[2][j] * B[k][2] + A[3][j] * B[k][3];

我建议以某种方式创建指定矩阵类:

#include <array>

class Matrix4
{
public:

std::array<float, 16> mElements{
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1 };

const float * dataPtr( void ) const { return mElements.data(); }

Matrix4 & multiply( const Matrix4 &mat );
Matrix4 & translate( const Vector3 &translation );
Matrix4 & scale( const Vector3 &scaler );
Matrix4 & rotate( float angle, const Vector3 &axis );
};

实现矩阵乘法。请注意,您必须将结果存储在缓冲区中。如果您将结果直接写回矩阵成员,那么您将更改元素,稍后将在嵌套循环中再次读取这些元素,结果将不正确:

Matrix4& Matrix4::multiply( const Matrix4 &mat )
{
// multiply the existing matrix by the new and store the result in a buffer
const float *A = dataPtr();
const float *B = mat.dataPtr();
std::array<float, 16> C;

for ( int k = 0; k < 4; ++ k ) {
for ( int j = 0; j < 4; ++ j ) {
C[k*4+j] =
A[0*4+j] * B[k*4+0] +
A[1*4+j] * B[k*4+1] +
A[2*4+j] * B[k*4+2] +
A[3*4+j] * B[k*4+3];
}
}

// copy the buffer to the attribute
mElements = C;

return *this;
}

像这样调整平移、旋转和缩放的方法:

Matrix4 & Matrix4::translate( const Vector3 &translation )
{
float x = translation.x;
float y = translation.y;
float z = translation.z;

Matrix4 transMat;
transMat.mElements = {
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
x, y, z, 1.0f };

return multiply(transMat);
}

Matrix4 & Matrix4::rotate( float angle, const Vector3 &axis )
{
float x = axis.x;
float y = axis.y;
float z = axis.z;

float c = cos(angle);
float s = sin(angle);

Matrix4 rotationMat;
rotationMat.mElements = {
x*x*(1.0f-c)+c, x*y*(1.0f-c)-z*s, x*z*(1.0f-c)+y*s, 0.0f,
y*x*(1.0f-c)+z*s, y*y*(1.0f-c)+c, y*z*(1.0f-c)-x*s, 0.0f,
z*x*(1.0f-c)-y*s, z*y*(1.0f-c)+x*s, z*z*(1.0f-c)+c, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f };

return multiply(rotationMat);
}

Matrix4 & Matrix4::scale( const Vector3 &scaler )
{
float x = scaler.x;
float y = scaler.y;
float z = scaler.z;

Matrix4 scaleMat;
scaleMat.mElements = {
x, 0.0f, 0.0f, 0.0f,
0.0f, y, 0.0f, 0.0f,
0.0f, 0.0f, z, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f };

return multiply(scaleMat);
}

如果你像这样使用矩阵类,

float   angle_radians = ....;
Vector3 scaleVec{ 0.2f, 0.2f, 0.2f };
Vector3 transVec{ 0.3f, 0.3f, 0.0f };
Vector3 rotateVec{ 0.0f, 0.0f, 1.0f };

Matrix4 model;
model.rotate( angle_rad, rotateVec );
model.translate( transVec );
model.scale( scaleVec );

那么结果会是这样的:

preview

关于c++ - 在 C++ 中使用您自己的 Matrix 类进行 OpenGL 对象旋转,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51669395/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com