在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);这是另一种行为,就像全局轴在模型的中心。因此,如果对象的中心等于全局坐标系的原点,则旋转是正确的。
发布于 2020-06-05 01:23:31
我会把Kudos归于@genpfault。听起来像是glm::rotate的实现是一个:https://github.com/g-truc/glm/blob/1498e094b95d1d89164c6442c632d775a2a1bab5/glm/ext/matrix_transform.inl
因此,它不涉及平移,它只改变矩阵的旋转部分,就像设置东西一样。为了执行动画或组合不同的转换,您需要使用另一个API。
发布于 2020-06-05 02:19:32
retMat = glm::rotate(curMat, ...)计算旋转矩阵,并将其与给定的curMat矩阵相乘。
返回的矩阵retMat可以与在与curMat相同的坐标系(也称为“空间”)中定义的任何点一起使用,以计算新的坐标,同样是在相同的空间中:newXYZ = retMat * oldXYZ。
指定给glm::rotate的旋转轴始终经过空间的原点。
如果您需要另一条旋转线(不包含原点),则必须执行序列"translate to some on line ==> rotate ==> translate back"
对于你的例子,我猜你的球体是这样定义的,它的中心是原点0,0,0。这意味着“模型空间”与“全局空间”是相同的。因此,您不需要在旋转之前平移球体。
一旦您旋转了对象,然后将其平移到您想要的点。
发布于 2020-06-07 00:11:03
在model+view+projection (MVP)矩阵(或四元数)操作中,您混合了模型矩阵和视图矩阵。您需要将模型从单位矩阵旋转到所需的RPY矩阵。然后,将对象移动和/或旋转到XYZ空间中所需的位置。最后,根据需要应用正交投影或透视投影。
重点是,您应该分别跟踪对象的原点相对于全局原点的位置。换句话说,您不仅拥有希望对象的质心所在的位置,还拥有旋转的中心(不一定是全局原点)。
为了在对象质心的局部框架中旋转对象,首先需要去除平移组件。这是Model+View部分。您可以通过在4x4矩阵的最后一列中仅对XYZ元素进行逆矩阵来实现这一点。然后将4x4旋转矩阵应用于质心。然后将对象移回所需的质心位置。
这有意义吗?
我建议你更多地研究MVP模型。OGL 4着色语言食谱(由Packt编写)是一个很好的资源。还有this link和this one。
但是,我应该注意到,您应该熟悉glm矩阵库的后端。我使用了一个自定义矩阵库,它展示了rotate()函数的实现。
https://stackoverflow.com/questions/62198942
复制相似问题