随笔 - 32  文章 - 94  trackbacks - 0
<2011年3月>
272812345
6789101112
13141516171819
20212223242526
272829303112
3456789

常用链接

留言簿(8)

随笔分类

随笔档案

好友连接

搜索

  •  

最新评论

阅读排行榜

评论排行榜

之前的一篇文章实现的是完全基于四叉树的动态地形渲染,虽然感觉那种方案是最优美的方案,假设CPU和GPU速度上没有差别的话,那种方案应该是最佳的了。但是现实中CPU速度还是比GPU慢不少的,因此,参考了这篇文章:http://nvidia.e-works.net.cn/document/200908/article8938_2.htm 并按其思路实现了分块的地形LOD算法,整体思路感觉比之前的完全动态地形渲染还要简单些。

1、文章中的裂缝消除部分提到了要把地形块分成5个部分,实际上只需要分成3个部分(中间独立部分、上或下,左或右)就可以了。
2、另外文章中提到的顶高度点渐变时的插值,好像需要实时频繁改变顶点数据,感觉对效率会影响很大,目前还不知道应该怎么处理好些,请教各位高手有没有具体实现思路。。。
3、还有文章提到的采用Triangle strip可以减少索引数目,也没有实现(偷懒),用四边形代替....


目前测试程序中该地形的块大小是33*33,总大小是1057*1057(即32*32个块),块距离lod比例是4,(即包围球半径 除以 中心到相机距离 再除以 4,如果值小于1就采用全分辨率,1--2是第2级分辨率.....直到一个块只用一个4边形表示的最低分辨率)
看起来效果好像还不如之前的完全动态LOD地形,可能还需要调整好每个块大小、距离比例等参数。

地形块之间的裂缝消除:


相关代码
  1#pragma once
  2
  3#include "VertexBuffer.h"
  4#include "SceneObject.h"
  5#include <hash_map>
  6#include "Shader.h"
  7
  8//////////////////////////////////////////////////////////////////////////
  9#include "TGAFile.h"
 10//////////////////////////////////////////////////////////////////////////
 11
 12namespace C_Y
 13{
 14    /*
 15    每个地形块长度:2^n+1,每个地形块顶点数 (2^n+2)*(2^n+2)
 16
 17    地形块数量:2^m * 2^m
 18
 19    地形总顶点数满足:(2^n+1) * 2^m +1 的平方
 20    */

 21    class CY_GeoMipMapTerrain
 22    {
 23        struct CY_LodBlock
 24        {
 25            CY_VertexBuffer m_VertexBuffer;            //顶点buffer
 26            
 27            CY_Vector3f m_CenterPos;                //中心位置
 28            float m_BoundingRadius;                    //包围球半径
 29        }
;
 30        struct CY_QuadTreeNode
 31        {
 32            CY_LodBlock *m_LeafBlock;                //叶结点
 33            CY_QuadTreeNode *m_Down;                //相邻的下结点
 34            CY_QuadTreeNode *m_Right;                //相邻的右结点
 35
 36            CY_QuadTreeNode *m_UpLeft;                //子结点
 37            CY_QuadTreeNode *m_UpRight;
 38            CY_QuadTreeNode *m_DownLeft;
 39            CY_QuadTreeNode *m_DownRight;
 40
 41            CY_Vector3f m_CenterPos;                //中心位置
 42            float m_BoundingRadius;                    //包围球半径
 43            
 44            int m_StartX;                            //索引所有顶点中,起始的顶点位置X
 45            int m_EndX;
 46            int m_StartY;
 47            int m_EndY;
 48
 49            int m_SelfLevel;                        //lod级别,负数表示不渲染,level越低越精细
 50
 51            CY_QuadTreeNode():m_LeafBlock(0),m_Down(0),m_Right(0),m_UpLeft(0),m_UpRight(0),m_DownLeft(0),m_DownRight(0){}
 52            ~CY_QuadTreeNode()
 53            {
 54                if(m_LeafBlock)
 55                    delete m_LeafBlock;
 56                if(m_UpLeft)
 57                    delete m_UpLeft;
 58                if(m_UpRight)
 59                    delete m_UpRight;
 60                if(m_DownRight)
 61                    delete m_DownRight;
 62                if(m_DownLeft)
 63                    delete m_DownLeft;
 64            }

 65            void GenRender(CY_Camera*&cam,std::vector<CY_QuadTreeNode*>&renderlist,const int&maxlevel);
 66            CY_Vector3f GetCenterPos();            //逐级获得中心点
 67            float GetBoundingRadius();            //逐级获得包围球半径
 68        }
;
 69        //---------------------------------------------------------------------------------------------
 70
 71        int m_BlockSize;                        //每个块的边长是多少格,必须是 2^n+1
 72        int m_BlockNum;                            //总的块数量的边长是多少块,宽和高一致,值必须是 2^m
 73
 74        int m_TotalSize;                        //总边长是多少个点(边上的顶点数),值必须是 m_BlockSize*m_BlockNum+1
 75
 76        CY_Vector3f m_UnitSize;                    //深、宽、高的比例
 77        float m_DistanceRate;                    //Lod优化程度
 78
 79        CY_QuadTreeNode *m_Root;                //根结点
 80        CY_QuadTreeNode **m_AllLeaf;            //所有叶节点,按照地形的排列进行排序
 81
 82        GLuint *m_LodBufferIndex;                //所有lod下的顶点索引缓冲,
 83        int *m_LodIndexCount;                    //缓冲的index数量
 84        int m_LodBufferCount;
 85
 86        GLuint m_RightEdgeIndex;                //右边缘的裂缝消除
 87        unsigned *m_Right_1_Index;
 88        unsigned *m_Right_Index;
 89
 90        GLuint m_DownEdgeIndex;                    //下边缘的裂缝消除
 91        unsigned *m_Down_1_Index;
 92        unsigned *m_Down_Index;
 93
 94        void InitIndexBuffer();
 95        void InitNode(CY_QuadTreeNode *&currNode,int Blocklength,int startX,int startY,int endX,int endY,CTargaImage&image);//处理的node,node的大小,node的起始、结束索引的顶点
 96        void InitLeaf(CY_LodBlock *&LeafBlock,int startX,int startY,int endX,int endY,CTargaImage&image);//处理叶子的block
 97        void InitAdjLeaf();
 98    public:
 99        CY_GeoMipMapTerrain();
100        ~CY_GeoMipMapTerrain();
101
102        void LoadTerrain(const std::wstring&);
103        void Render(const CY_EffectPassKind&pass);
104    }
;
105}

  1#include "GeoMipMapTerrain.h"
  2#include "SceneManager.h"
  3//////////////////////////////////////////////////////////////////////////
  4#include "TGAFile.h"
  5#include "MaterialSystem.h"
  6#include "LogManager.h"
  7//////////////////////////////////////////////////////////////////////////
  8
  9namespace C_Y
 10{
 11    void CY_GeoMipMapTerrain::CY_QuadTreeNode::GenRender(CY_Camera*&cam,std::vector<CY_QuadTreeNode*>&renderlist,const int&maxlevel)
 12    {    
 13        if(m_LeafBlock)
 14        {
 15            m_LeafBlock->m_VertexBuffer.PrepareThisGeometryChunk();
 16            m_SelfLevel=(cam->GetWorldPos()-m_CenterPos).QuickLength()/(m_BoundingRadius*4);
 17            if(m_SelfLevel>=maxlevel)
 18                m_SelfLevel=maxlevel-1;
 19            renderlist.push_back(this);
 20        }

 21        else
 22        {
 23            if(cam->GetFrustum()->SphereInFrustum(m_UpLeft->m_CenterPos,m_UpLeft->m_BoundingRadius))
 24                m_UpLeft->GenRender(cam,renderlist,maxlevel);
 25            if(cam->GetFrustum()->SphereInFrustum(m_UpRight->m_CenterPos,m_UpRight->m_BoundingRadius))
 26                m_UpRight->GenRender(cam,renderlist,maxlevel);
 27            if(cam->GetFrustum()->SphereInFrustum(m_DownLeft->m_CenterPos,m_DownLeft->m_BoundingRadius))
 28                m_DownLeft->GenRender(cam,renderlist,maxlevel);
 29            if(cam->GetFrustum()->SphereInFrustum(m_DownRight->m_CenterPos,m_DownRight->m_BoundingRadius))
 30                m_DownRight->GenRender(cam,renderlist,maxlevel);
 31        }

 32    }

 33    CY_Vector3f CY_GeoMipMapTerrain::CY_QuadTreeNode::GetCenterPos()
 34    {
 35        if(m_LeafBlock)
 36        {
 37            m_CenterPos=m_LeafBlock->m_CenterPos;
 38            return m_CenterPos;
 39        }

 40        else
 41        {
 42            m_CenterPos=(m_UpLeft->GetCenterPos()+m_DownLeft->GetCenterPos()+m_UpRight->GetCenterPos()+m_DownRight->GetCenterPos())/4;
 43            return m_CenterPos;
 44        }

 45    }

 46    float CY_GeoMipMapTerrain::CY_QuadTreeNode::GetBoundingRadius()
 47    {
 48        if(m_LeafBlock)
 49        {
 50            m_BoundingRadius=m_LeafBlock->m_BoundingRadius;
 51            return m_BoundingRadius;
 52        }

 53        else
 54        {
 55            m_BoundingRadius=0;
 56            float currr=(m_CenterPos-m_UpLeft->m_CenterPos).Length()+m_UpLeft->GetBoundingRadius();
 57            if(m_BoundingRadius<currr)
 58                m_BoundingRadius=currr;
 59            currr=(m_CenterPos-m_UpRight->m_CenterPos).Length()+m_UpRight->GetBoundingRadius();
 60            if(m_BoundingRadius<currr)
 61                m_BoundingRadius=currr;
 62            currr=(m_CenterPos-m_DownLeft->m_CenterPos).Length()+m_DownLeft->GetBoundingRadius();
 63            if(m_BoundingRadius<currr)
 64                m_BoundingRadius=currr;
 65            currr=(m_CenterPos-m_DownRight->m_CenterPos).Length()+m_DownRight->GetBoundingRadius();
 66            if(m_BoundingRadius<currr)
 67                m_BoundingRadius=currr;
 68            return m_BoundingRadius;
 69        }

 70    }

 71    //-----------------------------------------------------------------------------------------------------------------------
 72    CY_GeoMipMapTerrain::CY_GeoMipMapTerrain()
 73    {
 74        m_Root=0;
 75        m_AllLeaf=0;
 76        m_LodBufferIndex=0;
 77        m_LodIndexCount=0;
 78
 79        m_Right_1_Index=0;
 80        m_Right_Index=0;
 81        m_Down_1_Index=0;
 82        m_Down_Index=0;
 83    }

 84    CY_GeoMipMapTerrain::~CY_GeoMipMapTerrain()
 85    {
 86        if(m_Root)
 87            delete m_Root;
 88        if(m_AllLeaf)
 89            delete []m_AllLeaf;
 90        if(m_LodBufferIndex)
 91        {
 92            glDeleteBuffers(m_LodBufferCount,m_LodBufferIndex);
 93            delete []m_LodBufferIndex;
 94        }

 95        if(m_LodIndexCount)
 96            delete []m_LodIndexCount;
 97        if(m_Right_1_Index)
 98            delete []m_Right_1_Index;
 99        if(m_Right_Index)
100            delete []m_Right_Index;
101        if(m_Down_1_Index)
102            delete []m_Down_1_Index;
103        if(m_Down_Index)
104            delete []m_Down_Index;
105    }

106
107    void CY_GeoMipMapTerrain::InitIndexBuffer()
108    {
109        m_LodBufferCount=GetPow2Num(m_BlockSize-1)+1;
110        m_LodBufferIndex=new GLuint[m_LodBufferCount];
111        m_LodIndexCount=new int[m_LodBufferCount];
112
113        unsigned *AllIndex=new unsigned[(m_BlockSize-1)*(m_BlockSize-1)*4];
114        int step;
115        const int lineLength=m_BlockSize+1;
116        glGenBuffers(m_LodBufferCount,m_LodBufferIndex);
117        for(int i=0;i<m_LodBufferCount;++i)                        //计算索引值
118        {
119            step=1<<(m_LodBufferCount-i-1);
120            int n=0;
121            for(int y=0;y+step<m_BlockSize;y+=step)
122            {
123                for(int x=0;x+step<m_BlockSize;x+=step)
124                {
125                    if((y+step)*lineLength+step>=(m_BlockSize+1)*(m_BlockSize+1))
126                    {
127                        bool success;
128                        success=false;
129                    }

130                    AllIndex[n++]=y*lineLength+x+step;
131                    AllIndex[n++]=y*lineLength+x;
132
133                    AllIndex[n++]=(y+step)*lineLength+x;
134                    AllIndex[n++]=(y+step)*lineLength+step+x;
135
136                }

137            }

138            if(n!=(m_BlockSize-1)*(m_BlockSize-1)*4)
139            {
140                bool success;
141                success=false;
142            }

143            m_LodIndexCount[m_LodBufferCount-1-i]=n;
144            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,m_LodBufferIndex[m_LodBufferCount-1-i]);//最高精度的地形从0起
145            glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(unsigned)*n,AllIndex,GL_STATIC_DRAW);
146        }

147        delete []AllIndex;
148    }

149    void CY_GeoMipMapTerrain::InitNode(CY_QuadTreeNode *&currNode,int Blocklength,int startX,int startY,int endX,int endY,CTargaImage&image)
150    {
151        currNode=new CY_QuadTreeNode();
152        currNode->m_StartX=startX;
153        currNode->m_StartY=startY;
154        currNode->m_EndX=endX;
155        currNode->m_EndY=endY;
156        if(Blocklength>1)
157        {
158            InitNode(currNode->m_UpLeft,Blocklength/2,startX,startY,(startX+endX)/2,(startY+endY)/2,image);
159            InitNode(currNode->m_UpRight,Blocklength/2,(startX+endX)/2,startY,endX,(startY+endY)/2,image);
160            InitNode(currNode->m_DownLeft,Blocklength/2,startX,(startY+endY)/2,(startX+endX)/2,endY,image);
161            InitNode(currNode->m_DownRight,Blocklength/2,(startX+endX)/2,(startY+endY)/2,endX,endY,image);
162        }

163        else
164        {
165            InitLeaf(currNode->m_LeafBlock,startX,startY,endX,endY,image);
166            int index=startX/m_BlockSize+startY/m_BlockSize*m_BlockNum;
167            if(index>m_BlockNum*m_BlockNum)
168                bool success=false;
169            m_AllLeaf[index]=currNode;
170        }

171    }

172
173    void CY_GeoMipMapTerrain::InitLeaf(CY_LodBlock *&LeafBlock,int startX,int startY,int endX,int endY,CTargaImage&image)
174    {
175        bool success=(endX-startX)==m_BlockSize;
176        success=(endY-startY)==m_BlockSize;
177
178        LeafBlock=new CY_LodBlock();
179
180        LeafBlock->m_VertexBuffer.SetUsableVerAttr(CY_VER_ATT_POS);
181        LeafBlock->m_VertexBuffer.CreateBuffer((m_BlockSize+1)*(m_BlockSize+1));
182
183        int n=0,temp,tmpindex;
184        CY_Vector3f TotalPos(0,0,0);
185        CY_Vector3f tempPos;
186        for(int y=startY;y<=endY;++y)
187        {
188            for(int x=startX;x<=endX;++x)
189            {
190                tmpindex=x+y*m_TotalSize;                        //当前点在图中的索引
191                temp=image.GetImage()[tmpindex*4+3];            //点alpha
192
193                tempPos.Set(x*m_UnitSize.x,temp*m_UnitSize.z,y*m_UnitSize.y);
194                TotalPos+=tempPos;
195                LeafBlock->m_VertexBuffer.GetVertex(n)->m_Pos=tempPos;
196                ++n;
197            }

198        }

199        success=n==LeafBlock->m_VertexBuffer.GetVertexCount();
200        LeafBlock->m_VertexBuffer.GenVertexBuffer();
201
202        LeafBlock->m_CenterPos=TotalPos/n;    //得到这个地形块的中点
203
204        float r=0;
205        LeafBlock->m_BoundingRadius=0;
206        for(int i=0;i<n;++i)            //得到这个地形块的包围球半径
207        {
208            r=(LeafBlock->m_VertexBuffer.GetVertex(i)->m_Pos - LeafBlock->m_CenterPos).Length();
209            if(r>LeafBlock->m_BoundingRadius)
210                LeafBlock->m_BoundingRadius=r;
211        }

212    }

213    void CY_GeoMipMapTerrain::InitAdjLeaf()
214    {
215        int n=m_BlockNum*m_BlockNum;
216        for(int i=0;i<n;++i)
217        {
218            if(i%m_BlockNum!=m_BlockNum-1)
219                m_AllLeaf[i]->m_Right=m_AllLeaf[i+1];
220            if(i/m_BlockNum<m_BlockNum-1)
221                m_AllLeaf[i]->m_Down=m_AllLeaf[i+m_BlockNum];
222        }

223    }

224
225    void CY_GeoMipMapTerrain::LoadTerrain(const std::wstring&file)
226    {
227        CTargaImage image;
228        image.Load(file);
229        //-----------------------------------设置参数
230        m_BlockSize=33;
231        m_UnitSize.Set(1.0f,1.0f,0.3f);
232        m_DistanceRate=3.0f;
233
234        m_BlockNum=(image.GetWidth()-1)/m_BlockSize;                
235        m_AllLeaf=new CY_QuadTreeNode*[m_BlockNum*m_BlockNum];
236
237        m_TotalSize=image.GetWidth();
238        //------------------------------------产生tree结构和block
239        InitNode(m_Root,m_BlockNum,0,0,m_TotalSize-1,m_TotalSize-1,image);
240        //------------------------------------产生block的右、下近邻block
241        InitAdjLeaf();
242        //------------------------------------产生索引缓冲
243        InitIndexBuffer();
244
245        int i=0;
246        m_Right_1_Index=new unsigned[m_BlockSize];
247        for(;i<m_BlockSize;++i)                //右内边缘的点
248        {
249            int temp=(m_BlockSize+1)*i+(m_BlockSize-1);
250            m_Right_1_Index[i]=temp;
251        }

252
253        m_Right_Index=new unsigned[m_BlockSize+1];
254        for(i=0;i<=m_BlockSize;++i)            //右外边缘的点
255        {
256            int temp=(m_BlockSize+1)*(i+1)-1;
257            m_Right_Index[i]=temp;
258        }

259
260        m_Down_1_Index=new unsigned[m_BlockSize];
261        for(i=0;i<m_BlockSize;++i)            //下内边缘的点
262            m_Down_1_Index[i]=(m_BlockSize+1)*(m_BlockSize-1)+i;
263
264        m_Down_Index=new unsigned[m_BlockSize+1];
265        for(i=0;i<=m_BlockSize;++i)            //下外边缘的点
266            m_Down_Index[i]=m_BlockSize*(m_BlockSize+1)+i;
267
268        int edgesize=6*(m_BlockSize-1)+3;
269        unsigned *temp=new unsigned[edgesize];
270        for(i=0;i<edgesize;++i)
271            temp[i]=0;
272
273        temp[0]=m_BlockSize*m_BlockSize+m_BlockSize-1;
274        temp[1]=m_BlockSize*m_BlockSize+m_BlockSize-2;
275        temp[2]=(m_BlockSize+1)*(m_BlockSize+1)-1;
276
277                    
278        glGenBuffers(1,&m_RightEdgeIndex);
279        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,m_RightEdgeIndex);
280        glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(unsigned)*edgesize,temp,GL_STREAM_DRAW);//设置了初始大小,最右下的三角形索引
281
282
283        temp[0]=m_BlockSize*m_BlockSize+m_BlockSize-2;
284        temp[1]=(m_BlockSize+1)*(m_BlockSize+1)-1;
285        temp[2]=(m_BlockSize+1)*(m_BlockSize+1)-2;
286
287        glGenBuffers(1,&m_DownEdgeIndex);
288        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,m_DownEdgeIndex);
289        glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(unsigned)*edgesize,temp,GL_STREAM_DRAW);//设置了最右下的三角形索引
290        //------------------------------------产生包围球
291        m_Root->GetCenterPos();
292        m_Root->GetBoundingRadius();
293    }

294    void CY_GeoMipMapTerrain::Render(const CY_EffectPassKind&pass)
295    {
296        //////////////////////////////////////////////////////////////////////////
297        CY_EffectBase *e=CY_MaterialSystem::GetInstance()->GetEffectByName("terrainEff");
298        if(e)
299            e->PrepareEffectChunk(pass);
300
301        
302        CY_Camera *camera=CY_SceneManager::GetInstance()->GetActiveCamera();
303
304        int i=0,temp;
305        for(;i<m_BlockNum*m_BlockNum;++i)
306            m_AllLeaf[i]->m_SelfLevel=-1;
307        
308        std::vector<CY_QuadTreeNode*> AllRenderBlock;
309        m_Root->GenRender(camera,AllRenderBlock,m_LodBufferCount);
310
311        for(i=0;i<(int)AllRenderBlock.size();++i)
312        {
313            AllRenderBlock[i]->m_LeafBlock->m_VertexBuffer.PrepareThisGeometryChunk();
314            temp=AllRenderBlock[i]->m_SelfLevel;
315            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,m_LodBufferIndex[temp]);
316            glDrawElements(GL_QUADS,m_LodIndexCount[temp],GL_UNSIGNED_INT,0);
317            
318
319            unsigned *tempIndex=new unsigned[6*(m_BlockSize-1)];
320            int r1step=(m_BlockSize-1)>>(m_LodBufferCount-1-AllRenderBlock[i]->m_SelfLevel);
321            //消除右裂缝
322            if(AllRenderBlock[i]->m_Right &&AllRenderBlock[i]->m_Right->m_SelfLevel>=0)
323            {
324                int n=0;
325                int rstep=(m_BlockSize-1)>>(m_LodBufferCount-1-AllRenderBlock[i]->m_Right->m_SelfLevel);
326
327                int currR1=0,currR=0;
328                while(currR<m_BlockSize-1 || currR1<m_BlockSize-1)
329                {
330                    if(currR<currR1)
331                    {
332                        tempIndex[n++]=m_Right_Index[currR];
333                        tempIndex[n++]=m_Right_1_Index[currR1];
334                        currR+=rstep;
335                        tempIndex[n++]=m_Right_Index[currR];
336                    }

337                    else
338                    {
339                        tempIndex[n++]=m_Right_Index[currR];
340                        tempIndex[n++]=m_Right_1_Index[currR1];
341                        currR1+=r1step;
342                        tempIndex[n++]=m_Right_1_Index[currR1];
343                    }

344                }

345
346                glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,m_RightEdgeIndex);
347                glBufferSubData(GL_ELEMENT_ARRAY_BUFFER,sizeof(unsigned)*3,sizeof(unsigned)*n,tempIndex);
348                glDrawElements(GL_TRIANGLES,3+n,GL_UNSIGNED_INT,0);
349            }

350            //消除下裂缝
351            if(AllRenderBlock[i]->m_Down && AllRenderBlock[i]->m_Down->m_SelfLevel>=0)
352            {
353                int n=0;
354                int rstep=(m_BlockSize-1)>>(m_LodBufferCount-1-AllRenderBlock[i]->m_Down->m_SelfLevel);
355
356                int currR1=0,currR=0;
357                while(currR<m_BlockSize-1 || currR1<m_BlockSize-1)
358                {
359                    if(currR<currR1)
360                    {
361                        tempIndex[n++]=m_Down_1_Index[currR1];
362                        tempIndex[n++]=m_Down_Index[currR];
363                        currR+=rstep;
364                        tempIndex[n++]=m_Down_Index[currR];
365                    }

366                    else
367                    {
368                        tempIndex[n++]=m_Down_1_Index[currR1];
369                        tempIndex[n++]=m_Down_Index[currR];
370                        currR1+=r1step;
371                        tempIndex[n++]=m_Down_1_Index[currR1];
372                    }

373                }

374
375
376                glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,m_DownEdgeIndex);
377                glBufferSubData(GL_ELEMENT_ARRAY_BUFFER,sizeof(unsigned)*3,sizeof(unsigned)*n,tempIndex);
378                glDrawElements(GL_TRIANGLES,3+n,GL_UNSIGNED_INT,0);
379            }

380            delete []tempIndex;
381        }

382
383        //////////////////////////////////////////////////////////////////////////
384    }

385}
;
posted on 2010-02-09 19:24 陈昱(CY) 阅读(1997) 评论(0)  编辑 收藏 引用 所属分类: C++游戏编程图形学

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理