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

            天行健 君子當自強而不息

            創建3D圖形引擎(2)

             

            本篇是創建3D圖形引擎(1)的續篇,3D圖形引擎的代碼以創建游戲內核中編寫的代碼為基礎進行開發。

             

            下載源碼和工程

             

            視錐的介紹

            視錐(viewing frustum)是6個平面的集合,它從觀察點向外擴展,以確定某個多邊形是否能夠被觀察到。

            首先,可以將視錐看作是一個以觀察者開始擴展的金字塔,如下圖所示:

            這個金字塔代表了觀察范圍(field of viewFOV),位于觀察范圍內的物體是可見的,而位于觀察范圍外的物體則是不可見的。

            三維圖形引擎的每個物體都是由3D點(稱為頂點)構成的,每個視錐包含6個面(前、后、左、右、上、下)。通過一些數學計算,可以確定哪些頂點位于視錐內,哪些頂點位于視錐外。位于視錐內的頂點被渲染,而位于視錐外的頂點則不被渲染。同樣,當渲染多邊形時,只有那些在視錐內的頂點才被渲染。

             

            平面與裁剪

            視錐的6個側面被稱為剪切平面(clipping plane),Direct3D使用了一個名為D3DXPLANE的特定對象去包含平面數據,D3DXPLANE包含了4個變量:a、b、c、d,它們都是浮點型數據。

            定義好一個平面后,為它指定一個特定的方向,并將它從原點移到相應的位置。事實上,一個平面就是由一條法線以及它與原點的距離進行定義的,如下圖所示,它演示了一個平面在三維空間中的方位。

            不需要指定XYZ的具體數值,你只要使用變量AB、C,同時還有一個數值D來確定平面離原點的距離。為了定義一個平面,將A、B、C設置為法向量的值,這樣就可以使用一個平面去檢測指定的點位于平面的前面或者后面。
             

            為了計算視錐的6個平面,可以將當前的觀察變換矩陣和投影矩陣組合起來,然后使用組合矩陣直接計算每個平面的AB、C、D。

             

            平面可見性檢測

            為了檢測一個頂點位于平面的前方或后方,可以利用點積來計算,通過調用D3DXPlaneCoord函數來實現。

            Computes the dot product of a plane and a 3D vector. The w parameter of the vector is assumed to be 1.

            FLOAT D3DXPlaneDotCoord(
            CONST D3DXPLANE * pP,
            CONST D3DXVECTOR3 * pV
            );

            Parameters

            pP
            [in] Pointer to a source D3DXPLANE structure.
            pV
            [in] Pointer to a source D3DXVECTOR3 structure.

            Return Values

            The dot product of the plane and 3D vector.

            Remarks

            Given a plane (a, b, c, d) and a 3D vector (x, y, z) the return value of this function is a*x + b*y + c*z + d*1. The D3DXPlaneDotCoord function is useful for determining the plane's relationship with a coordinate in 3D space.

             

            完整視錐的檢測

            對于立方體和長方體,需檢測所有的拐角頂點。如果所有的頂點都位于任一平面之后,那么立方體或長方體就位于視錐之外(因而也在視野之外)。如果有任一頂點位于視錐之內,或者說位于任一平面前(也就是說不是所有的頂點都位于任一平面后),那就意味著立方體或者長方體是可見的。至于球體,只要它與每個平面的距離 等于或大于球形的平面,那么它就是可見的。

             

            FRUSTUM

            因為每次使用視錐所涉及的數學運算都是一樣的,所以完全可以創建一個類,讓它處理好數學方面的問題,包括創建視錐以及使用視錐去檢測一個物體是否可見等。

            //==============================================================================
            // This class encapsulate for frustum, judge whether other object is in frustum.
            //==============================================================================
            typedef class FRUSTUM
            {
            public:
                
            // Construct the six planes from current view and projection. 
                // Can override the default depth value.
                BOOL construct(GRAPHICS_PTR graphics, float z_distance = 0.0f);

                
            // The following functions check a single point, cube, rectangle, and sphere if 
                // contained in the frustum. A return value of TRUE means visible, FALSE not visible.
                // When checking cubes or rectangles, you can supply a BOOL variable that determines 
                // if all the points are in the frustum.

                BOOL check_point(
            float x_pos, float y_pos, float z_pos);

                BOOL check_cube(
            float x_center, float y_center, float z_center,
                                
            float radius,
                                BOOL* completely_contained = NULL);

                BOOL check_rectangle(
            float x_center, float y_center, float z_center,
                                     
            float x_radius, float y_radius, float z_radius,
                                     BOOL* completely_contained = NULL);

                BOOL check_sphere(
            float x_center, float y_center, float z_center,
                                  
            float radius);
                
            private:
                D3DXPLANE _planes[6];       
            // the frustum planes
            } *FRUSTUM_PTR;

            每當觀察或投影矩陣發生變化時,請調用construct去構造6個測試平面,如果僅希望最接近的物體能被看到,則可以為遠端剪切平面指定一個新的距離值。

            //----------------------------------------------------------------------------
            // Construct frustum.
            //----------------------------------------------------------------------------
            BOOL FRUSTUM::construct(GRAPHICS_PTR graphics, float z_distance)
            {
                D3DXMATRIX matrix, mat_view, mat_proj;

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

                
            // calculate FOV data
                graphics->get_device_com()->GetTransform(D3DTS_PROJECTION, &mat_proj);

                
            if(! float_equal(z_distance, 0.0f))
                {
                    
            // Calculate new projection matrix based on distance provided.
                    //
                    // projection matrix is:
                    // 
                    // | xScale     0          0               0 |
                    // | 0        yScale       0               0 |
                    // | 0          0       zf/(zf-zn)         1 |
                    // | 0          0       -zn*zf/(zf-zn)     0 |
                    //
                    // where:
                    //      yScale = cot(fovY/2)
                    //      xScale = yScale / aspect ratio

                    
            float z_min = -mat_proj._43 / mat_proj._33;
                    
            float q = z_distance / (z_distance - z_min);

                    mat_proj._33 = q;
                    mat_proj._43 = -q * z_min;
                }

                graphics->get_device_com()->GetTransform(D3DTS_VIEW, &mat_view);
                D3DXMatrixMultiply(&matrix, &mat_view, &mat_proj);

                
            // calculate the planes
                _planes[0].a = matrix._14 + matrix._13; // Near
                _planes[0].b = matrix._24 + matrix._23;
                _planes[0].c = matrix._34 + matrix._33;
                _planes[0].d = matrix._44 + matrix._43;
                D3DXPlaneNormalize(&_planes[0], &_planes[0]);

                _planes[1].a = matrix._14 - matrix._13; 
            // Far
                _planes[1].b = matrix._24 - matrix._23;
                _planes[1].c = matrix._34 - matrix._33;
                _planes[1].d = matrix._44 - matrix._43;
                D3DXPlaneNormalize(&_planes[1], &_planes[1]);

                _planes[2].a = matrix._14 + matrix._11; 
            // Left
                _planes[2].b = matrix._24 + matrix._21;
                _planes[2].c = matrix._34 + matrix._31;
                _planes[2].d = matrix._44 + matrix._41;
                D3DXPlaneNormalize(&_planes[2], &_planes[2]);

                _planes[3].a = matrix._14 - matrix._11; 
            // Right
                _planes[3].b = matrix._24 - matrix._21;
                _planes[3].c = matrix._34 - matrix._31;
                _planes[3].d = matrix._44 - matrix._41;
                D3DXPlaneNormalize(&_planes[3], &_planes[3]);

                _planes[4].a = matrix._14 - matrix._12; 
            // Top
                _planes[4].b = matrix._24 - matrix._22;
                _planes[4].c = matrix._34 - matrix._32;
                _planes[4].d = matrix._44 - matrix._42;
                D3DXPlaneNormalize(&_planes[4], &_planes[4]);

                _planes[5].a = matrix._14 + matrix._12; 
            // Bottom
                _planes[5].b = matrix._24 + matrix._22;
                _planes[5].c = matrix._34 + matrix._32;
                _planes[5].d = matrix._44 + matrix._42;
                D3DXPlaneNormalize(&_planes[5], &_planes[5]);

                
            return TRUE;
            }

            使用check系列函數判斷物體在視錐內是否可見。

            //----------------------------------------------------------------------------
            // Check one point whether in frustum.
            //----------------------------------------------------------------------------
            BOOL FRUSTUM::check_point(float x_pos, float y_pos, float z_pos)
            {
                
            // make sure point is in frustum
                for(short i = 0; i < 6; i++)
                {
                    
            if(D3DXPlaneDotCoord(&_planes[i], &D3DXVECTOR3(x_pos, y_pos, z_pos)) < 0.0f)
                        
            return FALSE;
                }

                
            return TRUE;
            }

            //----------------------------------------------------------------------------
            // Check whether a cube in frustum, if total cube in frustum then 
            // completely_contained will be set TRUE.
            //----------------------------------------------------------------------------
            BOOL FRUSTUM::check_cube(float x_center, float y_center, float z_center, 
                                     
            float radius, 
                                     BOOL* completely_contained)
            {
                DWORD num_points_in_frustum = 0;

                
            // count the number of points inside the frustum
                for(short i = 0; i < 6; i++)
                {
                    DWORD count = 8;
                    BOOL in_all_planes = TRUE;

                    
            // test all eight points against plane

                    
            if(D3DXPlaneDotCoord(&_planes[i], &D3DXVECTOR3(x_center - radius, y_center - radius, z_center - radius)) < 0.0f)
                    {
                        in_all_planes = FALSE;
                        count--;
                    }

                    
            if(D3DXPlaneDotCoord(&_planes[i], &D3DXVECTOR3(x_center + radius, y_center - radius, z_center - radius)) < 0.0f) 
                    {
                      in_all_planes = FALSE;
                      count--;
                    }

                    
            if(D3DXPlaneDotCoord(&_planes[i], &D3DXVECTOR3(x_center - radius, y_center + radius, z_center - radius)) < 0.0f) 
                    {
                      in_all_planes = FALSE;
                      count--;
                    }

                    
            if(D3DXPlaneDotCoord(&_planes[i], &D3DXVECTOR3(x_center + radius, y_center + radius, z_center - radius)) < 0.0f) 
                    {
                      in_all_planes = FALSE;
                      count--;
                    }

                    
            if(D3DXPlaneDotCoord(&_planes[i], &D3DXVECTOR3(x_center - radius, y_center - radius, z_center + radius)) < 0.0f) 
                    {
                      in_all_planes = FALSE;
                      count--;
                    }

                    
            if(D3DXPlaneDotCoord(&_planes[i], &D3DXVECTOR3(x_center + radius, y_center - radius, z_center + radius)) < 0.0f) 
                    {
                      in_all_planes = FALSE;
                      count--;
                    }

                    
            if(D3DXPlaneDotCoord(&_planes[i], &D3DXVECTOR3(x_center - radius, y_center + radius, z_center + radius)) < 0.0f) 
                    {
                      in_all_planes = FALSE;
                      count--;
                    }

                    
            if(D3DXPlaneDotCoord(&_planes[i], &D3DXVECTOR3(x_center + radius, y_center + radius, z_center + radius)) < 0.0f) 
                    {
                      in_all_planes = FALSE;
                      count--;
                    }

                    
            // if none contained, return FALSE.
                    if(count == 0)
                        
            return FALSE;

                    
            // update counter if they were all in front of plane.
                    if(in_all_planes)
                        ++num_points_in_frustum;
                }

                
            // store BOOL flag if completely contained
                if(completely_contained)
                    *completely_contained = (num_points_in_frustum == 6);

                
            return TRUE;
            }

            //----------------------------------------------------------------------------
            // Check whether a rectangle is in frustum, if total in then completely_contained
            // will be set TRUE.
            //----------------------------------------------------------------------------
            BOOL FRUSTUM::check_rectangle(float x_center, float y_center, float z_center, 
                                          
            float x_radius, float y_radius, float z_radius, 
                                          BOOL* completely_contained)
            {
                DWORD num_points_in_frustum = 0;

                
            // count the number of points inside the frustum
                for(short i = 0; i < 6; i++) 
                {
                    DWORD count = 8;
                    BOOL  in_all_planes = TRUE;
                    
                    
            // Test all eight points against plane

                    
            if(D3DXPlaneDotCoord(&_planes[i], 
                        &D3DXVECTOR3(x_center - x_radius, y_center - y_radius, z_center - z_radius)) < 0.0f) 
                    {
                      in_all_planes = FALSE;
                      count--;
                    }

                    
            if(D3DXPlaneDotCoord(&_planes[i], 
                        &D3DXVECTOR3(x_center + x_radius, y_center - y_radius, z_center - z_radius)) < 0.0f) 
                    {
                      in_all_planes = FALSE;
                      count--;
                    }

                    
            if(D3DXPlaneDotCoord(&_planes[i], 
                        &D3DXVECTOR3(x_center - x_radius, y_center + y_radius, z_center - z_radius)) < 0.0f) 
                    {
                      in_all_planes = FALSE;
                      count--;
                    }

                    
            if(D3DXPlaneDotCoord(&_planes[i], 
                        &D3DXVECTOR3(x_center + x_radius, y_center + y_radius, z_center - z_radius)) < 0.0f) 
                    {
                      in_all_planes = FALSE;
                      count--;
                    }

                    
            if(D3DXPlaneDotCoord(&_planes[i], 
                        &D3DXVECTOR3(x_center - x_radius, y_center - y_radius, z_center + z_radius)) < 0.0f) 
                    {
                      in_all_planes = FALSE;
                      count--;
                    }

                    
            if(D3DXPlaneDotCoord(&_planes[i], 
                        &D3DXVECTOR3(x_center + x_radius, y_center - y_radius, z_center + z_radius)) < 0.0f) 
                    {
                      in_all_planes = FALSE;
                      count--;
                    }

                    
            if(D3DXPlaneDotCoord(&_planes[i], 
                        &D3DXVECTOR3(x_center - x_radius, y_center + y_radius, z_center + z_radius)) < 0.0f) 
                    {
                      in_all_planes = FALSE;
                      count--;
                    }

                    
            if(D3DXPlaneDotCoord(&_planes[i], 
                        &D3DXVECTOR3(x_center + x_radius, y_center + y_radius, z_center + z_radius)) < 0.0f) 
                    {
                      in_all_planes = FALSE;
                      count--;
                    }

                    
            // If none contained, return FALSE
                    if(count == 0)
                      
            return FALSE;

                    
            // Update counter if they were all in front of plane
                    if(in_all_planes)
                        ++num_points_in_frustum;
                }

                
            // Store BOOL flag if completely contained
                if(completely_contained)
                    *completely_contained = (num_points_in_frustum == 6);

                
            return TRUE;
            }

            //----------------------------------------------------------------------------
            // Check whether a sphere is in frustum. 
            //----------------------------------------------------------------------------
            BOOL FRUSTUM::check_sphere(float x_center, float y_center, float z_center, 
                                       
            float radius)
            {
                
            // make sure radius is in frustum
                for(short i = 0; i < 6; i++)
                {
                    
            if(D3DXPlaneDotCoord(&_planes[i], &D3DXVECTOR3(x_center, y_center, z_center)) < -radius)
                        
            return FALSE;
                }

                
            return TRUE;
            }

            測試代碼:

            /************************************************************************************
            PURPOSE:
                frustum test.
            ************************************************************************************/


            #include "core_global.h"
            #include "frustum.h"

            #define MAX_OBJECTS 256

            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, "object clipping class");
                    strcpy(_caption, "object clipping 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);

                    
            // create a font
                    _font.create(&_graphics, "Arial", 16, TRUE, FALSE);

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

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

                    
            for(short i = 0; i < MAX_OBJECTS; i++)
                    {
                        _objects[i].create(&_graphics, &_mesh);

                        _objects[i].move((
            float) (rand() % 4000) - 2000.0f, 0.0f, (float) (rand() % 4000) - 2000.0f);
                    }

                    
            return TRUE;
                }

                BOOL frame()
                {
                    
            // read mouse data        
                    _mouse.read();

                    
            // position camera and rotate based on mouse position

                    _camera.move(0.0f, 100.0f, 0.0f);

                    
            // _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(_mouse.get_y_delta() / 200.0f, _mouse.get_x_delta() / 200.0f, 0.0f);

                    
            // set camera
                    _graphics.set_camera(&_camera);
                    
                    
            // render everything
                    _graphics.clear(D3DCOLOR_RGBA(0, 64, 128, 255));               

                    
            // begin render now
                    if(_graphics.begin_scene())
                    {
                        FRUSTUM frustum;
                        frustum.construct(&_graphics); 

                        
            long num_drawn = 0;

                        
            // render each object in frustums
                        for(short i = 0; i < MAX_OBJECTS; i++)
                        {
                            
            float radius;
                            
                            _objects[i].get_bounds(NULL, NULL, NULL, NULL, NULL, NULL, &radius);

                            
            if(frustum.check_sphere(_objects[i].get_x_pos(), _objects[i].get_y_pos(), _objects[i].get_z_pos(),
                                                    radius))
                            {
                                _objects[i].render();
                                num_drawn++;
                            }                
                        }

                        
            char stats[128];

                        
            // display statistics
                        sprintf(stats, "%lu of 256 objects drawn.", num_drawn);
                        _font.print(stats, 0, 0, 400, 100);
                            
                        _graphics.end_scene();
                    }

                    _graphics.display();

                    
            return TRUE;
                }

                BOOL shutdown()
                {
                    
            return TRUE;
                }

            private:  
                GRAPHICS        _graphics;
                CAMERA          _camera;
                FONT            _font;

                INPUT           _input;
                INPUT_DEVICE    _mouse;    

                MESH            _mesh;
                OBJECT          _objects[MAX_OBJECTS];
            };

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

                
            return app.run();
            }

            截圖:


            posted on 2007-10-19 19:59 lovedday 閱讀(1171) 評論(0)  編輯 收藏 引用

            公告

            導航

            統計

            常用鏈接

            隨筆分類(178)

            3D游戲編程相關鏈接

            搜索

            最新評論

            国内精品久久久久久久涩爱 | 久久久精品人妻无码专区不卡| 久久久精品免费国产四虎| 国产V亚洲V天堂无码久久久| 久久精品国产一区| 久久国产精品免费一区| 久久天天躁夜夜躁狠狠| 久久精品国产免费一区| 久久午夜福利电影| 日韩乱码人妻无码中文字幕久久| 国产V亚洲V天堂无码久久久| 久久天天躁狠狠躁夜夜2020老熟妇 | 精品国产91久久久久久久| 久久久国产精品| 麻豆AV一区二区三区久久| 久久99精品久久久久久秒播| 久久无码人妻一区二区三区午夜| 久久91精品国产91久久麻豆| 一本久久知道综合久久| 久久久噜噜噜久久中文字幕色伊伊| 人妻无码αv中文字幕久久| 狠狠久久综合伊人不卡| 久久99精品久久久久久动态图| 思思久久99热免费精品6| 久久国产精品-国产精品| 2020国产成人久久精品| 国产一区二区精品久久岳| 国产精品一久久香蕉产线看| 亚洲欧美日韩中文久久| 香蕉久久久久久狠狠色| 狠狠干狠狠久久| 国内精品伊人久久久久777| 国产香蕉久久精品综合网| 国产精品综合久久第一页| 蜜桃麻豆www久久| 国产成人综合久久综合| 成人资源影音先锋久久资源网| 精品久久久噜噜噜久久久 | 亚洲精品久久久www| 久久人人爽人人澡人人高潮AV| 欧美精品一区二区久久|