计算机图形学第四章---图形的表示与数据结构

本文深入探讨了计算机图形学中图形的表示与数据结构,包括几何信息与拓扑信息、坐标系、实体概念,以及各种表示方法如线框模型、实体模型、构造实体几何法、空间位置枚举表示等。同时介绍了OpenGL中的实体模型函数和层次模型,如显示列表和多级显示列表的应用。

 第四章 图形的表示与数据结构

如何在计算机中建立恰当的模型表示不同图形对象。
如何组织图形对象的描述数据以使存储这些数据所要的空间最省,检索、处理这些数据的速度较快。

基本概念——几何信息与拓扑信息
刚体运动:不改变图形上任意两点间的距离,也不改变图形的几何性质的运动。
拓扑运动:允许形体作弹性运动,即在拓扑关系中,对图形可随意地伸张扭曲。但图上各个点仍为不同的点,决不允许把不同的点合并成一个点。


基本概念——坐标系
建模坐标系(Modeling Coordinate System)
用户坐标系
观察坐标系(Viewing Coordinate System)
规格化设备坐标系(Normalized Device coordinate System)
设备坐标系(Device Coordinate System)

 

基本概念-实体
点的领域:如果P是点集S的一个元素,那么点P的以R(R>0)为半径的领域指的是围绕点P的半径为R的小球(二维情况下为小圆)。
开集的闭包:是指该开集与其所有边界点的集合并集,本身是一个闭集。
正则集:由内部点构成的点集的闭包就是正则集,三维空间的正则集就是正则形体。

组成三维物体的点的集合可以分为两类:
内点为点集中的这样一些点,它们具有完全包含于该点集的充分小的领域。
边界点:不具备此性质的点集中的点。

二维流形指的是对于实体表面上的任意一点,都可以找到一个围绕着它的任意小的领域,该领域与平面上的一个圆盘是拓扑等价的。

实体:对于一个占据有限空间的正则形体,如果其表面是二维流形,则该正则形体为实体。

基本概念——正则集合运算
有效实体的封闭性。
把能够产生正则形体的集合运算称为正则集合运算。

基本概念——平面多面体与欧拉公式
欧拉公式证明简单多面体的顶点数V、边数E和面数F满足如下关系:V-E+F=2。
非简单多面体需对欧拉公式加以扩展。令H表示多面体表面上孔的个数,G表示贯穿多面体的孔的个数,C表示独立的、不相连接的多面体数,则扩展后的欧拉公式为:V-E+F-H=2(C-G)。

4.2 三维形体的表示
线框模型与实体模型(实体造型技术)
可以将实体模型的表示大致分为三类:
边界表示(Boundary representation, B-reps)
构造实体几何表示
空间分割(Space-partitioning)表示

 

多边形表面模型:
边界表示(B-reps)的最普遍方式是多边形表面模型,它使用一组包围物体内部的平面多边形,也即平面多面体,来描述实体。
多边形表面模型——数据结构
几何信息:
建立3张表:顶点表、边表和多边形表来存储几何数据。
实体模型中,用多边形顶点坐标值以及多边形所在平面方程方式保存实体单个表面部分的空间方向信息

 

拓扑信息:翼边结构表示(Winged Edges Structure)

 

属性信息:用属性表来存储多边形面的属性,指明物体透明度及表面反射度的参数和纹理特征等等。


多边形网格:三维形体的边界通常用多边形网格(polygon mesh)的拼接来模拟。

 

扫描表示:
扫描表示法(sweep representation)可以利用简单的运动规则生成有效实体。


包含两个要素
一是作扫描运动的基本图形(截面);
二是扫描运动的方式。

 

 

构造实体几何法
构造实体几何法(CSG,Constructive Solid Geometry)由两个实体间的并、交或差操作生成新的实体。
在构造实体几何法中,集合运算的实现过程可以用一棵二叉树(称为CSG树)来描述。
树的叶子是基本体素或是几何变换参数;
树的非终端结点是施加于其子结点的正则集合算子(正则并、正则交和正则差)或几何变换的定义。
优点:如果体素设置比较齐全,通过集合运算就可以构造出多种不同的符合需要的实体。
缺点一:集合运算的中间结果难以用简单的代数方程表示,求交困难。
缺点二:CSG树不能显式地表示形体的边界,因而无法直接显示CSG树表示的形体。
解决:光线投射算法

 

空间位置枚举表示
空间位置枚举表示法将包含实体的空间分割为大小相同、形状规则(正方形或立方体)的体素,然后,以体素的集合来表示图形对象。
二维情况,常用二维数组存放。
三维情况下,常用三维数组p[i][j][k]来存放。

八叉树
八叉树(octrees)又称为分层树结构,它对空间进行自适应划分,采用具有层次结构的八叉树来表示实体。

BSP树
二叉空间分割(Binary Space Partitioning,BSP)树方法是一种类似于八叉树的空间分割方法,它每次将一实体用任一位置和任一方向的平面分为二部分(不同于八叉树方法的每次将实体用平行于笛卡尔坐标平面的三个两两垂直的平面分割)。

 

OpenGL中的实体模型函数
GLUT库中的多面体函数:


绘制实体或线框球面
              void glutSolidSphere/glutWireSphere (GLdouble radius, GLint slices, GLint stacks);
绘制实体或线框圆锥面
             void glutSolidCone/glutWireCone (GLdouble radius, GLdouble height, GLint slices, GLint stacks);
绘制实体或线框圆环
     void glutSolidTorus/ glutWireTorus(GLdouble innerRadius, GLdouble outerRadius, GLint slices,GLint stacks);
绘制实体或线框茶壶
      void glutSolidTeapot/glutWireTeapot (GLdouble size);
定义一个二次曲面
      GLUquadricObj *sphere;
激活二次曲面绘制器
      sphere = gluNewQuadric( );
指定二次曲面的绘制方式
      gluQuadricDrawStyle(sphere, GLU_LINE);
绘制二次曲面
     gluSphere(sphere, radius, slices, stacks);
      gluCylinder(sphere,baseRadius,topRadius, height, slices, stacks);
     gluDisk(sphere,innerRadius,outerRadius, slices, stacks);

 


4.4 层次模型
段与层次模型:
具有逻辑意义的有限个图素(或体素)及其附加属性的集合称为段,或者称为图段(二维空间中)、结构和对象。
段是可以嵌套
段与基本图形元素的区别在于,基本图形元素是用数据来描述的,而段是用规则来描述的。
段一般具有三个特性:可见性、醒目性和可选择性(可由交互式输入设备来选择)。
利用段的嵌套来构造复杂的对象或系统。
存储简单:一个段虽然在图中各处出现,但他的几何和拓扑信息只要保存一次。
编辑简单:删除、移动及缩放操作都可以以段为单位。

层次模型的实现:
系统的层次模型可以通过将一个图段嵌套到另一个图段中形成图段树来创建。不同的段和基本图形元素在各自的建模坐标系中定义。
图层。通过把功能相同的部分归类,并将它们绘制在同一层上,有助于图形的理解和管理。
一般图层不再嵌套。

OpenGL中的层次模型
显示列表的创建
    glNewList( listID, listMode );
  glutSolidCube(2.0);
  ……
    glEndList();
显示列表的执行
            void glListBase(GLuint offsetValue);
多级显示列表
           OpenGL支持创建多级显示列表,即在glNewList和glEndLsit函数对之间允许调用glCallList函数来执行其他显示列表。
显示列表的删除
           void glDeleteLists(GLuint listID, GLsizei range);


#include <gl/glut.h>

static GLsizei iMode = 1;
static GLfloat xRot = 0.0f;  //x方向旋转参数
static GLfloat yRot = 0.0f;  //y方向旋转参数
GLUquadricObj *obj;     //二次曲面对象

void Initial(void)
{
  glClearColor(1.0f, 1.0f, 1.0f, 1.0f);   
  glColor3f(0.0f, 0.0f, 0.0f);
  obj = gluNewQuadric( );
  gluQuadricDrawStyle(obj, GLU_LINE);  //以线框方式绘制二次曲面对象
}

void ChangeSize(int w, int h)
{
glViewport(0, 0, w, h);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluOrtho2D (-1.5f, 1.5f, -1.5f, 1.5f);
}

void Display(void)
{
  glClear(GL_COLOR_BUFFER_BIT);
  glMatrixMode(GL_MODELVIEW); 
  glLoadIdentity();
  glRotatef(xRot, 1.0f, 0.0f, 0.0f);  //旋转图形
  glRotatef(yRot, 0.0f, 1.0f, 0.0f);  //旋转图形
  
//指定需要绘制的图元
  switch(iMode) {
   case 1:
    glutWireTetrahedron(); break;
   case 2:
    glutSolidTetrahedron(); break;
   case 3:
    glutWireOctahedron(); break;
   case 4:
    glutSolidOctahedron(); break;
   case 5:
    glutWireSphere(1.0f,15,15);  break;
   case 6:
    glutSolidSphere(1.0f,15,15);  break;
   case 7:
    glutWireTeapot(1.0f);       break;
   case 8:
    glutSolidTeapot(1.0f);       break;
   case 9:
    gluSphere(obj, 1.0f, 15, 15);  break;
   case 10:
    gluCylinder(obj,1.0f,0.0f,1.0f,15,15); break;
   case 11:
    gluPartialDisk(obj,0.3f,0.8f,15,15,30.0f,260.0f); break;
   default: break;
  }
  glFlush();
}

void ProcessMenu(int value)
{
  iMode = value; 
  glutPostRedisplay();
}

void SpecialKeys(int key, int x, int y)
{
  if(key == GLUT_KEY_UP)  xRot-= 5.0f;
  if(key == GLUT_KEY_DOWN) xRot += 5.0f;
  if(key == GLUT_KEY_LEFT) yRot -= 5.0f;
  if(key == GLUT_KEY_RIGHT) yRot += 5.0f;
  if(xRot > 356.0f) xRot = 0.0f;
  if(xRot < -1.0f) xRot = 355.0f;
  if(yRot > 356.0f) yRot = 0.0f;
  if(yRot < -1.0f) yRot = 355.0f;
  glutPostRedisplay();
}

int main(int argc, char* argv[])
{
     int nGlutPolyMenu=0;
  int nGlutCurveMenu=0;
  int nGluCurveMenu=0;
  int nMainMenu=0;
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); 
  glutInitWindowSize(400,400);                 
  glutInitWindowPosition(100,100);             
  glutCreateWindow("OpenGL模型绘制函数示例");
  
  //创建菜单并定义菜单回调函数
  nGlutPolyMenu = glutCreateMenu(ProcessMenu); 
  glutAddMenuEntry("线框正四面体",1);               //创建GLUT多面体绘制菜单
  glutAddMenuEntry("实体正四面体",2);
  glutAddMenuEntry("线框正八面体",3);
  glutAddMenuEntry("实体正八面体",4);
  
  nGlutCurveMenu = glutCreateMenu(ProcessMenu);  //创建GLUT曲面绘制菜单
  glutAddMenuEntry("线框球面",5);
  glutAddMenuEntry("实体球面",6);
  glutAddMenuEntry("线框茶壶",7);
  glutAddMenuEntry("实体茶壶",8); 

  nGluCurveMenu = glutCreateMenu(ProcessMenu);  //创建GLU曲面绘制菜单
  glutAddMenuEntry("线框球面",9);
  glutAddMenuEntry("线框圆锥面",10);
  glutAddMenuEntry("线框圆环面",11); 

  nMainMenu = glutCreateMenu(ProcessMenu);  //创建主菜单
  glutAddSubMenu("GLUT多面体", nGlutPolyMenu);
     glutAddSubMenu("GLUT曲面", nGlutCurveMenu);
  glutAddSubMenu("GLU曲面", nGluCurveMenu);
  glutAttachMenu(GLUT_RIGHT_BUTTON); 

  glutDisplayFunc(Display);
  glutReshapeFunc(ChangeSize);
  glutSpecialFunc(SpecialKeys);
  
  Initial();                                   
  glutMainLoop();                              
  return 0;
}

 


#include <gl/glut.h>
GLuint OlympicRings;

void Initial(void)
{
  glClearColor(1.0f, 1.0f, 1.0f, 1.0f);   
  OlympicRings = glGenLists(1);
  glNewList(OlympicRings, GL_COMPILE);
   glColor3f(1.0, 1.0, 0.0);
   glTranslatef(-22.0, 0.0, 0.0);
   glutSolidTorus(0.5, 20.0, 15, 50);  //绘制黄色环
   glColor3f(0.0, 1.0, 0.0);
   glTranslatef(44.0, 0.0, 0.0);
   glutSolidTorus(0.5, 20.0, 15, 50);  //绘制绿色环
   glColor3f(0.0, 0.0, 0.0);
   glTranslatef(-22.0, 30.0, 0.0);
   glutSolidTorus(0.5, 20.0, 15, 50);  //绘制黑色环
   glColor3f(0.0, 0.0, 1.0);
   glTranslatef(-42.0, 0.0, 0.0);
   glutSolidTorus(0.5, 20.0, 15, 50);  //绘制蓝色环
   glColor3f(1.0, 0.0, 0.0);
   glTranslatef(84.0, 0.0, 0.0);
   glutSolidTorus(0.5, 20.0, 15, 50);  //绘制红色环
  glEndList();
}

void ChangeSize(int w, int h)
{
  glViewport(0, 0, w, h);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluOrtho2D (-70.0f, 70.0f, -70.0f, 70.0f);
}

void Display(void)
{
  glClear(GL_COLOR_BUFFER_BIT);
  glMatrixMode(GL_MODELVIEW); 
  glLoadIdentity();
  
  glCallList(OlympicRings);   //调用显示列表
  
  glFlush();
}

int main(int argc, char* argv[])
{
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); 
  glutInitWindowSize(400,400);                 
  glutInitWindowPosition(100,100);             
  glutCreateWindow("OpenGL模型绘制函数示例");
  glutDisplayFunc(Display);
  glutReshapeFunc(ChangeSize);
  Initial();                                   
  glutMainLoop();                              
  return 0;
}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值