如何使用 GLEW、OpenGL 或 SDL2 以椭圆运动围绕另一个圆旋转?

How rotate a circle around another with an elliptical motion with GLEW, OpenGL or SDL2?

我当前的代码:

#define GLEW_STATIC
#include <stdlib.h>
#include <SDL2/SDL.h>
#include <math.h>
#include <stdio.h>
#include <iostream>
#include<conio.h>
#include<dos.h>
#include <GL/glew.h>

using namespace std;

#ifdef WIN32
#include <GL/glew.h>

#else
#define GL3_PROTOTYPES 1
#include <GL3/gl3.h>

#endif

#include <SDL2/SDL.h>
#include <iostream>
void DrawCircle(float cx, float cy, float r, int num_segments);
void DrawEllipse(float cx, float cy, float a, float b, int num_segments);

int main(int argc, char **argv)
{
    // the window

    SDL_Window* fenetre(0);
    SDL_GLContext contexteOpenGL(0);

    SDL_Event evenements;
    bool terminer(false);


    // Initializing the SDL

    if(SDL_Init(SDL_INIT_VIDEO) < 0)
    {
        std::cout << "Erreur lors de l'initialisation de la SDL : " << SDL_GetError() << std::endl;
        SDL_Quit();

        return -1;
    }


    // Version OpenGL

    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);


    // Double Buffer

    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);


    // Creating the window

    fenetre = SDL_CreateWindow("Test SDL 2.0", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 600, 600, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);

    if(fenetre == 0)
    {
        std::cout << "Erreur lors de la creation de la fenetre : " << SDL_GetError() << std::endl;
        SDL_Quit();

        return -1;
    }


    // Creating the OpenGL context

    contexteOpenGL = SDL_GL_CreateContext(fenetre);

    if(contexteOpenGL == 0)
    {
        std::cout << SDL_GetError() << std::endl;
        SDL_DestroyWindow(fenetre);
        SDL_Quit();

        return -1;
    }


    #ifdef WIN32

        // We initialize GLEW

        GLenum initialisationGLEW( glewInit() );


        //If the initialization failed :

        if(initialisationGLEW != GLEW_OK)
        {
            // We display the error thanks to the function : glewGetErrorString(GLenum code)

            std::cout << "Erreur d'initialisation de GLEW : " << glewGetErrorString(initialisationGLEW) << std::endl;


            // leave SDL

            SDL_GL_DeleteContext(contexteOpenGL);
            SDL_DestroyWindow(fenetre);
            SDL_Quit();

            return -1;
        }

    #endif


    // Vertices and coordinates
 while(!terminer)
    {
         // Event Management

        SDL_WaitEvent(&evenements);

        if(evenements.window.event == SDL_WINDOWEVENT_CLOSE)
            terminer = true;

        // clean the screen

        glClear(GL_COLOR_BUFFER_BIT);
DrawCircle(0,0,0.3,50);
DrawCircle(0.5,0.5,0.1,50);
DrawEllipse(0,0,0.8,0.65,50);

         // Disable the Vertex Attrib array

        glDisableVertexAttribArray(0);


        //refresh window

        SDL_GL_SwapWindow(fenetre);
    }


    // leave SDL

    SDL_GL_DeleteContext(contexteOpenGL);
    SDL_DestroyWindow(fenetre);
    SDL_Quit();

    return 0;
}


void DrawCircle(float cx, float cy, float r, int num_segments)
{
glBegin(GL_LINE_LOOP);
for(int ii = 0; ii < num_segments; ii++)
{
float theta = 2.0 * M_PI * float(ii) / float(num_segments); //get the current angle

float x_c = r * cosf(theta);//calculate the x component
float y_c = r * sinf(theta);//calculate the y component
        glColor3f(1.0f,0.0f,0.0f);
glVertex2f(x_c + cx, y_c + cy);//output vertex
}
glEnd();
}
void DrawEllipse(float cx, float cy, float a, float b, int num_segments)
{
glBegin(GL_LINE_LOOP);
for(int ii = 0; ii < num_segments; ii++)
{
float theta = 2.0 * M_PI * float(ii) / float(num_segments); //get the current angle

float x_e = a * cosf(theta);//calculate the x component
float y_e = b * sinf(theta);//calculate the y component
        glColor3f(0.0f,0.0f,1.0f);
glVertex2f(x_e + cx, y_e + cy);//output vertex
}
glEnd();
}

例如,我想沿着蓝线将小圆圈绕着大圆圈旋转:


我想决定完成一个回合需要多长时间。

我是否必须组合 glRotatef()glTranslatef() 并使用矩阵?

我应该把它放在代码的什么地方?

首先请注意,由 glBegin/glEnd 序列绘制已被弃用 10 多年了。
阅读 Fixed Function Pipeline and see Vertex Specification and Shader 了解最先进的渲染方式。


Do I have to combine glRotatef() and glTranslatef() and use matrices?

不,不一定。

因为你在每一帧都计算了圆的几何形状,所以在每一帧计算圆的中心点就足够了,并将它传递给DrawCircle:

指定圆心极坐标角度的全局变量:

float g_theta = 0.0f;

像这样计算圆心:

float a = 0.8f;
float b = 0.65f;
float x = a * cosf(g_theta * M_PI / 180.0f);
float y = b * sinf(g_theta * M_PI / 180.0f);
g_theta += 1.0f;

DrawCircle(0, 0, 0.3, 50);
DrawCircle(x, y, 0.1, 50);
DrawEllipse(0, 0, a, b, 50);

如果你想做同样的事情,通过使用固定功能管道矩阵堆栈,那么你必须设置 GL_MODELVIEW 矩阵。

计算从圆心到世界中心的距离 (d)。应用距离的平移和世界 z 轴极坐标角度的旋转:

float a = 0.8f;
float b = 0.65f;
float x = a * cosf(g_theta * M_PI / 180.0f);
float y = b * sinf(g_theta * M_PI / 180.0f);
float d = sqrtf( x*x + y*y );

glMatrixMode( GL_MODELVIEW );
glLoadIdentity();

DrawCircle(0, 0, 0.3, 50);

glPushMatrix();
glRotatef( g_theta, 0, 0, 1 );  // rotation around the z axis
glTranslatef( d, 0, 0 );        // translation by the distance
g_theta += 1.0f;

DrawCircle(0, 0, 0.1, 50);
glPopMatrix();

DrawEllipse(0, 0, a, b, 50);