• <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)而不息

            創(chuàng)建3D圖形引擎(4)

             

            本篇是創(chuàng)建3D圖形引擎(3)的續(xù)篇,3D圖形引擎的代碼以創(chuàng)建游戲內(nèi)核中編寫的代碼為基礎(chǔ)進(jìn)行開發(fā)。

             

            下載源碼和工程

             

            將三維物體添加到世界中

            盲目地繪制成千的物體而沒有執(zhí)行任何的剪切,是導(dǎo)致在圖形-渲染通道中時(shí)間延遲的一個(gè)主要原因。需要再次使用視錐以快速確定哪些物體位于視野中,為了確定哪些物體是可見的,可將每個(gè)三維物體包圍到一個(gè)可見的球體中,稱之為框界球體(bounding sphere)。

            下圖演示了框界球體和視錐的運(yùn)用,它展示了一個(gè)場(chǎng)景,其中有三個(gè)物體和一個(gè)視錐,每個(gè)網(wǎng)格模型都有一個(gè)可見的框界球體圍繞著它。當(dāng)一個(gè)球體位于構(gòu)成視錐的6個(gè)平面前時(shí),它就被認(rèn)為是可見的。 可以看出僅兩個(gè)位于視錐中的物體是可見的,而另一個(gè)物體完全位于視錐外,繪制時(shí)能完全跳過那個(gè)位于視錐之外的物體。為了實(shí)現(xiàn)這一點(diǎn),必須計(jì)算每個(gè)物體的框界球體,然后檢測(cè)球體是否位于視錐之內(nèi)。

             

            網(wǎng)格模型的碰撞

            為了檢測(cè)一個(gè)多邊形是否堵塞了節(jié)點(diǎn)之間的路徑,可以在兩個(gè)節(jié)點(diǎn)發(fā)射一條想象中的射線,以檢測(cè)它們是否與一個(gè)平面相交。如下圖所示:

            有一個(gè)功能函數(shù)負(fù)責(zé)執(zhí)行交集的測(cè)試,以確保射線與平面的相交點(diǎn)位于多邊形內(nèi),并給出那個(gè)相交點(diǎn)的確切坐標(biāo),同時(shí)顯示從射線的開始點(diǎn)到相交點(diǎn)的距離長(zhǎng)度,它是一個(gè)非常有用的功能函數(shù)。

            Determines if a ray intersects with a mesh.

            HRESULT D3DXIntersect(
            LPD3DXBASEMESH pMesh,
            CONST D3DXVECTOR3 * pRayPos,
            CONST D3DXVECTOR3 * pRayDir,
            BOOL * pHit,
            DWORD * pFaceIndex,
            FLOAT * pU,
            FLOAT * pV,
            FLOAT * pDist,
            LPD3DXBUFFER * ppAllHits,
            DWORD * pCountOfHits
            );

            Parameters

            pMesh
            [in] Pointer to an ID3DXBaseMesh interface, representing the mesh to be tested.
            pRayPos
            [in] Pointer to a D3DXVECTOR3 structure, specifying the point where the ray begins.
            pRayDir
            [in] Pointer to a D3DXVECTOR3 structure, specifying the direction of the ray.
            pHit
            [out] Pointer to a BOOL. If the ray intersects a triangular face on the mesh, this value will be set to TRUE. Otherwise, this value is set to FALSE.
            pFaceIndex
            [out] Pointer to an index value of the face closest to the ray origin, if pHit is TRUE.
            pU
            [out] Pointer to a barycentric hit coordinate, U.
            pV
            [out] Pointer to a barycentric hit coordinate, V.
            pDist
            [out] Pointer to a ray intersection parameter distance.
            ppAllHits
            [out] Pointer to an ID3DXBuffer object, containing an array of D3DXINTERSECTINFO structures.
            pCountOfHits
            [out] Pointer to a DWORD that contains the number of entries in the ppAllHits array.

            Return Values

            If the function succeeds, the return value is D3D_OK. If the function fails, the return value can be: E_OUTOFMEMORY.

            Remarks

            The D3DXIntersect function provides a way to understand points in and around a triangle, independent of where the triangle is actually located. This function returns the resulting point by using the following equation: V1 + U(V2 - V1) + V(V3 - V1).

            Any point in the plane V1V2V3 can be represented by the barycentric coordinate (U,V). The parameter U controls how much V2 gets weighted into the result, and the parameter V controls how much V3 gets weighted into the result. Lastly, the value of [1 - (U + V)] controls how much V1 gets weighted into the result.

            Barycentric coordinates are a form of general coordinates. In this context, using barycentric coordinates represents a change in coordinate systems. What holds true for Cartesian coordinates holds true for barycentric coordinates.

            Barycentric coordinates define a point inside a triangle in terms of the triangle's vertices. For a more in-depth description of barycentric coordinates, see Mathworld's Barycentric Coordinates Description.

            我們編寫一個(gè)函數(shù)來檢測(cè)一條線段是否與一個(gè)網(wǎng)格中的三角形面相交。

            //------------------------------------------------------------------------------
            // Check if a polygon blocks path from start to end.
            //------------------------------------------------------------------------------
            BOOL is_ray_intersect_mesh(LPD3DXBASEMESH mesh,
                                       
            float x_start, float y_start, float z_start,
                                       
            float x_end, float y_end, float z_end,
                                       
            float* distance)
            {
                
            float x_diff, y_diff, z_diff;

                x_diff = x_end - x_start;
                y_diff = y_end - y_start;
                z_diff = z_end - z_start;

                D3DXVECTOR3 ray_pos(x_start, y_start, z_start);

                D3DXVECTOR3 ray_dir;
                D3DXVec3Normalize(&ray_dir, &D3DXVECTOR3(x_diff, y_diff, z_diff));

                BOOL is_hit;
                
            float u, v, dist;
                DWORD face_index;

                
            // determins if a ray intersects with a mesh
                D3DXIntersect(mesh, &ray_pos, &ray_dir, &is_hit, &face_index, &u, &v, &dist, NULL, NULL);

                
            if(is_hit)
                {
                    
            float ray_length = (float) sqrt(x_diff * x_diff + y_diff * y_diff + z_diff * z_diff);

                    
            if(dist > ray_length)
                        
            return FALSE;
                    
            else
                    {
                        
            if(distance != NULL)
                            *distance = dist;
                    }
                }

                
            return TRUE;
            }

            在一個(gè)多邊形層次中運(yùn)用碰撞檢測(cè)的另一個(gè)好處就是可以使物體隨著其下多邊形變化的高度而變化。換句話說,可以使物體永遠(yuǎn)在多邊形上移動(dòng),這樣就能在一個(gè)三維建模軟件里繪制層次,而不用定義哪些區(qū)域是物體可以“行走”的,因?yàn)槎噙呅尉褪悄切﹨^(qū)域,這使得四叉樹和八叉樹網(wǎng)格模型的處理更加容易。

            可通過下面這三個(gè)函數(shù)來執(zhí)行物體與多邊形的相交測(cè)試:

            //------------------------------------------------------------------------------
            // Get closest height above or below point.
            //------------------------------------------------------------------------------
            float get_closest_height(LPD3DXBASEMESH mesh, float x_pos, float y_pos, float z_pos)
            {
                
            float y_above, y_below;

                y_above = get_closest_height_above(mesh, x_pos, y_pos, z_pos);
                y_below = get_closest_height_below(mesh, x_pos, y_pos, z_pos);

                
            if(fabs(y_above - y_pos) < fabs(y_below - y_pos))
                    
            return y_above;

                
            return y_below;
            }

            //------------------------------------------------------------------------------
            // Get closet height below point.
            //------------------------------------------------------------------------------
            float get_closest_height_below(LPD3DXBASEMESH mesh, float x_pos, float y_pos, float z_pos)
            {
                BOOL is_hit;
                
            float u, v, dist;
                DWORD face_index;

                D3DXVECTOR3 ray_pos(x_pos, y_pos, z_pos);
                D3DXVECTOR3 ray_dir(0.0f, -1.0f, 0.0f);

                D3DXIntersect(mesh, &ray_pos, &ray_dir, &is_hit, &face_index, &u, &v, &dist, NULL, NULL);

                
            if(is_hit)
                    
            return y_pos - dist;

                
            return y_pos;
            }

            //------------------------------------------------------------------------------
            // Get closet height above point.
            //------------------------------------------------------------------------------
            float get_closest_height_above(LPD3DXBASEMESH mesh, float x_pos, float y_pos, float z_pos)
            {
                BOOL is_hit;
                
            float u, v, dist;
                DWORD face_index;

                D3DXVECTOR3 ray_pos(x_pos, y_pos, z_pos);
                D3DXVECTOR3 ray_dir(0.0f, 1.0f, 0.0f);

                D3DXIntersect(mesh, &ray_pos, &ray_dir, &is_hit, &face_index, &u, &v, &dist, NULL, NULL);

                
            if(is_hit)
                    
            return y_pos + dist;

                
            return y_pos;
            }

            為了方便,在NODE_TREE_MESH類中繼續(xù)封裝這些函數(shù):

            //------------------------------------------------------------------------------
            // Get closest height above or below point.
            //------------------------------------------------------------------------------
            float NODE_TREE_MESH::get_closest_height(float x_pos, float y_pos, float z_pos)
            {
                
            return ::get_closest_height(m_root_mesh->m_mesh, x_pos, y_pos, z_pos);
            }

            //------------------------------------------------------------------------------
            // Get closest height below point.
            //------------------------------------------------------------------------------
            float NODE_TREE_MESH::get_closest_height_below(float x_pos, float y_pos, float z_pos)
            {
                
            return ::get_closest_height_below(m_root_mesh->m_mesh, x_pos, y_pos, z_pos);
            }

            //------------------------------------------------------------------------------
            // Get closest height above point.
            //------------------------------------------------------------------------------
            float NODE_TREE_MESH::get_closest_height_above(float x_pos, float y_pos, float z_pos)
            {
                
            return ::get_closest_height_above(m_root_mesh->m_mesh, x_pos, y_pos, z_pos);
            }

            //------------------------------------------------------------------------------
            // Check if a polygon blocks path from start to end.
            //------------------------------------------------------------------------------
            BOOL NODE_TREE_MESH::is_ray_intersect_mesh(float x_start, float y_start, float z_start,
                                                 
            float x_end, float y_end, float z_end,
                                                 
            float* distance)
            {
                
            return ::is_ray_intersect_mesh(m_root_mesh->m_mesh, 
                                         x_start, y_start, z_start,
                                         x_end, y_end, z_end,
                                         distance);
            }

             

            當(dāng)網(wǎng)格模型發(fā)生碰撞時(shí)

            除了檢測(cè)物體網(wǎng)格模型與構(gòu)造世界的網(wǎng)格模型之間的碰撞,還需要知道較小網(wǎng)格模型碰撞的情況。舉個(gè)例子,如果不希望角色穿透其他的角色,就需要結(jié)合物體和物體之間(object-to-object)的碰撞檢測(cè)。進(jìn)行操作前需要了解一些事情,包括框界球體使用的知識(shí)。如下圖所示,其顯示了兩個(gè)怪物,它們都有長(zhǎng)長(zhǎng)的尾巴,那些尾巴影響了網(wǎng)格模型的框界球體的整體尺寸,為了包圍住整個(gè)網(wǎng)格模型(包括尾巴),球體將會(huì)很大。如果將這兩個(gè)怪物移動(dòng)到下圖所示的位置,會(huì)看到這兩個(gè)框界球體相交,但怪物并沒有那么靠近。

            盡管有許多辦法解決大型框界球體問題,但有一種快速執(zhí)行的方法。取代使用網(wǎng)格模型的框界球體,而是為每個(gè)網(wǎng)格模型計(jì)算自己的框界球體半徑,通過計(jì)算框界球體的半徑,可以快速調(diào)節(jié)它以覆蓋網(wǎng)格模型確實(shí)需要的空間。

            我們編寫一個(gè)函數(shù)來檢測(cè)兩個(gè)框界球體是否相交:

            //------------------------------------------------------------------------------
            // Check if two spheres intersect.
            //------------------------------------------------------------------------------
            BOOL is_tow_sphere_intersect(float x_center_1, float y_center_1, float z_center_1,
                                         
            float radius1,
                                         
            float x_center_2, float y_center_2, float z_center_2,
                                         
            float radius2)
            {
                
            float x_diff, y_diff, z_diff, dist;
                
                
            // calculate distance between two sphere center]
                
                x_diff = fabs(x_center_2 - x_center_1);
                y_diff = fabs(y_center_2 - y_center_1);
                z_diff = fabs(z_center_2 - z_center_1);

                dist = (
            float) sqrt(x_diff * x_diff + y_diff * y_diff + z_diff * z_diff); 

                
            // if two spheres intersect, retuen TRUE.
                if(dist <= radius1 + radius2)
                    
            return TRUE;

                
            return FALSE;
            }

             

            天框的使用

            天框(sky box)是一種圍繞觀察者進(jìn)行紋理映射的三維立方體的圖形技術(shù),渲染一個(gè)天框時(shí),觀察點(diǎn)總是定于中心位置,以便用戶始終能夠看到方框內(nèi)部紋理映射的表面,這種技術(shù)能夠制造出一種世界圍繞用戶的效果,如下圖所示:

            天框是非常容易是實(shí)現(xiàn),只需一個(gè)立方體網(wǎng)格模型(其表面朝向里面)即可,通過一個(gè)頂點(diǎn)緩沖區(qū)存儲(chǔ)立方體網(wǎng)格模型會(huì)非常不錯(cuò)。至于紋理,可以使用多達(dá)6個(gè)的紋理,每個(gè)表面一個(gè)紋理。網(wǎng)格模型并不需要很大,僅20.0單元大小的立方體就行了。紋理大小應(yīng)該為256 x 256或者更高,較小的紋理將出現(xiàn)拉伸而且不生動(dòng)。

             

            創(chuàng)建一個(gè)天框類

            SKY_BOX負(fù)責(zé)控制天框的每個(gè)方面,從創(chuàng)建渲染盒子所使用的頂點(diǎn)緩沖區(qū),到渲染時(shí)所使用的紋理。

            定義:

            enum SKY_BOX_SIDES  { TOP = 0, BOTTOM, LEFT, RIGHT, FRONT, BACK };

            //=====================================================================================
            // This calss encapsulate how to make sky box.
            //=====================================================================================
            typedef class SKY_BOX
            {
            private:
                typedef 
            struct SKY_BOX_VERTEX
                {
                    
            float x, y, z;
                    
            float u, v;
                } *SKY_BOX_VERTEX_PTR;

                
            #define SKY_BOX_FVF (D3DFVF_XYZ | D3DFVF_TEX1)

            private:
                GRAPHICS_PTR    m_graphics;         
            // parent GRAPHICS object
                TEXTURE         m_textures[6];      // face texture (0 - 5)
                VERTEX_BUFFER   m_vertex_buffer;    // mesh vertex buffer
                WORLD_POSITION  m_pos;              // sky box position

            public:
                SKY_BOX();
                ~SKY_BOX();

                BOOL create(GRAPHICS_PTR graphics);
                
            void free();

                BOOL load_texture(
            short side, pcstr filename, D3DCOLOR transparent = 0, D3DFORMAT format = D3DFMT_UNKNOWN);

                
            void rotate(float x_rot, float y_rot, float z_rot);
                
            void rotate_rel(float x_rot, float y_rot, float z_rot);

                BOOL render(CAMERA_PTR camera, BOOL alpha_blend = FALSE);
            } *SKY_BOX_PTR;

            實(shí)現(xiàn):

            //----------------------------------------------------------------------------------
            // Constructor, initialize member data.
            //----------------------------------------------------------------------------------
            SKY_BOX::SKY_BOX()
            {
                m_graphics = NULL;
            }

            //----------------------------------------------------------------------------------
            // Destructor, release allocated resource.
            //----------------------------------------------------------------------------------
            SKY_BOX::~SKY_BOX()
            {
                free();
            }

            //----------------------------------------------------------------------------------
            // Release allocated resource.
            //----------------------------------------------------------------------------------
            void SKY_BOX::free()
            {
                m_graphics = NULL;

                
            for(short i = 0; i < 6; i++)
                    m_textures[i].free();

                m_vertex_buffer.free();
            }

            //----------------------------------------------------------------------------------
            // Create a sky box class object.
            //----------------------------------------------------------------------------------
            BOOL SKY_BOX::create(GRAPHICS_PTR graphics)
            {
                SKY_BOX_VERTEX verts[24] = {
                    { -10.0f,  10.0f, -10.0f, 0.0f, 0.0f },  
            // Top
                    {  10.0f,  10.0f, -10.0f, 1.0f, 0.0f },
                    { -10.0f,  10.0f,  10.0f, 0.0f, 1.0f },
                    {  10.0f,  10.0f,  10.0f, 1.0f, 1.0f },

                    { -10.0f, -10.0f,  10.0f, 0.0f, 0.0f },  
            // Bottom
                    {  10.0f, -10.0f,  10.0f, 1.0f, 0.0f },
                    { -10.0f, -10.0f, -10.0f, 0.0f, 1.0f },
                    {  10.0f, -10.0f, -10.0f, 1.0f, 1.0f },

                    { -10.0f,  10.0f, -10.0f, 0.0f, 0.0f },  
            // Left
                    { -10.0f,  10.0f,  10.0f, 1.0f, 0.0f },
                    { -10.0f, -10.0f, -10.0f, 0.0f, 1.0f },
                    { -10.0f, -10.0f,  10.0f, 1.0f, 1.0f },

                    {  10.0f,  10.0f,  10.0f, 0.0f, 0.0f },  
            // Right
                    {  10.0f,  10.0f, -10.0f, 1.0f, 0.0f },
                    {  10.0f, -10.0f,  10.0f, 0.0f, 1.0f },
                    {  10.0f, -10.0f, -10.0f, 1.0f, 1.0f },

                    { -10.0f,  10.0f,  10.0f, 0.0f, 0.0f },  
            // Front
                    {  10.0f,  10.0f,  10.0f, 1.0f, 0.0f },
                    { -10.0f, -10.0f,  10.0f, 0.0f, 1.0f },
                    {  10.0f, -10.0f,  10.0f, 1.0f, 1.0f },
                    
                    {  10.0f,  10.0f, -10.0f, 0.0f, 0.0f },  
            // Back
                    { -10.0f,  10.0f, -10.0f, 1.0f, 0.0f },
                    {  10.0f, -10.0f, -10.0f, 0.0f, 1.0f },
                    { -10.0f, -10.0f, -10.0f, 1.0f, 1.0f },
                };

                free();     
            // free a prior sky box

                // error checking
                if((m_graphics = graphics) == NULL)
                    
            return FALSE;

                
            // create the vertex buffer (and copy over sky box vertices)
                if(m_vertex_buffer.create(m_graphics, 24, sizeof(SKY_BOX_VERTEX), SKY_BOX_FVF))
                    m_vertex_buffer.
            set(0, 24, (void*)verts);

                
            // rotate the sky box into default orientation
                rotate(0.0f, 0.0f, 0.0f);

                
            return TRUE;
            }

            //----------------------------------------------------------------------------------
            // Set a specific side's texture map, allow for transparent and storage format changes.
            //----------------------------------------------------------------------------------
            BOOL SKY_BOX::load_texture(short side, pcstr filename, D3DCOLOR transparent, D3DFORMAT format)
            {
                
            // error checking
                if(m_graphics == NULL || side < 0 || side > 5)
                    
            return FALSE;

                m_textures[side].free();    
            // free prior texture

                
            return m_textures[side].load(m_graphics, filename, transparent, format);
            }

            //----------------------------------------------------------------------------------
            // Rotate box to an absolute rotation.
            //----------------------------------------------------------------------------------
            void SKY_BOX::rotate(float x_rot, float y_rot, float z_rot)
            {
                m_pos.rotate(x_rot, y_rot, z_rot);
            }

            //----------------------------------------------------------------------------------
            // Rotate box to an relative rotation.
            //----------------------------------------------------------------------------------
            void SKY_BOX::rotate_rel(float x_rot, float y_rot, float z_rot)
            {
                m_pos.rotate_rel(x_rot, y_rot, z_rot);
            }

            //----------------------------------------------------------------------------------
            // Render the sky box (using optional alpha-blending) and using current view 
            // transformation from Camera.
            //----------------------------------------------------------------------------------
            BOOL SKY_BOX::render(CAMERA_PTR camera, BOOL alpha_blend)
            {
                
            // error checking
                if(m_graphics == NULL || camera == NULL)
                    
            return FALSE;

                
            // position sky box around viewer
                m_pos.move(camera->get_x_pos(), camera->get_y_pos(), camera->get_z_pos());
                m_graphics->set_world_position(&m_pos);

                
            // enable alpha testing and alpha blending

                m_graphics->enable_alpha_blending(TRUE);

                
            if(alpha_blend)
                    m_graphics->enable_alpha_blending(TRUE, D3DBLEND_SRCCOLOR, D3DBLEND_DESTCOLOR);

                
            // draw each layer
                for(short i = 0; i < 6; i++)
                {
                    
            if(m_textures[i].is_loaded())
                    {
                        m_graphics->set_texture(0, &m_textures[i]);
                        m_vertex_buffer.render(i * 4, 2, D3DPT_TRIANGLESTRIP);
                    }
                }

                
            // disable alpha testing and alpha blending

                m_graphics->enable_alpha_blending(FALSE);

                
            if(alpha_blend)
                    m_graphics->enable_alpha_blending(FALSE);

                
            return TRUE;
            }

            測(cè)試代碼:

            /************************************************************************************
            PURPOSE:
                 node tree mesh test.
            ************************************************************************************/


            #include "core_global.h"
            #include "frustum.h"
            #include "node_tree.h"
            #include "sky_box.h"

            class APP : public APPLICATION
            {
            public:
                APP()
                {
                    _width  = 640;
                    _height = 480;
                    
                    APPLICATION::_x_pos = (get_screen_width()  - _width) / 2;
                    APPLICATION::_y_pos = (get_screen_height() - _height) / 4;

                    _style = WS_BORDER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;

                    strcpy(_class_name, "node tree class");
                    strcpy(_caption, "node tree demo");
                }

                BOOL init()
                {
                    
            // initialize graphics and set display mode
                    _graphics.init();
                    _graphics.set_mode(get_hwnd(), TRUE, TRUE);
                    _graphics.set_perspective(D3DX_PI / 4, 1.3333f, 1.0f, 10000.0f);

                    show_mouse(TRUE);
                
                    
            // enable lighting and setup light

                    _graphics.enable_lighting(TRUE);
                    _graphics.set_ambient_light(24, 24, 24);
                    _graphics.enable_light(0, TRUE);
                    
                    _light.set_attenuation_0(0.4f);
                    _light.set_range(1000.0f);

                    
            // initialize input and input device
                    _input.init(get_hwnd(), get_inst());
                    _keyboard.create(&_input, KEYBOARD);
                    _mouse.create(&_input, MOUSE, TRUE);

                    
            // load the mesh and create a nodetree mesh from it

                    
            if(! _mesh.load(&_graphics, "..\\Data\\Level.x", "..\\Data\\"))
                        
            return FALSE;

                    _node_tree_mesh.create(&_graphics, &_mesh, QUADTREE);

                    
            // position view at origin
                    _x_pos = _y_pos = _z_pos = 0.0f;

                    
            // setup sky box
                    _sky_box.create(&_graphics);

                    
            for(short i = 0; i < 6; i++)
                        _sky_box.load_texture(i, "..\\data\\stars.bmp");

                    
            // initialize the sound system to play with
                    _sound.init(get_hwnd());
                    _sound_data.load_wav("..\\data\\cricket.wav");

                    
            for(short i = 0; i < 3; i++)
                        _sound_channel[i].create(&_sound, &_sound_data);

                    
            return TRUE;
                }

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

                    
            // play a random cricket sound
                    for(short i = 0; i< 3; i++)
                    {
                        
            if(!_sound_channel[i].is_playing() && rand()%256 < 16)
                            _sound_channel[i].play(&_sound_data, 10);
                    }

                    
            // calculate elapsed time (plus speed boost)
                    ulong time_elapsed = timeGetTime() - time_now;
                    time_now = timeGetTime();

                    
            // read keyboard and mouse data        
                    _keyboard.read();
                    _mouse.read();

                    
            // process input and update everything, ESC quits program.

                    
            if(_keyboard.get_key_state(KEY_ESC))
                        
            return FALSE;

                    
            float x_move, z_move;

                    
            // process movement
                    x_move = z_move = 0.0f;

                    
            if(_keyboard.get_key_state(KEY_UP) || _keyboard.get_key_state(KEY_W))
                    {
                        x_move = (
            float) sin(_camera.get_y_rotation()) * time_elapsed;
                        z_move = (
            float) cos(_camera.get_y_rotation()) * time_elapsed;
                    }
                    
                    
            if(_keyboard.get_key_state(KEY_DOWN) || _keyboard.get_key_state(KEY_S))
                    {
                        x_move = (
            float) -sin(_camera.get_y_rotation()) * time_elapsed;
                        z_move = (
            float) -cos(_camera.get_y_rotation()) * time_elapsed;
                    }

                    
            if(_keyboard.get_key_state(KEY_LEFT) || _keyboard.get_key_state(KEY_A))
                    {
                        x_move = (
            float) sin(_camera.get_y_rotation() - 1.57f) * time_elapsed;
                        z_move = (
            float) cos(_camera.get_y_rotation() - 1.57f) * time_elapsed;
                    }

                    
            if(_keyboard.get_key_state(KEY_RIGHT) || _keyboard.get_key_state(KEY_D))
                    {
                        x_move = (
            float) sin(_camera.get_y_rotation() + 1.57f) * time_elapsed;
                        z_move = (
            float) cos(_camera.get_y_rotation() + 1.57f) * time_elapsed;
                    }

                    
            // check for height changes (can step up to 64 units)
                    float height = _node_tree_mesh.get_closest_height_below(_x_pos, _y_pos + _above_floor, _z_pos);

                    
            if(_y_pos > height)
                    {
                        
            // dropping
                        if((_y_pos -= (float)time_elapsed) < height)
                            _y_pos = height;
                        
            else
                            x_move = z_move = 0.0f;
                    }
                    
            else
                    {
                        
            // climbing
                        _y_pos = height;
                    }

                    
            float dist;

                    
            // check for movement collision - can not walk past anything blocking path.
                    if(_node_tree_mesh.is_ray_intersect_mesh(_x_pos, _y_pos + _above_floor, _z_pos,
                                                             _x_pos + x_move, _y_pos + _above_floor, _z_pos + z_move,
                                                             &dist))
                    {
                        
            // adjust coordinates to be exactly 2.5 units away from target

                        
            float diff = dist - 2.5f;

                        D3DXVECTOR2 dir;
                        D3DXVec2Normalize(&dir, &D3DXVECTOR2(x_move, z_move));

                        dir *= diff;

                        x_move = dir.x;
                        z_move = dir.y;
                    }

                    
            // update view coordinats
                    _x_pos += x_move;
                    _z_pos += z_move;

                    
            // position camera and rotate based on mouse position

                    _camera.move(_x_pos, _y_pos + 50.0f, _z_pos);

                    
            // _mouse.get_y_delta():
                    //      get mouse's relative x movement coordinate.
                    //
                    // _mouse.get_x_delta():
                    //      get mouse's relative y movement coordinate.
                    _camera.rotate_rel((float) _mouse.get_y_delta() / 200.0f, (float) _mouse.get_x_delta() / 200.0f, 0.0f);

                    
            // position
                    _light.move(_x_pos, _y_pos + 60.0f, _z_pos);
                    _graphics.set_light(0, &_light);

                    FRUSTUM frustum;

                    
            // set camera and calculate frustum       
                    _graphics.set_camera(&_camera);
                    frustum.construct(&_graphics);
                    
                    
            // render everything
                    _graphics.clear_zbuffer(1.0f);               

                    
            // begin render now
                    if(_graphics.begin_scene())
                    {
                        _graphics.enable_zbuffer(FALSE);
                        _graphics.enable_lighting(FALSE);
                        _sky_box.render(&_camera);

                        _graphics.enable_zbuffer(TRUE);
                        _graphics.enable_lighting(TRUE);
                        _node_tree_mesh.render(&frustum);

                        _graphics.end_scene();
                    }

                    _graphics.display();

                    
            return TRUE;
                }

                BOOL shutdown()
                {
                    
            return TRUE;
                }

            private:  
                GRAPHICS        _graphics;
                CAMERA          _camera;
                LIGHT           _light;

                SOUND           _sound;
                SOUND_DATA      _sound_data;
                SOUND_CHANNEL   _sound_channel[3];

                SKY_BOX         _sky_box;

                INPUT           _input;
                INPUT_DEVICE    _keyboard;
                INPUT_DEVICE    _mouse;    

                MESH            _mesh;
                NODE_TREE_MESH  _node_tree_mesh;

                
            float           _x_pos, _y_pos, _z_pos;
                
                
            static const float _above_floor;
            };

            const float APP::_above_floor = 64.0f;

            int WINAPI WinMain(HINSTANCE inst, HINSTANCE, LPSTR cmd_line, int cmd_show)
            {
                APP app;

                
            return app.run();
            }

            截圖:






            posted on 2007-10-24 18:57 lovedday 閱讀(1516) 評(píng)論(1)  編輯 收藏 引用

            評(píng)論

            # re: 創(chuàng)建3D圖形引擎(4)[未登錄] 2009-04-16 22:41 cloud

            你寫的文章都挺不錯(cuò)的,至少我收獲不少,期待下一編。。。  回復(fù)  更多評(píng)論   


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


            公告

            導(dǎo)航

            統(tǒng)計(jì)

            常用鏈接

            隨筆分類(178)

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

            搜索

            最新評(píng)論

            中文字幕无码免费久久| 丁香五月网久久综合| 久久人做人爽一区二区三区| 欧美伊人久久大香线蕉综合| 久久久久久久久无码精品亚洲日韩 | 77777亚洲午夜久久多人| 一本色道久久88—综合亚洲精品 | 久久久久亚洲AV无码麻豆| 欧美激情精品久久久久| 久久久久人妻一区二区三区| 国产V综合V亚洲欧美久久| 国产精品久久久久蜜芽| 国产成人99久久亚洲综合精品 | 久久精品人妻中文系列| 99久久国产免费福利| 久久亚洲AV成人无码电影| 久久青青国产| 国产精品免费久久久久久久久 | 久久精品人人做人人爽电影蜜月| 久久综合久久鬼色| 青青草国产精品久久| 精品无码久久久久国产| 久久国产精品无| 青青热久久国产久精品| 久久久久久国产精品美女| 97精品久久天干天天天按摩| 亚洲国产欧洲综合997久久| 一级a性色生活片久久无少妇一级婬片免费放| 久久精品人人做人人爽97| 亚洲色大成网站www久久九| 亚洲国产日韩欧美综合久久| 久久天天躁狠狠躁夜夜av浪潮| 国产精品久久久久久福利漫画| 久久精品人人做人人妻人人玩| 亚洲愉拍99热成人精品热久久| 久久精品国产亚洲AV忘忧草18| 久久久精品国产| 国产成人无码精品久久久性色| 久久午夜无码鲁丝片秋霞 | 久久久久亚洲国产| 久久久亚洲欧洲日产国码是AV|