OpenGL基本图元的绘制

[TOC]

线框球体

主要计算圆的半径的变化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void Draw_Line_Sphere(int n=360, double r=1, int layer=5, int line=5){
    glPushMatrix();
        for(double i=0; i<=r; i+=r/layer){ // 纬线
            double new_r = sqrt(r*r-i*i);
            Draw_Circle(n, new_r, i);
            Draw_Circle(n, new_r, -i);
        }
        glRotatef(90, 0, 1, 0);
        for(double i=0; i<360; i+=360.0/line){ // 经线
            glRotated(360.0/line, 1, 0, 0);
            Draw_Circle(n, r, 0);
        }
    glPopMatrix();
}

线框锥体

void Draw_Line_Cylinder(int n=5, double r=0.5, double h=1, int layer = 10){
    glPushMatrix();
        for(int i=0; i<n; i++){ // 棱
            glBegin(GL_LINES);
                glVertex3f(0, 0, h);
                glVertex3f(r*cos(2*i*PI/n), r*sin(2*i*PI/n), 0);
            glEnd();
        }

        for(double i=0; i<h; i+=h/layer){ // 多边形框
            double new_r = r*(h-i)/h;
            Draw_Circle(n, new_r, i);
        }
    glPopMatrix();
}

扇形

计算出弧线的各点后,用 GL_Triang_FAN​ 画即可,用三角形逼近,也可以画凹的

1
2
3
4
5
6
7
void Draw_sector(double r, double angle){
   	glBegin(GL_TRIANGLE_FAN);
    	glVertex3f(0, 0, 0); //圆点
        for(double i=0; i<angle; i++)
			glVertex3f(r*cos(i*PI/180), r*sin(i*PI/180), 0);
    glEnd();
}

实现鼠标控制旋转

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int axis=2;
float theta[3];
void mouse(int btn, int state, int x, int y){
    if(btn == GLUT_LEFT_BUTTON && state == GLUT_DOWN) axis = 0;
    if(btn == GLUT_MIDDLE_BUTTON && state == GLUT_DOWN) axis = 1;
    if(btn == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) axis = 2;
}
void spinCube(){
    theta[axis] += 0.05;
    if(theta[axis] > 360) theta[axis] -= 360;
    glutPostRedisplay();
}

//glutMouseFunc(mouse);
//glutIdleFunc(spinCube);

画半圆柱面

类似画圆,在画圆的基础上增加了z轴坐标的变化。圆由直线段逼近,圆柱面自然由矩形逼近。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void Draw_Rect(Point p1, Point p2, Point p3, Point p4){

    glBegin(GL_POLYGON);
        glVertex3fv(p1.p);
        glVertex3fv(p2.p);
        glVertex3fv(p3.p);
        glVertex3fv(p4.p);
    glEnd();
}

void Draw_Circle(int n=180, double r=4, double h=10){
    for(double i=1; i<=180; i+=1){
        Point p1 = Point{r*cos((i-1)*PI/180), r*sin((i-1)*PI/180), 0}, p2 = Point{r*cos(i*PI/180), r*sin(i*PI/180), 0};
        Point p3 = p2; p3[2] = h; Point p4 = p1; p4[2] = h;

        double a = p2[0] + p1[0], b = p2[1] + p1[1];
        glNormal3f(-a, -b, 0);
        Draw_Rect(p1, p2, p3, p4);
    }
}

画坐标轴做参考系

1
2
3
4
5
6
7
void Coordinate_aixs(){
    glBegin(GL_LINES);
        glColor3f(1, 0, 0); glVertex3d(0, 0, 0); glVertex3d(1, 0, 0);
        glColor3f(0, 1, 0); glVertex3d(0, 0, 0); glVertex3d(0, 1, 0);
        glColor3f(0, 0, 1); glVertex3d(0, 0, 0); glVertex3d(0, 0, 1);
    glEnd();
}

文字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#define MAX_CHAR        128
void drawString(const char* str) {
    static int isFirstCall = 1;
    static GLuint lists;
    if(isFirstCall){
         isFirstCall = 0;
         lists = glGenLists(MAX_CHAR);
         wglUseFontBitmaps(wglGetCurrentDC(), 0, MAX_CHAR, lists);
    }
    for(; *str!='
#define MAX_CHAR        128
void drawString(const char* str) {
    static int isFirstCall = 1;
    static GLuint lists;
    if(isFirstCall){
         isFirstCall = 0;
         lists = glGenLists(MAX_CHAR);
         wglUseFontBitmaps(wglGetCurrentDC(), 0, MAX_CHAR, lists);
    }
    for(; *str!='\0'; ++str) glCallList(lists + *str);
}

void display(){
	glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glColor3f(0, 1, 1);
    glRasterPos2f(-0.2, 0.8);
    drawString("17040100906 - LCS");
}
'
; ++str) glCallList(lists + *str); } void display(){ glMatrixMode(GL_PROJECTION); glLoadIdentity(); glColor3f(0, 1, 1); glRasterPos2f(-0.2, 0.8); drawString("17040100906 - LCS"); }

球面

以下是半圆面的绘制,绘制整个球面可以做一个对称变换即可。绘制出来的效果可能不理想,可能需要设置参数每次的变化量。而且每个小四边形的法向量并没有精确计算,粗略的取了四边形顶点中的某个点到原点方向作为法向量。

具体思想:

  1. 和绘制圆形类似,圆形是每次将本次旋转角度得到的点和上一旋转角度得到的点相连,而绘制球面不仅要考虑相邻旋转角度,还要算出高度不同的相邻圆弧的半径和对应的旋转角度,这样就可以得到四个点,构成一个四面形,不断用四边形逼近球面。
  2. 和绘制线框球体类似,先计算各个高度的圆弧对应的半径,也就是对应剖面上的一条弦,用勾股定理就行。
  3. 确定好两个相邻高度的圆弧半径后,再考虑相邻的两个旋转角度,确定四个点,画四边形。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void Draw_Ball_Face(double r){
    for(double h0=0; h0<=r; h0+=1){
        double r0 = sqrt(r*r-h0*h0);
        for(double angle=0; angle<360; angle+=1){
            double h1 = h0-1, r1 = sqrt(r*r-h1*h1);
            Point p1 = Point{r0*cos(angle*PI/180), r0*sin(angle*PI/180), h0};
            Point p2 = Point{r0*cos((angle-1)*PI/180), r0*sin((angle-1)*PI/180), h0};
            Point p3 = Point{r1*cos((angle-1)*PI/180), r1*sin((angle-1)*PI/180), h1};
            Point p4 = Point{r1*cos(angle*PI/180), r1*sin(angle*PI/180), h1};
            
            glNormal3fv(p1.p); Draw_Rect(p1, p2, p3, p4);
        }
    }
}
# 使用单$作为行内数学公式分界符