一、概述

         为了增强所绘制场景的真实感,我们可以为场景增加光照。光照也有助于描述实体形状和立体感。使用光照时,我们无需自行指定顶点的颜色值:Direct3D会将顶点送入光照计算引擎,依据光源类型、材质以及物体表面相对于光源的朝向,计算出每个顶点的颜色值。基于某种光照模型计算出各顶点的颜色,会使绘制结果更加逼真。

二、光照的组成

          在Direct3D的光照模型中,光源发出的光由以下3个分量或3种类型的光组成
          ●环境光(Ambient Light)这种类型的光经其他表面反射到达物体表面,并照亮整个场景。物体之所以会被照亮,是由于其他物体对光的反射。要想以较低代价粗略地模拟这类反射光,环境光是一个很好的选择。
          ●漫射光(Diffuse Light)这种类型的光沿着特定的方向传播。当它到达某一表面时,将沿着各个方向均匀反射。由于漫射光沿所有点的方向均匀反射,无论从哪个方位观察,表面亮度均相同,所以采用该模型时,无需考虑观察者的位置。
          ●镜面光(Specular Light)这种类型的光沿特定的方向传播。当此类光到达一个表面时,将严格地沿着另一个方向反射,从而形成只能在一定角度范围内才能观察到的高亮度照射。镜面光与其他类型的光相比,计算量要大很多。默认状态下,Direct3D不进行镜面反射计算:如果想启用镜面光,必须将绘制状态D3DRS_SPECULARENABLE设为TRUE。
         每种类型的光都可用结构D3DCOLORVALUE或D3DXCOLOR来表示,这些类型描述了光线的颜色。描述光线颜色时,D3DXCOLOR类中的Alpha值都将被忽略。

三、材质

          在显示世界中,我们所观察到的物体的颜色是由该物体所反射的光的颜色决定的。例如一个纯红色的球体反射了全部的红色入射光,并吸收了所有非红色的光,所以该球体呈现为红色。Direct3D通过定义物体的材质来模拟同样的现象。材质允许我们定义物体表面对各种颜色光的反射比例
         材质的定义如下:
         typedef struct D3DMATERIAL9{
                D3DCOLORVALUE  Diffuse;
                D3DCOLORVALUE  Ambient;
                D3DCOLORVALUE  Specular;
                D3DCOLORVALUE  Emissive;
                float          Power;
         }D3DMATERIAL9, *LPD3DMATERIAL9;
        ●Diffuse 指定材质对漫射光的反射率。
        ●Ambient 指定材质对环境光的反射率。
        ●Specular 指定材质对镜面光的反射率。
        ●Emissive 该分量用于增强物体的亮度,使之看起来好像可以自己发光。
        ●Power 指定镜面高光点的锐度,该值越大,高光点的锐度越大。
       顶点结构中不含有材质属性,但我们必须对当前材质进行设定
        如下函数用来对当前材质进行设定:
           IDirect3DDevice9::SetMaterial(CONST D3DMATERIAL9* pMaterial)。
        要绘制几个具有不同材质的物体,我们可以这样书写代码:
        D3DMATERIAL9 blueMaterial, redMaterial;
        Device->SetMaterial(&blueMaterial);
        drawSphere();
        Device->SetMaterial(&redMaterial);
        drawSphere();

四、顶点法线

 
          面法线是一个描述多边形朝向的向量。
          顶点法线正是基于上述思路而产生的,但它并不用于指定每个多边形的法向量。顶点法线描述的是构成多边形的各个顶点的法线。
          面法线和顶点法线如下图所示:
          
          Direct3D需要知道顶点的法线方向,以确定光线到达表面时的入射角。而且,由于光照计算是对每个顶点进行的,所以Direct3D需要知道表面在每个顶点处的局部朝向(法线方向)。顶点法线与表面法线不一定相同。如下图所示:
             对于网格面,计算顶点法线最简单的做法就是求出三角形的面法向量,并将该面法向量作为各定点的法向量。当用三角形单元逼近表示曲面时,将面法向量作为构成该面片的顶点法线向量不可能产生很平滑的效果。一种更好的求取顶点法向量的方法是计算法向量均值。为求出顶点 V 的顶点法向量,我们需要求出共享顶点 V 的所有三角形的面法向量,顶点 V 的法向量可由这些面法向量取均值得到。

五、光源

        Direct3D支持3种光源:
        ●点光源(Point lights)该光源在世界坐标系中有固定的位置,并向所有的方向发射光线。
        ●方向光(Directional lights)该光源没有位置信息,所发射的光线互相平行地沿某一特定方向传播。
        ●聚光灯(Spot lights)这种类型的光源与手电筒类似:该光源有位置信息,其发射的光线呈锥形沿着特定方向传播。该锥形可用两个角度:θ 和 φ 来描述。θ 描述了内部锥形,φ 描述了外部锥形。
            代码中光源的定义如下:
             typedef struct _D3DLIGHT9 {
                D3DLIGHTTYPE    Type;
                D3DCOLORVALUE   Diffuse;
    D3DCOLORVALUE   Specular;
    D3DCOLORVALUE   Ambient;
    D3DVECTOR       Position;
    D3DVECTOR       Direction;
    float           Range;
    float           Falloff;
    float           Attenuation0;
    float           Attenuation1;
    float           Attenuation2;
    float           Theta;
    float           Phi;
  } D3DLIGHT9;
         ●Type定义了所要创建的光源类型。该参数可取一下3种枚举值:D3DLIGHT_POINT、D3DLIGHT_SPOT、D3DLIGHT_DIRECTIONAL。
        ●Diffuse 该光源所发出的漫射光的颜色。     
●Ambient该光源所发出的环境光的颜色。    
●Specular 该光源所发出的镜面光的颜色。    
        ●Position   用于描述光源在世界坐标系中位置的向量。对于方向光,该参数无意义。
        ●Direction   一个描述光在世界坐标系中传播方向的向量,使用时应将其单位化。对于点光源,该参数无意义。
        ●Range     光线“消亡”前,所能达到的最大光程。对于方向光,该参数无意义。
        ●Falloff    该值仅用于聚光灯。该参数定义了光强从内锥形到外锥形的衰减方式,该参数一般取为1。
        ●Attenuation0、Attenuation1、Attenuation2这些衰减变量定义了光强随距离衰减的方式。这些变量仅用于电光源和聚光灯。Attenuation0、Attenuation1、Attenuation2分别表示光的常量、线性、2次距离衰减系数。
        ●Theta  仅用于聚光灯。指定了内部锥形的圆锥角,单位为弧度。
        ●Phi      仅用于聚光灯。指定了外部锥形的圆锥角,单位为弧度。
        
        当D3DLIGHT9实例初始化完毕后,需要在Direct3D所维护的一个光源内部列表中对所要使用的光源进行注册:
      Device->SetLight(0, &light);
       一旦光源注册成功,我们就可以对其开关状态进行控制:
       Device->LightEnable(0, true);
默认状态下,光照是已经启用了的。
      注意光照计算模型(简称光照模型)和光源类型的区别。光照模型说明图形工作系统以什么样的方法计算灯光照射在物体上的颜色值,它只是一种计算方法,而不是具体的灯光。光源则定义了三维场景中具体的灯光,包括位置、方向、强度等信息。相同的光源可以根据物体表面材质的不同,通过不同的光照模型显示。三种光源,每种光源都可以发出三种光。

六、示例代码

        以下代码绘制了一个黄色的金字塔。
        
#include <Windows.h>
#include <mmsystem.h>
#include <d3dx9.h>
#pragma warning( disable : 4996 )
#include <strsafe.h>
#pragma warning( default : 4996 )LPDIRECT3D9             g_pD3D = NULL;
LPDIRECT3DDEVICE9       g_pd3dDevice = NULL;
LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL;struct CUSTOMVERTEX
{CUSTOMVERTEX(){}CUSTOMVERTEX(float ax, float ay, float az, float anx, float any, float anz){x = ax, y = ay, z = az, nx = anx, ny = any, nz = anz; }FLOAT x, y, z; FLOAT nx, ny, nz;
};#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_NORMAL)HRESULT InitD3D( HWND hWnd )
{if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )return E_FAIL;D3DPRESENT_PARAMETERS d3dpp;ZeroMemory( &d3dpp, sizeof( d3dpp ) );d3dpp.Windowed = TRUE;d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;d3dpp.EnableAutoDepthStencil = FALSE;d3dpp.AutoDepthStencilFormat = D3DFMT_D16;if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING,&d3dpp, &g_pd3dDevice ) ) ){return E_FAIL;}return S_OK;
}HRESULT InitGeometry()
{if( FAILED( g_pd3dDevice->CreateVertexBuffer( 12 * sizeof( CUSTOMVERTEX ),0, D3DFVF_CUSTOMVERTEX,D3DPOOL_DEFAULT, &g_pVB, NULL ) ) ){return E_FAIL;}CUSTOMVERTEX* pVertices;if( FAILED( g_pVB->Lock( 0, 0, ( void** )&pVertices, 0 ) ) )return E_FAIL;pVertices[0] = CUSTOMVERTEX(0.0f, 1.0f, 0.0f, -0.57735f, -0.57735f, -0.57735f);pVertices[1] = CUSTOMVERTEX( 1.0f, 0.0f,  0.0f, -0.57735f, -0.57735f, -0.57735f);pVertices[2] = CUSTOMVERTEX( 0.0f, 0.0f, 1.0f, -0.57735f, -0.57735f, -0.57735f);pVertices[3] = CUSTOMVERTEX(0.0f, 1.0f, 0.0f, 0.57735f, -0.57735f, -0.57735f);pVertices[4] = CUSTOMVERTEX( 0.0f, 0.0f,  1.0f, 0.57735f, -0.57735f, 0.57735f);pVertices[5] = CUSTOMVERTEX(-1.0f, 0.0f, 0.0f, 0.57735f, -0.57735f, -0.57735f);pVertices[6] = CUSTOMVERTEX(0.0f, 1.0f, 0.0f, 0.57735f, -0.57735f, 0.57735f);pVertices[7] = CUSTOMVERTEX(-1.0f, 0.0f, 0.0f, 0.57735f, -0.57735f, 0.57735f);pVertices[8] = CUSTOMVERTEX(0.0f, 0.0f, -1.0f, 0.57735f, -0.57735f, 0.57735f);pVertices[9] = CUSTOMVERTEX(0.0f, 1.0f, 0.0f, -0.57735f, -0.57735f, 0.57735f);pVertices[10] = CUSTOMVERTEX( 0.0f, 0.0f, -1.0f, -0.57735f, -0.57735f, 0.57735f);pVertices[11] = CUSTOMVERTEX(1.0f, 0.0f,  0.0f, -0.57735f, -0.57735f, 0.57735f);g_pVB->Unlock();return S_OK;
}VOID Cleanup()
{if( g_pVB != NULL )g_pVB->Release();if( g_pd3dDevice != NULL )g_pd3dDevice->Release();if( g_pD3D != NULL )g_pD3D->Release();
}VOID SetupMatrices()
{D3DXVECTOR3 vEyePt( 0.0f, 3.0f,-5.0f );D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f );D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );D3DXMATRIXA16 matView;D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );D3DXMATRIXA16 matProj;D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI / 4, 1.0f, 1.0f, 100.0f );g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
}VOID SetupLights()
{D3DMATERIAL9 mtrl;ZeroMemory( &mtrl, sizeof( D3DMATERIAL9 ) );mtrl.Diffuse.r = mtrl.Ambient.r = 1.0f;mtrl.Diffuse.g = mtrl.Ambient.g = 1.0f;mtrl.Diffuse.b = mtrl.Ambient.b = 0.0f;mtrl.Diffuse.a = mtrl.Ambient.a = 1.0f;g_pd3dDevice->SetMaterial( &mtrl );D3DXVECTOR3 vecDir;D3DLIGHT9 light;ZeroMemory( &light, sizeof( D3DLIGHT9 ) );light.Type = D3DLIGHT_DIRECTIONAL;light.Diffuse.r = 1.0f;light.Diffuse.g = 1.0f;light.Diffuse.b = 1.0f;vecDir = D3DXVECTOR3( 1, 0, 0 );D3DXVec3Normalize( ( D3DXVECTOR3* )&light.Direction, &vecDir );g_pd3dDevice->SetLight( 0, &light );g_pd3dDevice->LightEnable( 0, TRUE );g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );
}VOID Render()
{g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET,D3DCOLOR_XRGB( 0, 0, 255 ), 1.0f, 0 );if( SUCCEEDED( g_pd3dDevice->BeginScene() ) ){SetupLights();SetupMatrices();g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof( CUSTOMVERTEX ) );g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 4 );g_pd3dDevice->EndScene();}g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{switch( msg ){case WM_DESTROY:Cleanup();PostQuitMessage( 0 );return 0;}return DefWindowProc( hWnd, msg, wParam, lParam );
}INT WINAPI wWinMain( HINSTANCE hInst, HINSTANCE, LPWSTR, INT )
{WNDCLASSEX wc ={sizeof( WNDCLASSEX ), CS_CLASSDC, MsgProc, 0L, 0L,GetModuleHandle( NULL ), NULL, NULL, NULL, NULL,L"D3D Tutorial", NULL};RegisterClassEx( &wc );HWND hWnd = CreateWindow( L"D3D Tutorial", L"D3D Tutorial 04: Lights",WS_OVERLAPPEDWINDOW, 100, 100, 600, 600,NULL, NULL, wc.hInstance, NULL );if( SUCCEEDED( InitD3D( hWnd ) ) ){if( SUCCEEDED( InitGeometry() ) ){ShowWindow( hWnd, SW_SHOWDEFAULT );UpdateWindow( hWnd );MSG msg;ZeroMemory( &msg, sizeof( msg ) );while( msg.message != WM_QUIT ){if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) ){TranslateMessage( &msg );DispatchMessage( &msg );}elseRender();}}}UnregisterClass( L"D3D Tutorial", wc.hInstance );return 0;
}

运行效果如下:

    

Direct3D中的光照相关推荐

  1. Direct3D中的四大变换

    本系列文章由zhmxy555(毛星云)编写,转载请注明出处. 文章链接: http://blog.csdn.net/zhmxy555/article/details/8408723 作者:毛星云(浅墨 ...

  2. Direct3D中的纹理映射

    一.概要           为了使渲染的图形看起来更真实,Direct3D提供了在物体表面绘制纹理的功能.一般来说,纹理是表示物体表面细节的一幅或几幅二维图形,也称纹理贴图.借助纹理映射技术,我们可 ...

  3. 终于搞定Direct3D中视频播放

    弄了好长一段时间,今天终于把自己录的测试视频在Direct3D中显示出来,发个图留念. 翻了好久DirectShow的Sample例子Texture3D9,还有就是看参考书<<The De ...

  4. [Render] 适用于高级Unity创作者的通用渲染管线[4] - URP中的光照

    RuntimeMapMaker3D-Pro 英文原文:https://resources.unity.com/games/introduction-universal-render-pipeline- ...

  5. Introduction to 3D Game Programming with DirectX 11学习笔记 6 Direct3D中的绘制(一)

    顶点和顶点布局 在Direct3D中,顶点由空间位置和各种附加属性组成,Direct3D可以让我们灵活地建立属于我们自己的顶点格式:换句话说,它允许我们定义顶点的分量.要创建一个自定义的顶点格式,我们 ...

  6. Unity中调整光照特效的7个技巧

    适当为游戏场景添加光照效果,能够有效增强场景氛围,让玩家体验更佳.今天将为大家分享在Unity中调整光照特效的7个技巧,让整个游戏场景氛围更引人入胜. 1.使用线性颜色空间 在为场景添加光照效果之前, ...

  7. Unity5中的光照简介

    unity 5中的光照可以用整本书来说明,此文是过去几个月使用 unity5 的简单汇总.下面主要分6个部分来讲解. Forward(前向)与Deferred(延迟)渲染 Realtime(实时)与B ...

  8. 地堡中的光照问题_扑扑和火力地堡的更新

    地堡中的光照问题 重点 (Top highlight) Flutter is more than just an engine, a set of widgets, and some tools; i ...

  9. 关于Unity中的光照(六)

    反射探头 1:镜子金属等具有光滑表面的物体都会反射,而游戏中计算实时反射非常消耗CPU的资源, unity5.0新增了一个反射探头的技术,通过采样点,生成反射Cubemap,然后通过特定的着色器从Cu ...

最新文章

  1. LeetCode简单题之在区间范围内统计奇数数目
  2. 日期处理工具类 -【二】
  3. 用 C 语言开发一门编程语言 — 基于 Lambda 表达式的函数设计
  4. autoresetevent java_[原创]AutoResetEvent, ManualResetEvent的Java模拟
  5. CSS中的margin、border、padding区别 CSS padding margin border属性详解
  6. python3 字典有序_Python3 有序字典—OrderedDict()
  7. 计算机系统-电路设计10-寄存器的内部电路实现(输入与输出不同线)
  8. c语言int grade 5,C语言补考!!!
  9. python中聚类和分类的区别_聚类与分类有什么区别?
  10. 通达OA2017 工作流设计中“退回”功能的升级测试(图文)
  11. 涉密计算机违规外联检查,涉密计算机违规外联及移动存储介质使用检查的研究与实现...
  12. 国仁猫哥:视频号超详细运营攻略教程;教你如何打造一个优质的视频号【建议收藏】
  13. OpenCV基础教程——视频的读取与写入(超详细+附代码)
  14. libuv访问mysql_libuv中的QUEUE
  15. 记账的优缺点分析 聊聊记账这些事
  16. 阿里企业云邮箱 报错 526 Authentication failure[0]
  17. 面试:自我问题反思总结
  18. 解读阿里精准推广的核心算法
  19. 八码数 · 哈希+BFS
  20. 【ChatGPT】使用ChatGPT进行51单片机程序编程体验

热门文章

  1. ReadProcessMemory()
  2. 【新星计划】Demo---Expanding Cards------ 1/50(详解)
  3. MYSQL之如何列转行
  4. Android CardView 不显示阴影
  5. supervisor的程序控制修改参考方案
  6. Python: queue.Queue
  7. 知道浏览器下载的地方藏在哪里嘛?——看完你就知道
  8. SQL 开窗函数使用
  9. PCIE 3.0 4.0 GEN3 GEN4 速度如何
  10. Linux SWAP 交换分区配置说明