第 12 章 高性能图形技术

Preview:

DESCRIPTION

第 12 章 高性能图形技术. 高性能图形技术的定义. 加快图形应用程序的运行速度 提高动画的帧速率 加速图形应用程序对用户的交互响应 可用于计算机图形学、仿真、可视化、虚拟现实等领域. 高性能图形技术的分类. 建模技术 减少可见多边形数量 巧妙运用纹理(布告板、 mipmaps 、分层纹理) 减少光照计算 LOD 雾化 绘制技术 多边形剔除(背面剔除、视域体裁剪) BSP 树 动画技术 碰撞检测. 建模技术 -- 减少可见多边形数量. 无论从哪个视点观察,整个场景中只有有限个多边形可见(游戏中的墙) - PowerPoint PPT Presentation

Citation preview

第第 1212章 高性能图形技术章 高性能图形技术

22

高性能图形技术的定义高性能图形技术的定义 加快图形应用程序的运行速度加快图形应用程序的运行速度

提高动画的帧速率提高动画的帧速率 加速图形应用程序对用户的交互响应加速图形应用程序对用户的交互响应

可用于计算机图形学、仿真、可视化、虚拟可用于计算机图形学、仿真、可视化、虚拟现实等领域现实等领域

33

高性能图形技术的分类高性能图形技术的分类 建模技术建模技术

减少可见多边形数量减少可见多边形数量 巧妙运用纹理(布告板、巧妙运用纹理(布告板、 mipmapsmipmaps 、分层纹理)、分层纹理) 减少光照计算减少光照计算 LODLOD 雾化雾化

绘制技术绘制技术 多边形剔除(背面剔除、视域体裁剪)多边形剔除(背面剔除、视域体裁剪) BSPBSP 树树

动画技术动画技术 碰撞检测碰撞检测

44

建模技术建模技术 ---- 减少可见多边形数量减少可见多边形数量 无论从哪个视点观察,整个场景中只有有限无论从哪个视点观察,整个场景中只有有限

个多边形可见(游戏中的墙)个多边形可见(游戏中的墙) 大的多边形可使用纹理来显示其细节,作用大的多边形可使用纹理来显示其细节,作用

还是减少多边形数量还是减少多边形数量

lesson10

55

建模技术建模技术 ---- 布告板布告板 把表示复杂物体的纹理映射到二维矩形上,把表示复杂物体的纹理映射到二维矩形上,

该布告板总是朝向视点该布告板总是朝向视点 可用于显示树木、建筑、车辆等复杂物体,可用于显示树木、建筑、车辆等复杂物体,

而不必创建和绘制这些复杂物体而不必创建和绘制这些复杂物体

66

布告板代码示例布告板代码示例 #include <GLUT/glut.h>#include <GLUT/glut.h> ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // OpenGL// OpenGL编程练习编程练习-- by Yubing Guan (guanyubing1998@163.com)-- by Yubing Guan (guanyubing1998@163.com) // All Right Reserved.// All Right Reserved. /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// #include <math.h>#include <math.h> #include <stdio.h>#include <stdio.h> #define PI 3.1415#define PI 3.1415 #define TEX_WIDTH 256#define TEX_WIDTH 256 #define TEX_HEIGHT 256#define TEX_HEIGHT 256 static GLubyte texImage[TEX_WIDTH][TEX_HEIGHT][3];static GLubyte texImage[TEX_WIDTH][TEX_HEIGHT][3]; static GLuint texName[1]; // the number of textures in programfloat epx=0,epy=0,epz=30;//static GLuint texName[1]; // the number of textures in programfloat epx=0,epy=0,epz=30;//视点坐标视点坐标 float sita=0.0,fai=0.0;float sita=0.0,fai=0.0; float mx=0,my=0,mz=0,epx=0,epy=0,epz=20;float mx=0,my=0,mz=0,epx=0,epy=0,epz=20; typedef struct {typedef struct { float x;float x; float y;float y; float z;float z; }Vector3;}Vector3;

void setTexture2(void)void setTexture2(void) {{ FILE* fd;FILE* fd; GLubyte ch;GLubyte ch; int i,j,k;int i,j,k; fd=fopen("HongKong.256.256.raw","r");fd=fopen("HongKong.256.256.raw","r"); for (i=0;i<TEX_WIDTH;i++) {for (i=0;i<TEX_WIDTH;i++) { for (j=0; j<TEX_HEIGHT;j++) {for (j=0; j<TEX_HEIGHT;j++) { for (k=0;k<3;k++) {for (k=0;k<3;k++) { fread(&ch,1,1,fd);fread(&ch,1,1,fd); texImage[i][j][k]=(GLubyte)ch;texImage[i][j][k]=(GLubyte)ch; }} }} }} fclose(fd);fclose(fd); }}

void init()void init() {{ setTexture2();setTexture2(); glGenTextures(1, texName);glGenTextures(1, texName); glBindTexture(GL_TEXTURE_2D,texName[0]);glBindTexture(GL_TEXTURE_2D,texName[0]); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glTexImage2D(GL_TEXTURE_2D,0,GL_RGB8,TEX_WIDTH,TEX_HEIGHT,glTexImage2D(GL_TEXTURE_2D,0,GL_RGB8,TEX_WIDTH,TEX_HEIGHT, 0,GL_RGB,GL_UNSIGNED_BYTE,texImage);0,GL_RGB,GL_UNSIGNED_BYTE,texImage); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); glBindTexture(GL_TEXTURE_2D, texName[0]);glBindTexture(GL_TEXTURE_2D, texName[0]); glEnable(GL_TEXTURE_2D);glEnable(GL_TEXTURE_2D); glEnable(GL_DEPTH_TEST);glEnable(GL_DEPTH_TEST); printf("printf("按键盘相关键改变视点位置按键盘相关键改变视点位置 \n");\n"); }}

void tree()void tree() {{ glBegin(GL_QUADS);glBegin(GL_QUADS); glTexCoord2f(1,1);glTexCoord2f(1,1); glVertex3f(-10,-10,0);glVertex3f(-10,-10,0); glTexCoord2f(1,0);glTexCoord2f(1,0); glVertex3f(-10,10,0);glVertex3f(-10,10,0); glTexCoord2f(0,0);glTexCoord2f(0,0); glVertex3f(10,10,0);glVertex3f(10,10,0); glTexCoord2f(0,1);glTexCoord2f(0,1); glVertex3f(10,-10,0);glVertex3f(10,-10,0); glEnd();glEnd(); }} void myDisplay()void myDisplay() { { glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glPushMatrix();glPushMatrix(); glMatrixMode(GL_MODELVIEW);glMatrixMode(GL_MODELVIEW); glLoadIdentity();glLoadIdentity(); gluLookAt(epx,epy,epz,0,0,0,0,1,0);gluLookAt(epx,epy,epz,0,0,0,0,1,0); //glTranslatef(mx,my,mz);//glTranslatef(mx,my,mz); //glRotatef(fai,0,1,0);////glRotatef(fai,0,1,0);//再进行垂直角位移再进行垂直角位移 ,,顺序很重要顺序很重要!! //glRotatef(-sita,1,0,0);////glRotatef(-sita,1,0,0);//先进行水平角位移先进行水平角位移 tree();tree(); glPopMatrix();glPopMatrix(); glFlush();glFlush(); }} void reshape(int w,int h)void reshape(int w,int h) {{ glMatrixMode(GL_PROJECTION);glMatrixMode(GL_PROJECTION); glLoadIdentity();glLoadIdentity(); if (h==0) h=1;if (h==0) h=1; glViewport(0,0,w,h);glViewport(0,0,w,h); gluPerspective(60,(float)w/(float)h,1,1000);gluPerspective(60,(float)w/(float)h,1,1000); }} void myKeyboard(unsigned char key,int x,int y)void myKeyboard(unsigned char key,int x,int y) {{ Vector3 ep1;Vector3 ep1; float mol,tem,len2;float mol,tem,len2;

if(key=='w'||key=='W') epy+=6;if(key=='w'||key=='W') epy+=6; if(key=='Z'||key=='z') epy-=6;if(key=='Z'||key=='z') epy-=6; if(key=='A'||key=='a') epx+=6;if(key=='A'||key=='a') epx+=6; if(key=='S'||key=='s') epx-=6;if(key=='S'||key=='s') epx-=6; if(key=='Q'||key=='q') epz+=6;if(key=='Q'||key=='q') epz+=6; if(key=='e'||key=='E') epz-=6;if(key=='e'||key=='E') epz-=6; //////求视线方向向量求视线方向向量[epx-ob0,epy-ob1,epz-ob3],[epx-ob0,epy-ob1,epz-ob3],此处目标点为原点,故此处目标点为原点,故obob坐标为坐标为 ep1.x = epx;ep1.y=epy;ep1.z=epz;ep1.x = epx;ep1.y=epy;ep1.z=epz; mol=sqrt(epx*epx+epy*epy+epz*epz);//mol=sqrt(epx*epx+epy*epy+epz*epz);//视点与目标间的距离视点与目标间的距离 tem=mol-30;//tem=mol-30;//目标需要移动的距离目标需要移动的距离 ////标准化向量标准化向量 len2=ep1.x * ep1.x + ep1.y * ep1.y +ep1.z * ep1.z;len2=ep1.x * ep1.x + ep1.y * ep1.y +ep1.z * ep1.z; len2 = sqrt(len2);len2 = sqrt(len2); ep1.x /= len2;ep1.x /= len2; ep1.y /= len2;ep1.y /= len2; ep1.z /= len2;ep1.z /= len2; sita=asin(ep1.y)*360./(2*PI);//sita=asin(ep1.y)*360./(2*PI);//垂直角垂直角 fai=atan(ep1.x/ep1.z)*360./(2*PI);//fai=atan(ep1.x/ep1.z)*360./(2*PI);//水平角水平角 //////目标点在基向量方向移动的距离目标点在基向量方向移动的距离 mx=tem*cos(asin(ep1.y))*sin(atan(ep1.x/ep1.z));mx=tem*cos(asin(ep1.y))*sin(atan(ep1.x/ep1.z)); my=tem*sin(asin(ep1.y));my=tem*sin(asin(ep1.y)); mz=tem*cos(asin(ep1.y))*cos(atan(ep1.x/ep1.z));mz=tem*cos(asin(ep1.y))*cos(atan(ep1.x/ep1.z)); printf("printf("视点位置视点位置:[%.0f,%.0f,%.0f]\n",epx,epy,epz);:[%.0f,%.0f,%.0f]\n",epx,epy,epz); glutPostRedisplay();glutPostRedisplay(); }} void main()void main() { { glutInitDisplayMode(GLUT_SINGLE|GLUT_RGBA|GLUT_DEPTH);glutInitDisplayMode(GLUT_SINGLE|GLUT_RGBA|GLUT_DEPTH); glutInitWindowSize(600,600);glutInitWindowSize(600,600); glutInitWindowPosition(735,0);glutInitWindowPosition(735,0); glutCreateWindow("glutCreateWindow("布告板技术布告板技术");"); glutDisplayFunc(myDisplay);glutDisplayFunc(myDisplay); init();init(); glutReshapeFunc(reshape);glutReshapeFunc(reshape); glutKeyboardFunc(myKeyboard);glutKeyboardFunc(myKeyboard); glutMainLoop();glutMainLoop();

}}

77

建模技术建模技术 -- mipmaps-- mipmaps

将一个纹理创建成连续的变小的纹理 将一个纹理创建成连续的变小的纹理

88

建模技术建模技术 ---- 分层纹理(多纹理映射技分层纹理(多纹理映射技术)术) 多个纹理贴图到同一个多边形多个纹理贴图到同一个多边形

99

建模技术建模技术 - -- - 细节层次细节层次 LOD LOD figure12.1figure12.1

物体离视点较远时,使用较粗糙的模型;离物体离视点较远时,使用较粗糙的模型;离视点较近时,使用较精细的模型,可节约绘视点较近时,使用较精细的模型,可节约绘制时间制时间

OpenGL OpenGL 并不直接支持 并不直接支持 LODLOD 需解决的问题需解决的问题

如何自动选择不同 如何自动选择不同 levellevel ?? 避免物体的突然出现或突然消失、外观的突然避免物体的突然出现或突然消失、外观的突然

变化变化demo

1010

建模技术建模技术 ---- 雾化雾化 使物体变的朦胧使物体变的朦胧 可配合 可配合 LOD LOD 技术使用避免物体突然出现或技术使用避免物体突然出现或

消失消失

tutor

1111

绘制技术绘制技术 ---- 背面剔除背面剔除 原理:利用观察方向原理:利用观察方向 (V)(V) 和物体表面法向和物体表面法向 (N)(N) 之之

间的关系间的关系 NNE<0E<0 :不可见:不可见 NNEE00 :可见:可见

1212

绘制技术绘制技术 ---- 视域体裁剪视域体裁剪

1313

绘制技术绘制技术 -- BSP-- BSP 树树 二叉空间剖分树的基本原理二叉空间剖分树的基本原理 (BSP(BSP 树树 -Binary Space -Binary Space

Partitioning )Partitioning ) :: 如果场景中的多边形可以被一个平面分割成两部分如果场景中的多边形可以被一个平面分割成两部分 (( 如如

果有多边形跨越分割平面,则剖分该多边形果有多边形跨越分割平面,则剖分该多边形 )) ,那么当,那么当视点位于分割平面的正侧时,位于分割平面正侧的多边视点位于分割平面的正侧时,位于分割平面正侧的多边形会遮挡位于分割平面另一侧的多边形 形会遮挡位于分割平面另一侧的多边形

对位于分割平面两侧的多边形继续进行递归分割,直至对位于分割平面两侧的多边形继续进行递归分割,直至每一个分割平面两侧或一侧只有一个多边形每一个分割平面两侧或一侧只有一个多边形

分割过程可以用一个二叉树的数据结构来表示 分割过程可以用一个二叉树的数据结构来表示 在在 BSPBSP 树算法中,分割平面取作场景中的多边形树算法中,分割平面取作场景中的多边形

1414

动画技术动画技术 ---- 碰撞检测碰撞检测 用包围体近似表示物体,并用包围体进行碰用包围体近似表示物体,并用包围体进行碰

撞检测撞检测

1515

碰撞检测-球和球碰撞检测-球和球 球被表示为中心和它的半径,决定两个球是否相交就球被表示为中心和它的半径,决定两个球是否相交就

是求出它们之间的距离是否小于它们的直径。是求出它们之间的距离是否小于它们的直径。 在处理两个移动的球是否相交时,在处理两个移动的球是否相交时,

有一个有一个 bugbug 就是,当它们的移动就是,当它们的移动速度太快,会出现它们相交,但速度太快,会出现它们相交,但在相邻的两步检测不出它们是否在相邻的两步检测不出它们是否相交的情况,如图所示相交的情况,如图所示

有一个替代的办法就是细分相邻的时间片断,如果在有一个替代的办法就是细分相邻的时间片断,如果在这之间发生了碰撞,则确定有效。这之间发生了碰撞,则确定有效。

代码如下:代码如下: bool FindBallCol(TVector& ..)bool FindBallCol(TVector& ..)

1616

碰撞的物理模拟碰撞的物理模拟 为了计算对于一个静止物体的碰撞为了计算对于一个静止物体的碰撞 ,,我们需要知道我们需要知道

以下信息以下信息 :: 碰撞点碰撞点 ,, 碰撞法线碰撞法线 ,, 碰撞时间碰撞时间 .. 当我们找到了碰撞位置后当我们找到了碰撞位置后 ,,下一步我们需要知道它下一步我们需要知道它

是否发生在当前这一步中是否发生在当前这一步中 .. 如果距离碰撞点的位置如果距离碰撞点的位置小于这一步球体运动的间隔小于这一步球体运动的间隔 ,, 则碰撞发生则碰撞发生

1717

碰撞的物理模拟碰撞的物理模拟 对于一个静止物体的碰撞基于以下物理规律:对于一个静止物体的碰撞基于以下物理规律:

碰撞的入射角等于反射角碰撞的入射角等于反射角 .. 反射方向由以下公式计算 反射方向由以下公式计算 : :

R= 2*(-I dot N)*N + I R= 2*(-I dot N)*N + I

rt2=ArrayVel[BallNr].mag(); // rt2=ArrayVel[BallNr].mag(); // 返回速度向量的模 返回速度向量的模 ArrayVel[BallNr].unit(); // ArrayVel[BallNr].unit(); // 归一化速度向量 归一化速度向量 // // 计算反射向量计算反射向量ArrayVel[BallNr]=TVector::unit( (normal*(2*normal.dot(-ArrayVel[BallNr]))) + ArrayVel[BallNr] );ArrayVel[BallNr]=TVector::unit( (normal*(2*normal.dot(-ArrayVel[BallNr]))) + ArrayVel[BallNr] ); ArrayVel[BallNr]=ArrayVel[BallNr]*rt2; ArrayVel[BallNr]=ArrayVel[BallNr]*rt2;

1818

if (flag==1)if (flag==1) al -= 0.005;al -= 0.005; else else al += 0.005;al += 0.005;

if (al < 0 || al > 1)if (al < 0 || al > 1) flag = !flag;flag = !flag;