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

            D3D中的光照(1)

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

            5.1燈光的組成

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

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

            漫反射(Diffuse Reflection)——這種燈光按照特殊方向傳播。當(dāng)它照射到一個(gè)表面,它將在所有方向上均勻的反射。因?yàn)槁涔庠谒蟹较蛏隙季鶆虻姆瓷洌环瓷涞墓饩€將到達(dá)眼睛而與觀察點(diǎn)無關(guān),因此我們不必為觀察者考慮。因而,漫射光僅僅需要考慮燈光方向和表面的朝向。這種燈光將成為你的資源中照射的普通燈光。

            鏡面反射(Specular Reflection)——這種燈光按照特殊方向傳播。當(dāng)它照射到一個(gè)表面時(shí),它嚴(yán)格地按照一個(gè)方向反射。這將產(chǎn)生一個(gè)明亮的光澤,它能在某角度被看見。因?yàn)檫@種燈光在一個(gè)方向反射。明顯的觀察點(diǎn),必須考慮燈光的方向和表面朝向,且必須按照鏡面燈光等式來考慮。鏡面燈光被用在物體上產(chǎn)生高光的地方,這種光澤只有在燈光照射在磨光的表面上才會(huì)產(chǎn)生。

            鏡面光比其他燈光類型要求更多的計(jì)算;因此,Direct3D提供了一個(gè)開關(guān)選擇。實(shí)際上,它默認(rèn)是被關(guān)閉的;要使用鏡面光你必須設(shè)置D3DRS_SPECULARENABLE渲染狀態(tài)。

            Device->SetRenderState(D3DRS_SPECULARENABLE, true);

            每一種燈光都是通過D3DCOLORVALUE結(jié)構(gòu)或者描述燈光顏色的D3DXCOLOR來描繪的。這里有幾個(gè)燈光顏色的例子:

            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值用在描述燈光顏色時(shí)是被忽略的。

            5.2材質(zhì)

            在現(xiàn)實(shí)世界中我們看到的物體顏色將由物體反射回來的燈光顏色來決定。比如,一個(gè)紅色的球是紅色的,因?yàn)樗账械臒艄忸伾思t色光。紅色光是被球反射回來進(jìn)入我們眼睛的,因此我們看到的球是紅色的。Direct3D通過我們定義的物體材質(zhì)來模擬這些所有的現(xiàn)象。材質(zhì)允許我們定義表面反射燈光的百分比。在代碼中通過D3DMATERIAL9結(jié)構(gòu)描述一個(gè)材質(zhì)。

            typedef struct _D3DMATERIAL9 {

                   D3DCOLORVALUE Diffuse, Ambient, Specular, Emissive;

                   float Power;

            } D3DMATERIAL9;

            Diffuse——指定此表面反射的漫射光數(shù)量。

            Ambient——指定此表面反射的環(huán)境光數(shù)量。

            Specular——指定此表面反射的鏡面光數(shù)量

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

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

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

            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;

            這里我們?cè)O(shè)置綠色和藍(lán)色的值為0,這表明材質(zhì)反射0%此顏色的光。我們?cè)O(shè)置紅色為1,表示材質(zhì)反射100%的紅光。注意,我們能夠控制每種燈光反射的顏色(環(huán)境、漫射和鏡面光)。

             

            同樣假如我們定義一個(gè)只發(fā)出藍(lán)色光的光源,對(duì)球的光照將失敗因?yàn)樗{(lán)色光將被全部吸收而沒有紅光被反射。當(dāng)物體吸收了所有光以后,物體看起來就為黑色。同樣的,當(dāng)物體反射100%的紅、綠和藍(lán)光,物體就將呈現(xiàn)為白色。

            因?yàn)槭止ぬ畛湟粋€(gè)材質(zhì)結(jié)構(gòu)將是乏味的工作,我們添加下列有用的函數(shù)和全局材質(zhì)常數(shù)到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;
            }

             

            頂點(diǎn)結(jié)構(gòu)沒有材質(zhì)屬性;一個(gè)通用的材質(zhì)必須被設(shè)置。設(shè)置它我們使用IDirect3DDevice9::SetMaterial(CONST D3DMATERIAL9*pMaterial)方法。

            假設(shè)我們想渲染幾個(gè)不同材質(zhì)的物體;我們將按照如下的寫法去做:

            D3DMATERIAL9 blueMaterial, redMaterial;

             

            // set up material structures

            Device->SetMaterial(&blueMaterial);

            drawSphere(); // blue sphere

             

            Device->SetMaterial(&redMaterial);

            drawSphere(); // red sphere

            5.3頂點(diǎn)法線

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

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

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

            為了描述頂點(diǎn)的頂點(diǎn)法線,我們必須更新原來的頂點(diǎn)結(jié)構(gòu)::

            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;

             

            作為一個(gè)簡(jiǎn)單的物體比如立方體和球體,我們能夠通過觀察看見頂點(diǎn)法線。對(duì)于更多復(fù)雜的網(wǎng)格,我們需要一個(gè)更多的機(jī)械方法。假設(shè)一個(gè)由p0,p1,p2構(gòu)成的三角形,我們需要計(jì)算每個(gè)頂點(diǎn)的法線n0,n1,n2。

            簡(jiǎn)單的步驟,我們列舉它是為了找到由三個(gè)點(diǎn)構(gòu)成的三角形的面法線,同時(shí)使用面法線作為頂點(diǎn)法線。首先計(jì)算三角形上的兩個(gè)向量:

            • 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

            下面是一個(gè)C函數(shù),它通過三角形的三個(gè)頂點(diǎn)計(jì)算三角形的面法線。注意這個(gè)函數(shù)的三個(gè)頂點(diǎn)是按照順時(shí)針方向指定的。假如不是這樣,那么法線方向?qū)⑹窍喾吹摹?/p>

            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);

            }

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

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

            變換過程中把頂點(diǎn)法線變?yōu)閚on-normal,這是有可能的。因此最好通過D3DRS_NORMALIZENORMALS設(shè)置渲染狀態(tài),Direct3D重新單位化所有法線。

            Device->SetRenderState(D3DRS_NORMALIZENORMALS, true);


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


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


            公告

            導(dǎo)航

            統(tǒng)計(jì)

            常用鏈接

            隨筆分類(178)

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

            搜索

            最新評(píng)論

            国产成人无码精品久久久性色| 97久久天天综合色天天综合色hd| 无码任你躁久久久久久久| 狠狠色综合网站久久久久久久高清 | 欧美麻豆久久久久久中文| 狠狠色婷婷久久综合频道日韩 | 香蕉久久夜色精品国产2020| 97超级碰碰碰久久久久| 国产精品99久久久精品无码 | 999久久久免费国产精品播放| 国产精品99久久久精品无码| 久久国产成人| 香蕉久久一区二区不卡无毒影院 | 国产99久久久久久免费看| 一本久久a久久精品亚洲| 久久嫩草影院免费看夜色| 免费国产99久久久香蕉| 亚洲国产精品无码久久久秋霞2| 久久噜噜久久久精品66| 久久国产午夜精品一区二区三区| 久久国产精品77777| 久久免费的精品国产V∧| 久久精品国产2020| 伊人 久久 精品| 亚洲日本久久久午夜精品| 久久久久香蕉视频| 精品熟女少妇aⅴ免费久久| 久久―日本道色综合久久| 久久亚洲国产欧洲精品一| 久久久青草久久久青草| 久久99精品国产麻豆宅宅| 久久精品aⅴ无码中文字字幕重口| 亚洲AV无码1区2区久久| 亚洲AV无码成人网站久久精品大| 久久精品一区二区三区AV| 久久国语露脸国产精品电影| 99蜜桃臀久久久欧美精品网站| 四虎国产精品成人免费久久| 少妇无套内谢久久久久| 亚洲av日韩精品久久久久久a| 久久久久久久人妻无码中文字幕爆 |