• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

              C++博客 :: 首頁 :: 聯系 ::  :: 管理
              163 Posts :: 4 Stories :: 350 Comments :: 0 Trackbacks

            常用鏈接

            留言簿(48)

            我參與的團隊

            搜索

            •  

            積分與排名

            • 積分 - 400065
            • 排名 - 59

            最新評論

            閱讀排行榜

            評論排行榜

            這篇渲染模型的文章是由Brett Porter所寫的。
            這篇教程的代碼是從PortaLib3D中提取出來的,PortaLib3D是一個可以讀取3D文件實用庫。
            這篇教程的代碼是以第六課為基礎的,我們只討論改變的部分。

            這課中使用的模型是從Milkshape3D中提取出來的,Milkshape3D是一個非常好的建模軟件,它包含了自己的文件格式,所以你能很容易去分析和理解。

            但是文件格式并不能使你加載一個模型,你必須自己定義一個結構去保存數據,接著把數據讀入那個結構,我們將告訴你如何定義這樣一個結構。

            模型的定義在model.h中,好吧我們開始吧:
             
              

            // 頂點結構
            struct Vertex
            {
                char m_boneID;    // 頂點所在的骨骼
                float m_location[3];
            };

            // 頂點的個數和數據
            int m_numVertices;
            Vertex *m_pVertices;

              
             在這一課你,你可以忽略m_boneID,我們將在以后的教程中介紹骨骼動畫。m_location定義頂點的位置。
            下面是三角形結構
             
              

            // 三角形結構
            struct Triangle
            {
                float m_vertexNormals[3][3];
                float m_s[3], m_t[3];
                int m_vertexIndices[3];
            };

            // 使用的三角形
            int m_numTriangles;
            Triangle *m_pTriangles;

              
             3個頂點構成一個三角形,m_vertexIndices保存了三個頂點的索引。 m_s 和 m_t儲存了三個頂點的紋理坐標。m_vertexNormals保存了三個頂點的法線。
            下面我們定義網格結構
             
              

            // 網格結構
            struct Mesh
            {
                int m_materialIndex;
                int m_numTriangles;
                int *m_pTriangleIndices;
            };

            // 使用的網格
            int m_numMeshes;
            Mesh *m_pMeshes;

              
             m_pTriangleIndices指向包含在網格中三角形的數據,它是動態分配的。 m_materialIndex 指向了這個網格所用的材質。 
              

            // 材質屬性
            struct Material
            {
                float m_ambient[4], m_diffuse[4], m_specular[4], m_emissive[4];
                float m_shininess;
                GLuint m_texture;
                char *m_pTextureFilename;
            };

            // 使用的紋理
            int m_numMaterials;
            Material *m_pMaterials;

              
             這里我們使用與OpenGL中相對的材質。
            下面的代碼用來載入模型,我們通過重載loadModelData函數來實現它。

            我們創建了一個新類MilkshapeModel,它是從Model繼承而來的。 
              

            bool MilkshapeModel::loadModelData( const char *filename )
            {
                ifstream inputFile( filename, ios::in | ios::binary | ios::nocreate );
                if ( inputFile.fail())
                    return false;    // 不能打開文件,返回失敗

              
             以二進制的方式打開文件,如果失敗則返回 
              

                inputFile.seekg( 0, ios::end );
                long fileSize = inputFile.tellg();
                inputFile.seekg( 0, ios::beg );

              
             返回文件大小 
              

                byte *pBuffer = new byte[fileSize];
                inputFile.read( pBuffer, fileSize );
                inputFile.close();

              
             分配一個內存,載入文件,并關閉文件 
              

                const byte *pPtr = pBuffer;
                MS3DHeader *pHeader = ( MS3DHeader* )pPtr;
                pPtr += sizeof( MS3DHeader );

                if ( strncmp( pHeader->m_ID, "MS3D000000", 10 ) != 0 )
                    return false;    // 如果不是一個有效的MS3D文件則返回

                if ( pHeader->m_version < 3 || pHeader->m_version > 4 )
                    return false;    // 如果不能支持這種版本的文件,則返回失敗
              
             上面的文件讀取文件頭 
              

                int nVertices = *( word* )pPtr;
                m_numVertices = nVertices;
                m_pVertices = new Vertex[nVertices];
                pPtr += sizeof( word );

                int i;
                for ( i = 0; i < nVertices; i++ )
                {
                    MS3DVertex *pVertex = ( MS3DVertex* )pPtr;
                    m_pVertices[i].m_boneID = pVertex->m_boneID;
                    memcpy( m_pVertices[i].m_location, pVertex->m_vertex, sizeof( float )*3 );
                    pPtr += sizeof( MS3DVertex );
                }

              
             上面的代碼讀取頂點數據 
              

                int nTriangles = *( word* )pPtr;
                m_numTriangles = nTriangles;
                m_pTriangles = new Triangle[nTriangles];
                pPtr += sizeof( word );

                for ( i = 0; i < nTriangles; i++ )
                {
                    MS3DTriangle *pTriangle = ( MS3DTriangle* )pPtr;
                    int vertexIndices[3] = { pTriangle->m_vertexIndices[0], pTriangle->m_vertexIndices[1], pTriangle->m_vertexIndices[2] };
                    float t[3] = { 1.0f-pTriangle->m_t[0], 1.0f-pTriangle->m_t[1], 1.0f-pTriangle->m_t[2] };
                    memcpy( m_pTriangles[i].m_vertexNormals, pTriangle->m_vertexNormals, sizeof( float )*3*3 );
                    memcpy( m_pTriangles[i].m_s, pTriangle->m_s, sizeof( float )*3 );
                    memcpy( m_pTriangles[i].m_t, t, sizeof( float )*3 );
                    memcpy( m_pTriangles[i].m_vertexIndices, vertexIndices, sizeof( int )*3 );
                    pPtr += sizeof( MS3DTriangle );
                }

              
             上面的代碼用來讀取三角形信息,因為MS3D使用窗口坐標系而OpenGL使用笛卡兒坐標系,所以需要反轉每個頂點Y方向的紋理坐標 
              

                int nGroups = *( word* )pPtr;
                m_numMeshes = nGroups;
                m_pMeshes = new Mesh[nGroups];
                pPtr += sizeof( word );
                for ( i = 0; i < nGroups; i++ )
                {
                    pPtr += sizeof( byte );   
                    pPtr += 32;   

                    word nTriangles = *( word* )pPtr;
                    pPtr += sizeof( word );
                    int *pTriangleIndices = new int[nTriangles];
                    for ( int j = 0; j < nTriangles; j++ )
                    {
                        pTriangleIndices[j] = *( word* )pPtr;
                        pPtr += sizeof( word );
                    }

                    char materialIndex = *( char* )pPtr;
                    pPtr += sizeof( char );

                    m_pMeshes[i].m_materialIndex = materialIndex;
                    m_pMeshes[i].m_numTriangles = nTriangles;
                    m_pMeshes[i].m_pTriangleIndices = pTriangleIndices;
                }

              
             上面的代碼填充網格結構 
              

                int nMaterials = *( word* )pPtr;
                m_numMaterials = nMaterials;
                m_pMaterials = new Material[nMaterials];
                pPtr += sizeof( word );
                for ( i = 0; i < nMaterials; i++ )
                {
                    MS3DMaterial *pMaterial = ( MS3DMaterial* )pPtr;
                    memcpy( m_pMaterials[i].m_ambient, pMaterial->m_ambient, sizeof( float )*4 );
                    memcpy( m_pMaterials[i].m_diffuse, pMaterial->m_diffuse, sizeof( float )*4 );
                    memcpy( m_pMaterials[i].m_specular, pMaterial->m_specular, sizeof( float )*4 );
                    memcpy( m_pMaterials[i].m_emissive, pMaterial->m_emissive, sizeof( float )*4 );
                    m_pMaterials[i].m_shininess = pMaterial->m_shininess;
                    m_pMaterials[i].m_pTextureFilename = new char[strlen( pMaterial->m_texture )+1];
                    strcpy( m_pMaterials[i].m_pTextureFilename, pMaterial->m_texture );
                    pPtr += sizeof( MS3DMaterial );
                }

                reloadTextures();

              
             上面的代碼加載紋理數據 
              

                delete[] pBuffer;

                return true;
            }

              
             上面的代碼設置好了一切參數,但紋理還沒有載入內存,下面的代碼完成這個功能。 
              

            void Model::reloadTextures()
            {
                for ( int i = 0; i < m_numMaterials; i++ )
                    if ( strlen( m_pMaterials[i].m_pTextureFilename ) > 0 )
                        m_pMaterials[i].m_texture = LoadGLTexture( m_pMaterials[i].m_pTextureFilename );
                    else
                        m_pMaterials[i].m_texture = 0;
            }

              
             有了數據,就可以寫出繪制函數了,下面的函數根據模型的信息,按網格分組,分別繪制每一組的數據。 
              

            void Model::draw()
            {
                GLboolean texEnabled = glIsEnabled( GL_TEXTURE_2D );

                // 按網格分組繪制
                for ( int i = 0; i < m_numMeshes; i++ )
                {

                    int materialIndex = m_pMeshes[i].m_materialIndex;
                    if ( materialIndex >= 0 )
                    {
                        glMaterialfv( GL_FRONT, GL_AMBIENT, m_pMaterials[materialIndex].m_ambient );
                        glMaterialfv( GL_FRONT, GL_DIFFUSE, m_pMaterials[materialIndex].m_diffuse );
                        glMaterialfv( GL_FRONT, GL_SPECULAR, m_pMaterials[materialIndex].m_specular );
                        glMaterialfv( GL_FRONT, GL_EMISSION, m_pMaterials[materialIndex].m_emissive );
                        glMaterialf( GL_FRONT, GL_SHININESS, m_pMaterials[materialIndex].m_shininess );

                        if ( m_pMaterials[materialIndex].m_texture > 0 )
                        {
                            glBindTexture( GL_TEXTURE_2D, m_pMaterials[materialIndex].m_texture );
                            glEnable( GL_TEXTURE_2D );
                        }
                        else
                            glDisable( GL_TEXTURE_2D );
                    }
                    else
                    {
                        glDisable( GL_TEXTURE_2D );
                    }

                    glBegin( GL_TRIANGLES );
                    {
                        for ( int j = 0; j < m_pMeshes[i].m_numTriangles; j++ )
                        {
                            int triangleIndex = m_pMeshes[i].m_pTriangleIndices[j];
                            const Triangle* pTri = &m_pTriangles[triangleIndex];

                            for ( int k = 0; k < 3; k++ )
                            {
                                int index = pTri->m_vertexIndices[k];

                                glNormal3fv( pTri->m_vertexNormals[k] );
                                glTexCoord2f( pTri->m_s[k], pTri->m_t[k] );
                                glVertex3fv( m_pVertices[index].m_location );
                            }
                        }
                    }
                    glEnd();
                }

                if ( texEnabled )
                    glEnable( GL_TEXTURE_2D );
                else
                    glDisable( GL_TEXTURE_2D );
            }

              
             有了上面的函數,我們來看看如何使用它們。首先,我們定義一個MilkshapeModel類。 
              

                Model *pModel = NULL;    // 定義一個指向模型類的指針

              
             接著加載模型文件 
              

                pModel = new MilkshapeModel();
                if ( pModel->loadModelData( "data/model.ms3d" ) == false )
                {
                    MessageBox( NULL, "不能加載data/model.ms3d文件", "加載錯誤", MB_OK | MB_ICONERROR );
                    return 0;                                    // 返回失敗
                }

              
             接著載入紋理 
              

                pModel->reloadTextures();

              
             完成了初始化操作,我們來實際繪制我們的模型 
              

            int DrawGLScene(GLvoid)
            {
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    // 情況緩存
                glLoadIdentity();               
                gluLookAt( 75, 75, 75, 0, 0, 0, 0, 1, 0 );

                glRotatef(yrot,0.0f,1.0f,0.0f);

                //繪制模型
                pModel->draw();

                yrot+=1.0f;
                return TRUE;                        //成功返回
            }

              
             簡單吧?下一步我們該做什么?在以后的教程中,我將會加入骨骼動畫的知識,到時候見吧!
             
             
            posted on 2007-12-22 15:08 sdfasdf 閱讀(1588) 評論(0)  編輯 收藏 引用 所屬分類: OPENGL
            99久久精品国内| 久久久噜噜噜久久熟女AA片 | 亚洲国产成人精品久久久国产成人一区二区三区综 | 国内精品伊人久久久久网站| 久久久艹| 久久66热人妻偷产精品9| 国产激情久久久久影院老熟女免费| 国产精品美女久久久免费| 亚洲精品第一综合99久久| 国产精品久久久久…| 久久久久久久91精品免费观看| 久久久久高潮毛片免费全部播放| 国内精品久久久久久久久| 99精品国产99久久久久久97| 狠狠人妻久久久久久综合| 久久久久亚洲av无码专区喷水| 婷婷久久综合九色综合绿巨人 | 精品久久香蕉国产线看观看亚洲| 久久国产成人亚洲精品影院| 久久精品无码一区二区无码| 精品伊人久久久| 思思久久好好热精品国产| 99久久国产综合精品五月天喷水 | 久久精品国产亚洲AV无码偷窥| 欧美大战日韩91综合一区婷婷久久青草 | 久久精品国产99久久久| 老男人久久青草av高清| 久久久久亚洲?V成人无码| 成人妇女免费播放久久久| 日本欧美久久久久免费播放网 | 91秦先生久久久久久久| 91精品国产色综合久久| 久久精品无码专区免费东京热| 午夜欧美精品久久久久久久| 久久亚洲精品国产亚洲老地址| 亚洲AV伊人久久青青草原| 青春久久| 久久人做人爽一区二区三区| 亚洲精品美女久久久久99| 久久婷婷五月综合色奶水99啪| 色欲久久久天天天综合网精品|