OpenGL画旋转立方体

内容

  1. 设置颜色
  2. 设置顶点坐标
  3. 根据点画 面
  4. 根据面画体并设置颜色
  5. Init函数
  6. reshape函数
  7. mouse跟踪函数
  8. 设置旋转角度
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#include <windows.h>
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#include <bits/stdc++.h>
using namespace std;

GLfloat colors[][3] = { //
    {1, 0, 0},{0, 1, 0},{0, 0, 1},{1, 1, 0},{0, 1, 1},{1, 0, 1}
};
GLfloat vertices[][3] = { //
    {-1.0, -1.0, 1.0},{-1.0, 1.0, 1.0},{1.0, 1.0, 1.0},
    {1.0, -1.0, 1.0},{-1.0, -1.0, -1.0},{-1.0, 1.0, -1.0},
    {1.0, 1.0, -1.0},{1.0, -1.0, -1.0} 
};

void reshape(int w, int h){
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-4.0, 4.0, -4.0, 4.0, -4.0, 4.0);
}

void polygon(int a, int b, int c, int d){
    glBegin(GL_POLYGON);
        glVertex3fv(vertices[a]);
        glVertex3fv(vertices[b]);
        glVertex3fv(vertices[c]);
        glVertex3fv(vertices[d]);
    glEnd();
}

void colorcube(){
    glColor3fv(colors[0]); polygon(0, 3, 2, 1);
    glColor3fv(colors[1]); polygon(2, 3, 7, 6);
    glColor3fv(colors[2]); polygon(0, 4, 7, 3);
    glColor3fv(colors[3]); polygon(1, 2, 6, 5);
    glColor3fv(colors[4]); polygon(4, 5, 6, 7);
    glColor3fv(colors[5]); polygon(0, 1, 5, 4);
}

void init(){
    glClearColor(1, 1, 1, 1);
    glColor3f(0, 0, 0);
    glEnable(GL_DEPTH_TEST); //设置消隐
}

int axis;
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();
}

void display(){
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //记得清除DEPTH_BUFFER
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(1, 1, 1, 0, 0, 0, 0, 1, 0);

    glRotatef(theta[0], 1, 0, 0);
    glRotatef(theta[1], 0, 1, 0);
    glRotatef(theta[2], 0, 0, 1);
    colorcube();
    glutSwapBuffers();
}
int main(int argc, char** argv){
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(500, 500);
    glutInitWindowPosition(100, 100);
    glutCreateWindow("SpinCube");

    glutReshapeFunc(reshape);
    glutDisplayFunc(display);
    glutMouseFunc(mouse);
    glutIdleFunc(spinCube);
    init();

    glutMainLoop();
}

光照版本

《OpenGL编程基础(第三版)》中文版教程的 6.6-P130旋转立方体的明暗计算 中的法向量的设置有误,和书中前面章节设置的面不符。

一般设置光照时也都会设置物体的材质,因为在启用光照后原来的函数 $glcolor()$ 函数不会起作用,用设置材质来替代原来的颜色设置。设置物体材质并不是设置物体的真实属性,设置的是光照到物体上的反射光效果,所以随着光源颜色的变化物体呈现的颜色也是不同的。

设置光照和材质的一般的步骤

  1. 设定要用的材质和光照
  2. 设定结构体指针,便于修改材质和光照属性
  3. 设置键盘和鼠标监控函数
  4. 指定每个面的法向量
  5. 设定旋转参数,确定旋转方向和速度
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#include <windows.h>
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#include <bits/stdc++.h>
using namespace std;
#include <stdlib.h>
const double PI = acos(-1.0);

typedef struct materialStruct{ // Material
    GLfloat ambient[4];
    GLfloat diffuse[4];
    GLfloat specular[4];
    GLfloat shininess;
}materialStruct;

void materials(materialStruct *materials){ // Set material
    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, materials->ambient);
    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, materials->diffuse);
    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, materials->specular);
    glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, materials->shininess);
}

materialStruct brassMaterials = { // brass
    {0.33, 0.22, 0.03, 1.0},
    {0.78, 0.57, 0.11, 1.0},
    {0.99, 0.91, 0.81, 1.0},
    27.8
};
materialStruct redPlasticMaterials = { // redPlastic
    {0.3, 0.0, 0.0, 1.0},
    {0.6, 0.0, 0.0, 1.0},
    {0.8, 0.6, 0.6, 1.0},
    32.0
};
materialStruct whiteShinyMaterials = { // whiteShiny
    {1.0, 1.0, 1.0, 1.0},
    {1.0, 1.0, 1.0, 1.0},
    {1.0, 1.0, 1.0, 1.0},
    100.0
};

typedef struct lightingStruct{ //Lighting
    GLfloat ambient[4];
    GLfloat diffuse[4];
    GLfloat specular[4];
}lightingStruct;

void lighting(lightingStruct *lighting){
    glLightfv(GL_LIGHT0, GL_AMBIENT, lighting->ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, lighting->diffuse);
    glLightfv(GL_LIGHT0, GL_SPECULAR, lighting->specular);
}

lightingStruct whiteLighing = { // whiteLighting
    {0, 0, 0, 1},
    {1, 1, 1, 1},
    {1, 1, 1, 1}
};
lightingStruct coloredLighting = { // coloredLighting
    {0.2, 0, 0, 1},
    {0, 1, 0, 1},
    {0, 0, 1, 1}
};
GLfloat light0_pos[4] = {0.9, 0.9, 2.25, 0}; // LightPostion

materialStruct *currentMaterials;
lightingStruct *currentLighting;

GLfloat normals[][3] = { //
    {0.0, 0.0, 1.0},{1.0, 0.0, 0.0},
    {0.0,-1.0,0.0},{0.0,1.0,0.0},
    {0.0,0.0,-1.0},{-1.0,0.0,0.0}
};

GLfloat vertices[][3] = { //
    {-1.0, -1.0, 1.0},{-1.0, 1.0, 1.0},{1.0, 1.0, 1.0},
    {1.0, -1.0, 1.0},{-1.0, -1.0, -1.0},{-1.0, 1.0, -1.0},
    {1.0, 1.0, -1.0},{1.0, -1.0, -1.0} 
};

void reshape(int w, int h){
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-4.0, 4.0, -4.0, 4.0, -4.0, 4.0);
}

void polygon(int a, int b, int c, int d){
    glBegin(GL_POLYGON);
        glVertex3fv(vertices[a]);
        glVertex3fv(vertices[b]);
        glVertex3fv(vertices[c]);
        glVertex3fv(vertices[d]);
    glEnd();
}

void colorcube(){
    // 设置法线
    glNormal3fv(normals[0]); polygon(0, 3, 2, 1);
    glNormal3fv(normals[1]); polygon(2, 3, 7, 6);
    glNormal3fv(normals[2]); polygon(0, 4, 7, 3);
    glNormal3fv(normals[3]); polygon(1, 2, 6, 5);
    glNormal3fv(normals[4]); polygon(4, 5, 6, 7);
    glNormal3fv(normals[5]); polygon(0, 1, 5, 4);
}

void init(){ // Active & Initive Lighting
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);

    currentMaterials = &redPlasticMaterials;
    materials(currentMaterials);

    currentLighting = &whiteLighing;
    lighting(currentLighting);
    glLightfv(GL_LIGHT0, GL_POSITION, light0_pos);
}

int axis;
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();
}
void display(){
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(1, 1, 1, 0, 0, 0, 0, 1, 0);

    glRotatef(theta[0], 1, 0, 0);
    glRotatef(theta[1], 0, 1, 0);
    glRotatef(theta[2], 0, 0, 1);

    colorcube();
    glutSwapBuffers();
}
void key(unsigned char k, int x, int y){
    switch(k){
    case '1': glutIdleFunc(NULL); break;
    case '2': glutIdleFunc(spinCube); break;
    case '3': currentMaterials = &redPlasticMaterials; break;
    case '4': currentMaterials = &whiteShinyMaterials; break;
    case '5': currentMaterials = &brassMaterials; break;
    case '6': currentLighting = &whiteLighing; break;
    case '7': currentLighting = &coloredLighting; break;
    case 'q': exit(0); break;
    }
    materials(currentMaterials);
    lighting(currentLighting);

    glutPostRedisplay();
}

int main(int argc, char** argv){
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(500, 500);
    glutInitWindowPosition(100, 100);
    glutCreateWindow("SpinCube");

    glutReshapeFunc(reshape);
    glutDisplayFunc(display);
    glutMouseFunc(mouse);
    glutIdleFunc(spinCube);
    glutKeyboardFunc(key);
    init();

    glutMainLoop();
}
# 使用单$作为行内数学公式分界符