1.实验目的:

  • 掌握B样条、NURBS(非均匀有理B样条)曲线、曲面的概念。
  • 掌握B样条、NURBS曲面编程方法。

2.实验内容:

  • 结合示范代码了解曲线B样条曲面生成原理与算法实现,尤其是NURBS曲面。
  • 调试、编译、修改示范程序。

3.实验原理:

求值器能够描述任何角度的多项式或有理多项式样条或表面,包括B-样条,NURBS(非均匀有理B-样条)表面,Bezier曲线和表面,以及Hermite样条。由于求值器只提供了对曲线或表面底层描述,需要使用更高层次的NURBS接口来生成B样条曲面。
OpenGL提供了NURBS接口,该接口封装了大量代码,不仅包含渲染功能,也提供了修剪曲面等额外功能,NURBS函数使用平面多边形进行渲染。B样条曲面包含非均匀有理B-样条,另外Bezier的缺点是增加很多控制点时曲线变得不可控,而B样条曲面调整4个控制点可以得到较好的效果。
NURBS接口生成B样条曲面的过程如下。
(1)生成控制点和创建NURBS对象:

GLUnurbsObj *theNurb;
init_surface();
theNurb = gluNewNurbsRenderer();glEnable(GL_AUTO_NORMAL);  // 开启自动生成法线向量:
glEnable(GL_NORMALIZE); //规范化法线向量

(2)设置NURBS渲染属性和回调函数,一般的属性设置包括以下3种:

gluNurbsProperty(theNurb, GLU_SAMPLING_METHOD, GLU_PATH_LENGTH);
gluNurbsProperty(theNurb, GLU_SAMPLING_TOLERANCE, 25.0);
gluNurbsProperty(theNurb, GLU_DISPLAY_MODE, GLU_FILL);
gluNurbsCallback(theNurb, GLU_ERROR, nurbsError);//这里可能需要强制转nurbsError类型。

(3)获取NURBS获取分格化后的基本直线和多边形图元,包括顶点,颜色,纹理坐标,法线。获取NURBS获取图元的前提条件,需要设置GLU_NURBS_TESSELLATOR属性。 这样NURBS分格化的直线和多边形图元不会直接渲染,而是返回到回调函数重新提交给渲染管线。

gluNurbsProperty(theNurb, GLU_NURBS_MODE, GLU_NURBS_TESSELLATOR);
gluNurbsProperty(theNurb, GLU_SAMPLING_TOLERANCE, 25.0);
gluNurbsProperty(theNurb, GLU_DISPLAY_MODE, GLU_FILL);

设置回调函数:

gluNurbsCallback(theNurb, GLU_ERROR, nurbsError);
gluNurbsCallback(theNurb, GLU_NURBS_BEGIN, beginCallback);
gluNurbsCallback(theNurb, GLU_NURBS_VERTEX, vertexCallback);
gluNurbsCallback(theNurb, GLU_NURBS_NORMAL, normalCallback);
gluNurbsCallback(theNurb, GLU_NURBS_END, endCallback);

(4)开始绘制:

 gluBeginSurface(theNurb)。

(5)根据控制点绘制曲线或曲面:

gluNurbsSurface(theNurb,8, knots, 8, knots,4 * 3, 3, &ctlpoints[0][0][0], 4, 4, L_MAP2_VERTEX_3);

(6) 修剪NURBS表面,在这里可以定义修剪曲线,来修剪NURBS表面,按照规定根据曲线绕向行走左边的区域会被保留,右边的区域会被踢除,嵌套的曲线中的外部和内部曲线绕向不能相同否则剔除区域就会产生二义性而出现错误。
定义修剪曲线可以通过:gluPwlCurve函数来创建一条分段的线性曲线或用gluNurbsCurve函数创建一条NURBS曲线。gluPwlCurve不能定义很弯曲的曲线,更多是定义线段集合,gluNurbsCurve可以定义比较弯曲的曲线。gluBeginTrim (theNurb);void APIENTRY gluPwlCurve (GLUnurbs *nobj, GLint count(//曲线上点数), GLfloat *array (由array数组提供曲线上的点,array两个相邻顶点之间浮点值的个数,可以是2,3), GLint stride,GLenum type(//GLU_MAP1_TRIM2 或GLU_MAP1_TRIM3)); gluEndTrim (theNurb);
(7)通过gluEndSurface(theNurb)来完成曲线或曲面的绘制。
(8)通过gluDeleteNurbsRenderer(theNurb)来清理NURBS对象,释放所占的内存。

4.实验代码:

#include <GL/glut.h>
#include <stdlib.h>
#include <stdio.h>#ifndef CALLBACK
#define CALLBACK
#endifGLfloat ctlpoints[4][4][3];
int showPoints = 0;GLUnurbsObj *theNurb;//初始化曲面控制点,控制点阈值[-3,+3]
void init_surface(void)
{int u, v;for (u = 0; u < 4; u++) {for (v = 0; v < 4; v++) {ctlpoints[u][v][0] = 2.0*((GLfloat)u - 1.5);ctlpoints[u][v][1] = 2.0*((GLfloat)v - 1.5);if ((u == 1 || u == 2) && (v == 1 || v == 2))ctlpoints[u][v][2] = 3.0;elsectlpoints[u][v][2] = -3.0;}}}void CALLBACK nurbsError(GLenum errorCode)
{const GLubyte *estring;estring = gluErrorString(errorCode);fprintf(stderr, "Nurbs Error: %s\n", estring);exit(0);
}/*  Initialize material property and depth buffer.
*/
void init(void)
{GLfloat mat_diffuse[] = { 0.7, 0.7, 0.7, 1.0 };GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };GLfloat mat_shininess[] = { 100.0 };glClearColor(0.0, 0.0, 0.0, 0.0);glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);glEnable(GL_LIGHTING);glEnable(GL_LIGHT0);glEnable(GL_DEPTH_TEST);// 开启自动生成法线向量glEnable(GL_AUTO_NORMAL);// 规范化法线向量,不规范会有问题的glEnable(GL_NORMALIZE);// 1.生成控制点和创建NURBS对象init_surface();theNurb = gluNewNurbsRenderer();// 2.设置NURBS渲染属性和回调函数// 参数可以是GLU_DOMAIN_DISTANCE,那么需要GLU_U_STEP或GLU_V_STEP来指定u,v方向的采样点数量默认都是100.gluNurbsProperty(theNurb, GLU_SAMPLING_METHOD, GLU_PATH_LENGTH);// GLU_PATH_LENGTH时最大边分格化距离,边长度超过该距离就会分割出更多顶点和轮廓。// GLU_PARAMETRIC_ERROR被分格化的多边形和他们近似模拟的表面之间的最大距离,超过则分格化的多边形会被分割。gluNurbsProperty(theNurb, GLU_SAMPLING_TOLERANCE, 25.0);gluNurbsProperty(theNurb, GLU_DISPLAY_MODE, GLU_FILL);// 如果在视景体外部那么不启用分格化,提高性能gluNurbsProperty(theNurb, GLU_CULLING, GLU_TRUE);// 从OGL服务器获取投影矩阵,模型视图矩阵和视口,如果是GLU_FALSE那么需要gluLoadSampliingMatrices来提供这些矩阵。gluNurbsProperty(theNurb, GLU_AUTO_LOAD_MATRIX, GLU_TRUE);// 获取属性值用gluGetNurbsPropertyGLfloat cullMethod = 0.0f;gluGetNurbsProperty(theNurb, GLU_CULLING, &cullMethod);// 设置错误回调gluNurbsCallback(theNurb, GLU_ERROR, (void(__stdcall*) (void))nurbsError);
}void myDisplay(void)
{// 每个控制点(节点)uv的上下界,从[0,1]类似求值器的插值指定GLfloat knots[8] = { 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0 };int i, j;glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glPushMatrix();glRotatef(330.0, 1., 0., 0.);glScalef(0.5, 0.5, 0.5);// 3.开始绘制gluBeginSurface(theNurb);    gluNurbsSurface(theNurb,8, knots, 8, knots,4 * 3, 3, &ctlpoints[0][0][0],4, 4, GL_MAP2_VERTEX_3);gluNurbsSurface(theNurb,8, knots, 8, knots,4 * 3, 3, &ctlpoints[0][0][0],4, 4, GL_MAP2_NORMAL);// 完成曲线或曲面的绘制gluEndSurface(theNurb);// 曲线的绘制用glBeginCurve, glNurbsCurve glEndCurve来指定,参数含义同曲面。if (showPoints) {glPointSize(5.0);glDisable(GL_LIGHTING);glColor3f(1.0, 1.0, 0.0);glBegin(GL_POINTS);for (i = 0; i < 4; i++) {for (j = 0; j < 4; j++) {glVertex3f(ctlpoints[i][j][0],ctlpoints[i][j][1], ctlpoints[i][j][2]);}}glEnd();glEnable(GL_LIGHTING);}glPopMatrix();glFlush();
}void myReshape(int w, int h)
{glViewport(0, 0, (GLsizei)w, (GLsizei)h);glMatrixMode(GL_PROJECTION);glLoadIdentity();gluPerspective(45.0, (GLdouble)w / (GLdouble)h, 3.0, 8.0);glMatrixMode(GL_MODELVIEW);glLoadIdentity();glTranslatef(0.0, 0.0,-5.0);
}void myKeyboard(unsigned char key, int x, int y)
{switch (key) {case 'c':case 'C':showPoints = !showPoints;glutPostRedisplay();break;case 27:gluDeleteNurbsRenderer(theNurb);exit(0);break;default:break;}
}int main(int argc, char** argv)
{glutInit(&argc, argv);glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);glutInitWindowSize(500, 500);glutInitWindowPosition(100, 100);glutCreateWindow(argv[0]);init();glutReshapeFunc(myReshape);glutDisplayFunc(myDisplay);glutKeyboardFunc(myKeyboard);glutMainLoop();return 0;
}

运行结果如图A.11(a)所示。

图A.11(a)生成B样条曲面

5.实验提高

根据控制点(-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)重新生成并显示B样条曲面,见图A.11(b)。

图A.11(b)重新生成B样条曲面

实验11 B样条曲面生成相关推荐

  1. 实验10:创建带有生命周期方法的bean ||实验11:测试bean的后置处理器

    实验10:创建带有生命周期方法的bean 实验11:测试bean的后置处理器 MyBeanPostProcessor.java package com.atguigu.bean;import org. ...

  2. c语言实验11答案,c语言实验9-11参考答案

    c语言实验9-11参考答案 (4页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 9.90 积分 数组 上机题9.编写程序:从键盘输入一串整数保存到数组中, ...

  3. 王爽汇编语言 实验11

    第十章的实验11出的有点不同.一是相对简单一些,还有似乎没有用到太多本章的内容.比如MOVSB 就没用到.下面是我的代码  1 assume ds:datasg, cs:code    2 datas ...

  4. 计算机图形学真实感显示代码,计算机图形学实验 - 真实感图形场景的生成

    <计算机图形学实验 - 真实感图形场景的生成>由会员分享,可在线阅读,更多相关<计算机图形学实验 - 真实感图形场景的生成(4页珍藏版)>请在人人文库网上搜索. 1.计算机图形 ...

  5. 华北水利水电C 语言实验11,华北水利水电大学C语言实验11.doc

    华北水利水电大学C语言实验11 C语言程序设计实验报告 实验11.结构体程序设计 班级 2013156 学号 201315613 姓名 吴浩 [实验目的] (1)掌握结构体类型的概念.定义和使用: ( ...

  6. 头哥 (Educoder)数据结构与算法实验:实验11 TYJ动态规划

    实验11 TYJ动态规划 第1关:多段图的最短路径问题 任务描述 本关任务:设图G=(V, E)是一个带权有向连通图,如果把顶点集合V划分成k个互不相交的子集Vi(2≤k≤n, 1≤i≤k),使得E中 ...

  7. 电子学:第012课——实验 11:光和声

    电子学:第xx课--实验 11:光和声 是时候让你自己开展第一个功能和目的齐备的项目了.最终你会做成一个非常简单的声音合成器. 需要的物品 面包板.连接线.剪线钳.剥线钳.万用表 9 V 电池和连接器 ...

  8. 《汇编语言》王爽(第四版) 第十一章 实验11

    文章目录 前言 一.实验任务 二.实现思路 三.实现代码 四.DIY时间 1.需求分析 2.最终效果 3.实现代码 总结 前言 本文是王爽老师<汇编语言>(第四版) 第十一章 实验11 的 ...

  9. 操作系统实验11:内存管理实验(DAY 62)

    文章目录 1:实验要求: 2:代码实现 3:实验分析: 4:结果分析 1:出现两个进程 2:设置内存空间为256 3:再重复一次上一步操作 4:输入5,展示内存空间 5:输入4,杀死2号进程. 1:实 ...

  10. 软件工程实验一--编程随机生成30个四则运算,算数包括100以内的整数和真分数。...

    软件工程实验一: --编程随机生成30个四则运算,算数包括100以内的整数和真分数. 实验思路:先利用rand()函数随机生成两个算数,包括100以内的整数和真分数,生成100以内的整数,用rand( ...

最新文章

  1. GLPI生成中文PDF报表
  2. Python-Matplotlib绘制简单图像
  3. HarmonyOS之深入解析服务卡片的使用
  4. 《 第一行代码 》读后感
  5. java 构造 statict_java学习:构造方法、static、final
  6. java 线程状态_面试官问:为什么Java线程没有Running状态?我懵了
  7. Android Handler机制之总目录
  8. 上传大文件至阿里云服务器解决方案(理论上无限大文件,支持批量处理)
  9. H3CIE(WLAN)学习笔记(3)——802.11帧格式与介质访问规则
  10. 企业微信标签在哪?如何设置?
  11. 74HC595芯片组成测试工具_流水灯
  12. 最萌吸血鬼猎人,螺旋猫COS『BLOOD C』更衣小夜
  13. 全球首个大规模虐童图像数据库!标记15万图像、20类信息,自动判断图片是否违法​...
  14. r语言remarkdown展示图_为什么Markdown R有较大概率成为科技写作主流? ← 阳志平的个人网站::技术...
  15. RabbitMQ用户管理界面各个标签的解释,使用图片标注
  16. 分组Top N问题(二) - Hadoop MapReduce实现
  17. Excel下载(easyExcel)
  18. 如何看懂公司的财务报表(3)
  19. 深入了解Spring(第二天)
  20. CAD二次开发--两条线交叉求交点坐标的方法建议(IntersectWith的使用注意)

热门文章

  1. Openwrt编译教程:从头开始所有步骤(日志记录)
  2. redis实现周边景点由近到远排序
  3. springboot自行车在线租赁管理系统毕业设计源码101157
  4. 图形推理的50大规律
  5. 青山遮不住——2020的10大技术趋势
  6. php7 电子书 下载,php7.3.8中文电子手册
  7. 8153网卡linux驱动,绿联Type-c千兆网卡RTL8153驱动
  8. 几何画板如何绘制动态正切函数图像
  9. LG android TV 蓝牙,LG TV Plus
  10. 【毕业设计】基于Android的家校互动平台开发(内含完整代码和所有文档)——爱吖校推(你关注的,我们才推)