立方体纹理映射.docx
《立方体纹理映射.docx》由会员分享,可在线阅读,更多相关《立方体纹理映射.docx(11页珍藏版)》请在冰豆网上搜索。
立方体纹理映射
立方体纹理映射.
1问题描述与算法思想
1.1纹理映射简介
纹理映射(TextureMapping)是将纹理空间中的纹理像素映射到屏幕空间中的像素的过程。
在三维图形中,纹理映射(TextureMapping)的方法运用得最广,尤其描述具有真实感的物体。
比如绘制一面砖墙,就可以使用一幅具有真实感的图像或者照片作为纹理贴到一个矩形上,这样,一面逼真的砖墙就画好了。
如果不用纹理映射的方法,这墙上的每一块砖都要作为一个独立的多边形来绘制。
另外,纹理映射能够保证在变换多边形时,多边形上的纹理也会随之变化。
例如,用透视投影模式观察墙面时,离视点远的墙壁的砖块的尺寸就会缩小,而离视点近的就会大些,这些是符合视觉规律的。
此外,纹理映射也被用在其他一些领域。
如飞行仿真中常把一大片植被的图像映射到一些大多边形上用以表示地面,或者用大理石、木材等自然物质的图像作为纹理映射到多边形上表示相应的物体。
纹理对象通过一个单独的数字来标识。
这允许硬件能够在内存中保存多个纹理,而不是每次使用的时候再加载它们,从而减少了运算量,提高了速度。
纹理映射是真实感图像制作的一个重要部分,运用它可以方便的制作出极具真实感的图形而不必花过多时间来考虑物体的表面细节。
然而纹理加载的过程可能会影响程序运行速度,当纹理图像非常大时,这种情况尤为明显。
如何妥善的管理纹理,减少不必要的开销,是系统优化时必须考虑的一个问题。
还好,相关软件提供了纹理对象对象管理技术来解决上述问题。
与显示列表一样,纹理对象通过一个单独的数字来标识。
立方体映射(cube-map)纹理是一种特殊类型的纹理,用于环境映射,使用一组图像并把他们作为立方体的面。
立方体映射的6个面用正方形并且大小相同的6个子纹理表示。
要从立方体纹理中采样的时候,使用的纹理坐标是3维,并且被看做来自原点的方向。
方向指向用来读取纹理的立方体映射表面的位置。
立方体纹理映射主要思想是通过观察向量和表面的法向量反射来确定采样的纹理坐标。
1.2实验目的
1)掌握位图纹理读入方法;
2)掌握立方体纹理映射算法。
1.3功能要求
1)建立三维坐标系Oxyz,远点位于屏幕客户区中心,x轴水平向右为正,y轴垂直向上为正,z轴垂直于屏幕指向观察者。
2)设置屏幕背景色为黑色。
3)读入六张构成天空盒的位图作为纹理映射到立方体的可见表面上。
4)按下鼠标左键缩小立方体,按下鼠标右键增大立方体。
5)使用键盘方向旋转纹理立方体。
6)使用动画按钮播放或停止立方体动画。
1.4算法原理(算法思想)
立方体进行纹理映射是纹理对象并不是直接绑定到着色器,而是绑定到一
个纹理单元,纹理单元的索引将会传递给做涩琪。
要绑定到一个纹理单元,先要将其激活,可以使用glActiveTexture()函数。
可以使用多个纹理单元,每个纹理单元可以绑定到相同的或者不同的纹理对象。
只要纹理对象的类型不同,一个纹理单元可以绑定多个纹理对象。
通过采样器变量来使用多个纹理。
在片元着色器中,采样函数需要通过采样器变量访问变量来访问多个纹理单元。
采样器对象与纹理对象不同。
纹理对象中包含了纹理数据以及配置采样操作的参数,这些参数是采样状态额一部分。
另外也可以创建一个采样对象,用采样状态参数配置它,并把它绑定到纹理单元中。
这样,采样器对象会覆盖纹理对象中定义的采样状态。
2总体设计:
功能类的结构设计
1)定义CFace类,将面片定点索引号和位图定点索引号绑定在一起,Normal为面片的法失量;
2)定义COLORREF类型的Image二维数组,用voidCTestView:
:
ReadImage(int
nface)函数读入纹理图片;
3)voidCTestView:
:
ReadFace()定义面表,将四边形面片三维顶点的索引号和位图二维顶点的索引号对应起来;
4)voidCTestView:
:
DrawObject(CDC*pDC)绘制立方体,在绘制立方体之前先对立方体进行背面剔除以提高效率,绘制时先调用ReadImage()函数读入纹理,再调用ZBuffer类的SetPoint()函数绑定纹理,最后根据TextureMap()函数根据位图颜色绘制立方体的可见面;
5)在CZBuffer类中添加纹理映射函数TextureMap(),填充立方体每个可见面内部时,使用COLORREF类型的clr变量读出Image纹理数组对应点的颜色值进行绘制;
6)voidCTestView:
:
InitParameter(),透视变换参数初始化,设定用户坐标系的视点球坐标;
7)voidCTestView:
:
PerProject(CP3P),进行透视变换。
实现世界坐标系到观察坐标系的转换及屏幕坐标系到二维坐标系的转换;
8)voidCTestView:
:
OnLButtonDown(UINTnFlags,CPointpoint),鼠标左键函数;voidCTestView:
:
OnRButtonDblClk(UINTnFlags,CPointpoint),鼠标右键函数。
点击鼠标左键使立方体缩小,点击右键使立方体增大;
9)voidCTestView:
:
OnKeyDown(UINTnChar,UINTnRepCnt,UINTnFlags),键盘控制函数,点击键盘不同按键控制立方体的旋转;
10)voidCTestView:
:
ClearImaMem(),最终删除纹理对象。
3详细设计(流程图)
开纹义定生成纹透视变换结
源程序(核心功能程序)4绘制立方体4.1
绘制voidCTestView:
:
DrawObject(CDC*pDC)//立方体{
CPi3Point[4];//面的顶点坐标
CP2Texture[4];//面的纹理坐标
CZBuffer*zbuf=newCZBuffer;
zbuf->InitDeepBuffer(800,800,-1000);
for(intnFace=0;nFace<6;nFace++)
{
CVectorVS(P[F[nFace].p[1]],ViewPoint);//面的视矢量
CVector
V01(P[F[nFace].p[0]],P[F[nFace].p[1]]);//面的一条边矢量
CVector
V12(P[F[nFace].p[1]],P[F[nFace].p[2]]);//面的另一条边矢量
CVectorVN=V01*V12;//面的法矢量
if(Dot(VS,VN)>=0)//背面剔除
{
for(int
nEdge=0;nEdge{
PerProject(P[F[nFace].p[nEdge]]);
Point[nEdge]=ScreenP;
Texture[nEdge]=F[nFace].t[nEdge];
}
ReadImage(nFace);
zbuf->SetPoint(Point,Texture,4);//初始化(绑定顶点和各个顶点的纹理坐标点)
zbuf->CreateBucket();//创建桶表
zbuf->CreateEdge();//创建边表
zbuf->TextureMap(pDC,Image);//纹理映射
zbuf->ClearMemory();
ClearImaMem();
}
}
deletezbuf;
}
4.2读入图片
voidCTestView:
:
ReadImage(intnface)//读入图片
{
BYTE
Texture[]={IDB_FRONT,IDB_BACK,IDB_LEF
T,IDB_RIGHT,IDB_TOP,IDB_BOTTOM};
CBitmapNewBitmap;
NewBitmap.LoadBitmap(Texture[nface]);//调入位图资源
NewBitmap.GetBitmap(&bmp);//得获的信息到Bitmap结构体中CBitmapint
nbytesize=(bmp.bmWidth*bmp.bmHeight*bmp.bmBitsPixel+7)/8;//获得位图的总字节数开辟装载位图的im=newBYTE[nbytesize];//
缓冲区NewBitmap.GetBitmapBits(nbytesize,(LPVOI
将位图拷贝到缓冲区D)im);//COLORREF*[bmp.bmHeight];//Image=new
建立二维颜色数组for(intn1=0;n1{
Image[n1]=new
COLORREF[bmp.bmWidth];
}
位n1=bmp.bmHeight-1;n1>=0;n1--)//for(int
图高度
{
for(intn2=0;n2<=bmp.bmWidth-1;n2++)//位图宽度
{
intpos=n1*bmp.bmWidthBytes+4*n2;//位置
Image[n1][n2]=RGB(im[pos+2],im[pos+1],im[pos]);
}
}
delete[]im;
}
4.3鼠标键盘操作函数
voidCTestView:
:
OnLButtonDown(UINTnFlags,
CPointpoint)//鼠标左键函数
{
//TODO:
Addyourmessagehandlercode
hereand/orcalldefault
R+=100;
Invalidate(FALSE);
CView:
:
OnLButtonDown(nFlags,point);
}
voidCTestView:
:
OnRButtonDblClk(UINT
鼠标右键函数nFlags,CPointpoint)//{
code//TODO:
Addyourmessagehandler
hereand/orcalldefault
R-=100;
Invalidate(FALSE);
CView:
:
OnRButtonDblClk(nFlags,point);
}
nChar,CTestView:
:
OnKeyDown(UINTvoid
UINTnRepCnt,UINTnFlags)
{
codeAdd//TODO:
yourmessagehandler
hereand/orcalldefault
if(!
Play)
{
switch(nChar)
{
caseVK_UP:
afa=-5;
tran.RotateX(afa);
break;
caseVK_DOWN:
afa=5;
tran.RotateX(afa);
break;
caseVK_LEFT:
beta=-5;
tran.RotateY(beta);
break;
caseVK_RIGHT:
beta=5;
tran.RotateY(beta);
break;
default:
break;
}
Invalidate(FALSE);
}
CView:
:
OnKeyDown(nChar,nRepCnt,
nFlags);
}
5运行效果图
6结论与总结
这一次的课程设计我选的是立方体纹理映射,与以前上课时要求完成的作业有很大的区别,难度上提升了不少。
上课时图形学实验作业的代码都是有实验参考书,但这次课程设计却是没有代码提示的,需要自己查询资料并结合自己的理解来一行行的敲代码。
在敲代码的过程中自然是错误百出,无论是变量定义错误还是输入大小写错误或是标点符号输入错误都会导致最后的图形出不来。
此次写代码用的语言是C++,与此代码类似,编过相关类型的代码,也思考了实现相关功能的对应函数,并完整的实现过程序。
在这个过程中,需要不
断地改进,不断地完善,调试,分析,和尝试,才能最终得出结果。
而且复合基本要求,就要在设计过程中勇于探讨,勇于实践。
当时是刚开始写这门科目的代码,一开始无从下手,直到查阅了很多资料,了解了一些相关知识,然后慢慢尝试。
这次在以前的基础上增加了一些难度,虽然程序总体来说较复杂,因为要区分字母的大小写,还要区分标点符号,写的过程中容易出错,并充分使用所给的已知信息。
如何通过空间模型来实现,如何使用函数来绘制模型的各个部分,并进行异常处理整个过程要足够的细心和耐心,但我相信,只要不断尝试,不断分析、改正,最终会的出结果。
我认为,对于类似的实践性较强的科目,我们从书本上学到的东西是远远不够的,课本上只是讲了个大概思路,让我们对这门课有个基本的了解,而更多的是需要我们自己课外查资料来完善课本上不能学到的,具体操作需要我们课余时间抽空练习操作过程,从网上查阅相关资料。
同时也培养了自己的自学能力和探索精神,学这门课,不仅需要足够的信心,还要有耐心,我相信,只要用心学,一定会不断地取得进步的。