Computer Graphics Experiment II Part.2 3D Boxman

图形学实验二第二部分——智障的3D小人 demo以及相机相关请看上一篇博文——3D Touring

绘图基本函数

首先要实现个画正方体和长方体的函数,正方体是直接画六个面,长方体则是更改了scale后的画正方体。

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
void drawCube(double xPos, double yPos, double zPos)
{
glPushMatrix();
glTranslated(xPos, yPos, zPos);
glBegin(GL_POLYGON);
glVertex3d(0.0f, 0.0f, 0.0f); //顶面
glVertex3d(0.0f, 0.0f, -1.0f);
glVertex3d(-1.0f, 0.0f, -1.0f);
glVertex3d(-1.0f, 0.0f, 0.0f);
glVertex3d(0.0f, 0.0f, 0.0f); //正面
glVertex3d(-1.0f, 0.0f, 0.0f);
glVertex3d(-1.0f, -1.0f, 0.0f);
glVertex3d(0.0f, -1.0f, 0.0f);
glVertex3d(0.0f, 0.0f, 0.0f); //右面
glVertex3d(0.0f, -1.0f, 0.0f);
glVertex3d(0.0f, -1.0f, -1.0f);
glVertex3d(0.0f, 0.0f, -1.0f);
glVertex3d(-1.0f, 0.0f, 0.0f); //左面
glVertex3d(-1.0f, 0.0f, -1.0f);
glVertex3d(-1.0f, -1.0f, -1.0f);
glVertex3d(-1.0f, -1.0f, 0.0f);
glVertex3d(0.0f, -1.0f, 0.0f); //底面
glVertex3d(0.0f, -1.0f, -1.0f);
glVertex3d(-1.0f, -1.0f, -1.0f);
glVertex3d(-1.0f, -1.0f, 0.0f);
glVertex3d(0.0f, 0.0f, -1.0f); //背面
glVertex3d(-1.0f, 0.0f, -1.0f);
glVertex3d(-1.0f, -1.0f, -1.0f);
glVertex3d(0.0f, -1.0f, -1.0f);
glEnd();
glPopMatrix();
}
void drawBox(double xPos, double yPos, double zPos, double xLen, double yLen, double zLen)
{
glPushMatrix();
glTranslated(xPos, yPos, zPos);
glScaled(xLen, yLen, zLen);
drawCube(0, 0, 0);
glPopMatrix();
}

然后画小人所需要用到的绘图函数基本就完成了。

小人的组成

本次试验中,先从简单的情况入手,我先将小人分成了身体、头、左臂、右臂、左腿、右腿五个部分,五个部分用树结构链接,其中身体是根节点,其他的均是其子节点。

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
Man() {
body = Box(Vector3d(1,2,5), Vector3d(1, 2, 3), Vector3d(0,0,0));
body.color = Vector3d(0, 0, 1);
int angArm = sin(time/100) * 30;
int angLeg= sin(time/100) * 10;
Box *head = new Box(Vector3d(0,-0.5,1),Vector3d(1,1,1));
Box *lArm = new Box(Vector3d(0,0.8,0),Vector3d(0.8,0.8,2),
Vector3d(0,1,0),
Vector3d(-0.5,0,0),
angArm);
Box *rArm = new Box(Vector3d(0,-2,0),Vector3d(0.8,0.8,2),
Vector3d(0,-1,0),
Vector3d(-0.5,0,0),
angArm);
Box *lLeg = new Box(Vector3d(0,-0.1,-3),Vector3d(0.8,0.8,2),
Vector3d(0,-1,0),
Vector3d(-0.5,0,0),
angLeg);
Box *rLeg = new Box(Vector3d(0,-1.1,-3),Vector3d(0.8,0.8,2),
Vector3d(0,1,0),
Vector3d(-0.5,0,0),
angLeg);
body.addNxt(head);
body.addNxt(lArm);
body.addNxt(rArm);
body.addNxt(lLeg);
body.addNxt(rLeg);
}

注意下这两句

1
2
int angArm = sin(time/100) * 30;
int angLeg= sin(time/100) * 10;

计算了胳膊和腿根据time的摆动(旋转)角度,需要注意的是,在后面调用时注意其正负号,避免出现顺拐的情况(x 其中,Box是一个封装起来的长方体,主要包括了一个长方体、颜色、旋转点、旋转轴、存储树结构的指针数组等。

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
class Box {
public:
int len;
double angle;
Vector3d base, scale, rotN, color, rotP;
Box* nxt[maxnxt];
Box() {
angle = 0;
len = 0;
color = Vector3d(1, 1, 1);
rotP = Vector3d(0, 0, 0);
};
Box(Vector3d base_, Vector3d scale_,
Vector3d rotN_=Vector3d(0,0,0),
Vector3d rotP_=Vector3d(0,0,0),
double angle_=0,
Vector3d color_ = Vector3d(1, 1, 1)) {
angle = angle_;
base = base_;
scale = scale_;
rotN = rotN_;
len = 0;
rotP = rotP_;
color = color_;
}
void draw() {
glPushMatrix();
if (rotN.norm() != 0) {
glTranslated(rotP.x(), rotP.y(), rotP.z()); //平移到旋转点
glRotated(angle, rotN.x(), rotN.y(), rotN.z()); //旋转
glTranslated(-rotP.x(), -rotP.y(), -rotP.z()); //平移回去
}
glColor3d(color.x(), color.y(), color.z());
glTranslated(base.x(), base.y(), base.z());
drawBox(Vector3d(0,0,0),scale);
for (int i = 0; i < len; i++) {
glPushMatrix();
nxt[i]->draw();
glPopMatrix();
}
glPopMatrix();
}
void addNxt(Box *x) {
nxt[len] = x;
len++;
}
};

大部分的组成都介绍的差不多了,当然这个系统还是比较简单,调试时除了写相机系统时由于没有坐标系没有很方便的找出错误,另外深度测试时卡了一会儿之外剩下的还算蛮顺利,具体代码请移步github