How to Draw a Rotating Sun in OpenGL (traditional)

93 Views Asked by At

I need to draw a sun that keep rotating (spinning) on it original position / pivot point that placed on position (450, 450), but it now is not spinning on it original point instead it continuing spinning 360 degree over the screen and back to original position again and again. Anyone know how to solve it and keep the sun spinning at it original position, please modify the code. Appreciate those help.

Code for Sun

#include <windows.h>  // for MS Windows
#include <GL/glut.h>  // GLUT, include glu.h and gl.h
#include <math.h>

float sunAngle = 0.0f; // Angle for sun rotation

 // Drawing Circle
void circle(GLfloat rx, GLfloat ry, GLfloat cx, GLfloat cy)
{
    glBegin(GL_POLYGON);
    glVertex2f(cx, cy);
    for (int i = 0; i <= 360; i++)
    {
        float angle = i * 3.1416 / 180;
        float x = rx * cos(angle);
        float y = ry * sin(angle);
        glVertex2f((x + cx), (y + cy));
    }
    glEnd();
}

// Drawing Sun 
void sun()
{
    glPushMatrix();
    glRotatef(sunAngle, 0.0, 0.0, 1.0); 

    // Draw the object
    glColor3f(1.0f, 1.0f, 0.0f); // Yellow color
    circle(20, 30, 450, 450);
    glTranslatef(-450, -450, 0.0);

    glPopMatrix();
}

void update(int value) {
    // Update sun angle for rotation
    sunAngle += 1.0f;
    if (sunAngle > 360) {
        sunAngle -= 360;
    }
    // tell GLUT to call update again in 20 milliseconds
    glutTimerFunc(20, update, 0);
}

void display (void){
    glClear(GL_COLOR_BUFFER_BIT);
    //Sky Color
    glColor3ub(30, 144, 255);
    glBegin(GL_POLYGON);
    glVertex2d(0, 0);
    glVertex2d(500, 0);
    glVertex2d(500, 500);
    glVertex2d(0, 500);
    glEnd();

    sun();
    glFlush();
    glutSwapBuffers();
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowSize(900, 500);
    glutInitWindowPosition(100, 100);
    glutCreateWindow("Sun");
    init();
    glutDisplayFunc(display);
    glutTimerFunc(16, update, 0);

    glutMainLoop();
    return 0;
}
1

There are 1 best solutions below

6
fana On

(Now I don't have environment to try OpenGL, but, I think...)

Center of rotation (of glRotatef) is origin.
So, May be,

void sun()
{
    glPushMatrix();

    glTranslatef(450, 450, 0.0);  //translate center of sun to (450,450) after rotating
    glRotatef(sunAngle, 0.0, 0.0, 1.0);  //rotate around origin.

    // Draw the object
    glColor3f(1.0f, 1.0f, 0.0f);
    circle(20, 30, 0, 0);  //here (cx,cy) is origin
    

    glPopMatrix();
}

That is, put the circle at origin, and rotate it around origin, then translate it to (450,450).


Then...

I tried my this answer.
(Since I don't have GLUT, I used GLFW (and GLEW), but this point will not be problem.)

As a result, yellow ellipse is rotating at same position. So, I think this answer is not wrong.

My Test Code:

//I used GLEW and GLFW
#include "glew.h"
#include "glfw3.h"

#include <gl/GLU.h>
#include <cmath>

float sunAngle = 0.0f;

// Drawing Circle (This code is just copied from question)
void circle(GLfloat rx, GLfloat ry, GLfloat cx, GLfloat cy)
{
    glBegin(GL_POLYGON);
    glVertex2f(cx, cy);
    for (int i = 0; i <= 360; i++)
    {
        float angle = i * 3.1416 / 180;
        float x = rx * cos(angle);
        float y = ry * sin(angle);
        glVertex2f((x + cx), (y + cy));
    }
    glEnd();
}

//
//Test target code is only this function (My Answer)
//
void sun()
{
    glPushMatrix();

    glTranslatef(450, 450, 0.0);  //translate center of sun to (450,450) after rotating
    glRotatef(sunAngle, 0.0, 0.0, 1.0);  //rotate around origin.

    glColor3f(1.0f, 1.0f, 0.0f);
    circle(20, 30, 0, 0);  //here (cx,cy) is origin

    glPopMatrix();
}

//For scale adjustment
const double scaleX = 1.0 / (2 * 450.0 );
bool NeedToUpdateScale = true;
void OnWndResize( GLFWwindow *const pWnd, int w, int h ){   NeedToUpdateScale = true;   }

//
int main()
{
    if( glfwInit() != GLFW_TRUE )return 0;
    GLFWwindow *pWindow = nullptr;
    {
        if( !(pWindow = glfwCreateWindow( 640, 480, "GLFW", NULL, NULL )) )return 1;
        glfwMakeContextCurrent( pWindow );

        //set callback
        //(for GULT, glutReshapeFunc() can be used. )
        glfwSetWindowSizeCallback( pWindow, OnWndResize );
    }

    //main loop
    while( glfwWindowShouldClose( pWindow ) == 0 )
    {
        if( glfwGetKey( pWindow, GLFW_KEY_ESCAPE ) == GLFW_PRESS ){ glfwDestroyWindow( pWindow );   break;  }

        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

        if( NeedToUpdateScale )
        {//Adjusting aspect ratio to 1.0
            int W,H;
            glfwGetWindowSize( pWindow, &W, &H );
            glViewport( 0,0, W,H );

            glLoadIdentity();
            double scaleY = scaleX *(double)W/(double)H;
            glScaled( scaleX, scaleY, 1.0 );

            NeedToUpdateScale = false;
        }

        //(Drawing 2 axises to visualizing aspect ratio)
        glBegin(GL_LINES);
        glColor3d( 1.0, 0.0, 0.0 );
        glVertex3d( 0, 0, 0 );
        glVertex3d( 450, 0, 0 );
        glVertex3d( 0, 0, 0 );
        glVertex3d( 0, 450, 0 );
        glEnd();

        sun();

        glfwSwapBuffers( pWindow );
        glfwPollEvents();
        
        //Update sun angle for rotation
        sunAngle += 1.0f;
        if (sunAngle > 360) {
            sunAngle -= 360;
        }
    }

    //
    glfwTerminate();
    return 0;
}

Code edited to to handle aspect ratio:

  • In main loop, scaling is modified to keep aspect ratio to 1.0. And this processed only when the flag NeedToUpdateScale is on.
  • The flag NeedToUpdateScale is set to on when window resized (using callback. For GLUT, glutReshapeFunc() can be used.)
  • Additionally, added axis drawing code. Drawn 2 line length will be always same because aspect ratio adjusted to keeping 1.0. And the length of lines is 450 the same value of position of sun. It will make the position of sun to understand.

Here, I used glScaled to adujst aspect ratio, but usually, glOrtho() etc will be used.


Now I created GLUT version code.
(In this version, the axis drawing code I added into above code is omitted because we can grasp about scaling result with existing sky-colored box)

Changed points are commented in code below.

Running this code, sky colored square region appears in the upper right area of the window, and a yellow ellipse rotates near the upper right corner of the region. enter image description here

#include <glut.h>  //I used freeglut and including freeglut's glut.h
#include <math.h>

float sunAngle = 0.0f;

void circle(GLfloat rx, GLfloat ry, GLfloat cx, GLfloat cy)
{
    glBegin(GL_POLYGON);
    glVertex2f(cx, cy);
    for (int i = 0; i <= 360; i++)
    {
        float angle = i * 3.1416 / 180;
        float x = rx * cos(angle);
        float y = ry * sin(angle);
        glVertex2f((x + cx), (y + cy));
    }
    glEnd();
}

//Changed implementation of this function (as already said in this answer).
void sun()
{
    glPushMatrix();

    glTranslatef(450, 450, 0.0);  //translate center of sun to (450,450) after rotating
    glRotatef(sunAngle, 0.0, 0.0, 1.0);  //rotate around origin.

    glColor3f(1.0f, 1.0f, 0.0f);
    circle(20, 30, 0, 0);  //here (cx,cy) is origin

    glPopMatrix();
}

void update(int value) {
    sunAngle += 1.0f;
    if (sunAngle > 360) {
        sunAngle -= 360;
    }
    glutTimerFunc(20, update, 0);

    //Added this.
    glutPostRedisplay();
}

void display (void){
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3ub(30, 144, 255);
    glBegin(GL_POLYGON);
    glVertex2d(0, 0);
    glVertex2d(500, 0);
    glVertex2d(500, 500);
    glVertex2d(0, 500);
    glEnd();

    sun();
    glFlush();

    //Comment outed. because you use GLUT_SINGLE in main()
    //glutSwapBuffers();
}

//Added this callback func
//  Adjusting aspect ratio to 1.0
void resize( int W, int H )
{
    const double scaleX = 1.0 / (2 * 450.0 );
    glViewport( 0,0, W,H );

    glLoadIdentity();
    double scaleY = scaleX *(double)W/(double)H;
    glScaled( scaleX, scaleY, 1.0 );
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowSize(900, 500);
    glutInitWindowPosition(100, 100);
    glutCreateWindow("Sun");

    //Your code is not including implementation of this function `init`.
    //Here, I just comment outed this call.
    //init();
    
    glutDisplayFunc(display);
    glutTimerFunc(16, update, 0);

    //Added this callback registering
    glutReshapeFunc( resize );

    glutMainLoop();
    return 0;
}