第04讲 光照与材质

更新时间:2024-06-21 00:45:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

光照与材质

一、光照模型:

1、环境光:环境光没有位置和方向,它是光线经过多次散射后所形成的光。所有的光线都均匀地从各个方向照射到物体上,并且照亮场景中的所有物体。环境光只有一个颜色值,而且不会衰减,所以在所有方向和所有物体表面上投射的环境光的数量是恒定不变的。

环境光是完全独立于场景中的任何发光物体的光照模型,所以环境光模型也被称作全局光照模型。在Direct3D应用程序中,可以调用IDirect3DDevice接口的SetRenderState方法设置场景中的环境光。例如: // 设置灰色的环境光

g_pd3dDevice->SetRenderState( D3DRS_AMBIENT, D3DCOLOR_XRGB(222, 222, 222) );

2、漫反射光:漫反射光在生活中最为普遍,太阳的直射、日光灯的照射都可以看成漫反射的近似。漫反射不同于环境光,漫反射光的空间位置和方向对物体的照明有很大影响。但与观察者位置无关,因此在漫反射光照模型中一个物体的表面在所有方向上的反射都是一样的,如图4.1所示。

3、镜面反射光:镜面反射发生在光滑物体(如金属物品、玻璃制品等)的表面,当光线照射到这类物体表面时产生的高光反射,并且当观察者移动自己所处的位置,反射的亮度也不一样,观察方向与反射光线越靠拢,发射光的强大就越大,如图4.2所示。

由于镜面反射的计算量比较大,Direct3D在默认状态下不对物体进行镜面反射计算,可以调

用SetRenderState方法启用镜面反射。例如:

g_pd3dDevice->SetRenderState ( D3DRS_SPECULARENABLE , TRUE );

二、光源类型:

Direct3D提供了三种光源类型:点光源(Point Light)、方向光(Directional Light)和聚光灯(Spot Light)。在Direct3D中,光源类型及其属性由D3DLIGHT9结构表示。该结构体的定义如下:

typedef struct D3DLIGHT9 {

D3DLIGHTTYPE Type; // 光源类型 D3DCOLORVALUE Diffuse; // 漫反射光强度 D3DCOLORVALUE Specular; // 环境光强度 D3DCOLORVALUE Ambient; // 镜面反射光强度 D3DVECTOR Position; // 光源位置 D3DVECTOR Direction; // 光照方向 float Range; // 光照范围 float Attenuation0; // 衰减系数1 float Attenuation1; // 衰减系数2

float Attenuation2; // 衰减系数3 float Falloff; // 聚光灯的辐射系数 float Theta; // 聚光灯的内锥体大小 float Phi; // 聚光灯的外锥体大小 } D3DLIGHT9, *LPD3DLIGHT;

1、点光源是从一个中心点向空间中各个方向发射相等强度光线的光源。点光源具有颜色和位置,但没有确定的方向。点光源向各个方向发出光相,并且光的亮度会随着距离而衰减,如图4.3所示。

为了能够使用点光源,在应用程序中需要提供光源的位置、颜色和衰减系数等参数。例如,下面的代码将创建一个范围为1000.0f,颜色为白色且位于原点的点光源。 D3DLIGHT9 light;

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

light.Type = D3DLIGHT_POINT; // 点光源 light.Ambient = D3DCOLOR_XRGB(255, 255, 255); // 环境光, 白色 light.Ambient.r= light.Ambient.g= light.Ambient.b=

light.Diffuse = D3DCOLOR_XRGB(255, 255, 255); // 漫反射光, 白色 light.Specular = D3DCOLOR_XRGB(255, 255, 255); // 镜面反射光, 白色 light.Position = D3DXVECTOR3(0.0f, 0.0f, 0.0f); // 点光源位置, 原点 light.Range = 1000.0f; // 光照范围, 1000 light.Attenuation0 = 1.0f; // 衰减系数 实例:

2、方向光是从无穷远处发出的一组平行、均匀的光线,在场景中以相同的方向传播。方向光发出的光只有颜色和方向,并且不会受到衰减和范围的影响,如图4.4所示。

在初始化方向光时,当指定D3DLIGHT9结构类型的变量时,需要指定Type成员为D3DLIGHT_DIRECTION,并制定方向光的光照方向。例如: D3DLIGHT9 light;

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

light.Type = D3DLIGHT_DIRECTIONAL; // 方向光 light.Ambient = D3DCOLOR_XRGB(255, 255, 255); light.Diffuse = D3DCOLOR_XRGB(255, 255, 255); light.Specular = D3DCOLOR_XRGB(255, 255, 255);

light.Direction = D3DXVECTOR3(1.0f, 0.0f, 1.0f); // 光照方向

3、聚光灯发出圆锥形的光,并且由内锥体和外锥体两部分组成。其中内锥中的光最亮,而外锥以外则没有光,从内锥体到外锥体间光强逐渐衰减,如图4.5所示。

D3DLIGHT9结构体包含了Falloff、Theta和Phi三个成员描述聚光灯。其中,Falloff字段用于控制光强如何从内锥的外侧向外锥的内侧减弱,通常将该字段设为1.0f,以使光在两个圆锥间平滑地减弱。Theta和Phi字段用于控制聚光灯的内、外锥体的大小,分别以弧度表示内、外锥体的角度。

在创建一个聚光灯时,除了指定Falloff、Theta和Phi成员的值外,还需要指定聚光灯的光照范围、方向和衰减系数。例如: D3DLIGHT9 light;

::ZeroMemory(&light, sizeof(light)); light.Type = D3DLIGHT_SPOT; // 聚光灯 //light.Ambient = 0.0f;

light.Diffuse = D3DCOLOR_XRGB(255, 255, 255); light.Specular = D3DCOLOR_XRGB(255, 255, 255);

light.Position = D3DXVECTOR3(-10.0f, 5.0f, -10.0f); // 位置 light.Direction = D3DXVECTOR3(1.0f, 0.0f, 1.0f); // 光照方向 light.Range = 1000.0f; // 光照范围 light.Falloff = 1.0f; // 辐射系数 light.Attenuation0 = 1.0f; // 衰减系数 light.Theta = 0.4f; // 内锥体大小 light.Phi = 0.9f; // 外锥体大小

三、 D3D材质

Direct3D提供D3DMATERIAL9结构用于描述物体的材质,其中包含了反射环境光、漫反射光和镜面反射光的颜色属性。该结构体的定义如下: typedef struct D3DMATERIAL9 {

D3DCOLORVALUE Diffuse; D3DCOLORVALUE Ambient; D3DCOLORVALUE Specular; D3DCOLORVALUE Emissive; float Power;

} D3DMATERIAL9, *LPD3DMATERIAL9; 当初始化D3DMATERIQAL9结构后,可以调用IDirect3DDevice9接口的SetMaterial方法设置材质。例如:

D3DMATERIAL9 mtrl;

ZeroMemory( &mtrl, sizeof(D3DMATERIAL9) );

mtrl.Diffuse.r = mtrl.Ambient.r = mtrl.Specular.r = 1.0f; mtrl.Diffuse.g = mtrl.Ambient.g = mtrl.Specular.g = 1.0f; mtrl.Diffuse.b = mtrl.Ambient.b = mtrl.Specular.b = 0.0f; mtrl.Diffuse.a = mtrl.Ambient.a = mtrl.Specular.a = 1.0f; g_pd3dDevice->SetMaterial( &mtrl );

完整实例:

绘制四个三角形围成的椎状体:

_D3DVECTOR {x=0.00000000 y=0.70710671 z=-0.70710671 } _D3DVECTOR

+

#include #include #include

LPDIRECT3D9 g_pD3D = NULL; //Direct3D对象 LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; //Direct3D设备对象

LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL; //顶点缓冲区对象 LPDIRECT3DINDEXBUFFER9 g_pIB = NULL; // 索引缓冲区对象

struct CUSTOMVERTEX { D3DXVECTOR3 position; D3DXVECTOR3 normal; };

#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_NORMAL) //设置光照与材质 void setlighting() { D3DMATERIAL9 mtrl; //设置材质 mtrl.Ambient = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);; mtrl.Diffuse = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f); mtrl.Specular = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f); mtrl.Emissive = D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f); mtrl.Power = 1.0f;

g_pd3dDevice->SetMaterial( &mtrl); D3DLIGHT9 dir_light; //设置方向光照 ZeroMemory(&dir_light, sizeof(dir_light));

dir_light.Type = D3DLIGHT_DIRECTIONAL;

dir_light.Diffuse.r =dir_light.Diffuse.g=dir_light.Diffuse.b=1.0f; dir_light.Specular.r = dir_light.Specular.g=dir_light.Specular.b=0.3f; dir_light.Ambient.r = dir_light.Ambient.g=dir_light.Ambient.b=0.6f; dir_light.Direction = D3DXVECTOR3(-1.0f, 0.0f, 0.0f); dir_light.Range=1000; g_pd3dDevice->SetLight(0, &dir_light); g_pd3dDevice->LightEnable(0, TRUE); g_pd3dDevice->SetRenderState(D3DRS_NORMALIZENORMALS, TRUE); g_pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE, TRUE); g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, true); }

//----------------------------------------------------------------------------- // Desc: 设置观察矩阵和投影矩阵.设置观察矩阵和投影矩阵 //----------------------------------------------------------------------------- VOID SetupViewandProjMatrices() { //建立并设置观察矩阵 D3DXVECTOR3 vEyePt( 5.0f,5.0f,-5.0f ); D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f ); D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );

D3DXMATRIX matView; D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec ); g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView ); //建立并设置投影矩阵 D3DXMATRIX matProj; D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.0f, 1.0f, 1000.0f ); g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj ); }

//----------------------------------------------------------------------------- // Desc: 初始化Direct3D

//----------------------------------------------------------------------------- HRESULT InitD3D( HWND hWnd ) { //创建Direct3D对象, 该对象用于创建Direct3D设备对象 if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) ) return E_FAIL; //设置D3DPRESENT_PARAMETERS结构, 准备创建Direct3D设备对象 D3DPRESENT_PARAMETERS d3dpp; ZeroMemory( &d3dpp, sizeof(d3dpp) ); d3dpp.Windowed = TRUE; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; //创建Direct3D设备对象 if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING,&d3dpp, &g_pd3dDevice ) ) ) { return E_FAIL; } //设置剔出模式为不剔出任何面(正面和反面) g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE ); //关闭光照处理, 默认情况下启用光照处理 g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE ); //g_pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD); g_pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT); ////g_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME); //设置观察和投影矩阵 SetupViewandProjMatrices(); setlighting(); //设置视区

// SetupViewPort(); return S_OK;

}

//----------------------------------------------------------------------------- // Desc: 释放创建的对象.、结束处理

//----------------------------------------------------------------------------- VOID Cleanup() { //释放顶点缓冲区对象 if( g_pVB != NULL ) g_pVB->Release(); //释放Direct3D设备对象 if( g_pd3dDevice != NULL ) g_pd3dDevice->Release(); //释放Direct3D对象 if( g_pD3D != NULL ) g_pD3D->Release(); //释放索引缓冲区对象 if(g_pIB != NULL) g_pIB->Release(); }

//5.绘制图形

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; // memcpy( pVertices, vertices, sizeof(vertices) );

D3DXVECTOR3 u,v,nor; //前面 pVertices[0].position=D3DXVECTOR3(-1.0f, 0.0f, -1.0f); pVertices[1].position=D3DXVECTOR3(0.0f, 1.0f, 0.0f); pVertices[2].position=D3DXVECTOR3(1.0f, 0.0f, -1.0f);

v=pVertices[0].position-pVertices[1].position; u=pVertices[2].position-pVertices[1].position; D3DXVec3Cross(&nor,&u,&v); D3DXVec3Normalize(&nor,&nor); pVertices[0].normal=pVertices[1].normal=pVertices[2].normal=nor; //左边

pVertices[3].position=D3DXVECTOR3(-1.0f, 0.0f, 1.0f); pVertices[4].position=D3DXVECTOR3(0.0f, 1.0f, 0.0f); pVertices[5].position=D3DXVECTOR3(-1.0f, 0.0f, -1.0f);; v=pVertices[3].position-pVertices[4].position; u=pVertices[5].position-pVertices[4].position; D3DXVec3Cross(&nor,&u,&v); D3DXVec3Normalize(&nor,&nor); pVertices[3].normal=pVertices[4].normal=pVertices[5].normal=nor; //右边 pVertices[6].position=D3DXVECTOR3(1.0f, 0.0f, -1.0f); pVertices[7].position=D3DXVECTOR3(0.0f, 1.0f, 0.0f); pVertices[8].position=D3DXVECTOR3(1.0f, 0.0f, 1.0f); v=pVertices[6].position-pVertices[7].position; u=pVertices[8].position-pVertices[7].position; D3DXVec3Cross(&nor,&u,&v); D3DXVec3Normalize(&nor,&nor); pVertices[6].normal=pVertices[7].normal=pVertices[8].normal=nor; //后面 pVertices[9].position=D3DXVECTOR3(1.0f, 0.0f, 1.0f); pVertices[10].position=D3DXVECTOR3(0.0f, 1.0f, 0.0f); pVertices[11].position=D3DXVECTOR3(-1.0f, 0.0f, 1.0f); v=pVertices[9].position-pVertices[10].position; u=pVertices[11].position-pVertices[10].position; D3DXVec3Cross(&nor,&u,&v); D3DXVec3Normalize(&nor,&nor); pVertices[9].normal=pVertices[10].normal=pVertices[11].normal=nor; g_pVB->Unlock(); return S_OK; }

//----------------------------------------------------------------------------- // Desc: 渲染图形.渲染函数

//----------------------------------------------------------------------------- VOID Render() { //清空后台缓冲区

g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(45, 50,255), 1.0f, 0 ); //开始在后台缓冲区绘制图形 if( SUCCEEDED( g_pd3dDevice->BeginScene() ) ) { g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof(CUSTOMVERTEX) ); g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX ); g_pd3dDevice->SetIndices( g_pIB ); //设置索引缓冲区 //D3DXMATRIX Ry; //D3DXMatrixRotationY(&Ry,::timeGetTime()/1000.0f); //g_pd3dDevice->SetTransform(D3DTS_WORLD,&Ry); g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0,4 ); //结束在后台缓冲区渲染图形 g_pd3dDevice->EndScene(); } //将在后台缓冲区绘制的图形提交到前台缓冲区显示 g_pd3dDevice->Present( NULL, NULL, NULL, NULL ); }

//----------------------------------------------------------------------------- // Desc: 消息处理.消息处理

//-----------------------------------------------------------------------------

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

//----------------------------------------------------------------------------- // Desc: 入口函数.程序入口

//-----------------------------------------------------------------------------

INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT ) { //注册窗口类 WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC , MsgProc, 0L, 0L,

}

GetModuleHandle(NULL), NULL, NULL, NULL, NULL, L\, NULL }; RegisterClassEx( &wc ); //创建窗口

HWND hWnd = CreateWindow( L\,L\坐标变换\, WS_OVERLAPPEDWINDOW, 200, 100, 500,500, GetDesktopWindow(), NULL, wc.hInstance, NULL ); //初始化Direct3D

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 ); } else { Render(); //渲染图形 } } } }

UnregisterClass( L\, wc.hInstance ); return 0;

实例2:

void setlighting() { D3DMATERIAL9 mtrl; mtrl.Ambient = D3DXCOLOR(1.0f, 1.0f, 0.0f, 1.0f);; mtrl.Diffuse = D3DXCOLOR(1.0f, 1.0f, 0.0f, 1.0f); mtrl.Specular = D3DXCOLOR(1.0f, 1.0f, 0.0f, 1.0f); mtrl.Emissive = D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f); mtrl.Power = 1.0f;

g_pd3dDevice->SetMaterial( &mtrl);

D3DLIGHT9 dir_light; D3DXVECTOR3 dir_vec;

ZeroMemory(&dir_light, sizeof(dir_light));

dir_light.Type = D3DLIGHT_DIRECTIONAL;

dir_light.Diffuse.r =dir_light.Diffuse.g=dir_light.Diffuse.b=1.0f; dir_vec=D3DXVECTOR3 (cos(::timeGetTime()/1000.0f),0,sin(::timeGetTime()/1000.0f)); D3DXVec3Normalize((D3DXVECTOR3*)&dir_light.Direction,&dir_vec); dir_light.Range=1000; g_pd3dDevice->SetLight(0, &dir_light); g_pd3dDevice->LightEnable(0, TRUE); g_pd3dDevice->SetRenderState(D3DRS_NORMALIZENORMALS, TRUE); g_pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE, TRUE); g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, true); }

//5.绘制图形

HRESULT InitGeometry() {

//创顶点缓冲区

if( FAILED( g_pd3dDevice->CreateVertexBuffer(50*2*sizeof(CUSTOMVERTEX), { }

//填充顶点缓冲区

CUSTOMVERTEX* pVertices;

if( FAILED( g_pVB->Lock( 0, 0, (void**)&pVertices, 0 ) ) )

return E_FAIL;

return E_FAIL;

0, D3DFVF_CUSTOMVERTEX,

D3DPOOL_DEFAULT, &g_pVB, NULL ) ) )

for( DWORD i=0; i<50; i++ ) {

FLOAT theta = (2*D3DX_PI*i)/(50-1);

pVertices[2*i+0].position = D3DXVECTOR3( sinf(theta),-1.0f, cosf(theta) );

pVertices[2*i+0].normal=D3DXVECTOR3( sinf(theta),0, cosf(theta) ); pVertices[2*i+1].position = D3DXVECTOR3( sinf(theta), 1.0f, cosf(theta) ); pVertices[2*i+1].normal=D3DXVECTOR3( sinf(theta),0, cosf(theta) );

} }

g_pVB->Unlock(); return S_OK;

//----------------------------------------------------------------------------- // Desc: 渲染图形.渲染函数

//----------------------------------------------------------------------------- VOID Render() { }

//清空后台缓冲区

g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(45, 50,255), 1.0f, 0 );

setlighting();

//开始在后台缓冲区绘制图形

if( SUCCEEDED( g_pd3dDevice->BeginScene() ) ) {

g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof(CUSTOMVERTEX) );

g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );

g_pd3dDevice->DrawPrimitive( D3DPT_TRI IP, 0, 2*50-2 );

//结束在后台缓冲区渲染图形 g_pd3dDevice->EndScene();

}

//将在后台缓冲区绘制的图形提交到前台缓冲区显示 g_pd3dDevice->Present( NULL, NULL, NULL, NULL );

试一试使用聚光灯的效果:

D3DLIGHT9 dir_light1;

D3DXVECTOR3 dir_vec1;

ZeroMemory(&dir_light1, sizeof(dir_light1)); dir_light1.Type = D3DLIGHT_SPOT; dir_light1.Specular.r = dir_light1.Specular.g=0.8f;

g_pd3dDevice->SetLight(1, &dir_light1); dir_light1.Specular.b=0.0f;

dir_light1.Position= D3DXVECTOR3(5.0f, 0.0f, 0.0f); dir_light1.Range=100;

dir_light1.Falloff=1.0f;// 辐射系数 dir_light1.Attenuation0 = 1.0f; dir_light1.Theta dir_light1.Phi

= 0.4f; = 0.6f;

// 衰减系数

// 内锥体大小 // 外锥体大小

dir_light1.Direction = D3DXVECTOR3(-1,0,0);

g_pd3dDevice->LightEnable(1, TRUE);

本文来源:https://www.bwwdw.com/article/vnj3.html

Top