OpenGL曲线曲面的绘制与3D模型的装载与显示.docx
《OpenGL曲线曲面的绘制与3D模型的装载与显示.docx》由会员分享,可在线阅读,更多相关《OpenGL曲线曲面的绘制与3D模型的装载与显示.docx(24页珍藏版)》请在冰豆网上搜索。
OpenGL曲线曲面的绘制与3D模型的装载与显示
实验7OpenGL曲线、曲面的绘制与3D模型的装载与显示
实验目的:
1)理解Bezier曲线、曲面绘制的基本原理;理解OpenGL中一维、二维插值求值器的用法。
2)掌握OpenGL中曲线、曲面绘图的方法,对比不同参数下的绘图效果差异;
实验要求:
1)教师领读代码;
2)学生上机实验;
3)针对代码1,分别或同时去掉开关1和开关2的代码注释,查看并记录实验效果;用公式说明Bezier曲线、曲面的绘制计算过程;
4)针对代码2,分别或同时去掉各开关,观察并记录显示效果差异;用公式说明Bezier曲面插值点的计算过程;说明线框模型与曲面模型的区别;
5)针对代码3:
实验和观察材质参数、光照参数、坐标参数对实验效果的影响;
6)理解均匀与非均匀样条有理曲线或曲面的差异;
7)针对代码4:
掌握非均匀有理B样条曲面(NURBS曲面)的曲面绘制方法;
8)阅读
9)OpenGL如何装载并显示3DMAX导出的3D模型实验及代码,课外自行完成。
代码1:
用四个控制点绘制一条三次Bezier曲线:
//Demo:
用四个控制顶点来画一条三次Bezier曲线
#include
#include
#include
//4个控制点的3D坐标——z坐标全为0
GLfloatctrlpoints[4][3]={
{-4,-4,0},{-2,4,0},{2,-4,0},{4,4,0}
};
voidinit(void)
{
//背景色
glClearColor(0.0,0.0,0.0,1.0);
//将控制点坐标映射为曲线坐标
//参数:
GL_MAP1_VERTEX_3,3维点坐标
//参数2和3:
控制参数t或u的取值范围[0,1]
//参数4:
曲线内插值点间的步长3——3维坐标
//参数5:
曲线间的补偿为顶点数4个——总步长为12
//参数6:
控制点二维数组首元素地址
//note:
若是在这里设置了相关参数,后续对ctrlpoints内容更改曲线不变
glMap1f(GL_MAP1_VERTEX_3,0.0,1.0,3,4,&ctrlpoints[0][0]);
//打开开关——允许3维坐标控制点到参数点转换开关
glEnable(GL_MAP1_VERTEX_3);
glShadeModel(GL_FLAT);
//代码开关2:
去掉本注释,可启用反走样
/*
glEnable(GL_BLEND);
glEnable(GL_LINE_SMOOTH);//允许直线反走样
glHint(GL_LINE_SMOOTH_HINT,GL_FASTEST);//Antialiasthelines
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
*/
}
voiddisplay(void)
{
inti;
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0,1.0,1.0);
//代码开关1:
去掉本注释,查看动态的曲线绘图效果:
动态更新控制点坐标
/*
for(intt=0;t<4;t++){
for(intj=0;j<3;j++)
ctrlpoints[t][j]=(rand()%1024/1024.0-0.5)*10;
}
//动态映射
glMap1f(GL_MAP1_VERTEX_3,0.0,1.0,3,4,&ctrlpoints[0][0]);
*/
glLoadIdentity();
glColor3f(1.0,0.0,0.0);
//绘制连续线段
glBegin(GL_LINE_STRIP);
//参数t或u取值为i/30,共计31个点
for(i=0;i<=30;i++)
glEvalCoord1f((GLfloat)i/30.0);//根据4个控制点坐标的参数化插值
glEnd();
/*显示控制点*/
glPointSize(5.0);
glBegin(GL_POINTS);
for(i=0;i<4;i++)
glVertex3fv(&ctrlpoints[i][0]);
glEnd();
glTranslatef(-0.1f,0.1f,0.0f);
glColor3f(0.0,1.0,0.0);
//glLineWidth(2.0);
//绘制连续线段——线段数越多,曲线越光滑
glBegin(GL_LINE_STRIP);
//设置参数t或u取值为i/60,共计61个点
//实验:
若让t从-2变化到+2,可看到什么效果
for(i=0;i<=60;i++)
glEvalCoord1f((GLfloat)i/60.0);//根据4个控制点坐标的参数化插值
glEnd();
glTranslatef(-0.1f,0.1f,0.0f);
glColor3f(1.0,1.0,1.0);
//绘制连续线段
glBegin(GL_LINE_STRIP);
//设置参数t或u取值为i/60,共计61个点
//实验:
若让t从-2变化到+2,可看到什么效果
for(i=0;i<=100;i++)
glEvalCoord1f((GLfloat)i/100.0);
glEnd();
glutSwapBuffers();
}
//3D空间中绘制2D效果,采用正交投影
voidreshape(GLsizeiw,GLsizeih)
{
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if(w<=h)
glOrtho(-5.0,5.0,-5.0*(GLfloat)h/(GLfloat)w,5.0*(GLfloat)h/(GLfloat)w,-5.0,5.0);
else
glOrtho(-5.0*(GLfloat)w/(GLfloat)h,5.0*(GLfloat)w/(GLfloat)h,-5.0,5.0,-5.0,5.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
voidkeyboard(unsignedcharkey,intx,inty)
{//请参考"变换示例参考"一文,考虑添加键盘命令,交互式来控制金字塔的旋转
switch(key)
{
case'x':
case'X':
case27:
//ESC键
exit(0);
break;
default:
break;
}
}
intmain(intargc,char**argv)
{
srand((unsignedint)time(0));
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH);//使用双缓存模式和深度缓存
glutInitWindowSize(800,800);
glutInitWindowPosition(0,0);
glutCreateWindow("2DBezier曲线");
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutIdleFunc(display);//设置空闲时调用的函数
glutMainLoop();
return0;
}
效果图:
动态曲线绘制效果图:
关闭代码开关1,打开代码开关2,查看直线反走样效果:
对比分析反走样前后曲线绘制效果差异。
代码2:
用4*4个控制点绘制一个三次Bezier曲面线框模型
//Demo:
用4*4个控制顶点来画一个三次Bezier曲面线框模型
#include
#include
#include
/*控制点的坐标*/
GLfloatctrlpoints[4][4][3]={
{{-1.5,-1.5,2.0},
{-0.5,-1.5,2.0},
{0.5,-1.5,-1.0},
{1.5,-1.5,2.0}
},
{{-1.5,-0.5,1.0},
{-0.5,1.5,2.0},
{0.5,0.5,1.0},
{1.5,-0.5,-1.0}},
{{-1.5,0.5,2.0},
{-0.5,0.5,1.0},
{0.5,0.5,3.0},
{1.5,-1.5,1.5}},
{{-1.5,1.5,-2.0},
{-0.5,1.5,-2.0},
{0.5,0.5,1.0},
{1.5,1.5,-1.0}}};
voidinit(void)
{
//背景色
glClearColor(0.0,0.0,0.0,1.0);
//将控制点坐标映射为曲面坐标
//参数:
GL_MAP1_VERTEX_3,3维点坐标
//参数2和3:
控制参数u的取值范围[0,1]
//参数4:
x方向元素间的步长为3个GLfloat
//参数5:
x方向曲线间的步长为4个控制点——曲线由4个控制点确定
//参数6-7:
控制参数v的取值范围[0,1]
//参数8:
y方向元素间的步长为12个GLfloat元素
//参数9:
y方向每条曲线的控制点数量为4
//note:
若是在这里设置了相关参数,后续对ctrlpoints内容更改曲线不变
glMap2f(GL_MAP2_VERTEX_3,0,1,3,4,0,1,12,4,&ctrlpoints[0][0][0]);
//允许二维映射
glEnable(GL_MAP2_VERTEX_3);
//二维映射:
x、y方向U和V的参数[0,1],且中间插值数量为各20个
glMapGrid2f(20,0.0,1.0,20,0.0,1.0);
//允许深度测试
glEnable(GL_DEPTH_TEST);
//代码开关2:
启用反走样
glEnable(GL_BLEND);
glEnable(GL_LINE_SMOOTH);
glHint(GL_LINE_SMOOTH_HINT,GL_FASTEST);//Antialiasthelines
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
}
voiddisplay(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glColor3f(0.0,1.0,0.0);
glPushMatrix();
//代码开关1:
去掉注释查看效果;更改旋转角度参数,查看效果
//glRotatef(0.1,1.0,1.0,1.0);
inti,j;
//生成2D网格坐标,以从控制点参数插值确定网格点所对应的点集所对应的坐标
for(j=0;j<=8;j++){
glBegin(GL_LINE_STRIP);
for(i=0;i<=30;i++)
glEvalCoord2f((GLfloat)i/30.0,(GLfloat)j/8.0);//固定y坐标时x方向的网格坐标
glEnd();
glBegin(GL_LINE_STRIP);
for(i=0;i<=30;i++)
glEvalCoord2f((GLfloat)j/8.0,(GLfloat)i/30.0);//固定x坐标时y方向的网格坐标
glEnd();
}
//查看网格所确定的插值点(u,v)的位置
glColor3f(1,0,0);
glBegin(GL_POINTS);
for(j=0;j<=8;j++){
for(i=0;i<=30;i++)
glVertex3f((GLfloat)i/30.0,(GLfloat)j/8.0,0);
for(i=0;i<=30;i++)
glVertex3f((GLfloat)j/8.0,(GLfloat)i/30.0,0);
}
glEnd();
glPopMatrix();
glutSwapBuffers();
}
voidreshape(GLsizeiw,GLsizeih)
{
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if(w<=h)
glOrtho(-5.0,5.0,-5.0*(GLfloat)h/(GLfloat)w,5.0*(GLfloat)h/(GLfloat)w,-5.0,5.0);
else
glOrtho(-5.0*(GLfloat)w/(GLfloat)h,5.0*(GLfloat)w/(GLfloat)h,-5.0,5.0,-5.0,5.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
voidkeyboard(unsignedcharkey,intx,inty)
{//请参考"变换示例参考"一文,考虑添加键盘命令,交互式来控制金字塔的旋转
switch(key)
{
case'x':
case'X':
case27:
//ESC键
exit(0);
break;
default:
break;
}
}
intmain(intargc,char**argv)
{
srand((unsignedint)time(0));
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH);//使用双缓存模式和深度缓存
glutInitWindowSize(800,800);
glutInitWindowPosition(0,0);
glutCreateWindow("Bezier曲面线框模型");
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutIdleFunc(display);//设置空闲时调用的函数
glutMainLoop();
return0;
}
效果:
未打开注释开关1时的效果:
打开注释开关1时的效果:
代码3:
用4*4个控制点绘制一个三次Bezier曲面并添加光照效果
//curve.cpp:
Definestheentrypointfortheconsoleapplication.
//
#include"stdafx.h"
//Demo:
用4*4个控制顶点来画一个三次Bezier曲面
#include
#include
#include
/*控制点的坐标*/
GLfloatctrlpoints[4][4][3]={
{{-1.5,-1.5,2.0},
{-0.5,-1.5,2.0},
{0.5,-1.5,-1.0},
{1.5,-1.5,2.0}},
{{-1.5,-0.5,1.0},
{-0.5,1.5,2.0},
{0.5,0.5,1.0},
{1.5,-0.5,-1.0}},
{{-1.5,0.5,2.0},
{-0.5,0.5,1.0},
{0.5,0.5,3.0},
{1.5,-1.5,1.5}},
{{-1.5,1.5,-2.0},
{-0.5,1.5,-2.0},
{0.5,0.5,1.0},
{1.5,1.5,-1.0}}};
voidinit(void)
{
//背景色
glClearColor(0.0,0.0,0.0,1.0);
//将控制点坐标映射为曲面坐标
//参数:
GL_MAP1_VERTEX_3,3维点坐标
//参数2和3:
控制参数u的取值范围[0,1]
//参数4:
x方向元素间的步长为3个GLfloat
//参数5:
x方向曲线间的步长为4个控制点——曲线由4个控制点确定
//参数6-7:
控制参数v的取值范围[0,1]
//参数8:
y方向元素间的步长为12个GLfloat元素
//参数9:
y方向每条曲线的控制点数量为4
//note:
若是在这里设置了相关参数,后续对ctrlpoints内容更改曲线不变
glMap2f(GL_MAP2_VERTEX_3,0,1,3,4,0,1,12,4,&ctrlpoints[0][0][0]);
//允许二维映射
glEnable(GL_MAP2_VERTEX_3);
//二维映射:
x、y方向U和V的参数[0,1],且中间插值数量为各20个
glMapGrid2f(20,0.0,1.0,20,0.0,1.0);
//允许深度测试
glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
//代码开关4:
取消下面两行代码,查看曲面显示效果差异
//打开自动法矢量开关
//glEnable(GL_AUTO_NORMAL);
//允许正则化法矢量
//glEnable(GL_NORMALIZE);
//代码开关3:
设置材质与光源
GLfloatambient[]={0.4,0.6,0.2,1.0};
GLfloatposition[]={0.0,1.0,3.0,1.0};
GLfloatmat_diffuse[]={0.2,0.4,0.8,1.0};
GLfloatmat_specular[]={1.0,1.0,1.0,1.0};
GLfloatmat_shininess[]={80.0};
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glLightfv(GL_LIGHT0,GL_AMBIENT,ambient);
glLightfv(GL_LIGHT0,GL_POSITION,position);
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);
glMaterialfv(GL_FRONT,GL_SHININESS,mat_shininess);
}
voiddisplay(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glColor3f(0.0,1.0,0.0);
//如果不希望旋转,则启用push和pop矩阵命令,并注释掉glRotatef行
//glPushMatrix();
//代码开关1:
去掉注释查看效果;更改旋转角度参数,查看效果
glRotatef(1.0,1.0,1.0,1.0);
glEvalMesh2(GL_FILL,0,20,0,20);
//glPopMatrix();
glutSwapBuffers();
}
voidreshape(GLsizeiw,GLsizeih)
{
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if(w<=h)
glOrtho(-5.0,5.0,-5.0*(GLfloat)h/(GLfloat)w,5.0*(GLfloat)h/(GLfloat)w,-5.0,5.0);
else
glOrtho(-5.0*(GLfloat)w/(GLfloat)h,5.0*(GLfloat)w/(GLfloat)h,-5.0,5.0,-5.0,5.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
voidkeyboard(unsignedcharkey,intx,inty)
{//请参考"变换示例参考"一文,考虑添加键盘命令,交互式来控制金字塔的旋转
switch(key)
{
case'x':
case'X':
case27:
//ESC键
exit(0);
break;
default:
break;
}
}
intmain(intargc,char**argv)
{
srand((unsignedint)time(0));
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH);//使用双缓存模式和深度缓存
glutInitWindowSize(800,800);
glutInitWindowPosition(0,0);
glutCreateWindow("Bezier曲面");
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glu