(OpenGL) Rotate object

2019-08-02 20:05发布

I'm making a program that rotates six-point stars with two triangles overlapping when I click the mouse button.

  1. Click right mouse button: star spins
  2. Click middle mouse button: star's color changes(white → blue)

I've applied the codes to rotate a rectangle, but when I click right mouse button, it doesn't rotate and makes a jump around.

And when the middle mouse button is clicked, the color changing is successful but it is initialized by rotating the star. I would like to rotate the star with the color changed by clicking the middle button while rotating.

Please let me know what is the problem.

/////////////////////////// Header /////////////////////////////
#include <stdlib.h>
#include <GL/glut.h>

float v1[3] = { 365.0, 465.0, 0.0 };
float v2[3] = { 365.0, 420.0, 0.0 };
float v3[3] = { 400.0, 485.0, 0.0 };
float v4[3] = { 400.0, 400.0, 0.0 };
float v5[3] = { 435.0, 465.0, 0.0 };
float v6[3] = { 435.0, 420.0, 0.0 };

static GLfloat spin = 0.0;

//////////////////////// Functions ////////////////////////////
void init(void) {
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glShadeModel(GL_FLAT);
}

void reshape(int w, int h) {
    glViewport(0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0.0, 500.0, 0.0, 500.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void spinDisplay(void) {
    spin = spin + 2.0;

    if (spin > 360.0) {
        spin = spin - 360.0;
    }

    glutPostRedisplay();
}

void triangle_1(void) {         /////////// first triangle ///////////
    glColor3f(1.0, 1.0, 1.0);

    glBegin(GL_TRIANGLE_FAN);
    glVertex3fv(v1);
    glVertex3fv(v4);
    glVertex3fv(v5);

    glEnd();
}

void triangle_2(void) {         ///////// second triangle /////////
    glColor3f(1.0, 1.0, 1.0);

    glBegin(GL_TRIANGLE_FAN);
    glVertex3fv(v2);
    glVertex3fv(v3);
    glVertex3fv(v6);

    glEnd();
}

void triangle_1p(void) {       ///// first triangle (color changed) /////
    glColor3f(0.0, 0.0, 1.0);

    glBegin(GL_TRIANGLE_FAN);
    glVertex3fv(v1);
    glVertex3fv(v4);
    glVertex3fv(v5);

    glEnd();
}

void triangle_2p(void) {       ///// second triangle (color changed) /////
    glColor3f(0.0, 1.0, 0.0);

    glBegin(GL_TRIANGLE_FAN);
    glVertex3fv(v2);
    glVertex3fv(v3);
    glVertex3fv(v6);

    glEnd();
}

void display(void) {            ///////// star display /////////
    glClear(GL_COLOR_BUFFER_BIT);
    glPushMatrix();
    glRotatef(spin, 0.0, 0.0, 1.0);

    triangle_1();
    triangle_2();

    glPopMatrix();

    glutSwapBuffers();
}

void display_p(void) {         ///// star display (color changed) /////
    glClear(GL_COLOR_BUFFER_BIT);
    glPushMatrix();
    glRotatef(spin, 0.0, 0.0, 1.0);

    triangle_1p();
    triangle_2p();

    glPopMatrix();

    glutSwapBuffers();
}

/////////////////////// Mouse Click ///////////////////////
void mouse(int button, int state, int x, int y) {
    switch (button) {
    case GLUT_LEFT_BUTTON:
        if (state == GLUT_DOWN)
            glutIdleFunc(NULL);
        break;
    case GLUT_MIDDLE_BUTTON:
        if (state == GLUT_DOWN)
            glutIdleFunc(display_p);
        break;
    case GLUT_RIGHT_BUTTON:
        if (state == GLUT_DOWN)
            glutIdleFunc(spinDisplay);
        break;
    default:
        break;
    }
}

//////////////////////////// Main /////////////////////////////
int main(int argc, char **argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowSize(500, 500);
    glutInitWindowPosition(300, 300);
    glutCreateWindow("6-Point Star");

    init();

    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutMouseFunc(mouse);
    glutMainLoop();

    return 0;
}

1条回答
神经病院院长
2楼-- · 2019-08-02 20:56

when I click right mouse button, it doesn't rotate and makes a jump around

It actually isn't jumping around, it's rotating around the origin (bottom left corner of the display).

The reason this happens if because you're rotating then translating. Since you have hardcoded the star's position of x = 400 and y = 442.5 into your vertices. If you make so that the the center of the star is at 0x0 (subtracting 400x442.5) then you'll see the star is rotating around itself in the bottom left corner of the display.

float v1[3] = { -35.0f,  22.5f, 0.0f };
float v2[3] = { -35.0f, -22.5f, 0.0f };
float v3[3] = {   0.0f,  42.5f, 0.0f };
float v4[3] = {   0.0f, -42.5f, 0.0f };
float v5[3] = {  35.0f,  22.5f, 0.0f };
float v6[3] = {  35.0f, -22.5f, 0.0f };

Now in display() you then translate before rotating:

glTranslatef(x, y, 0.0f);
glRotatef(spin, 0.0, 0.0, 1.0);

Considering float x = 400.0f, y = 442.5f; to be defined elsewhere.

Now you'll see the star back at the same place, but rotating around itself.

I would like to rotate the star with the color changed by clicking the middle button while rotating.

Instead of duplicating all your code for each mode, you could keep the colors as variables.

float color1[3] = { 1.0f, 1.0f, 1.0f };
float color2[3] = { 1.0f, 1.0f, 1.0f };

int mode = 1;

Now in mouse() on GLUT_MIDDLE_BUTTON then you switch around the colors.

case GLUT_MIDDLE_BUTTON:
    if (state == GLUT_DOWN) {
        if (mode == 1) {
            color1[0] = 0.0f, color1[1] = 0.0f, color1[2] = 1.0f;
            color2[0] = 0.0f, color2[1] = 1.0f, color2[2] = 0.0f;
            mode = 2;
        }
        else if (mode == 2) {
            color1[0] = 1.0f, color1[1] = 1.0f, color1[2] = 1.0f;
            color2[0] = 1.0f, color2[1] = 1.0f, color2[2] = 1.0f;
            mode = 1;
        }
    }

Then in triangle_1 and triangle_2 remember to replace glColor3f() with glColor3fv(color1) and glColor3fv(color2).

Instead of all that, you could also just set mode in mouse and do something like this in triangle_1 (also doing likewise in triangle_2):

if (mode == 2)
    glColor3f(0.0, 0.0, 1.0);
else
    glColor3f(1.0, 1.0, 1.0);

The choice is of course up to you.

All in all, now you should be able to see the star rotating around itself, and toggle the colors when middle mouse button is clicked.

This now also means that you can delete display_p, triangle_1p and triangle_2p.

查看更多
登录 后发表回答