opengl:繪製球體

數學基礎

球面參數方程

球面的參數曲線可以用球座標表示,引入參數u,v,其中v是球面點與原點的連線與z軸正向的夾角,u表示連線在xy平面的投影與x軸正向的夾角,如下圖所示:

球座標

則球面參數方程可以表示爲:

這裏寫圖片描述

球面法向量

已知球面的參數方程以後,很容易求得給定點的法向量,分別對u和v方向求偏導數,然後對兩個所得向量進行叉積即可:
這裏寫圖片描述

實現細節

已知參數方程以後,需要進行離散,分別設定u和v的步長:ustep、vstep。然後通過不同的u和v,求得座標系中點的實際座標(x,y,z),在實現中有一點需要注意的是:

這裏寫圖片描述

u=0與u=v這兩條線上點的是球體的兩個上下極點,所以進行渲染時需要區分,其中如圖中間段的離散點可以按照四邊形進行渲染,而上下兩段則需要按照三角形進行渲染。

代碼描述:

這裏只是繪製了球面,如果想繪製球體,只用在渲染時,加入點的法向量即可。

點的數據結構:

class Point
{
public:
    Point(){};
    Point(double a,double b,double c):x(a),y(b),z(c){};
public:
    double x;
    double y;
    double z;
};

參數座標(u,v)轉換成時機座標(x,y,z)函數

Point getPoint(double u,double v)
{
    double x = sin(PI*v)*cos(PI2*u);
    double y = sin(PI*v)*sin(PI2*u);
    double z = cos(PI*v);
    return Point(x,y,z);
}

繪製球面

void drawWire()
{
    double ustep = 1/(double)uStepsNum, vstep = 1/(double)vStepNum;
    double u = 0,v = 0;
    //繪製下端三角形組
    for(int i = 0;i<uStepsNum;i++)
    {
        glBegin(GL_LINE_LOOP);
        Point a = getPoint(0,0);
        glVertex3d(a.x,a.y,a.z);
        Point b = getPoint(u,vstep);
        glVertex3d(b.x,b.y,b.z);
        Point c = getPoint(u+ustep,vstep);
        glVertex3d(c.x,c.y,c.z);
        u += ustep;
        glEnd();
    }
    //繪製中間四邊形組
    u = 0, v = vstep;
    for(int i=1;i<vStepNum-1;i++)
    {
        for(int j=0;j<uStepsNum;j++)
        {
            glBegin(GL_LINE_LOOP);
            Point a = getPoint(u,v);
            Point b = getPoint(u+ustep,v);
            Point c = getPoint(u+ustep,v+vstep);
            Point d = getPoint(u,v+vstep);
            glVertex3d(a.x,a.y,a.z);
            glVertex3d(b.x,b.y,b.z);
            glVertex3d(c.x,c.y,c.z);
            glVertex3d(d.x,d.y,d.z);
            u += ustep;
            glEnd();
        }
        v += vstep;
    }
    //繪製下端三角形組
    u = 0;
    for(int i=0;i<uStepsNum;i++)
    {
        glBegin(GL_LINE_LOOP);
        Point a = getPoint(0,1);
        Point b = getPoint(u,1-vstep);
        Point c = getPoint(u+ustep,1-vstep);
        glVertex3d(a.x,a.y,a.z);
        glVertex3d(b.x,b.y,b.z);
        glVertex3d(c.x,c.y,c.z);
        glEnd();
    }
}

初始化設置與繪圖函數

#define PI 3.14159265358979323846
#define PI2 6.28318530717958647692

GLsizei width = 600,height = 600;

int uStepsNum = 50,vStepNum = 50;
void init()
{
    glClearColor(0,1,1,1);
    glClearDepth(1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glClearColor(0,1,1,1);
    glClearDepth(1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    GLfloat light_position [ ] = { 1.0f, 1.0f, 1.0f, 0.0f };
    GLfloat light_ambient  [ ] = { 0.2f, 0.2f, 0.2f, 0.2f };
    GLfloat light_diffuse  [ ] = { 0.5f, 0.5f, 0.5f, 0.2f };
    GLfloat light_specular [ ] = { 0.5f, 0.5f, 0.5f, 0.2f };
    glLightfv(GL_LIGHT0, GL_POSITION,  light_position);
    glLightfv(GL_LIGHT0, GL_AMBIENT,   light_ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE,   light_diffuse);
    glLightfv(GL_LIGHT0, GL_SPECULAR,  light_specular);

    glEnable (GL_COLOR_MATERIAL);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_AUTO_NORMAL);
    glEnable (GL_NORMALIZE);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc (GL_LESS);
}
void displayFunc()
{
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    glColor3f(1.0,0.0,0.0);
    glPointSize(1.0);
    glRotated(30,1,0,0);
    glRotated(60,0,1,0);
    glRotated(90,0,0,1);
    drawWire();
    glutSwapBuffers();
}

主函數

int main(int argc,char* argv[])
{
    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
    glutInitWindowPosition(100,100);
    glutInitWindowSize(width,height);
    glutCreateWindow("Sphere");

    init();
    glutDisplayFunc(displayFunc);
    glutMainLoop();
}

效果展示

這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章