[英]How to rotate a model around a global axis in openGL?
在 OpenGL 中,我想圍繞全局軸旋轉 Model。
我試圖旋轉的 object 看起來像這樣:
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
};
啟動 object 的 function 看起來像:
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 軸。 Object 的中心位於 (3, 1, 0) 處,因此如果原點位於 (3, 0, 1) 處,則圍繞 90 度旋轉。
我嘗試使用glm::rotate
方法來做到這一點:
glm::vec3 axis;
axis = { 1.0, 0.0f, 0.0f };
sphere.model = glm::rotate(sphere.model, glm::radians(90.0f), axis);
但這只會圍繞其本地軸旋轉 object。
我嘗試的另一個解決方案是這個:
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);
另一方面,就像全局軸位於 model 的中心一樣。 因此,如果 object 的中心等於全局坐標系的原點,則旋轉是正確的。
我會向@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
。 這意味着“模型空間”與“全局空間”相同。 因此,您無需在旋轉之前平移球體。
旋轉 object 后,將其平移到您希望的位置。
在您的模型+視圖+投影 (MVP) 矩陣(或四元數)操作中,您正在混合 model 和視圖矩陣。 您需要將 model 從單位矩陣旋轉到所需的 RPY 矩陣。 然后,您將 object 移動和/或旋轉到您想要在 XYZ 空間中的位置。 最后,您可以根據需要應用正交投影或透視投影。
關鍵是您應該分別跟蹤 OBJECT 的原點相對於 GLOBAL 原點的位置。 換句話說,您擁有 object 的質心所在的位置,還有旋轉中心(不一定是全局原點)。
為了在 object 質心的局部框架中旋轉 object,您需要首先擺脫平移組件。 這是模型+視圖部分。 您可以通過對 4x4 矩陣的最后一列中的 XYZ 元素進行逆矩陣來做到這一點。 然后將 4x4 旋轉矩陣應用於質心。 然后將 object 移回所需的質心位置。
這有意義嗎?
我建議您更多地研究 MVP model。 OGL 4 着色語言食譜(由 Packt 提供)是一個很好的資源。 還有這個鏈接和這個。
但是,我應該注意,您應該熟悉 glm 矩陣庫的后端。 我使用了一個自定義矩陣庫,顯示了rotate()
function 的實現。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.