在 OpenGL 中旋转立方体
Rotating cubes in OpenGL
我想要一个围绕中心旋转的立方体。这是我可以用这个转换做的事情:
model = glm::rotate(identity, glm::radians(-100.0f * time), glm::vec3(0.0, 1.0, 0.0)); //rotate around y-axis
model = glm::translate(model, glm::vec3(8.0, 0.0, 0.0));
model = glm::rotate(model, glm::radians(-100.0f * time), glm::vec3(1.0, 0.0, 0.0)); //self-rotation
现在我想要一个立方体,它会随着第一个立方体绕 y 轴旋转而旋转。
想象一下,第一个立方体是地球,第二个立方体是月球。
我试过了,但没用。
test = glm::rotate(test, glm::radians(-100.0f * time), glm::vec3(0.0, 1.0, 0.0));
test = glm::translate(test, glm::vec3(3.0, 0.0, 0.0));
test = glm::translate(test, glm::vec3(8.0, 0.0, 0.0));
test = glm::rotate(test, glm::radians(-100.0f * time), glm::vec3(0.0, 1.0, 0.0));
test = glm::translate(test, glm::vec3(-8.0, 0.0, 0.0));
test = glm::rotate(test, glm::radians(-100.0f * time), glm::vec3(1.0, 0.0, 0.0)); // self-rotation
知道我做错了什么吗?
这是旋转的图片:
对象A绕B旋转顺序:A自转,平移A到B的偏移量,绕B旋转,平移B位置。由于 B 是太阳,我假设它位于您的世界原点,并且一切都在 xz 平面上(笛卡尔坐标系而非 OpenGL 坐标系),因此变为:
model = glm::rotate(identity, glm::radians(-100.0f * time), glm::vec3(1.0, 0.0, 0.0)); //self-rotation
model = glm::translate(model, glm::vec3(8.0, 0.0, 0.0)); // earth is 8 away from sun, where unrotated about sun is 8 units east
model = glm::rotate(model, glm::radians(-100.0f * time), glm::vec3(0.0, 1.0, 0.0)); //rotate about sun
// no need for another translation since sun is at origin
然后对于父对象为地球的对象,在解析父对象到世界的关系之前,首先要解析该关系:
model = glm::rotate(identity, glm::radians(-100.0f * time), glm::vec3(1.0, 0.0, 0.0)); //self-rotation of moon
model = glm::translate(model, glm::vec3(-4.0, 0.0, 0.0)); // moon is 4 away from Earth, where unrotated about Earth is 4 units west
model = glm::rotate(model, glm::radians(-100.0f * time), glm::vec3(0.0, 1.0, 0.0)); //rotate about Earth
// translate to Earth origin, which is calculate from above code block
免责声明,我没有用glm-math,这只是几何变换的顺序,不知道直接翻译成glm::x
您的评论表明您有这样的操作顺序:
mvp = m_projection*m_view*m_model
vertex' = mvp*vertex
意思是m_view
是视图的逆矩阵,m_model
是实际网格的直接矩阵。
所以你应该设置 m_projection
和 m_view
一次,然后只更新 m_model
.
我不使用 GLM(我有自己的数学库)但是 IIRC 它们模仿旧的固定管道矩阵数学。所以当我这样做时(C++/VCL/OpenGL/GLSL ...我知道要点应该是 VBO/VAO 我只是想快速测试):
//---------------------------------------------------------------------------
// ang ,ang speed,body r,orbit r
// [deg] ,[deg/s] [unit],[unit]
float rs=1.0; // star
float a0=0.0,da0= 50.0,r0=0.5,R0= 7.0; // planet
float a1=0.0,da1=200.0,r1=0.2,R1= 1.0; // moon
float a2=0.0,da2=250.0,r2=0.2,R2= 1.5; // moon
float a3=0.0,da3= 20.0,r3=0.5,R3=10.0; // planet
float a4=0.0,da4=150.0,r4=0.2,R4= 1.0; // moon
float a5=0.0,da5=180.0,r5=0.2,R5= 1.5; // moon
float b =0.0,db =50.0; // common self rotation
//---------------------------------------------------------------------------
void gl_draw()
{
GLint ix;
GLfloat mp[16],mv[16],mm[16],m0[16];
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
float aspect=float(xs)/float(ys);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0/aspect,aspect,0.1,100.0);
glGetFloatv(GL_PROJECTION_MATRIX,mp);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0,0.0,-25.0);
glGetFloatv(GL_MODELVIEW_MATRIX,mv);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glGetFloatv(GL_MODELVIEW_MATRIX,mm);
glDisable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
glDisable(GL_CULL_FACE);
// glEnable(GL_CULL_FACE);
// GLSL sphere shader
glUseProgram(prog_id);
ix=glGetUniformLocation(prog_id,"m_projection"); glUniformMatrix4fv(ix,1,false,mp);
ix=glGetUniformLocation(prog_id,"m_view"); glUniformMatrix4fv(ix,1,false,mv);
ix=glGetUniformLocation(prog_id,"m_model");
// sun
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(b,0.0,0.0,1.0);
glGetFloatv(GL_MODELVIEW_MATRIX,mm); glUniformMatrix4fv(ix,1,false,mm);
glBegin(GL_POINTS); glColor3f(1.0,1.0,0.0); glVertex4f(0.0,0.0,0.0,rs); glEnd();
// planet
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(a0,0.0,0.0,1.0);
glTranslatef(R0,0.0,0.0);
glGetFloatv(GL_MODELVIEW_MATRIX,m0);
glRotatef(b,0.0,0.0,1.0);
glGetFloatv(GL_MODELVIEW_MATRIX,mm); glUniformMatrix4fv(ix,1,false,mm);
glBegin(GL_POINTS); glColor3f(0.0,0.7,1.0); glVertex4f(0.0,0.0,0.0,r0); glEnd();
// moon
glLoadMatrixf(m0);
glRotatef(a1,0.0,0.0,1.0);
glTranslatef(R1,0.0,0.0);
glRotatef(b,0.0,0.0,1.0);
glGetFloatv(GL_MODELVIEW_MATRIX,mm); glUniformMatrix4fv(ix,1,false,mm);
glBegin(GL_POINTS); glColor3f(0.4,0.4,0.4); glVertex4f(0.0,0.0,0.0,r1); glEnd();
// moon
glLoadMatrixf(m0);
glRotatef(a2,0.0,0.0,1.0);
glTranslatef(R2,0.0,0.0);
glRotatef(b,0.0,0.0,1.0);
glGetFloatv(GL_MODELVIEW_MATRIX,mm); glUniformMatrix4fv(ix,1,false,mm);
glBegin(GL_POINTS); glColor3f(0.4,0.4,0.4); glVertex4f(0.0,0.0,0.0,r2); glEnd();
// planet
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(a3,0.0,0.0,1.0);
glTranslatef(R3,0.0,0.0);
glGetFloatv(GL_MODELVIEW_MATRIX,m0);
glRotatef(b,0.0,0.0,1.0);
glGetFloatv(GL_MODELVIEW_MATRIX,mm); glUniformMatrix4fv(ix,1,false,mm);
glBegin(GL_POINTS); glColor3f(0.0,0.7,1.0); glVertex4f(0.0,0.0,0.0,r3); glEnd();
// moon
glLoadMatrixf(m0);
glRotatef(a4,0.0,0.0,1.0);
glTranslatef(R4,0.0,0.0);
glRotatef(b,0.0,0.0,1.0);
glGetFloatv(GL_MODELVIEW_MATRIX,mm); glUniformMatrix4fv(ix,1,false,mm);
glBegin(GL_POINTS); glColor3f(0.4,0.4,0.4); glVertex4f(0.0,0.0,0.0,r4); glEnd();
// moon
glLoadMatrixf(m0);
glRotatef(a5,0.0,0.0,1.0);
glTranslatef(R5,0.0,0.0);
glRotatef(b,0.0,0.0,1.0);
glGetFloatv(GL_MODELVIEW_MATRIX,mm); glUniformMatrix4fv(ix,1,false,mm);
glBegin(GL_POINTS); glColor3f(0.4,0.4,0.4); glVertex4f(0.0,0.0,0.0,r5); glEnd();
glUseProgram(0);
glFlush();
SwapBuffers(hdc);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
// this is periodicaly called by timer
gl_draw();
float dt=0.001*float(Timer1->Interval); // timer period in seconds
a0=fmod(a0+da0*dt,360.0);
a1=fmod(a1+da1*dt,360.0);
a3=fmod(a3+da3*dt,360.0);
a4=fmod(a4+da4*dt,360.0);
a5=fmod(a5+da5*dt,360.0);
b =fmod(b +db *dt,360.0);
}
//---------------------------------------------------------------------------
我得到了这个输出(使用我的球体着色器):
着色器只是将点 x,y,z,r
作为球体 3D 中心和半径,发射 BBOX 四边形并使用法线着色渲染内接球体。它还使用颜色和您的 3 个矩阵。
所以如果我没看错你应该这样做:
model = identity;
model = glm::rotate(model, glm::radians(b), glm::vec3(0.0, 1.0, 0.0));
// render star
model = identity;
model = glm::rotate(model, glm::radians(a0), glm::vec3(0.0, 1.0, 0.0));
model = glm::translate(model, glm::vec3(R0, 0.0, 0.0));
model0= model;
model = glm::rotate(model, glm::radians(b), glm::vec3(0.0, 1.0, 0.0));
// render planet
model = model0;
model = glm::rotate(model, glm::radians(a1), glm::vec3(0.0, 1.0, 0.0));
model = glm::translate(model, glm::vec3(R1, 0.0, 0.0));
model = glm::rotate(model, glm::radians(b), glm::vec3(0.0, 1.0, 0.0));
// render moon
model = model0;
model = glm::rotate(model, glm::radians(a2), glm::vec3(0.0, 1.0, 0.0));
model = glm::translate(model, glm::vec3(R2, 0.0, 0.0));
model = glm::rotate(model, glm::radians(b), glm::vec3(0.0, 1.0, 0.0));
// render moon
model = identity;
model = glm::rotate(model, glm::radians(a3), glm::vec3(0.0, 1.0, 0.0));
model = glm::translate(model, glm::vec3(R3, 0.0, 0.0));
model0= model;
model = glm::rotate(model, glm::radians(b), glm::vec3(0.0, 1.0, 0.0));
// render planet
model = model0;
model = glm::rotate(model, glm::radians(a4), glm::vec3(0.0, 1.0, 0.0));
model = glm::translate(model, glm::vec3(R4, 0.0, 0.0));
model = glm::rotate(model, glm::radians(b), glm::vec3(0.0, 1.0, 0.0));
// render moon
model = model0;
model = glm::rotate(model, glm::radians(a5), glm::vec3(0.0, 1.0, 0.0));
model = glm::translate(model, glm::vec3(R5, 0.0, 0.0));
model = glm::rotate(model, glm::radians(b), glm::vec3(0.0, 1.0, 0.0));
// render moon
如果这不起作用,那么您在矩阵顺序和使用的数学之间存在其他一些不匹配,或者 GLM 的行为与我预期的不同。我为 self-rotations 使用了共同的角度,所以你只需为你的身体添加索引 ...
还要注意旧的 GL 旋转使用 [deg]
所以如果 GLM 想要 [rad]
你需要转换角度和 angular 速度常数 ...
如果你想要更多precise/related真实世界或更好的视觉效果,请看这个:
我想要一个围绕中心旋转的立方体。这是我可以用这个转换做的事情:
model = glm::rotate(identity, glm::radians(-100.0f * time), glm::vec3(0.0, 1.0, 0.0)); //rotate around y-axis
model = glm::translate(model, glm::vec3(8.0, 0.0, 0.0));
model = glm::rotate(model, glm::radians(-100.0f * time), glm::vec3(1.0, 0.0, 0.0)); //self-rotation
现在我想要一个立方体,它会随着第一个立方体绕 y 轴旋转而旋转。 想象一下,第一个立方体是地球,第二个立方体是月球。 我试过了,但没用。
test = glm::rotate(test, glm::radians(-100.0f * time), glm::vec3(0.0, 1.0, 0.0));
test = glm::translate(test, glm::vec3(3.0, 0.0, 0.0));
test = glm::translate(test, glm::vec3(8.0, 0.0, 0.0));
test = glm::rotate(test, glm::radians(-100.0f * time), glm::vec3(0.0, 1.0, 0.0));
test = glm::translate(test, glm::vec3(-8.0, 0.0, 0.0));
test = glm::rotate(test, glm::radians(-100.0f * time), glm::vec3(1.0, 0.0, 0.0)); // self-rotation
知道我做错了什么吗?
这是旋转的图片:
对象A绕B旋转顺序:A自转,平移A到B的偏移量,绕B旋转,平移B位置。由于 B 是太阳,我假设它位于您的世界原点,并且一切都在 xz 平面上(笛卡尔坐标系而非 OpenGL 坐标系),因此变为:
model = glm::rotate(identity, glm::radians(-100.0f * time), glm::vec3(1.0, 0.0, 0.0)); //self-rotation
model = glm::translate(model, glm::vec3(8.0, 0.0, 0.0)); // earth is 8 away from sun, where unrotated about sun is 8 units east
model = glm::rotate(model, glm::radians(-100.0f * time), glm::vec3(0.0, 1.0, 0.0)); //rotate about sun
// no need for another translation since sun is at origin
然后对于父对象为地球的对象,在解析父对象到世界的关系之前,首先要解析该关系:
model = glm::rotate(identity, glm::radians(-100.0f * time), glm::vec3(1.0, 0.0, 0.0)); //self-rotation of moon
model = glm::translate(model, glm::vec3(-4.0, 0.0, 0.0)); // moon is 4 away from Earth, where unrotated about Earth is 4 units west
model = glm::rotate(model, glm::radians(-100.0f * time), glm::vec3(0.0, 1.0, 0.0)); //rotate about Earth
// translate to Earth origin, which is calculate from above code block
免责声明,我没有用glm-math,这只是几何变换的顺序,不知道直接翻译成glm::x
您的评论表明您有这样的操作顺序:
mvp = m_projection*m_view*m_model
vertex' = mvp*vertex
意思是m_view
是视图的逆矩阵,m_model
是实际网格的直接矩阵。
所以你应该设置 m_projection
和 m_view
一次,然后只更新 m_model
.
我不使用 GLM(我有自己的数学库)但是 IIRC 它们模仿旧的固定管道矩阵数学。所以当我这样做时(C++/VCL/OpenGL/GLSL ...我知道要点应该是 VBO/VAO 我只是想快速测试):
//---------------------------------------------------------------------------
// ang ,ang speed,body r,orbit r
// [deg] ,[deg/s] [unit],[unit]
float rs=1.0; // star
float a0=0.0,da0= 50.0,r0=0.5,R0= 7.0; // planet
float a1=0.0,da1=200.0,r1=0.2,R1= 1.0; // moon
float a2=0.0,da2=250.0,r2=0.2,R2= 1.5; // moon
float a3=0.0,da3= 20.0,r3=0.5,R3=10.0; // planet
float a4=0.0,da4=150.0,r4=0.2,R4= 1.0; // moon
float a5=0.0,da5=180.0,r5=0.2,R5= 1.5; // moon
float b =0.0,db =50.0; // common self rotation
//---------------------------------------------------------------------------
void gl_draw()
{
GLint ix;
GLfloat mp[16],mv[16],mm[16],m0[16];
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
float aspect=float(xs)/float(ys);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0/aspect,aspect,0.1,100.0);
glGetFloatv(GL_PROJECTION_MATRIX,mp);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0,0.0,-25.0);
glGetFloatv(GL_MODELVIEW_MATRIX,mv);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glGetFloatv(GL_MODELVIEW_MATRIX,mm);
glDisable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
glDisable(GL_CULL_FACE);
// glEnable(GL_CULL_FACE);
// GLSL sphere shader
glUseProgram(prog_id);
ix=glGetUniformLocation(prog_id,"m_projection"); glUniformMatrix4fv(ix,1,false,mp);
ix=glGetUniformLocation(prog_id,"m_view"); glUniformMatrix4fv(ix,1,false,mv);
ix=glGetUniformLocation(prog_id,"m_model");
// sun
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(b,0.0,0.0,1.0);
glGetFloatv(GL_MODELVIEW_MATRIX,mm); glUniformMatrix4fv(ix,1,false,mm);
glBegin(GL_POINTS); glColor3f(1.0,1.0,0.0); glVertex4f(0.0,0.0,0.0,rs); glEnd();
// planet
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(a0,0.0,0.0,1.0);
glTranslatef(R0,0.0,0.0);
glGetFloatv(GL_MODELVIEW_MATRIX,m0);
glRotatef(b,0.0,0.0,1.0);
glGetFloatv(GL_MODELVIEW_MATRIX,mm); glUniformMatrix4fv(ix,1,false,mm);
glBegin(GL_POINTS); glColor3f(0.0,0.7,1.0); glVertex4f(0.0,0.0,0.0,r0); glEnd();
// moon
glLoadMatrixf(m0);
glRotatef(a1,0.0,0.0,1.0);
glTranslatef(R1,0.0,0.0);
glRotatef(b,0.0,0.0,1.0);
glGetFloatv(GL_MODELVIEW_MATRIX,mm); glUniformMatrix4fv(ix,1,false,mm);
glBegin(GL_POINTS); glColor3f(0.4,0.4,0.4); glVertex4f(0.0,0.0,0.0,r1); glEnd();
// moon
glLoadMatrixf(m0);
glRotatef(a2,0.0,0.0,1.0);
glTranslatef(R2,0.0,0.0);
glRotatef(b,0.0,0.0,1.0);
glGetFloatv(GL_MODELVIEW_MATRIX,mm); glUniformMatrix4fv(ix,1,false,mm);
glBegin(GL_POINTS); glColor3f(0.4,0.4,0.4); glVertex4f(0.0,0.0,0.0,r2); glEnd();
// planet
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(a3,0.0,0.0,1.0);
glTranslatef(R3,0.0,0.0);
glGetFloatv(GL_MODELVIEW_MATRIX,m0);
glRotatef(b,0.0,0.0,1.0);
glGetFloatv(GL_MODELVIEW_MATRIX,mm); glUniformMatrix4fv(ix,1,false,mm);
glBegin(GL_POINTS); glColor3f(0.0,0.7,1.0); glVertex4f(0.0,0.0,0.0,r3); glEnd();
// moon
glLoadMatrixf(m0);
glRotatef(a4,0.0,0.0,1.0);
glTranslatef(R4,0.0,0.0);
glRotatef(b,0.0,0.0,1.0);
glGetFloatv(GL_MODELVIEW_MATRIX,mm); glUniformMatrix4fv(ix,1,false,mm);
glBegin(GL_POINTS); glColor3f(0.4,0.4,0.4); glVertex4f(0.0,0.0,0.0,r4); glEnd();
// moon
glLoadMatrixf(m0);
glRotatef(a5,0.0,0.0,1.0);
glTranslatef(R5,0.0,0.0);
glRotatef(b,0.0,0.0,1.0);
glGetFloatv(GL_MODELVIEW_MATRIX,mm); glUniformMatrix4fv(ix,1,false,mm);
glBegin(GL_POINTS); glColor3f(0.4,0.4,0.4); glVertex4f(0.0,0.0,0.0,r5); glEnd();
glUseProgram(0);
glFlush();
SwapBuffers(hdc);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
// this is periodicaly called by timer
gl_draw();
float dt=0.001*float(Timer1->Interval); // timer period in seconds
a0=fmod(a0+da0*dt,360.0);
a1=fmod(a1+da1*dt,360.0);
a3=fmod(a3+da3*dt,360.0);
a4=fmod(a4+da4*dt,360.0);
a5=fmod(a5+da5*dt,360.0);
b =fmod(b +db *dt,360.0);
}
//---------------------------------------------------------------------------
我得到了这个输出(使用我的球体着色器):
着色器只是将点 x,y,z,r
作为球体 3D 中心和半径,发射 BBOX 四边形并使用法线着色渲染内接球体。它还使用颜色和您的 3 个矩阵。
所以如果我没看错你应该这样做:
model = identity;
model = glm::rotate(model, glm::radians(b), glm::vec3(0.0, 1.0, 0.0));
// render star
model = identity;
model = glm::rotate(model, glm::radians(a0), glm::vec3(0.0, 1.0, 0.0));
model = glm::translate(model, glm::vec3(R0, 0.0, 0.0));
model0= model;
model = glm::rotate(model, glm::radians(b), glm::vec3(0.0, 1.0, 0.0));
// render planet
model = model0;
model = glm::rotate(model, glm::radians(a1), glm::vec3(0.0, 1.0, 0.0));
model = glm::translate(model, glm::vec3(R1, 0.0, 0.0));
model = glm::rotate(model, glm::radians(b), glm::vec3(0.0, 1.0, 0.0));
// render moon
model = model0;
model = glm::rotate(model, glm::radians(a2), glm::vec3(0.0, 1.0, 0.0));
model = glm::translate(model, glm::vec3(R2, 0.0, 0.0));
model = glm::rotate(model, glm::radians(b), glm::vec3(0.0, 1.0, 0.0));
// render moon
model = identity;
model = glm::rotate(model, glm::radians(a3), glm::vec3(0.0, 1.0, 0.0));
model = glm::translate(model, glm::vec3(R3, 0.0, 0.0));
model0= model;
model = glm::rotate(model, glm::radians(b), glm::vec3(0.0, 1.0, 0.0));
// render planet
model = model0;
model = glm::rotate(model, glm::radians(a4), glm::vec3(0.0, 1.0, 0.0));
model = glm::translate(model, glm::vec3(R4, 0.0, 0.0));
model = glm::rotate(model, glm::radians(b), glm::vec3(0.0, 1.0, 0.0));
// render moon
model = model0;
model = glm::rotate(model, glm::radians(a5), glm::vec3(0.0, 1.0, 0.0));
model = glm::translate(model, glm::vec3(R5, 0.0, 0.0));
model = glm::rotate(model, glm::radians(b), glm::vec3(0.0, 1.0, 0.0));
// render moon
如果这不起作用,那么您在矩阵顺序和使用的数学之间存在其他一些不匹配,或者 GLM 的行为与我预期的不同。我为 self-rotations 使用了共同的角度,所以你只需为你的身体添加索引 ...
还要注意旧的 GL 旋转使用 [deg]
所以如果 GLM 想要 [rad]
你需要转换角度和 angular 速度常数 ...
如果你想要更多precise/related真实世界或更好的视觉效果,请看这个: