• <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>

            天行健 君子當(dāng)自強(qiáng)而不息

            2D和3D圖形引擎的混合(2)

             

            本篇是2D和3D圖形引擎的混合(1)的續(xù)篇。

             

            在游戲如最終幻想和寄生前夜(兩者都是由Square公司出品)中,可以在欣賞三維模型的同時(shí),享受到非常精美的預(yù)先渲染好的背景圖像。將二維和三維圖形混合在一起,一直以來(lái)都是游戲公司高度保密的技術(shù),現(xiàn)在可以 揭開(kāi)謎底一看究竟。

            如何從一個(gè)二維圖像中獲取三維的深度信息呢?有幾種方法可以實(shí)現(xiàn)三維物體在二維圖像中的背景幕效果。

            (1)在一個(gè)三維建模工具中創(chuàng)建預(yù)先進(jìn)行渲染的背景幕,例如Caligari公司的gamespace lightdiscreet公司的3D Studio Max,并將圖像與包含每個(gè)像素z值的深度緩沖區(qū)一起保存。對(duì)于游戲中的每一幀,將圖像的深度緩沖區(qū)拷貝到背景深度緩沖區(qū)中,并繼續(xù)繪制三維物體。

            (2)在層次中創(chuàng)建背景幕,從底層開(kāi)始,一個(gè)接一個(gè)地繪制每個(gè)圖像,并將三維角色繪制到適當(dāng)?shù)膶哟紊希@樣就可以使用后面的層次覆蓋較低層次的部分內(nèi)容(以及三維物體)。

            (3)使用一個(gè)非常詳盡的預(yù)先渲染好的背景幕,以及一個(gè)在三維建模軟件中渲染場(chǎng)景的簡(jiǎn)化的網(wǎng)格模型。使用網(wǎng)格模型以呈現(xiàn)z數(shù)值并進(jìn)行碰撞檢測(cè),三維物體可以使用z緩沖區(qū)負(fù)責(zé)繪制正確的深度。

            我們采用第三種方法來(lái)繪制。

             

            二維背景幕的處理

            用一個(gè)三維建模軟件開(kāi)發(fā)二維的背景幕,例如gamespace light(而不是使用一個(gè)繪圖程序,因?yàn)樾枰獜慕\浖蝎@取多邊形的數(shù)據(jù)),下圖顯示了一個(gè)簡(jiǎn)單的網(wǎng)格模型以及最終的渲染效果:

            一旦場(chǎng)景被渲染好,就需要將它作為一個(gè)位圖保存到磁盤(pán)上,那個(gè)位圖文件需要被切分成較小的紋理,如下圖所示,這個(gè)背景幕被切割成多個(gè)Direct3D可以處理的紋理,比如背景幕圖像為640 x 480,所以紋理將為256 x 256(對(duì)于塊1245),以及128 x 256(對(duì)于塊36)。

             

            場(chǎng)景網(wǎng)格模型的處理

            詳盡的層次看起來(lái)非常不錯(cuò),現(xiàn)在想要包含一些三維物體到它里面。首先,需要構(gòu)造一個(gè)簡(jiǎn)化的場(chǎng)景,可使用兩種方法,包括填充每一幀的深度緩沖區(qū),以便三維物體能夠正確地與二維的背景幕進(jìn)行混合;作為運(yùn)動(dòng)物體的碰撞網(wǎng)格模型。

            因?yàn)榫W(wǎng)格模型必須在每幀中被渲染出來(lái),以便創(chuàng)建場(chǎng)景中的z緩存,使用越少的多邊形當(dāng)然越好,然而必須使用足夠的多邊形以確保三維物體能夠被正確地混合,如下圖所示,它顯示了最終渲染好的圖像,實(shí)際的場(chǎng)景網(wǎng)格模型,以及簡(jiǎn)化的場(chǎng)景網(wǎng)格模型。

            當(dāng)處理一個(gè)簡(jiǎn)化的網(wǎng)格模型時(shí),僅使用了兩種材質(zhì)(沒(méi)有紋理)。第一種材質(zhì)代表了實(shí)際繪制到背景幕上的多邊形區(qū)域,而第二種材質(zhì)隱藏了在交集測(cè)試中所使用的多邊形,對(duì)于第二種材質(zhì),使用的alpha的數(shù)值為0.0(意味著它是不可見(jiàn)的,不會(huì)被實(shí)際渲染)。

            應(yīng)該使用正確的多邊形數(shù)量去渲染場(chǎng)景。如果有太多的多邊形,引擎將變得非常緩慢。如果多邊形太少,將會(huì)在玩游戲時(shí)得到貼圖錯(cuò)誤的信息。請(qǐng)這樣思考一下:一個(gè)使用了500個(gè)多邊形的球形網(wǎng)格模型,很明顯比一個(gè)簡(jiǎn)化的網(wǎng)格模型復(fù)雜許多,在一個(gè)簡(jiǎn)化的網(wǎng)格模型里,僅需要足夠的多邊形去表示球體,并確保它在進(jìn)行渲染時(shí)覆蓋相同的屏幕區(qū)域。

            下圖演示了在創(chuàng)建簡(jiǎn)化網(wǎng)格模型時(shí)常出現(xiàn)的一個(gè)錯(cuò)誤,那就是使用了太少的多邊形。

            為了簡(jiǎn)化網(wǎng)格模型中多邊形的數(shù)量,切割掉那些看不到的表面或者在交集測(cè)試中所使用的表面,同時(shí)僅繪制那些實(shí)際覆蓋三維物體的多邊形 。舉個(gè)例子,如果在背景幕中有一個(gè)盒子,而玩家角色從不會(huì)接近它,那么在簡(jiǎn)化的網(wǎng)格模型中就不用繪制它。

            對(duì)于本例中的背景幕,僅需要繪制如下的簡(jiǎn)化網(wǎng)格模型:

             

            場(chǎng)景的渲染

            現(xiàn)在將完成最后一步,以確保背景幕圖像能夠包含深度信息(通過(guò)簡(jiǎn)化的網(wǎng)格模型)。如果加載了背景幕圖像和簡(jiǎn)化的網(wǎng)格模型,就可以很容易地渲染游戲中的每幀,通過(guò)使用如下步驟:

            (1)將z緩沖區(qū)清除為1.0(并確保z緩沖區(qū)被啟動(dòng))。

            (2)渲染簡(jiǎn)化的網(wǎng)格模型(因而填充場(chǎng)景的z緩沖區(qū)),跳過(guò)那些數(shù)值為0.0的多邊形(它們是不可見(jiàn)的)。

            (3)禁用z緩沖區(qū)。

            (4)使用ID3DXSprite位塊傳送背景幕紋理。

            (5)啟動(dòng)z緩沖區(qū)。


            絕大多數(shù)新近的顯卡都允許處理
            1024 x 1024像素大小的紋理,這意味著可以將整個(gè)背景幕圖像加載到內(nèi)存中,而不需要將它切割成6個(gè)小紋理。

            在繪制好背景幕后,剩下的就是將三維物體(網(wǎng)格模型)繪制到場(chǎng)景中,因?yàn)閆緩沖區(qū)包含了所有與每個(gè)像素相關(guān)的深度數(shù)值。請(qǐng)不要猶豫,隨心所欲繪制角色、物體、甚至是增強(qiáng)背景的圖像。

             

            下載源碼和工程

             

            代碼:

            /************************************************************************************
            PURPOSE:
                 3D in 2D test.
            ************************************************************************************/


            #include "core_common.h"
            #include "core_framework.h"
            #include "core_graphics.h"
            #include "core_input.h"

            #define ANIM_NONE   -1
            #define ANIM_WALK    1
            #define ANIM_IDLE    2

            const float g_angles[13] = {
                   0.0f, 4.71f, 0.0f, 5.495f, 1.57f, 0.0f,  
                   0.785f, 0.0f,  3.14f, 3.925f, 0.0f, 0.0f, 2.355f 
            };

            class APP : public FRAMEWORK
            {
            private:  
                CAMERA          m_camera;
                   
                INPUT           m_input;
                INPUT_DEVICE    m_keyboard; 

                TEXTURE         m_background[6];

                
            // the simplified scene mesh and object
                MESH            m_scene_mesh;    
                OBJECT          m_scene;

                
            // 3D meshes and objects
                MESH            m_monster_mesh;
                OBJECT          m_monster;
                ANIMATION       m_monster_anim;
                
                
            static const float m_above_floor;

            public:
                BOOL init()
                {
                    
            if(! create_display(g_hwnd, get_client_width(g_hwnd), get_client_height(g_hwnd), 16, TRUE, TRUE))
                        
            return FALSE;
                    
                    set_perspective(0.6021124f, 1.3333f, 1.0f, 10000.0f);                

                    ShowCursor(TRUE);                          

                    
            // initialize input and input device
                    m_input.create(g_hwnd, get_window_inst());
                    m_keyboard.create_keyboard(&m_input);     

                    
            // load the backdrop textures
                    for(short i = 0; i < 6; i++)
                    {
                        
            char filename[81];
                
                        sprintf(filename, "..\\data\\scene%u.bmp", i+1);

                        
            if(! m_background[i].load(filename, 0, D3DFMT_UNKNOWN))
                            
            return FALSE;
                    }

                    
            // load the scene mesh and configure object

                    
            if(! m_scene_mesh.load("..\\Data\\Scene.x", ".\\"))
                        
            return FALSE;

                    m_scene.create(&m_scene_mesh);

                    
            // load the monster mesh and setup monster object

                    
            if(! m_monster_mesh.load("..\\data\\yodan.x", "..\\data\\"))
                        
            return FALSE;

                    m_monster_anim.load("..\\data\\yodan.x", &m_monster_mesh);
                    m_monster_anim.set_loop(TRUE, "Idle");
                    m_monster_anim.set_loop(TRUE, "Walk");

                    m_monster.create(&m_monster_mesh);
                    
                    
            // position the camera for the scene        

                    m_camera.move(0.0f, 200.0f, -650.0f);
                    m_camera.rotate(0.348888f, 0.0f, 0.0f);

                    g_d3d_device->SetTransform(D3DTS_VIEW, m_camera.get_view_matrix());        
                    
                    
            return TRUE;
                }

                BOOL frame()
                {
                    
            static DWORD time_begin = timeGetTime();       

                    
            // calculate elapsed time (plus speed boost)
                    DWORD time_end = timeGetTime();
                    
            ulong time_elapsed = time_end - time_begin;
                    time_begin = time_end;

                    
            // read keyboard data        
                    m_keyboard.read();

                    
            // process input and update everything, ESC quits program.
                    if(m_keyboard.get_key_state(KEY_ESC))
                        
            return FALSE;
                    
                    
            // process movement

                    
            long dir = 0;

                    
            if(m_keyboard.get_key_state(KEY_UP))
                        dir |= 1;

                    
            if(m_keyboard.get_key_state(KEY_RIGHT))
                        dir |= 2;

                    
            if(m_keyboard.get_key_state(KEY_DOWN))
                        dir |= 4;

                    
            if(m_keyboard.get_key_state(KEY_LEFT))
                        dir |= 8;

                    
            float x_move, z_move;

                    x_move = z_move = 0.0f;

                    
            if(dir)
                    {
                        m_monster.rotate(0.0f, g_angles[dir], 0.0f);

                        x_move =  cos(g_angles[dir]) * (time_elapsed * 0.25f);
                        z_move = -sin(g_angles[dir]) * (time_elapsed * 0.25f);
                    }

                    
            float x_pos, y_pos, z_pos;

                    
            // get monster coordinates in local variables (make it easier)
                    x_pos = m_monster.get_x_pos();
                    y_pos = m_monster.get_y_pos();
                    z_pos = m_monster.get_z_pos();

                    D3DXMESH_PTR d3d_mesh = m_scene_mesh.get_root_mesh_info()->m_d3d_mesh;

                    
            // check for collision in movement (4 points).
                    //
                    // I hard-coded the bounding size of the object (25 radius) and added ability to climb up at mose 32 units.
                    for(long i = 0; i < 4; i++)
                    {
                        
            float x_add[4] = {  0.0f, 25.0f,    0.0f,  -25.0f };
                        
            float z_add[4] = { 25.0f,  0.0f,  -25.0f,    0.0f };

                        
            float dist;            

                        
            if(is_ray_intersect_mesh(d3d_mesh,
                                                 x_pos + x_add[i],           y_pos + m_above_floor, z_pos + z_add[i],
                                                 x_pos + x_add[i] + x_move,  y_pos + m_above_floor, z_pos + z_add[i] + z_move,
                                                 &dist))
                        {
                            
            // clear out movement and break
                            x_move = z_move = 0.0f;
                            
            break;
                        }
                    }
                   
                    
            // fix height of monster
                    y_pos = closest_height_below_object(d3d_mesh, x_pos, y_pos + m_above_floor, z_pos);

                    
            // move monster and set new animations as needed
                    m_monster.move(x_pos + x_move, y_pos, z_pos + z_move);        

                    
            static short last_anim = ANIM_NONE;

                    
            if(!float_equal(x_move, 0.0f) || !float_equal(z_move, 0.0f))
                    {
                        
            if(last_anim != ANIM_WALK)
                        {
                            last_anim = ANIM_WALK;
                            m_monster.set_anim_info_set(&m_monster_anim, "Walk", time_end / 20);
                        }
                    }
                    
            else
                    {
                        
            if(last_anim != ANIM_IDLE)
                        {
                            last_anim = ANIM_IDLE;
                            m_monster.set_anim_info_set(&m_monster_anim, "Idle", time_end / 20);
                        }
                    }

                    
            // update monster animations
                    m_monster.update_anim_info_set(time_end / 20, TRUE);       
                    
                    
            // render everything
                    clear_display_zbuffer(1.0f);                       

                    
            // begin render now
                    if(SUCCEEDED(g_d3d_device->BeginScene()))        
                    {
                        
            // render the level mesh
                        g_d3d_device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
                        m_scene.render();

                        
            // draw the backdrop (composed of six textures)

                        g_d3d_device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);

                        g_d3d_sprite->Begin(0);

                        
            for(int row = 0; row < 2; row++)
                        {
                            
            for(int col = 0; col < 3; col++)
                                m_background[row * 3 + col].draw(col * 256, row * 256, 0, 0, 0, 0, 1.0f, 1.0f, 0xFFFFFFFF);
                        }

                        g_d3d_sprite->End();

                        
            // draw the 3D monster
                        
                        g_d3d_device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);

                        m_monster.render();

                        g_d3d_device->EndScene();            
                    }

                    present_display();

                    
            return TRUE;
                }

                BOOL shutdown()
                {
                    destroy_display();

                    
            return TRUE;
                }
            };

            const float APP::m_above_floor = 32.0f;

            int WINAPI WinMain(HINSTANCE inst, HINSTANCE, LPSTR cmd_line, int cmd_show)
            {
                DWORD client_width  = 640;
                DWORD client_height = 480;
                DWORD x_pos = (get_screen_width()  - client_width) / 2;
                DWORD y_pos = (get_screen_height() - client_height) / 4;

                DWORD window_style = WS_BORDER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;

                
            if(! build_window(inst, "3d_in_2d_class", "3D in 2D Test", window_style,
                                  x_pos, y_pos, client_width, client_height))
                {
                    
            return -1;
                }

                APP app;
                app.run();

                
            return 0;
            }

             

            截圖:


            posted on 2007-10-28 01:09 lovedday 閱讀(1444) 評(píng)論(5)  編輯 收藏 引用

            評(píng)論

            # re: 2D和3D圖形引擎的混合(2) 2007-10-28 23:28 neoragex2002

            有點(diǎn)意思。不過(guò)你這個(gè)場(chǎng)景選取得不太好,帶粒子效果的,很容易看出來(lái)是烘培出來(lái)的背景。  回復(fù)  更多評(píng)論   

            # re: 2D和3D圖形引擎的混合(2) 2007-10-28 23:32 neoragex2002

            至于簡(jiǎn)化場(chǎng)景用的導(dǎo)航網(wǎng)格這種技法,至少在2000年前就有人用了,heh  回復(fù)  更多評(píng)論   

            # re: 2D和3D圖形引擎的混合(2) 2007-10-29 00:11 lovedday

            謝謝,你的博客寫(xiě)的不錯(cuò),有空我會(huì)多去看看,順便請(qǐng)教請(qǐng)教。 ^_^  回復(fù)  更多評(píng)論   

            # re: 2D和3D圖形引擎的混合(2) 2007-11-01 20:30 風(fēng)在奔跑

            本來(lái)就是烘培出來(lái)的背景吧?  回復(fù)  更多評(píng)論   

            # re: 2D和3D圖形引擎的混合(2) 2010-06-02 15:45 guest

            @風(fēng)在奔跑
            下載的代碼中data目錄沒(méi)有文件啊  回復(fù)  更多評(píng)論   


            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


            公告

            導(dǎo)航

            統(tǒng)計(jì)

            常用鏈接

            隨筆分類(178)

            3D游戲編程相關(guān)鏈接

            搜索

            最新評(píng)論

            一本大道久久香蕉成人网 | 久久久久亚洲AV综合波多野结衣 | 久久99精品久久久大学生| 久久精品国产第一区二区三区| 久久婷婷色综合一区二区| 日本精品久久久久影院日本| 久久综合综合久久97色| 久久久久久久久无码精品亚洲日韩| 久久不见久久见免费影院www日本| 国产精品永久久久久久久久久 | 久久亚洲精品无码观看不卡| 欧美久久久久久午夜精品| 久久精品黄AA片一区二区三区| 伊人伊成久久人综合网777| 久久久久亚洲av无码专区导航| 久久久久久久免费视频| 国产精品99久久久久久宅男| 久久国产欧美日韩精品免费| 93精91精品国产综合久久香蕉| 九九热久久免费视频| 麻豆成人久久精品二区三区免费 | 久久99精品久久久久婷婷| 久久久精品2019免费观看| 久久无码国产| 国产亚洲色婷婷久久99精品91 | 怡红院日本一道日本久久| 亚洲精品无码久久久久去q| 国产午夜精品久久久久免费视| 老男人久久青草av高清| 国产福利电影一区二区三区久久久久成人精品综合 | 久久久久99这里有精品10| 国产精品成人久久久久久久| 69国产成人综合久久精品| 亚洲国产精品久久66| 66精品综合久久久久久久| 婷婷久久香蕉五月综合加勒比| 亚洲国产欧洲综合997久久| 一97日本道伊人久久综合影院| 国内精品久久久久影院薰衣草 | 波多野结衣久久精品| 久久这里都是精品|