资源描述
《计算机图形学》
实验报告
2011年1月
实验四 图形综合运用
4.1 实验目的
1、通过本次实验,掌握三维图形的旋转等变换和消隐的基本概念和相关算法。
2、掌握凸多面体的消隐算法和实现。
3、进一步熟练和掌握编程环境中三维图形的绘制和消隐的程序设计方法。
4.2 实验内容
利用openGL绘制模型
4.2.1绘制一个三维几何图形 简单光照例程 "light0.cpp"
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
void myinit(void)
{
GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
}
void CALLBACK display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
auxSolidSphere(1.0);
glFlush();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho (-1.5, 1.5, -1.5*(GLfloat)h/(GLfloat)w,
1.5*(GLfloat)h/(GLfloat)w, -10.0, 10.0);
else
glOrtho (-1.5*(GLfloat)w/(GLfloat)h,
1.5*(GLfloat)w/(GLfloat)h, -1.5, 1.5, -10.0, 10.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void main(void)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
auxInitPosition (0, 0, 500, 500);
auxInitWindow ("Simple Lighting");
myinit();
auxReshapeFunc (myReshape);
auxMainLoop(display);
}
程序运行结果:显示一个具有灰色光影的球。其中函数myinit()中包含了关键的设定光源位置、启动光照等几句,而其它程序语言几乎与以前的没有多大区别,但效果却完全不一样。
4.2.2 OpenGL法向定义
OpenGL法向定义函数为:
void glNormal3{bsifd}(TYPE nx,TYPE ny,TYPE nz);
void glNormal3{bsifd}v(const TYPE *v);
设置当前法向值。非向量形式定义法向采用第一种方式,即在函数中分别给出法向三个分量值nx、ny和nz;向量形式定义采用第二种,即将v设置为一个指向拥有三个元素的指针,例如v[3]={nx,ny,nz}。因为法向的各分量值只定义法向的方向,因此它的大小不固定,但最好将各值限制在[-1.0,1.0]之间,即法向归一化;若法向不归一化,则在定义法向之前必须启动法向归一,即调用函数glEnable(GL_NORMALIZE),这样会降低整个程序运行性能。
自定义颜色立方体法向程序 "nmlcolr.cpp"
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
static GLfloat p1[]={0.5,-0.5,-0.5}, p2[]={0.5,0.5,-0.5},
p3[]={0.5,0.5,0.5}, p4[]={0.5,-0.5,0.5},
p5[]={-0.5,-0.5,0.5}, p6[]={-0.5,0.5,0.5},
p7[]={-0.5,0.5,-0.5}, p8[]={-0.5,-0.5,-0.5};
static GLfloat m1[]={1.0,0.0,0.0}, m2[]={-1.0,0.0,0.0},
m3[]={0.0,1.0,0.0}, m4[]={0.0,-1.0,0.0},
m5[]={0.0,0.0,1.0}, m6[]={0.0,0.0,-1.0};
static GLfloat c1[]={0.0,0.0,1.0}, c2[]={0.0,1.0,1.0},
c3[]={1.0,1.0,1.0}, c4[]={1.0,0.0,1.0},
c5[]={1.0,0.0,0.0}, c6[]={1.0,1.0,0.0},
c7[]={0.0,1.0,0.0}, c8[]={1.0,1.0,1.0};
void myinit(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
void DrawColorBox(void);
void myinit(void)
{
GLfloat light_ambient[]={0.3,0.2,0.5};
GLfloat light_diffuse[]={1.0,1.0,1.0};
GLfloat light_position[] = { 2.0, 2.0, 2.0, 1.0 };
GLfloat light1_ambient[]={0.3,0.3,0.2};
GLfloat light1_diffuse[]={1.0,1.0,1.0};
GLfloat light1_position[] = { -2.0, -2.0, -2.0, 1.0 };
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glLightfv(GL_LIGHT1, GL_AMBIENT, light1_ambient);
glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse);
glLightfv(GL_LIGHT1, GL_POSITION, light1_position);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHT1);
glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
glColorMaterial(GL_FRONT_AND_BACK,GL_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
}
void CALLBACK display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glRotatef(45,0.0,1.0,0.0);
glRotatef(315,0.0,0.0,1.0);
DrawColorBox();
glPopMatrix();
glFlush();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho (-1.5, 1.5, -1.5*(GLfloat)h/(GLfloat)w,
1.50*(GLfloat)h/(GLfloat)w, -10.0, 10.0);
else
glOrtho (-1.5*(GLfloat)w/(GLfloat)h,
1.5*(GLfloat)w/(GLfloat)h, -1.5, 1.5, -10.0, 10.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity ();
}
void DrawColorBox(void)
{
glBegin (GL_QUADS);
glColor3fv(c1);
glNormal3fv(m1);
glVertex3fv(p1);
glColor3fv(c2);
glVertex3fv(p2);
glColor3fv(c3);
glVertex3fv(p3);
glColor3fv(c4);
glVertex3fv(p4);
glColor3fv(c5);
glNormal3fv(m5);
glVertex3fv(p5);
glColor3fv(c6);
glVertex3fv(p6);
glColor3fv(c7);
glVertex3fv(p7);
glColor3fv(c8);
glVertex3fv(p8);
glColor3fv(c5);
glNormal3fv(m3);
glVertex3fv(p5);
glColor3fv(c6);
glVertex3fv(p6);
glColor3fv(c3);
glVertex3fv(p3);
glColor3fv(c4);
glVertex3fv(p4);
glColor3fv(c1);
glNormal3fv(m4);
glVertex3fv(p1);
glColor3fv(c2);
glVertex3fv(p2);
glColor3fv(c7);
glVertex3fv(p7);
glColor3fv(c8);
glVertex3fv(p8);
glColor3fv(c2);
glNormal3fv(m5);
glVertex3fv(p2);
glColor3fv(c3);
glVertex3fv(p3);
glColor3fv(c6);
glVertex3fv(p6);
glColor3fv(c7);
glVertex3fv(p7);
glColor3fv(c1);
glNormal3fv(m6);
glVertex3fv(p1);
glColor3fv(c4);
glVertex3fv(p4);
glColor3fv(c5);
glVertex3fv(p5);
glColor3fv(c8);
glEnd();
}
void main(void)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
auxInitPosition (0, 0, 500,400);
auxInitWindow ("ColorBox");
myinit();
auxReshapeFunc (myReshape);
auxMainLoop(display);
}
以上程序运行结果:是一个自定义法向的彩色正方体,其中每个顶点的颜色值不一样,且为光滑的明暗处理模式。
4.2.3 雾化效果
雾化效果在当今的计算机图形学中应用极广,它不仅可以使场景中的物体看起来更加真
实,而且还可提高绘制速度。在很多情况下,计算机图像有时会出现不符合实际的精细和棱
角分明,上一节的反走样技术可以通过光顺着物体的边界反走样,使其看起来更真实,雾化处理可以使物体看起来更加自然,即在雾中,离视点远的物体会变得模糊。
雾,是一个描述类似于大气效果的一般术语,在视景仿真中应用很广。它可以模拟烟雾(haze)、薄雾(mist)、浓烟(smoke)和污染(pollution)等效果。当启动雾后,离视点较远的物体开始淡化成雾的颜色,同时,雾的浓度可以控制,即随着距离的增加物体变淡的速率可控,雾的颜色也可以任意设定。雾在两种颜色方式下都能使用。
在OpenGL程序中使用雾化效果非常容易。其步骤有三,如下:
一、启动雾。 函数调用为glEnable(GL_FOG);
二、控制雾。 函数调用为glFog*(),用它选择控制浓度和颜色的雾方程,其具体形式为:
void glFog{if}[v](GLenum pname,TYPE param);
设置计算雾的参数和函数。若pname为GL_FOG_MODE,则param可以是GL_EXP(缺省)、GL_EXP2或GL_LINEAR,分别代表三个雾因子。若pname为GL_FOG_DENSITY、GL_FOG_START或GL_FOG_END,则param为雾方程中对应的density、start和end的值。缺省值为1、0、1。
在RGBA方式下,pname可以是GL_FOG_COLOR,此时参数param为指向含有RGBA值的向量指针。同样,在颜色表方式下,pname相应值为GL_FOG_INDEX,其对应的param是雾的颜色索引值。
三、若有必要,可用函数glHint(GL_FOG_HINT)提供一个值。
RGBA方式下使用雾的实例 "fogrgb.cpp":
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <math.h>
#include <GL/glaux.h>
#include <stdio.h>
void myinit(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
void myinit(void)
{
GLfloat mat_ambient[] = { 0.7, 0.6, 0.4, 1.00 };
GLfloat mat_diffuse[] = {0.7,0.0,0.99,1.0};
GLfloat mat_specular[] = { 1.0, 0.0, 1.0, 1.00 };
GLfloat mat_shininess[] = { 15.0 };
GLfloat position[] = { 5.0, 5.0, 5.0, 1.0 };
GLfloat fogColor[4] = {0.6, 0.6, 0.6, 1.0};
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glLightfv(GL_LIGHT0, GL_POSITION, position);
glFrontFace (GL_CW);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_FOG);
{
glFogi (GL_FOG_MODE, GL_LINEAR);
glFogfv (GL_FOG_COLOR, fogColor);
glFogf (GL_FOG_START, 3.0);
glFogf (GL_FOG_END,15.0);
glHint (GL_FOG_HINT, GL_DONT_CARE);
glClearColor(0.3, 0.3, 0.3, 1.0);
}
}
void CALLBACK display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glTranslatef(-3.0,-1.5,-2.0);
auxSolidTorus(0.6,1.5);
glPopMatrix();
glPushMatrix();
glTranslatef(-0.5,-0.5,-7.0);
auxSolidTorus(0.6,1.5);
glPopMatrix();
glPushMatrix();
glTranslatef(2.0,0.8,-10.0);
auxSolidTorus(0.6,1.5);
glPopMatrix();
glFlush();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= (h*3))
glOrtho (-6.0, 6.0, -2.0*((GLfloat) h*3)/(GLfloat) w,
2.0*((GLfloat) h*3)/(GLfloat) w, 0.0, 10.0);
else
glOrtho (-6.0*(GLfloat) w/((GLfloat) h*3),
6.0*(GLfloat) w/((GLfloat) h*3), -2.0, 2.0, 0.0, 10.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity ();
}
void main(void)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
auxInitPosition (0, 0, 500, 400);
auxInitWindow ("Fog_RGB_mode");
myinit();
auxReshapeFunc (myReshape);
auxMainLoop(display);
}
以上程序运行结果是:显示三个不同远近的蓝紫色环形圈在雾中的效果,这里的雾化计算采用线性方式(GL_LINEAR)。
4.2.4 OpenGL动画
OpenGL提供了双缓存,可以用来制作动画。也就是说,在显示前台缓存内容中的一帧画面时,后台缓存正在绘制下一帧画面,当绘制完毕,则后台缓存内容便在屏幕上显示出来,而前台正好相反,又在绘制下一帧画面内容。这样循环反复,屏幕上显示的总是已经画好的图形,于是看起来所有的画面都是连续的。
在OpenGL中,设计这样的动画程序很简单,只需掌握一个重点函数,即:
void auxSwapBuffers(void);
设置交换缓存。即执行完一次绘制过程,便交换前后台缓存,以便让下一帧图形在屏幕后绘制完成。当然,使用不同的窗口系统设置交换缓存的函数也可能不一样,比如在X窗口系统下,就最好用glxSwapBufferS()。
此外,在窗口显示模式中还应设置双缓存模式。下面看一个双缓存动画例子dbufcolr.c,
这个程序是在nmlcolr.cpp的基础上改制而成的,对比起来看看,就会发现OpenGL动画程序设计其实是件极其容易和有趣的事情。
双缓存动画例程 dbufcolr.cpp
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
/* 定义旋转和比例因子的初始值 */
GLfloat step=0.0,s=0.1;
/* 定义立方体的顶点坐标值 */
static GLfloat p1[]={0.5,-0.5,-0.5}, p2[]={0.5,0.5,-0.5},
p3[]={0.5,0.5,0.5}, p4[]={0.5,-0.5,0.5},
p5[]={-0.5,-0.5,0.5}, p6[]={-0.5,0.5,0.5},
p7[]={-0.5,0.5,-0.5}, p8[]={-0.5,-0.5,-0.5};
/* 定义立方体的顶点方向值 */
static GLfloat m1[]={1.0,0.0,0.0}, m2[]={-1.0,0.0,0.0},
m3[]={0.0,1.0,0.0}, m4[]={0.0,-1.0,0.0},
m5[]={0.0,0.0,1.0}, m6[]={0.0,0.0,-1.0};
/* 定义立方体的顶点颜色值 */
static GLfloat c1[]={0.0,0.0,1.0}, c2[]={0.0,1.0,1.0},
c3[]={1.0,1.0,1.0}, c4[]={1.0,0.0,1.0},
c5[]={1.0,0.0,0.0}, c6[]={1.0,1.0,0.0},
c7[]={0.0,1.0,0.0}, c8[]={1.0,1.0,1.0};
void myinit(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK stepDisplay (void);
void CALLBACK startIdleFunc (AUX_EVENTREC *event);
void CALLBACK stopIdleFunc (AUX_EVENTREC *event);
void CALLBACK display(void);
void DrawColorBox(void);
void myinit(void)
{
GLfloat light_ambient[]={0.3,0.2,0.5};
GLfloat light_diffuse[]={1.0,1.0,1.0};
GLfloat light_position[] = { 2.0, 2.0, 2.0, 1.0 };
GLfloat light1_ambient[]={0.3,0.3,0.2};
GLfloat light1_diffuse[]={1.0,1.0,1.0};
GLfloat light1_position[] = { -2.0, -2.0, -2.0, 1.0 };
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glLightfv(GL_LIGHT1, GL_AMBIENT, light1_ambient);
glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse);
glLightfv(GL_LIGHT1, GL_POSITION, light1_position);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHT1);
glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
glColorMaterial(GL_FRONT_AND_BACK,GL_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
}
void CALLBACK display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
s+=0.005;
if(s>1.0)s=0.1;
glPushMatrix();
glScalef(s,s,s);
glRotatef(step,0.0,1.0,0.0);
glRotatef(step,0.0,0.0,1.0);
glRotatef(step,1.0,0.0,0.0);
DrawColorBox();
glPopMatrix();
glFlush();
auxSwapBuffers(); /* 交换缓存 */
}
void CALLBACK stepDisplay (void)
{
step = step + 1.0;
if (step > 360.0)
step = step - 360.0;
display();
}
void CALLBACK startIdleFunc (AUX_EVENTREC *event)
{
auxIdleFunc(stepDisplay);
}
void CALLBACK stopIdleFunc (AUX_EVENTREC *event)
{
auxIdleFunc(0);
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho (-1.5, 1.5, -1.5*(GLfloat)h/(GLfloat)w,
1.50*(GLfloat)h/(GLfloat)w, -10.0, 10.0);
else
glOrtho (-1.5*(GLfloat)w/(GLfloat)h,
1.5*(GLfloat)w/(GLfloat)h, -1.5, 1.5, -10.0, 10.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity ();
}
void DrawColorBox(void)
{
glBegin (GL_QUADS);
glColor3fv(c1);
glNormal3fv(m1);
glVertex3fv(p1);
glColor3fv(c2);
glVertex3fv(p2);
glColor3fv(c3);
glVertex3fv(p3);
glColor3fv(c4);
glVertex3fv(p4);
glColor3fv(c5);
glNormal3fv(m5);
glVertex3fv(p5);
glColor3fv(c6);
glVertex3fv(p6);
glColor3fv(c7);
glVertex3fv(p7);
glColor3fv(c8);
glVertex3fv(p8);
glColor3fv(c5);
glNormal3fv(m3);
glVertex3fv(p5);
glColor3fv(c6);
glVertex3fv(p6);
glColor3fv(c3);
glVertex3fv(p3);
glColor3fv(c4);
glVertex3fv(p4);
glColor3fv(c1);
glNormal3fv(m4);
glVertex3fv(p1);
glColor3fv(c2);
glVertex3fv(p2);
glColor3fv(c7);
glVertex3fv(p7);
glColor3fv(c8);
glVertex3fv(p8);
glColor3fv(c2);
glNormal3fv(m5);
glVertex3fv(p2);
glColor3fv(c3);
glVertex3fv(p3);
glColor3fv(c6);
glVertex3fv(p6);
glColor3fv(c7);
glVertex3fv(p7);
glColor3fv(c1);
glNormal3fv(m6);
glVertex3fv(p1);
glColor3fv(c4);
glVertex3fv(p4);
glColor3fv(c5);
glVertex3fv(p5);
glColor3fv(c8);
glVertex3fv(p8);
glEnd();
}
void main(void)
{
auxInitDisplayMode (AUX_DOUBLE | AUX_RGBA); /* 设置双缓存和RGBA颜色模式*/
auxInitPosition (0, 0, 500,400);
auxInitWindow ("Double_Buffer_Animation");
myinit();
auxReshapeFunc (myReshape);
auxIdleFunc (stepDisplay);
auxMouseFunc (AUX_LEFTBUTTON, AUX_MOUSEDOWN, startIdleFunc);
auxMouseFunc (AUX_RIGHTBUTTON, AUX_MOUSEDOWN, stopIdleFunc);
auxMainLoop(display);
}
以上程序运行结果:是在屏幕上显示一个不断旋转和由小到大变化的五彩立方体。
4.2.5 实时动画
实现小球的动态模型。实现其翻转、移动等基本变换。
"实时动画.cpp"
4.2.6 纹理坐标
1)坐标定义
在绘制纹理映射场景时,不仅要给每个顶点定义几何坐标,而且也要定义纹理坐标。经过多种变换后,几何坐标决定顶点在屏幕上绘制的位置,而纹理坐标决定纹理图像中的哪一个纹素赋予该顶点。并且顶点之间的纹理坐标插值与基础篇中所讲的平滑着色插值方法相同。
纹理图像是方形数组,纹理坐标通常可定义成一、二、三或四维形式,称为s,t,r和q坐标,以区别于物体坐标(x,y,z,w)和其他坐标。一
展开阅读全文