1. 概述
高级计算机三维建模第二次小实习,利用opengl在提供的基础代码上绘制完整的齿轮。绘制思路如下图:
2. 注意事项
- 对 p 0 , p 7 , p 6 , p 3 p_0,p_7,p_6,p_3 p0,p7,p6,p3这四点所组成的平面采取了三角形绘制的方式,绘制顺序为 p 7 → p 0 → p 6 → p 3 p_7\rightarrow p_0\rightarrow p_6\rightarrow p_3 p7→p0→p6→p3,每一次循环中一次顺序绘制面,到下一次循环中的第一个点则为 p 5 → p 4 → p i p_5\rightarrow p_4\rightarrow p_i p5→p4→pi,这样,使用GL_TRIANGLE_STRIP进行绘制,即可连续绘制出齿轮一个面;
- 当使用glEnable(GL_CULL_FACE)时,绘制齿轮的反面时,重点需要注意,绘制点的顺序要由原来的逆时针变为顺时针(注:opengl绘制时,默认逆时针为正面),即顺序变为 p 0 → p 7 → p 3 → p 6 p_0\rightarrow p_7\rightarrow p_3\rightarrow p_6 p0→p7→p3→p6,这样,当翻转齿轮时,才能够看见齿轮背面;或者不使用glEnable((GL_CULL_FACE);
- 记得添加法线,否则由于默认正面的原因,齿轮背面看起来是黑的,法线信息根据z轴(垂直于屏幕)来决定,齿轮正面朝外(即为+),背面朝内(即为-);
- 齿轮齿的法线比较麻烦,因为是旋转一周的,无法指定固定朝向。
3. 绘制结果与代码
3.1 齿轮结果图
3.2 完整代码
#include <GL/freeglut.h>
#include <stdlib.h>
#include <math.h>
const double PI=3.14159265;
GLfloat g_rotx = 20.0, g_roty = 30.0, g_rotz = 0.0, g_angle=0.0;
GLfloat g_modelPos[3] = {0, 0, -20};
GLfloat g_lightPos[4] = {15.0, 15.0, 10.0, 0.0};
GLfloat g_color1[4] = {0.8, 0.1, 0.0, 1.0};
GLfloat g_color2[4] = {0.0, 0.8, 0.2, 1.0};
GLfloat g_color3[4] = {0.2, 0.2, 1.0, 1.0};
bool g_bStartAnim = true;
static void resize(int w, int h)
{
glViewport(0,0,(GLsizei)w,(GLsizei)h);
glMatrixMode(GL_PROJECTION) ;
glLoadIdentity() ;
gluPerspective(45.0,(GLfloat)w/(GLfloat)h,0.2,100.0) ;
glMatrixMode(GL_MODELVIEW) ;
glLoadIdentity() ;
}
void init(void)
{
glLightfv(GL_LIGHT0, GL_POSITION, g_lightPos);
//glEnable(GL_CULL_FACE);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
}
/*Input: inner_radius - radius of hole at center
outer_radius - radius at center of teeth
width - width of gear
teeth - number of teeth
tooth_depth - depth of tooth */
void DrawGear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, GLint teeth, GLfloat tooth_depth)
{
GLint i;
GLfloat r0, r1, r2;
GLfloat angle, da;
GLfloat u, v, len;
r0 = inner_radius;
r1 = outer_radius - tooth_depth / 2.0;
r2 = outer_radius + tooth_depth / 2.0;
da = 2.0 * PI / teeth / 4.0;
glShadeModel(GL_FLAT);
glNormal3f(0.0, 0.0, 1.0);
//Draw front face
glBegin(GL_TRIANGLE_STRIP);
for (i = 0; i <= teeth; i++)
{
angle = i * 2.0 * PI / teeth;
glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
glNormal3f(0,0,1);
glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
glNormal3f(0,0,1);
glVertex3f(r0 * cos(angle + 3 * da), r0 * sin(angle + 3 * da), width * 0.5);
glNormal3f(0,0,1);
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5);
glNormal3f(0,0,1);
}
glEnd();
//Draw front sides of teeth
glBegin(GL_QUADS);
da = 2.0 * PI / teeth / 4.0;
for (i = 0; i < teeth; i++)
{
angle = i * 2.0 * PI / teeth;
glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
glNormal3f(0,0,1);
glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
glNormal3f(0,0,1);
glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), width * 0.5);
glNormal3f(0,0,1);
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5);
glNormal3f(0,0,1);
}
glEnd();
//Draw back face
glBegin(GL_TRIANGLE_STRIP);
for (i = 0; i <= teeth; i++)
{
angle = i * 2.0 * PI / teeth;
/*glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0);
glNormal3f(0,0,-1);
glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0);
glNormal3f(0,0,-1);
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0);
glNormal3f(0,0,-1);
glVertex3f(r0 * cos(angle + 3 * da), r0 * sin(angle + 3 * da), width * 0);
glNormal3f(0,0,-1);*/
glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0);
glNormal3f(0,0,-1);
glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0);
glNormal3f(0,0,-1);
glVertex3f(r0 * cos(angle + 3 * da), r0 * sin(angle + 3 * da), width * 0);
glNormal3f(0,0,-1);
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0);
glNormal3f(0,0,-1);
}
glEnd();
//Draw back sides of teeth
glBegin(GL_QUADS);
da = 2.0 * PI / teeth / 4.0;
for (i = 0; i < teeth; i++)
{
angle = i * 2.0 * PI / teeth;
glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0);
glNormal3f(0,0,-1);
glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0);
glNormal3f(0,0,-1);
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0);
glNormal3f(0,0,-1);
glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), width * 0);
glNormal3f(0,0,-1);
}
glEnd();
//xiaoyuan
glBegin(GL_QUAD_STRIP);
for(i = 0; i <= teeth; i++)
{
angle = i * 2.0 * PI / teeth;
glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0);
glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
glVertex3f(r0 * cos(angle+3*da), r0 * sin(angle+3*da), width * 0);
glVertex3f(r0 * cos(angle+3*da), r0 * sin(angle+3*da), width * 0.5);
}
glEnd();
//dayuan
glBegin(GL_QUAD_STRIP);
for(i = 0; i <= teeth; i++)
{
angle = i * 2.0 * PI / teeth;
glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0);
glVertex3f(r1 * cos(angle+3*da), r1 * sin(angle+3*da), width * 0.5);
glVertex3f(r1* cos(angle+3*da), r1 * sin(angle+3*da), width * 0);
}
glEnd();
//shangchi
glBegin(GL_QUADS);
for(i = 0; i < teeth; i++)
{
angle = i * 2.0 * PI / teeth;
glVertex3f(r2 * cos(angle+da), r2 * sin(angle+da), width * 0.5);
glNormal3f(1,0,0);
glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
glNormal3f(1,0,0);
glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0);
glNormal3f(1,0,0);
glVertex3f(r2* cos(angle+da), r2 * sin(angle+da), width * 0);
glNormal3f(1,0,0);
}
glEnd();
//xiachi
glBegin(GL_QUADS);
for(i = 0; i < teeth; i++)
{
angle = i * 2.0 * PI / teeth;
glVertex3f(r2* cos(angle+2*da), r2 * sin(angle+2*da), width * 0);
glVertex3f(r1 * cos(angle+3*da), r1 * sin(angle+3*da), width * 0);
glVertex3f(r1 * cos(angle+3*da), r1 * sin(angle+3*da), width * 0.5);
glVertex3f(r2 * cos(angle+2*da), r2 * sin(angle+2*da), width * 0.5);
}
glEnd();
//zuiwaimian
glBegin(GL_QUADS);
for(i = 0; i < teeth; i++)
{
angle = i * 2.0 * PI / teeth;
glVertex3f(r2 * cos(angle+2*da), r2 * sin(angle+2*da), width * 0.5);
glVertex3f(r2 * cos(angle+1*da), r2 * sin(angle+1*da), width * 0.5);
glVertex3f(r2* cos(angle+1*da), r2 * sin(angle+1*da), width * 0);
glVertex3f(r2 * cos(angle+2*da), r2 * sin(angle+2*da), width * 0);
}
glEnd();
}
static void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if(g_bStartAnim)
g_angle = 30*glutGet(GLUT_ELAPSED_TIME) / 1000.0;
glLoadIdentity() ;
glTranslatef(g_modelPos[0], g_modelPos[1], g_modelPos[2]);
glPushMatrix();
glRotatef(g_rotx, 1.0, 0.0, 0.0);
glRotatef(g_roty, 0.0, 1.0, 0.0);
glRotatef(g_rotz, 0.0, 0.0, 1.0);
glPushMatrix();
glTranslatef(-3.0, -2.0, 0.0);
glRotatef(g_angle, 0.0, 0.0, 1.0);
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, g_color1);
DrawGear(1.0, 4.0, 1.0, 20, 0.7);
glPopMatrix();
glPopMatrix();
glutSwapBuffers();
}
static void key(unsigned char key, int x, int y)
{
switch (key)
{
case 27 :
exit(0);
break;
case 'w':
g_rotx += 5;
break;
case 's':
g_rotx -= 5;
break;
case 'a':
g_roty += 5;
break;
case 'd':
g_roty -= 5;
break;
case 'q':
g_rotz += 5;
break;
case 'e':
g_rotz -= 5;
break;
case 'z':
g_modelPos[2] += 1;
break;
case 'x':
g_modelPos[2] -= 1;
break;
case ' ':
g_bStartAnim = !g_bStartAnim;
break;
}
glutPostRedisplay();
}
static void idle(void)
{
glutPostRedisplay();
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitWindowSize(800, 600);
glutInitWindowPosition(10,10);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutCreateWindow("Shapes");
glutReshapeFunc(resize);
glutDisplayFunc(display);
glutKeyboardFunc(key);
glutIdleFunc(idle);
glClearColor(1, 1, 1, 1);
init();
glutMainLoop();
return 0;
}