OpenGL 奇怪的立方体旋转
OpenGL weird cube rotation
我正在自学现代 OpenGL。我目前 运行 在渲染 3D 立方体时遇到问题。
首先我创建了一个精灵,这是我的 class 包含位置、宽度、高度和单个矩形精灵的纹理。然后我将它传递给我的渲染器 class 来创建一个立方体,它的每面墙都由相同的精灵组成。
void Renderer::constructWall(maths::vec3 bottomLeft, maths::vec3 topLeft, maths::vec3 topRight, maths::vec3 bottomRight, maths::vec4 color){
m_Buffer->position = bottomLeft;
m_Buffer->color = maths::vec4(color.x, color.y, color.z, 1.0f);
m_Buffer->tex = maths::vec2(0.0f, 0.0f);
m_Buffer++;
m_Buffer->position = topLeft;
m_Buffer->color = maths::vec4(color.x, color.y, color.z, 1.0f);
m_Buffer->tex = maths::vec2(0.0f, 1.0f);
m_Buffer++;
m_Buffer->position = topRight;
m_Buffer->color = maths::vec4(color.x, color.y, color.z, 1.0f);
m_Buffer->tex = maths::vec2(1.0f, 1.0f);
m_Buffer++;
m_Buffer->position = bottomRight;
m_Buffer->color = maths::vec4(color.x, color.y, color.z, 1.0f);
m_Buffer->tex = maths::vec2(1.0f, 0.0f);
m_Buffer++;
m_IndexCount += 6;
}
m_Buffer是一个VertexData类型的指针,是一个struct:
struct VertexData{
maths::vec3 position;
maths::vec4 color;
maths::vec2 tex;
};
m_IndexCount 是一个简单的计数器,用于计算当我在渲染器 class 中提交刷新时需要渲染的索引数。
我通过对立方体的顶点建模并以这种方式使用 constructWall 函数来创建立方体:
maths::vec3 A(vertex.x, vertex.y, -depth/2);
maths::vec3 B(vertex.x, vertex.y + size.y, -depth / 2);
maths::vec3 C(vertex.x + size.x, vertex.y + size.y, -depth / 2);
maths::vec3 D(vertex.x + size.x, vertex.y, -depth / 2);
maths::vec3 E(vertex.x, vertex.y, depth/2);
maths::vec3 F(vertex.x, vertex.y + size.y, depth/2);
maths::vec3 G(vertex.x + size.x, vertex.y + size.y, depth/2);
maths::vec3 H(vertex.x + size.x, vertex.y, depth/2);
constructWall(A, B, C, D, color1);
constructWall(E, F, G, H, color1);
constructWall(A, B,F,E, color1);
constructWall(D, C, G, H, color1);
constructWall(A, E, H, D, color1);
constructWall(B, F, G, C, color1);
当我创建一个立方体时它工作得很好,在一个轴上旋转它也可以,但是当我尝试在多个轴上旋转它时,我的立方体有时会表现得很奇怪:
还有我的矩阵码:
mat4::mat4()
{
for (int i = 0; i < 4 * 4; i++)
elements[i] = 0.0f;
}
mat4::mat4(float diagonal)
{
for (int i = 0; i < 4 * 4; i++)
elements[i] = 0.0f;
elements[0 + 0 * 4] = diagonal;
elements[1 + 1 * 4] = diagonal;
elements[2 + 2 * 4] = diagonal;
elements[3 + 3 * 4] = diagonal;
}
mat4 mat4::identity()
{
return mat4(1.0f);
}
mat4& mat4::multiply(const mat4& other)
{
float data[16];
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
float sum = 0.0f;
for (int e = 0; e < 4; e++)
{
sum += elements[x + e * 4] * other.elements[e + y * 4];
}
data[x + y * 4] = sum;
}
}
memcpy(elements, data, 4 * 4 * sizeof(float));
return *this;
}
vec3 mat4::multiply(const vec3& other) const
{
return vec3(
columns[0].x * other.x + columns[1].x * other.y + columns[2].x * other.z + columns[3].x,
columns[0].y * other.x + columns[1].y * other.y + columns[2].y * other.z + columns[3].y,
columns[0].z * other.x + columns[1].z * other.y + columns[2].z * other.z + columns[3].z
);
}
vec4 mat4::multiply(const vec4& other) const
{
return vec4(
columns[0].x * other.x + columns[1].x * other.y + columns[2].x * other.z + columns[3].x * other.w,
columns[0].y * other.x + columns[1].y * other.y + columns[2].y * other.z + columns[3].y * other.w,
columns[0].z * other.x + columns[1].z * other.y + columns[2].z * other.z + columns[3].z * other.w,
columns[0].w * other.x + columns[1].w * other.y + columns[2].w * other.z + columns[3].w * other.w
);
}
mat4 operator*(mat4 left, const mat4& right)
{
return left.multiply(right);
}
mat4& mat4::operator*=(const mat4& other)
{
return multiply(other);
}
vec3 operator*(const mat4& left, const vec3& right)
{
return left.multiply(right);
}
vec4 operator*(const mat4& left, const vec4& right)
{
return left.multiply(right);
}
mat4 mat4::orthographic(float left, float right, float bottom, float top, float near, float far)
{
mat4 result(1.0f);
result.elements[0 + 0 * 4] = 2.0f / (right - left);
result.elements[1 + 1 * 4] = 2.0f / (top - bottom);
result.elements[2 + 2 * 4] = 2.0f / (near - far);
result.elements[0 + 3 * 4] = (left + right) / (left - right);
result.elements[1 + 3 * 4] = (bottom + top) / (bottom - top);
result.elements[2 + 3 * 4] = (far + near) / (far - near);
return result;
}
mat4 mat4::perspective(float fov, float aspectRatio, float near, float far)
{
mat4 result(1.0f);
float q = 1.0f / tan(toRadians(0.5f * fov));
float a = q / aspectRatio;
float b = (near + far) / (near - far);
float c = (2.0f * near * far) / (near - far);
result.elements[0 + 0 * 4] = a;
result.elements[1 + 1 * 4] = q;
result.elements[2 + 2 * 4] = b;
result.elements[3 + 2 * 4] = -1.0f;
result.elements[2 + 3 * 4] = c;
return result;
}
mat4 mat4::translation(const vec3& translation)
{
mat4 result(1.0f);
result.elements[0 + 3 * 4] = translation.x;
result.elements[1 + 3 * 4] = translation.y;
result.elements[2 + 3 * 4] = translation.z;
return result;
}
mat4 mat4::rotation(float angle, const vec3& axis)
{
mat4 result(1.0f);
float r = toRadians(angle);
float c = cos(r);
float s = sin(r);
float omc = 1.0f - c;
float x = axis.x;
float y = axis.y;
float z = axis.z;
result.elements[0 + 0 * 4] = x * omc + c;
result.elements[1 + 0 * 4] = y * x * omc + z * s;
result.elements[2 + 0 * 4] = x * z * omc - y * s;
result.elements[0 + 1 * 4] = x * y * omc - z * s;
result.elements[1 + 1 * 4] = y * omc + c;
result.elements[2 + 1 * 4] = y * z * omc + x * s;
result.elements[0 + 2 * 4] = x * z * omc + y * s;
result.elements[1 + 2 * 4] = y * z * omc - x * s;
result.elements[2 + 2 * 4] = z * omc + c;
return result;
}
mat4 mat4::scale(const vec3& scale)
{
mat4 result(1.0f);
result.elements[0 + 0 * 4] = scale.x;
result.elements[1 + 1 * 4] = scale.y;
result.elements[2 + 2 * 4] = scale.z;
return result;
}
在您的代码中计算围绕任意轴旋转的对角线元素的公式似乎有误。尝试更改为:
result.elements[0 + 0 * 4] = x * x + (1.0f - (x * x)) * c;
result.elements[1 + 0 * 4] = y * x * omc + z * s;
result.elements[2 + 0 * 4] = x * z * omc - y * s;
result.elements[0 + 1 * 4] = x * y * omc - z * s;
result.elements[1 + 1 * 4] = y * y + (1.0f - (y * y)) * c;
result.elements[2 + 1 * 4] = y * z * omc + x * s;
result.elements[0 + 2 * 4] = x * z * omc + y * s;
result.elements[1 + 2 * 4] = y * z * omc - x * s;
result.elements[2 + 2 * 4] = z * z + (1.0f - (z * z)) * c;
参考本文第 5.2 节mathematical explanation。
我正在自学现代 OpenGL。我目前 运行 在渲染 3D 立方体时遇到问题。
首先我创建了一个精灵,这是我的 class 包含位置、宽度、高度和单个矩形精灵的纹理。然后我将它传递给我的渲染器 class 来创建一个立方体,它的每面墙都由相同的精灵组成。
void Renderer::constructWall(maths::vec3 bottomLeft, maths::vec3 topLeft, maths::vec3 topRight, maths::vec3 bottomRight, maths::vec4 color){
m_Buffer->position = bottomLeft;
m_Buffer->color = maths::vec4(color.x, color.y, color.z, 1.0f);
m_Buffer->tex = maths::vec2(0.0f, 0.0f);
m_Buffer++;
m_Buffer->position = topLeft;
m_Buffer->color = maths::vec4(color.x, color.y, color.z, 1.0f);
m_Buffer->tex = maths::vec2(0.0f, 1.0f);
m_Buffer++;
m_Buffer->position = topRight;
m_Buffer->color = maths::vec4(color.x, color.y, color.z, 1.0f);
m_Buffer->tex = maths::vec2(1.0f, 1.0f);
m_Buffer++;
m_Buffer->position = bottomRight;
m_Buffer->color = maths::vec4(color.x, color.y, color.z, 1.0f);
m_Buffer->tex = maths::vec2(1.0f, 0.0f);
m_Buffer++;
m_IndexCount += 6;
}
m_Buffer是一个VertexData类型的指针,是一个struct:
struct VertexData{
maths::vec3 position;
maths::vec4 color;
maths::vec2 tex;
};
m_IndexCount 是一个简单的计数器,用于计算当我在渲染器 class 中提交刷新时需要渲染的索引数。 我通过对立方体的顶点建模并以这种方式使用 constructWall 函数来创建立方体:
maths::vec3 A(vertex.x, vertex.y, -depth/2);
maths::vec3 B(vertex.x, vertex.y + size.y, -depth / 2);
maths::vec3 C(vertex.x + size.x, vertex.y + size.y, -depth / 2);
maths::vec3 D(vertex.x + size.x, vertex.y, -depth / 2);
maths::vec3 E(vertex.x, vertex.y, depth/2);
maths::vec3 F(vertex.x, vertex.y + size.y, depth/2);
maths::vec3 G(vertex.x + size.x, vertex.y + size.y, depth/2);
maths::vec3 H(vertex.x + size.x, vertex.y, depth/2);
constructWall(A, B, C, D, color1);
constructWall(E, F, G, H, color1);
constructWall(A, B,F,E, color1);
constructWall(D, C, G, H, color1);
constructWall(A, E, H, D, color1);
constructWall(B, F, G, C, color1);
当我创建一个立方体时它工作得很好,在一个轴上旋转它也可以,但是当我尝试在多个轴上旋转它时,我的立方体有时会表现得很奇怪:
还有我的矩阵码:
mat4::mat4()
{
for (int i = 0; i < 4 * 4; i++)
elements[i] = 0.0f;
}
mat4::mat4(float diagonal)
{
for (int i = 0; i < 4 * 4; i++)
elements[i] = 0.0f;
elements[0 + 0 * 4] = diagonal;
elements[1 + 1 * 4] = diagonal;
elements[2 + 2 * 4] = diagonal;
elements[3 + 3 * 4] = diagonal;
}
mat4 mat4::identity()
{
return mat4(1.0f);
}
mat4& mat4::multiply(const mat4& other)
{
float data[16];
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
float sum = 0.0f;
for (int e = 0; e < 4; e++)
{
sum += elements[x + e * 4] * other.elements[e + y * 4];
}
data[x + y * 4] = sum;
}
}
memcpy(elements, data, 4 * 4 * sizeof(float));
return *this;
}
vec3 mat4::multiply(const vec3& other) const
{
return vec3(
columns[0].x * other.x + columns[1].x * other.y + columns[2].x * other.z + columns[3].x,
columns[0].y * other.x + columns[1].y * other.y + columns[2].y * other.z + columns[3].y,
columns[0].z * other.x + columns[1].z * other.y + columns[2].z * other.z + columns[3].z
);
}
vec4 mat4::multiply(const vec4& other) const
{
return vec4(
columns[0].x * other.x + columns[1].x * other.y + columns[2].x * other.z + columns[3].x * other.w,
columns[0].y * other.x + columns[1].y * other.y + columns[2].y * other.z + columns[3].y * other.w,
columns[0].z * other.x + columns[1].z * other.y + columns[2].z * other.z + columns[3].z * other.w,
columns[0].w * other.x + columns[1].w * other.y + columns[2].w * other.z + columns[3].w * other.w
);
}
mat4 operator*(mat4 left, const mat4& right)
{
return left.multiply(right);
}
mat4& mat4::operator*=(const mat4& other)
{
return multiply(other);
}
vec3 operator*(const mat4& left, const vec3& right)
{
return left.multiply(right);
}
vec4 operator*(const mat4& left, const vec4& right)
{
return left.multiply(right);
}
mat4 mat4::orthographic(float left, float right, float bottom, float top, float near, float far)
{
mat4 result(1.0f);
result.elements[0 + 0 * 4] = 2.0f / (right - left);
result.elements[1 + 1 * 4] = 2.0f / (top - bottom);
result.elements[2 + 2 * 4] = 2.0f / (near - far);
result.elements[0 + 3 * 4] = (left + right) / (left - right);
result.elements[1 + 3 * 4] = (bottom + top) / (bottom - top);
result.elements[2 + 3 * 4] = (far + near) / (far - near);
return result;
}
mat4 mat4::perspective(float fov, float aspectRatio, float near, float far)
{
mat4 result(1.0f);
float q = 1.0f / tan(toRadians(0.5f * fov));
float a = q / aspectRatio;
float b = (near + far) / (near - far);
float c = (2.0f * near * far) / (near - far);
result.elements[0 + 0 * 4] = a;
result.elements[1 + 1 * 4] = q;
result.elements[2 + 2 * 4] = b;
result.elements[3 + 2 * 4] = -1.0f;
result.elements[2 + 3 * 4] = c;
return result;
}
mat4 mat4::translation(const vec3& translation)
{
mat4 result(1.0f);
result.elements[0 + 3 * 4] = translation.x;
result.elements[1 + 3 * 4] = translation.y;
result.elements[2 + 3 * 4] = translation.z;
return result;
}
mat4 mat4::rotation(float angle, const vec3& axis)
{
mat4 result(1.0f);
float r = toRadians(angle);
float c = cos(r);
float s = sin(r);
float omc = 1.0f - c;
float x = axis.x;
float y = axis.y;
float z = axis.z;
result.elements[0 + 0 * 4] = x * omc + c;
result.elements[1 + 0 * 4] = y * x * omc + z * s;
result.elements[2 + 0 * 4] = x * z * omc - y * s;
result.elements[0 + 1 * 4] = x * y * omc - z * s;
result.elements[1 + 1 * 4] = y * omc + c;
result.elements[2 + 1 * 4] = y * z * omc + x * s;
result.elements[0 + 2 * 4] = x * z * omc + y * s;
result.elements[1 + 2 * 4] = y * z * omc - x * s;
result.elements[2 + 2 * 4] = z * omc + c;
return result;
}
mat4 mat4::scale(const vec3& scale)
{
mat4 result(1.0f);
result.elements[0 + 0 * 4] = scale.x;
result.elements[1 + 1 * 4] = scale.y;
result.elements[2 + 2 * 4] = scale.z;
return result;
}
在您的代码中计算围绕任意轴旋转的对角线元素的公式似乎有误。尝试更改为:
result.elements[0 + 0 * 4] = x * x + (1.0f - (x * x)) * c;
result.elements[1 + 0 * 4] = y * x * omc + z * s;
result.elements[2 + 0 * 4] = x * z * omc - y * s;
result.elements[0 + 1 * 4] = x * y * omc - z * s;
result.elements[1 + 1 * 4] = y * y + (1.0f - (y * y)) * c;
result.elements[2 + 1 * 4] = y * z * omc + x * s;
result.elements[0 + 2 * 4] = x * z * omc + y * s;
result.elements[1 + 2 * 4] = y * z * omc - x * s;
result.elements[2 + 2 * 4] = z * z + (1.0f - (z * z)) * c;
参考本文第 5.2 节mathematical explanation。