在OpenGL中,我想绕全局轴旋转模型。
我尝试旋转的对象看起来像这样:
class Object {
public:
inline Object()
: vao(0),
positionBuffer(0),
colorBuffer(0),
indexBuffer(0),
elements(0)
{}
inline ~Object() { // GL context must exist on destruction
glDeleteVertexArrays(1, &vao);
glDeleteBuffers(1, &indexBuffer);
glDeleteBuffers(1, &colorBuffer);
glDeleteBuffers(1, &positionBuffer);
}
GLuint vao; // vertex-array-object ID
GLuint positionBuffer; // ID of vertex-buffer: position
GLuint colorBuffer; // ID of vertex-buffer: color
GLuint indexBuffer; // ID of index-buffer
GLuint elements; // Number of Elements
glm::mat4x4 model; // model matrix
};
启动对象的功能如下:
void initObject(Object &obj, vector<glm::vec3> &vertices, vector<glm::vec3> &colors, vector<GLushort> &indices, glm::vec3 offset)
{
GLuint programId = program.getHandle();
GLuint pos;
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
// Step 0: Create vertex array object.
glGenVertexArrays(1, &obj.vao);
glBindVertexArray(obj.vao);
// Step 1: Create vertex buffer object for position attribute and bind it to the associated "shader attribute".
glGenBuffers(1, &obj.positionBuffer);
glBindBuffer(GL_ARRAY_BUFFER, obj.positionBuffer);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), vertices.data(), GL_STATIC_DRAW);
// Bind it to position.
pos = glGetAttribLocation(programId, "position");
glEnableVertexAttribArray(pos);
glVertexAttribPointer(pos, 3, GL_FLOAT, GL_FALSE, 0, 0);
// Step 2: Create vertex buffer object for color attribute and bind it to...
glGenBuffers(1, &obj.colorBuffer);
glBindBuffer(GL_ARRAY_BUFFER, obj.colorBuffer);
glBufferData(GL_ARRAY_BUFFER, colors.size() * sizeof(glm::vec3), colors.data(), GL_STATIC_DRAW);
// Bind it to color.
pos = glGetAttribLocation(programId, "color");
glEnableVertexAttribArray(pos);
glVertexAttribPointer(pos, 3, GL_FLOAT, GL_FALSE, 0, 0);
// Step 3: Create vertex buffer object for indices. No binding needed here.
glGenBuffers(1, &obj.indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, obj.indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(GLushort), indices.data(), GL_STATIC_DRAW);
// Unbind vertex array object (back to default).
glBindVertexArray(0);
// Modify model matrix.
obj.model = glm::translate(glm::mat4(1.0f), offset);
}
现在,我得到了一个镶嵌的八面体作为球体的实例,我想绕一个全局轴(特别是X轴)旋转它。该对象的中心位于(3,1,0),因此,绕90度旋转应该使原点位于(3,0,1)。
我尝试使用glm::rotate
方法执行此操作:
glm::vec3 axis;
axis = { 1.0, 0.0f, 0.0f };
sphere.model = glm::rotate(sphere.model, glm::radians(90.0f), axis);
但是那只会绕对象的本地轴旋转它。
我尝试过的另一种解决方案是:
glm::vec3 axis;
axis = glm::inverse(sphere.model) * glm::vec4(1.0, 0.0, 0.0, 0.0f);
sphere.model = glm::rotate(sphere.model, (2.0f*3.1415f)/48.0f, axis);
另一只手的行为就像全局轴位于模型的中心。因此,如果对象的中心等于全局坐标系的原点,则旋转将正确。
我会向@genpfault表示敬意。听起来像glm :: rotate的实现是:[https://github.com/g-truc/glm/blob/1498e094b95d1d89164c6442c632d775a2a1bab5/glm/ext/matrix_transform.inl
因此它不触碰平移,它仅改变矩阵的旋转部分,就像设置物体一样。为了执行动画或组合不同的转换,您需要使用另一个API。
[retMat = glm::rotate(curMat, ...)
计算旋转矩阵,并将其与给定的curMat
矩阵相乘。
返回的矩阵retMat
可以与在curMat
相同的坐标系(也称为“空间”)中定义的任何点一起使用,以再次在相同的空间newXYZ = retMat * oldXYZ
中计算新坐标。] >
赋予glm::rotate
的旋转轴始终穿过该空间的原点。 如果您需要另一条旋转线(不包含原点),则必须执行序列“转换到直线上的某个点==>旋转==>向后平移”
对于您的情况,我想您的球体是这样定义的,其中心是原点0,0,0
。这意味着“模型空间”与“全局空间”相同。因此,您无需在旋转之前平移球体。
旋转对象后,将其平移到所需的位置。
在模型+视图+投影(MVP)矩阵(或四元数)运算中,您正在混合模型和视图矩阵。您需要将模型从单位矩阵旋转到所需的RPY矩阵。然后,将对象移动和/或旋转到XYZ空间中所需的位置。最后,您可以根据需要应用正交投影或透视投影。