《学OpenGL编3D游戏》

From:http://narita1982.bokee.com/6506125.html

我觉得虽然高明理的《学OpenGL编3D游戏》虽然没有NeHe讲得那么细,甚至可以说只有源代码,原理少得可怜,比如摄像机,比如加载3D模型……什么原理都没有,但是我感觉却比NeHe明白,程序也简单明了,让人看了会比较有信心,NeHe实在把我吓了一跳,不知道看NeHe的教程什么时候才能编出一个3D游戏来。

组合模型 内容:
~1~  初始化OpenGL环境   (恩,比NeHe强很多,NeHe到处都是判断,实在是晕)
~2~  初始化材质、灯光(恩,还是比NeHe的强,NeHe让人搞不懂多材质是怎么进行的)
~3~  二次几何体 (恩……还是比NeHe强,倒……)
         二次几何体感觉简而言之就是OpenGL内置的一些比较复杂的模型,比如球、圆锥、圆柱什么的。初始化可以看看NeHe的教程 http://www.owlei.com/DancingWind/Course/Tutorial_18.htm

关于:
~1~glLoadIdentity()和glPushMatrix()

glLoadIdentity()将当前的矩阵清零,不可再恢复;
glPushMatrix()将当前矩阵压入栈中,当前矩阵不清零,其下的操作及显示在当前的矩阵下继续进行,在使用glPopMatrix()后,当前的矩阵恢复到调用glPushMatrix()之前,在两者之间的各种变换不在起作用。

~2~关于物体平移、旋转顺序

感觉是一个很恶的问题,必须作适当的选择才能使物体作正确的自转和公转。
『转载』通常的做法是先调用glClear()和glLoadIdentity()函数完成屏幕的清空和对矩阵的单位矩阵重置,随后调用glPushMatrix()进行压栈并可在之后执行对场景的旋转、平移、缩放、绘制列表的执行等操作直到glPopMatrix()函数被调用。在glPopMatrix()出栈之后需要通过glFlush()函数强制绘图的完成。

该教程也转得比较乱。

试了下,在旋转和平移的时候一定要想清楚目前(0,0,0)点是不是还是屏幕中心(gltranslatef之后据就不是了),坐标系有没有旋转(glRotatef后坐标系会旋转)。当要作相对移动的时候就把gltranslate()和glRotatef()放在glPushMatrix()和glPopMatrix()之间,这样比较清楚。

按照教程拼了个飞机~改了个花哨点的材质~嘿嘿~~虽然我是不太喜欢飞机啦





这些天看坂本千寻看得郁闷了,一点进展都没有。比起复杂的程序架构,偶尔看看框架和环境心情还是比较愉快的。框架比起算法来有的时候真是简单多了……寒。



可以说——远没有想象中的那么难(还是功力渐长?)。不过由于一些细节问题,还是费了偶一番工夫。>_<、

高度图

Like this:


用(x,y)点的象素值作为3D空间(x,z)点高度(即空间某点数值为(heightmapx,pixel_value_at(heightmapx,heightmapy),heightmapy))。
正规的话应该用灰度图,因为灰度图像素点为8位,取值为0~255。不过偶觉得用RGB比较方便拉,因为COLORREF CImage::GetPixel(int x,int y)可以返回(x,y)点的像素值,然后用::GetRValue()就可以获得R通道的数值了。

~~~~~~~~~~~~~~~~~~~~~~~~~
RGB一个像素为24位,R、G、B每个通道占8位(取值为0~255)。


用下面的方法,显示256x256的图超级慢(要画256x256x4个点),但是显示上面32x32的图还是满快的。

贴材质

Like this:


       512x512

NeHe有几个显示地形和漫游的教程,之前不明白的时候不知道哪个才是关键,搞得偶七荤八素的。
其实揭示了地形及地形材质原理的是《飘动的旗帜》,这个最简单却最是最关键的。
http://www.owlei.com/DancingWind/Course/Tutorial_11.htm

这部分没有用《学OpenGL编3D游戏》的方法,回头研究下贴上来。

   V0--------->V1
               |
               |
               |
               |
               V
  V3<--------- V2

对于每个方块按照 v0->v1->v2->v3点的顺序绘图。如果用材质坐标还是(0,0)(1,0)(1,1)(0,1),每个方块上将贴上完整的材质,那么对于上面地形图,将看到32x32个材质图片。
所以需要把材质切成32x32块,然后让每一块方块映射其中之一。

如果v0为(x,z),v1为(x+1,z),v2为(x+1,z+1),v3为(x,z+1)

所以就有:

glBegin(GL_QUADS)
for(int x=0,x 小于heightmapWidth, x++)
   
   
for(int z=0,z
 小于heightmapHeight,z++)
  {
       
glTexCoord2f( (float)x/heightmapWidth, (float)z/heightmapHeight);    
           glVertex3f( v0_x,v0_y,v0_z);

           glTexCoord2f( (float)(x+1)/heightmapWidth, (float)z/heightmapHeight);    
           glVertex3f( v1_x,v1_y,v1_z);

         glTexCoord2f( (float)(x+1)/heightmapWidth, (float)(z+1)/heightmapHeight);    
           glVertex3f( v2_x,v2_y,v2_z);

           glTexCoord2f( (float)x/heightmapWidth, (float)(z+1)/heightmapHeight);    
           glVertex3f( v3_x,v3_y,v3_z);

    }

glEnd();

细节
细节决定成败,偶真是深刻体会了下。
float
偶按上面方法切割了材质,却死活也显示不出来。折腾了半天,发现原来是float的问题,int/int=int,所以材质坐标就成了(0,0)(0,0)(0,0)(0,0)了,怪不得什么也没有呢。>_<、

天空盒
天空盒原理都没什么难的。就是画长方形,然后材质映射。
但一点需要注意,否则就会出现难看的接缝了。
要在每次绑定材质之后设置

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);

这将会把你的材质拉伸到绑定单位的大小。嘿嘿,别看就两句,不过是关键所在哦。

秀下效果吧~ 

呵呵~还不错哦~~

posted @ 2009-08-31 15:30  Revive and Strive  阅读(1975)  评论(0编辑  收藏  举报