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

            天行健 君子當自強而不息

            D3D中的光照(1)

            為了提高場景的真實性,我們可以為其加入燈光。燈光也能幫助表現物體的立體感以及物體的實體形狀。當使用燈光時,我們不再自己指定頂點的顏色;Direct3D中每個頂點都通過燈光引擎來計算頂點顏色,該計算是基于定義的燈光資源,材質以及燈光資源關心的表面方向。通過燈光模型計算頂點顏色會得到更真實的場景。

            5.1燈光的組成

                   在Direct3D燈光模型中,燈光是通過燈光資源的三個成員之一來照射的,即有三種燈光。

            環境光(Ambient Light)——這種類型的燈光將被其他所有表面反射且被用在照亮整個場景。例如,物體的各部分都被照亮,對于一個角度,甚至穿過不在光源直接照射的地方他們都能被照亮。環境光的使用是粗略的,便宜的,它模仿反射光。

            漫反射(Diffuse Reflection)——這種燈光按照特殊方向傳播。當它照射到一個表面,它將在所有方向上均勻的反射。因為漫射光在所有方向上都均勻的反射,被反射的光線將到達眼睛而與觀察點無關,因此我們不必為觀察者考慮。因而,漫射光僅僅需要考慮燈光方向和表面的朝向。這種燈光將成為你的資源中照射的普通燈光。

            鏡面反射(Specular Reflection)——這種燈光按照特殊方向傳播。當它照射到一個表面時,它嚴格地按照一個方向反射。這將產生一個明亮的光澤,它能在某角度被看見。因為這種燈光在一個方向反射。明顯的觀察點,必須考慮燈光的方向和表面朝向,且必須按照鏡面燈光等式來考慮。鏡面燈光被用在物體上產生高光的地方,這種光澤只有在燈光照射在磨光的表面上才會產生。

            鏡面光比其他燈光類型要求更多的計算;因此,Direct3D提供了一個開關選擇。實際上,它默認是被關閉的;要使用鏡面光你必須設置D3DRS_SPECULARENABLE渲染狀態。

            Device->SetRenderState(D3DRS_SPECULARENABLE, true);

            每一種燈光都是通過D3DCOLORVALUE結構或者描述燈光顏色的D3DXCOLOR來描繪的。這里有幾個燈光顏色的例子:

            D3DXCOLOR redAmbient(1.0f, 0.0f, 0.0f, 1.0f);

            D3DXCOLOR blueDiffuse(0.0f, 0.0f, 1.0f, 1.0f);

            D3DXCOLOR whiteSpecular(1.0f, 1.0f, 1.0f, 1.0f);

            注意:在D3DXCOLOR類中的alpha值用在描述燈光顏色時是被忽略的。

            5.2材質

            在現實世界中我們看到的物體顏色將由物體反射回來的燈光顏色來決定。比如,一個紅色的球是紅色的,因為它吸收所有的燈光顏色除了紅色光。紅色光是被球反射回來進入我們眼睛的,因此我們看到的球是紅色的。Direct3D通過我們定義的物體材質來模擬這些所有的現象。材質允許我們定義表面反射燈光的百分比。在代碼中通過D3DMATERIAL9結構描述一個材質。

            typedef struct _D3DMATERIAL9 {

                   D3DCOLORVALUE Diffuse, Ambient, Specular, Emissive;

                   float Power;

            } D3DMATERIAL9;

            Diffuse——指定此表面反射的漫射光數量。

            Ambient——指定此表面反射的環境光數量。

            Specular——指定此表面反射的鏡面光數量

            Emissive——這個是被用來給表面添加顏色,它使得物體看起來就象是它自己發出的光一樣。

            Power——指定銳利的鏡面高光;它的值是高光的銳利值。

            舉例,想得到一個紅色的球。我們將定義球的材質來只反射紅光吸收其他顏色的所有光:

            D3DMATERIAL9 red;

            ::ZeroMemory(&red, sizeof(red));

            red.Diffuse = D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f); // red

            red.Ambient = D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f); // red

            red.Specular = D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f); // red

            red.Emissive = D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f); // no emission

            red.Power = 5.0f;

            這里我們設置綠色和藍色的值為0,這表明材質反射0%此顏色的光。我們設置紅色為1,表示材質反射100%的紅光。注意,我們能夠控制每種燈光反射的顏色(環境、漫射和鏡面光)。

             

            同樣假如我們定義一個只發出藍色光的光源,對球的光照將失敗因為藍色光將被全部吸收而沒有紅光被反射。當物體吸收了所有光以后,物體看起來就為黑色。同樣的,當物體反射100%的紅、綠和藍光,物體就將呈現為白色。

            因為手工填充一個材質結構將是乏味的工作,我們添加下列有用的函數和全局材質常數到d3dUtility.h/cpp文件中:

            // lights
            D3DLIGHT9 init_directional_light(D3DXVECTOR3* direction, D3DXCOLOR* color);
            D3DLIGHT9 init_point_light(D3DXVECTOR3
            * position, D3DXCOLOR* color);
            D3DLIGHT9 init_spot_light(D3DXVECTOR3
            * position, D3DXVECTOR3* direction, D3DXCOLOR* color);

            // materials
            D3DMATERIAL9 init_material(D3DXCOLOR ambient, D3DXCOLOR diffuse, D3DXCOLOR specular, 
                                       D3DXCOLOR emissive, 
            float power);

            const D3DMATERIAL9 WHITE_MATERIAL  = init_material(WHITE,  WHITE,  WHITE,  BLACK, 2.0f);
            const D3DMATERIAL9 RED_MATERIAL       = init_material(RED,       RED,       RED,    BLACK, 2.0f);
            const D3DMATERIAL9 GREEN_MATERIAL  = init_material(GREEN,  GREEN,  GREEN,  BLACK, 2.0f);
            const D3DMATERIAL9 BLUE_MATERIAL   = init_material(BLUE,   BLUE,   BLUE,   BLACK, 2.0f);
            const D3DMATERIAL9 YELLOW_MATERIAL = init_material(YELLOW, YELLOW, YELLOW, BLACK, 2.0f);

            D3DLIGHT9 init_directional_light(D3DXVECTOR3
            * direction, D3DXCOLOR* color)
            {
                D3DLIGHT9 light;
                ZeroMemory(
            &light, sizeof(light));

                light.Type        
            = D3DLIGHT_DIRECTIONAL;
                light.Ambient    
            = *color * 0.6f;
                light.Diffuse    
            = *color;
                light.Specular    
            = *color * 0.6f;
                light.Direction 
            = *direction;

                
            return light;
            }

            D3DLIGHT9 init_point_light(D3DXVECTOR3
            * position, D3DXCOLOR* color)
            {
                D3DLIGHT9 light;
                ZeroMemory(
            &light, sizeof(light));

                light.Type            
            = D3DLIGHT_POINT;
                light.Ambient        
            = *color * 0.6f;
                light.Diffuse        
            = *color;
                light.Specular        
            = *color * 0.6f;
                light.Position        
            = *position;
                light.Range            
            = 1000.0f;
                light.Falloff        
            = 1.0f;
                light.Attenuation0    
            = 1.0f;
                light.Attenuation1    
            = 0.0f;
                light.Attenuation2    
            = 0.0f;

                
            return light;
            }

            D3DLIGHT9 init_spot_light(D3DXVECTOR3
            * position, D3DXVECTOR3* direction, D3DXCOLOR* color)
            {
                D3DLIGHT9 light;
                ZeroMemory(
            &light, sizeof(light));

                light.Type            
            = D3DLIGHT_SPOT;
                light.Ambient        
            = *color * 0.6f;
                light.Diffuse        
            = *color;
                light.Specular        
            = *color * 0.6f;
                light.Position        
            = *position;
                light.Direction        
            = *direction;
                light.Range            
            = 1000.0f;
                light.Falloff        
            = 1.0f;
                light.Attenuation0    
            = 1.0f;
                light.Attenuation1    
            = 0.0f;
                light.Attenuation2    
            = 0.0f;
                light.Theta            
            = 0.4f;
                light.Phi            
            = 0.9f;

                
            return light;
            }

            D3DMATERIAL9 init_material(D3DXCOLOR ambient, D3DXCOLOR diffuse, D3DXCOLOR specular, 
                                       D3DXCOLOR emissive, 
            float power)
            {
                D3DMATERIAL9 material;

                material.Ambient  
            = ambient;
                material.Diffuse  
            = diffuse;
                material.Specular 
            = specular;
                material.Emissive 
            = emissive;
                material.Power      
            = power;

                
            return material;
            }

             

            頂點結構沒有材質屬性;一個通用的材質必須被設置。設置它我們使用IDirect3DDevice9::SetMaterial(CONST D3DMATERIAL9*pMaterial)方法。

            假設我們想渲染幾個不同材質的物體;我們將按照如下的寫法去做:

            D3DMATERIAL9 blueMaterial, redMaterial;

             

            // set up material structures

            Device->SetMaterial(&blueMaterial);

            drawSphere(); // blue sphere

             

            Device->SetMaterial(&redMaterial);

            drawSphere(); // red sphere

            5.3頂點法線

                   面法線(face normal)是描述多邊形表面方向的一個向量(如圖5.1)。

            頂點法線(Vertex normals)也是基于同樣的概念,但是我們與其指定每個多邊形的法線,還不如為每個頂點指定(如圖5.2)。

            Direct3D需要知道頂點法線以便它能夠確定燈光照射到物體表面的角度,并且一旦計算了每個頂點的燈光,Direct3D需要知道每個頂點的表面方向。注意頂點法線不一定和面法線相同。球體/環形物就是很好的實物例子,它們的頂點法線和三角形法線是不相同的(如圖5.3)。

            為了描述頂點的頂點法線,我們必須更新原來的頂點結構::

            class cLightVertex
            {
            public:
                
            float m_x, m_y, m_z;
                
            float m_nx, m_ny, m_nz; 

                cLightVertex() {}

                cLightVertex(
            float x, float y, float z, float nx, float ny, float nz)
                {
                    m_x  
            = x;    m_y  = y;    m_z  = z;
                    m_nx 
            = nx;    m_ny = ny;    m_nz = nz;
                }
            };

            const DWORD LIGHT_VERTEX_FVF = D3DFVF_XYZ | D3DFVF_NORMAL;

             

            作為一個簡單的物體比如立方體和球體,我們能夠通過觀察看見頂點法線。對于更多復雜的網格,我們需要一個更多的機械方法。假設一個由p0,p1,p2構成的三角形,我們需要計算每個頂點的法線n0,n1,n2。

            簡單的步驟,我們列舉它是為了找到由三個點構成的三角形的面法線,同時使用面法線作為頂點法線。首先計算三角形上的兩個向量:

            • p1p0 = u

            • p2p0 = v

            Then the face normal is:

            • n = u × v

            Since each vertex normal is the same as the face normal:

            • n0 = n1 = n2 = n

            下面是一個C函數,它通過三角形的三個頂點計算三角形的面法線。注意這個函數的三個頂點是按照順時針方向指定的。假如不是這樣,那么法線方向將是相反的。

            void ComputeNormal(D3DXVECTOR3* p0, D3DXVECTOR3* p1, D3DXVECTOR3* p2, D3DXVECTOR3* out)

            {

                   D3DXVECTOR3 u = *p1 - *p0;

                   D3DXVECTOR3 v = *p2 - *p0;

                   D3DXVec3Cross(out, &u, &v);

                   D3DXVec3Normalize(out, out);

            }

            當用三角形近似表示曲面時,使用面法線作為頂點法線不能表現一個平滑的結果。一個更好的方法是找到頂點法線的平均法線。為了找到頂點v的頂點法線vn,我們找到網格模型中所有三角形的面法線記為頂點v。vn是通過計算他們的平均面法線得到的。這里有一個例子,假設有3個三角形它們的面法線分別是n0,n1,n2,指定為頂點v。那么vn的平均法線就是:

            vn = (1/3) . (n0 + n1 + n2)

            變換過程中把頂點法線變為non-normal,這是有可能的。因此最好通過D3DRS_NORMALIZENORMALS設置渲染狀態,Direct3D重新單位化所有法線。

            Device->SetRenderState(D3DRS_NORMALIZENORMALS, true);


            posted on 2008-03-16 13:39 lovedday 閱讀(1154) 評論(0)  編輯 收藏 引用

            公告

            導航

            統計

            常用鏈接

            隨筆分類(178)

            3D游戲編程相關鏈接

            搜索

            最新評論

            久久精品国产网红主播| 亚洲综合久久夜AV | 国产一级做a爰片久久毛片| 99久久免费国产精品| 久久综合九色欧美综合狠狠| 国产成人综合久久精品红| 国产精品一区二区久久不卡| 97久久精品人人做人人爽| 久久天天躁狠狠躁夜夜躁2014| 国产精品18久久久久久vr| 亚州日韩精品专区久久久| 久久精品国产亚洲AV香蕉| 青青热久久国产久精品 | 无码人妻久久一区二区三区 | 日本精品久久久久中文字幕| 亚洲国产天堂久久久久久| 久久99国产综合精品女同| 久久久久亚洲爆乳少妇无| 婷婷久久综合九色综合98| 精品久久久久久国产| 欧美午夜A∨大片久久| 岛国搬运www久久| www.久久99| 99久久无码一区人妻a黑| 亚洲精品国产美女久久久| 久久综合色老色| 久久国产视频99电影| 999久久久国产精品| 精品国产91久久久久久久| MM131亚洲国产美女久久| 性高湖久久久久久久久| 天堂久久天堂AV色综合| 日日狠狠久久偷偷色综合免费| 国产精品成人久久久久三级午夜电影| 国产婷婷成人久久Av免费高清| 乱亲女H秽乱长久久久| 久久精品国产亚洲av麻豆小说| 中文字幕热久久久久久久| 色婷婷综合久久久久中文| 久久精品亚洲精品国产色婷| 色婷婷综合久久久久中文一区二区 |