Search code examples
c++openglrotationtransformationglm-math

Rotating cubes in OpenGL


I want to have a cube that rotates around the center. This is something i can do with this transformation:

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

Now I want a cube that will rotate around the first cube as it is rotating around y-axis. Imagine that the first cube is the Earth and the second cube is the moon. I tried this, but it didn't work.

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

Any ideas what I'm doing wrong? Here is a picture of the rotations: Sun - Earth - Moon Rotations


Solution

  • Your comment suggest you have this order of operations:

    mvp = m_projection*m_view*m_model
    vertex' = mvp*vertex
    

    meaning m_view is inverse matrix of view and m_model is direct matrix of actual mesh.

    So you should set m_projection and m_view once and then just updating the m_model.

    I do not use GLM (have my own libs for math) however IIRC they mimic old fixed pipeline matrix math. So when I do this (C++/VCL/OpenGL/GLSL ... I know the points should be VBO/VAO I just wanted test quickly):

    //---------------------------------------------------------------------------
    //    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);
        }
    //---------------------------------------------------------------------------
    

    I got this output (using my sphere shader):

    preview

    The shader just takes point x,y,z,r as a sphere 3D center and radius, emit BBOX quad and render inscribed sphere with normal shading. It also uses color and your 3 matrices.

    So if I see it right you should do something like this:

    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
    

    If this is not working then your got some other mismatch between matrix order and used math or the GLM behaves differently than I expect. I used common angle for self-rotations so you just add indexes for your bodies ...

    Also beware old GL rotations use [deg] so if GLM want [rad] you need to convert the angles and angular speed constants ...

    If you want to have something more precise/related to real world or better visually see this: