首页 > 技术文章 > Direct3D正方体光照效果

sjslove 2020-04-25 20:04 原文

(1) 绘制一个正方体,不指定正方体每个顶点的颜色,通过为场景添加光照效果,使得正方体看起来像是红色的。修改材质的属性和光照的属性,记录属性变化后程序运行的结果,分析结果并给出结论。

光照的组成

在Direct3D的光照模型中,由光源发出的光主要有3种类型:
   环境光(AmbientLight)               ——这种类型的灯光将被其他所有表面反射且被用在照亮整个场景。
   漫反射(DiffuseReflection)          ——这种灯光按照特殊方向传播。当它照射到一个表面,它将在所有方向上均匀的反射。(与位置无关,需考虑光传播方向及物体表面朝向)
   镜面反射(SpecularReflection)       ——这种灯光按照特殊方向传播。当它照射到一个表面时,它严格地按照一个方向反射。(需考虑观察者位置,光传播方向及物体表面朝向)
1. 头文件:d3dUtility.h
#include <d3dx9.h>
#include <string>

#ifndef __d3dUtilityH__
#define __d3dUtilityH__

//定义命名空间
namespace d3d
{

    //绘制窗体
    bool InitD3D(
HINSTANCE hInstance,
// [in] Application instance. //当前应用程序实例的句柄 int width, int height, // [in] Backbuffer dimensions. //窗口宽高 bool windowed, // [in] Windowed (true)or full screen (false). //窗体类型 D3DDEVTYPE deviceType, // [in] HAL or REF //设备的类型 IDirect3DDevice9** device // 设备用接口, 每个 D3D 程序至少有一个设备
   );// [out]The created device. 


   //消息循环 int EnterMsgLoop(bool (*ptr_display)(float timeDelta)); //回调函数 //处理窗口消息的函数 LRESULT CALLBACK WndProc(HWND hwnd,UINT msg, WPARAM wParam,LPARAM lParam); //窗口句柄、消息、 消息类型wParam(键盘消息) //释放资源   template<class T> void Release(T t) { if( t ) { t->Release(); t = 0; } } //删除资源   template<class T> void Delete(T t) { if( t ) { delete t; t = 0; } } //定义颜色信息 const D3DXCOLOR WHITE( D3DCOLOR_XRGB(255, 255, 255) ); //白色 const D3DXCOLOR BLACK( D3DCOLOR_XRGB( 0, 0, 0) ); //黑色 const D3DXCOLOR YELLOW( D3DCOLOR_XRGB(255, 255, 0) ); //黄色 const D3DXCOLOR CYAN( D3DCOLOR_XRGB( 0, 255, 255) ); //青色 const D3DXCOLOR MAGENTA( D3DCOLOR_XRGB(255, 0, 255) ); //紫红色 const D3DXCOLOR RED( D3DCOLOR_XRGB(255, 0, 0) ); //红色 const D3DXCOLOR GREEN( D3DCOLOR_XRGB( 0, 255, 0) ); //绿色 const D3DXCOLOR BLUE( D3DCOLOR_XRGB( 0, 0, 255) ); //蓝色                  //D3DCOLOR_XRGB(r,g,b) - Alpha值为1,三个byte分别表示红,绿,蓝



每种类型的光都可以使用D3DCOLORVALUE结构或D3DXCOLOR来描述光的颜色

//类型:D3DXCOLOR
  //红色环境光
//const D3DXCOLOR redAmbient(1.0f, 0.0f, 0.0f, 1.0f);
////漫反射光
//const D3DXCOLOR blueDiffuse(0.0f, 0.0f, 1.0f, 1.0f);
////镜面反射光
//const D3DXCOLOR whiteSpecular(1.0f, 1.0f, 1.0f, 1.0f);



//声明材质
D3DMATERIAL9 InitMtrl(D3DXCOLOR a /*环境光的颜色*/ , D3DXCOLOR d /*漫反射光的颜色*/, D3DXCOLOR s /*镜面光的颜色*/, D3DXCOLOR e /*增强物体的亮度*/, float p /*镜面高光点*/ );
//定义材质颜色
//白色材质
const D3DMATERIAL9 WHITE_MTRL  = InitMtrl(WHITE, WHITE, WHITE, BLACK, 2.0f);
//红色材质
const D3DMATERIAL9 RED_MTRL    = InitMtrl(RED, RED, RED, BLACK, 2.0f);
//绿色材质
const D3DMATERIAL9 GREEN_MTRL  = InitMtrl(GREEN, GREEN, GREEN, BLACK, 2.0f);
//蓝色材质
const D3DMATERIAL9 BLUE_MTRL   = InitMtrl(BLUE, BLUE, BLUE, BLACK, 2.0f);
//黄色材质
const D3DMATERIAL9 YELLOW_MTRL = InitMtrl(YELLOW, YELLOW, YELLOW, BLACK, 2.0f);

//d3dmaterial9
//物体表面对光的反射百分比
//Diffuse:指定此材质表面对漫射光的反射率
//Ambient——指定此材质表面对环境光的反射率;
//Specular——指定此材质表面对镜面光的反射率;
//Emissive——增强物体的亮度。
//Power——指定镜面高光点的锐度


//声明光源
//方向光(只有方向,没有位置)
D3DLIGHT9 InitDirectionalLight(D3DXVECTOR3* direction, D3DXCOLOR* color);
//点光源(只有位置,没有方向)
D3DLIGHT9 InitPointLight(D3DXVECTOR3* position, D3DXCOLOR* color);
//聚光灯(既有位置,又有方向)
D3DLIGHT9 InitSpotLight(D3DXVECTOR3* position, D3DXVECTOR3* direction, D3DXCOLOR* color);


//创建法向量(应用求三角锥的法向量)
//D3DXVECTOR3 CreatNormalVector(D3DXVECTOR3 P0,D3DXVECTOR3 P1,D3DXVECTOR3 P2){
//    向量(以原点为起始点)
//    
//    D3DXVECTOR3 P3;//结果
//
//    向量的减法
//    D3DXVECTOR3 U1=P1-P0; //(方向为p0->p1)
//    D3DXVECTOR3 V1=P2-P0; //(方向为p0->p2)
//
//    结构体
//    D3DXVECTOR3 *D3DXVec3Cross{
//        D3DXVECTOR3 *out; //结果
//        const D3DXVECTOR3 *pv1;
//        const D3DXVECTOR3 *pv2;
//    }
//    向量的叉积p3 = U1 * V1 
//    D3DXVec3Cross(&P3,&U1,&V1);

// 法向量归一化 // 结构体 // /* // D3DXVECTOR3 *D3DXVec3Normalize( // _Inout_ const D3DXVECTOR3 *pOut, // _In_ const D3DXVECTOR3 *pV // ); // // pOut 操作的结果 // pV 操作的源 // // 输入放在第二个参数,输出放在第一个参数。 // // 操作的过程:输入三维的向量,将向量归一化后输出(也就是保证向量模为1) // 比如输入的三维向量为P3( a, b, c ),那么输出的结果为v_out(a / L, b / L, c / L) // L = sqrt( a^2 + b^2 + c^2 ) // // */ // D3DXVec3Normalize(&P3,&P3); // // return P3; // //} //D3DXVECTOR3 P0(-1,0,-1); //D3DXVECTOR3 P1(0,1,0); //D3DXVECTOR3 P2(1,0,-1); //D3DXVECTOR3 P3 = CreatNormalVector(P0,P1,P2); } #endif // __d3dUtilityH__

 

 

2. d3dUtility.cpp
//引入头文件
#include "d3dUtility.h" //函数调用:初始化D3D bool d3d::InitD3D(HINSTANCE hInstance,int width, int height,bool windowed,D3DDEVTYPE deviceType,IDirect3DDevice9** device) //当前应用程序实例的句柄、 窗口宽高、 窗台类型、 设备类型、 设备用接口 { //************* 第一部分: 创建一个窗口开始 ***************
//(1)创建程序主窗口 // Create the main application window.
//1. 设计一个窗口类 WNDCLASS wc; wc.style = CS_HREDRAW | CS_VREDRAW; //风格样式 当窗口的水平(hredraw)或垂直(vredraw)尺寸发生变化时,窗口将被重绘 wc.lpfnWndProc = (WNDPROC)d3d::WndProc; //指定回调函数名(处理窗口产生的消息)的指针 wc.cbClsExtra = 0; //类额外内存 wc.cbWndExtra = 0; //窗口额外内存 wc.hInstance = hInstance; //当前应用程序实例的句柄,由 WinMain 传入 wc.hIcon = LoadIcon(0, IDI_APPLICATION); //图标 wc.hCursor = LoadCursor(0, IDC_ARROW); //光标 wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //设置窗口背景色,调用函数GetStockObject设置,需要把返回值强制转换成HBRUSH类型 wc.lpszMenuName = 0; //菜单名,0 为无菜单 wc.lpszClassName = L"1704210731_绘制图形"; // 指向窗口名的指针   
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//2. 注册窗口类 //传入WNDCLASS类型的变量地址 if( !RegisterClass(&wc) ) { ::MessageBoxA(0, "注册窗口失败!", 0, 0); return false; }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//3. 注册成功后,创建窗口 HWND hwnd = 0; hwnd = ::CreateWindow( L"1704210731_绘制图形", L"1704210731_绘制图形", WS_EX_TOPMOST,0, 0, width, height,0 /*parent hwnd*/, 0 /* menu */, hInstance, 0 /*extra*/); //和 wc.lpszClassName 相同、窗口的显示名称、指定这个窗口是顶部式窗口、表示窗口的横|纵坐标为默认值、表示窗口的宽|高为默认值、当前应用程序实例的句柄 //窗口创建失败 if( !hwnd ) { ::MessageBoxA(0, "窗口创建失败!", 0, 0); return false; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //4. 窗口显示 //传入CreateWindow返回的HWND类型参数 ::ShowWindow(hwnd, SW_SHOW); //显示窗口,用窗口句柄hwnd来指定需要显示的窗口 //因为还没有写窗口过程的回调函数,所以只能在后台运行 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//5. 窗口更新 //传入CreateWindow返回的HWND类型参数 ::UpdateWindow(hwnd); //************* 第一部分: 创建一个窗口结束 *************** //************* 第二部分: 初始化 D3D 开始 *************** //当显示了一个窗口后,需要继续创建一个Direct3D 9设备,这个设备用于绘制3D场景。 //(2)初始化 D3D 设备 // Init D3D:   //存储设备信息 HRESULT hr = 0; //COM 要求所有的方法都会返回一个 HRESULT 类型的错误号 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Step 1: Create the IDirect3D9 object. //1. 获取IDirect3D9 接口 IDirect3D9* d3d9 = 0; //(1)创建IDirect3D9 接口,这个接口用于获得物理设备的信息和创建一个IDirect3DDevice接口 d3d9 = Direct3DCreate9(D3D_SDK_VERSION); //(1)在创建一个IDirect3D9 接口对象来显示设备时 //(3)应该先设置该设备接口对象的顶点处理类型(硬件顶点处理类型、软件顶点处理类型) //(2)在这之前需要判断显卡是否支持这个技术类型
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//创建失败 if( !d3d9 ) { ::MessageBoxA(0, "创建IDirect3D9接口失败!", 0, 0); return false; }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Step 2: Check for hardware vp. //2. 检测显卡是否支持顶点转换和光照 //D3DCAPS9 保存了设备性能信息(包含顶点处理,纹理,shader等信息) D3DCAPS9 caps; //(2)判断显卡是否支持这个技术类型 //获取设备性能 d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, deviceType, &caps); //显卡、设备类型(HAL)通过硬件抽象层(HAL,Hardware Abstraction Layer)操作图形设备、返回一个已初始化的D3DCAPS9 结构 //硬件设备( D3DDEVTYPE_HAL ),软件设备(D3DDEVTYPE_REF)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//将顶点运算类型用变量vp保存供以后使用 int vp = 0; //设备性能是否可以使用硬件顶点处理 if( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT ) //硬件顶点处理 vp = D3DCREATE_HARDWARE_VERTEXPROCESSING; else vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING; //软件顶点处理 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Step 3: Fill out the D3DPRESENT_PARAMETERS structure. //初始化一个D3DPRESENT_PARAMETERS结构实例,这个结构包含了许多数据成员允许我们制定将要创建的IDirect3DDevice9接口的特性。 D3DPRESENT_PARAMETERS d3dpp; d3dpp.BackBufferWidth = width; //后备缓冲宽640像素 d3dpp.BackBufferHeight = height; //后备缓冲高480像素 d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8; //后备缓冲模式:32 位像素格式 d3dpp.BackBufferCount = 1; //后备缓冲表面的数量 d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; //全屏抗锯齿的类型 d3dpp.MultiSampleQuality = 0; //全屏抗锯齿的质量等级 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; //表面在交换链中是如何被交换的 d3dpp.hDeviceWindow = hwnd; //与设备相关的窗口句柄,在窗口绘制 d3dpp.Windowed = windowed; //窗口模式 d3dpp.EnableAutoDepthStencil = true; //自动创建深度|模版缓冲 d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8; //深度|模版缓冲的格式 深度值用24位二进制表示,模板8位 d3dpp.Flags = 0; //附加特性 d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; //刷新率 d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; //交换链中后台缓存切换到前台缓存的最大速率,立即交换 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Step 4: Create the device. //假如能支持硬件顶点处理,创建一个基于已经初始化好的D3DPRENSENT_PARAMENTS结构的IDirect3DDevice9对象 hr = d3d9->CreateDevice( D3DADAPTER_DEFAULT, // primary adapter //主显卡 deviceType, // device type //设备类型 hwnd, // window associated with device //窗口句柄 vp, // vertex processing //顶点处理方式 &d3dpp, // present parameters //指定一个已经初始化好的D3DPRESENT _PARAMETERS实例 device); // return created device //返回创建的设备
//创建失败 if( FAILED(hr) ) { // try again using a 16-bit depth buffer //将深度|模版缓冲的格式改为16位的深度缓冲 d3dpp.AutoDepthStencilFormat = D3DFMT_D16; //创建 hr = d3d9->CreateDevice( D3DADAPTER_DEFAULT, deviceType, hwnd, vp, &d3dpp, device); //16位的深度缓冲的对象创建失败 if( FAILED(hr) ) { d3d9->Release(); // done with d3d9 object //释放资源 ::MessageBoxA(0, "创建设备失败!", 0, 0); return false; } } d3d9->Release(); // done with d3d9 object return true; } //消息循环 int d3d::EnterMsgLoop( bool (*ptr_display)(float timeDelta) ) { MSG msg; ::ZeroMemory(&msg, sizeof(MSG)); static float lastTime = (float)timeGetTime(); while(msg.message != WM_QUIT) { if(::PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { ::TranslateMessage(&msg); ::DispatchMessage(&msg); } else { float currTime = (float)timeGetTime(); float timeDelta = (currTime - lastTime)*0.001f; ptr_display(timeDelta); lastTime = currTime; } } return msg.wParam; }



材质:物体表面对光的反射百分比。

//3.  (1)创建材质
//材质球
    //d3dmaterial9 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;
    ////指定当前材质
    ////setmaterial(const d3dmaterial9 *pmaterial)
    //device->setmaterial(&red);

//结构体
//typedef struct _D3DMATERIAL9{
//    D3DXCOLOR Diffuse /*漫反射*/,Ambient/*环境光*/,Specular/*镜面光*/,Emissive/*增强物体的亮度*/;
//    float Power/*镜面高光点*/;
//}D3DMATERIAL9;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//创建材质函数 D3DMATERIAL9 d3d::InitMtrl(D3DXCOLOR a, D3DXCOLOR d, D3DXCOLOR s, D3DXCOLOR e, float p) {
   //材质对象 D3DMATERIAL9 mtrl;
  //材质的颜色 mtrl.Ambient
= a; //材质环境光的颜色 mtrl.Diffuse = d; //材质漫反射光的颜色 mtrl.Specular = s; //材质镜面光的颜色 mtrl.Emissive = e; //增强亮度的颜色 mtrl.Power = p; //光的强度 return mtrl; }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//4. (1)创建光源
//光源结构体
//typedef struct _D3DLIGHT9 {
  //直射光
//    D3DLIGHTTYPE Type; /*光源类型:点光源、方向光源、聚光灯*/
//    //灯光类型,共3种:D3DLIGHT_POINT、D3DLIGHT_DIRECTIONAL(Directional)、D3DLIGHT_SPOT
//
//    //材质光的颜色
//    D3DCOLORVALUE Diffuse;  /*光源发出的漫反射光颜色*/
//    D3DCOLORVALUE Specular; /*镜面光的颜色*/
//    D3DCOLORVALUE Ambient; /*环境光的颜色*/
//
//    D3DVECTOR Position;  //位置(点光源没有方向有位置),用向量表示的光源世界坐标位置(对方向光无效)
//    D3DVECTOR Direction; //方向(方向光有方向没有位置没有角度),用向量表示的光源世界坐标照射方向(对点光源无效)
//    float Range;  //角度,灯光能够传播的最大范围(对方向光无效)
//    float Falloff; //衰弱,灯光从内圆锥到外圆锥之间的强度衰减(仅对聚光灯有效),该值通常设为1.0f。
//
//    //灯光衰减变量,用来定义灯光强度的传播距离衰减(对方向光无效)
//    float Attenuation0; /*定义恒定衰减*/
//    float Attenuation1; /*定义线性衰减*/
//    float Attenuation2; /*定义二次衰减*/
//    /*Attenuation0通常为 0.0f,Attenuation1通常为1.0f,Attenuation2通常为0.0f。*/
//
//    float Theta; /*指定灯光内圆锥的角度(仅对聚光灯有效),单位是弧度*/
//    float Phi; /*指定外圆锥的角度(仅对聚光灯有效),单位是弧度*/
//} D3DLIGHT9;

//(3)设置光源
    //D3DLIGHT9 light;
    //::ZeroMemory(&light, sizeof(light));
    //light.Type      = D3DLIGHT_DIRECTIONAL;
    //light.Ambient   = d3d::RED;
    //light.Diffuse   = d3d::RED * 0.3f;
    //light.Specular  = d3d::RED * 0.6f;
    ////方向光:下面到上面
    //light.Direction = D3DXVECTOR3(0.0f,-1.0f,0.0f);s

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//方向光 D3DLIGHT9 d3d::InitDirectionalLight(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 d3d::InitPointLight(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.Attenuation0
= 1.0f; light.Attenuation1 = 0.0f; light.Attenuation2 = 0.0f; return light; } //聚光灯 D3DLIGHT9 d3d::InitSpotLight(D3DXVECTOR3* position, D3DXVECTOR3* direction, D3DXCOLOR* color) { D3DLIGHT9 light; ::ZeroMemory(&light, sizeof(light));    //聚光灯 light.Type = D3DLIGHT_SPOT;
  
   //光照的反射率 light.Ambient
= *color * 0.0f; 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; }

 

流程:
1.定义带法向量的顶点结构体 2.创建顶点缓存并写数据 3.创建材质,并设置材质(设置材质对每种光的反射率) 4.创建光源,启动光源(设置光源的位置,方向和颜色) 5.设置取景变换和投影变换 6.绘制三角锥体

 

3. d3dinit.cpp
//////////////////////////////////////////////////////////////////////////////////////////////////

#include "d3dUtility.h"

//全局常量 const int Width = 640; const int Height = 480; // Globals //设备接口初始化 IDirect3DDevice9* Device = 0; //创建指向顶点缓冲区的指针对象 IDirect3DVertexBuffer9* cube = 0; //创建指向索引缓冲区的指针对象 //IDirect3DIndexBuffer9* IB = 0; //ID3DXMesh* sphere; // Framework Functions //定义结构体表示顶点 //创建带有颜色的顶点结构 //1. 定义带法向量的顶点结构体 struct Vertex { Vertex(){} //构造函数(初始化) Vertex(float x, float y, float z, float nx, float ny, float nz) { //顶点信息 _x = x; _y = y; _z = z; //法向量的信息 _nx = nx; _ny = ny ; _nz = nz; } //成员变量 float _x, _y, _z; //成员变量(法线) float _nx, _ny, _nz; //静态成员(顶点结构) static const DWORD FVF; }; //顶点格式 //让顶点信息包含法向量D3DFVF_NORMAL的信息 const DWORD Vertex::FVF = D3DFVF_XYZ | D3DFVF_NORMAL; //设置 bool Setup() { //1.创建缓冲区 //创建顶点缓冲 //顶点缓存接口IDirect3DVertexBuffer9() //Device->CreateVertexBuffer(4*sizeof(ColorVertex), D3DUSAGE_WRITEONLY,ColorVertex::FVF, D3DPOOL_DEFAULT, &sanjiaozhui, 0); //顶点缓冲区的长度4个、对缓存的操作(不能对缓存区进行读取)、灵活顶点格式 、顶点缓冲区的内存类型自动调度 、顶点缓冲区指针地址IDirect3DVertexBuffer9**、保留参数 //2. 创建顶点缓存并写数据
    //
IDirect3DVertexBuffer9* cube = 0;
  
  Device->CreateVertexBuffer(36*sizeof(Vertex), D3DUSAGE_WRITEONLY,Vertex::FVF, D3DPOOL_DEFAULT, &cube, 0);
//D3DXCreateSphere(Device,1.0f,20,20,&sphere,0);

    //创建索引缓存
    //索引缓存接口CreateIndexBuffer()
    //创建索引缓存并写数据
    /*Device->CreateIndexBuffer(
        36*sizeof(WORD),
        D3DUSAGE_WRITEONLY,
        D3DFMT_INDEX16,
        D3DPOOL_DEFAULT,
        &IB,
        0);*/


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    //访问顶点缓存内容
    //创建指向顶点结构体的指针对象
    Vertex *vertexs;
    //锁定访问的顶点缓冲区
    cube->Lock(0, 0, (void**)&vertexs, 0);
    //(1)UINT类型OffsetToLock,偏移量
    //(2)UINT类型的SizeToLock,所要锁定的字节数
    //(3)锁定整个缓冲区,获取指向缓存内容的指针
    //(4)描述锁定的方式

    //(2)对顶点缓冲区进行操作,将顶点数据写入
     //前面
    //法向量朝前
    vertexs[0] =  Vertex(-1.0f,  0.0f,  -1.0f,  0.0f,0.0f,-1.0f);
    vertexs[1] =  Vertex(-1.0f,  2.0f,  -1.0f,  0.0f,0.0f,-1.0f);
    vertexs[2] =  Vertex( 1.0f,  2.0f,  -1.0f,  0.0f,0.0f,-1.0f);
    vertexs[3] =  Vertex(-1.0f,  0.0f,  -1.0f,  0.0f,0.0f,-1.0f);
    vertexs[4] =  Vertex( 1.0f,  2.0f,  -1.0f,  0.0f,0.0f,-1.0f);
    vertexs[5] =  Vertex( 1.0f,  0.0f,  -1.0f,  0.0f,0.0f,-1.0f);
    
    //上面
    //法向量朝上
    vertexs[6] =  Vertex(-1.0f,  2.0f,  -1.0f,   0.0f,1.0f,0.0f);
    vertexs[7] =  Vertex(-1.0f,  2.0f,   1.0f,   0.0f,1.0f,0.0f);
    vertexs[8] =  Vertex( 1.0f,  2.0f,   1.0f,   0.0f,1.0f,0.0f);
    vertexs[9] =  Vertex(-1.0f,  2.0f,  -1.0f,   0.0f,1.0f,0.0f);
    vertexs[10]=  Vertex( 1.0f,  2.0f,   1.0f,   0.0f,1.0f,0.0f);
    vertexs[11]=  Vertex( 1.0f,  2.0f,  -1.0f,   0.0f,1.0f,0.0f);

    //右边
    //法向量朝右
    vertexs[12] =  Vertex( 1.0f,  0.0f,  -1.0f,  1.0f,0.0f,0.0f);
    vertexs[13] =  Vertex( 1.0f,  2.0f,  -1.0f,  1.0f,0.0f,0.0f);
    vertexs[14] =  Vertex( 1.0f,  2.0f,   1.0f,  1.0f,0.0f,0.0f);
    vertexs[15] =  Vertex( 1.0f,  0.0f,  -1.0f,  1.0f,0.0f,0.0f);
    vertexs[16] =  Vertex( 1.0f,  2.0f,   1.0f,  1.0f,0.0f,0.0f);
    vertexs[17] =  Vertex( 1.0f,  0.0f,   1.0f,  1.0f,0.0f,0.0f);

    //左边
    //法向量朝左
    vertexs[18] =  Vertex(-1.0f,  0.0f,  -1.0f,  -1.0f,0.0f,0.0f);
    vertexs[19] =  Vertex(-1.0f,  2.0f,   1.0f,  -1.0f,0.0f,0.0f);
    vertexs[20] =  Vertex(-1.0f,  2.0f,  -1.0f,  -1.0f,0.0f,0.0f);
    vertexs[21] =  Vertex(-1.0f,  0.0f,  -1.0f,  -1.0f,0.0f,0.0f);
    vertexs[22] =  Vertex(-1.0f,  0.0f,   1.0f,  -1.0f,0.0f,0.0f);
    vertexs[23] =  Vertex(-1.0f,  2.0f,   1.0f,  -1.0f,0.0f,0.0f);

    //后面
    //法向量朝后
    vertexs[24] =  Vertex(-1.0f,  0.0f,   1.0f, 0.0f,0.0f,1.0f);
    vertexs[25] =  Vertex( 1.0f,  2.0f,   1.0f, 0.0f,0.0f,1.0f);
    vertexs[26] =  Vertex(-1.0f,  2.0f,   1.0f, 0.0f,0.0f,1.0f);
    vertexs[27] =  Vertex(-1.0f,  0.0f,   1.0f, 0.0f,0.0f,1.0f);
    vertexs[28] =  Vertex( 1.0f,  0.0f,   1.0f, 0.0f,0.0f,1.0f);
    vertexs[29] =  Vertex( 1.0f,  2.0f,   1.0f, 0.0f,0.0f,1.0f);

    //下面
    //法向量朝下
    vertexs[30] =  Vertex(-1.0f,  0.0f,  -1.0f, 0.0f,-1.0f,0.0f);
    vertexs[31] =  Vertex( 1.0f,  0.0f,   1.0f, 0.0f,-1.0f,0.0f);
    vertexs[32] =  Vertex(-1.0f,  0.0f,   1.0f, 0.0f,-1.0f,0.0f);
    vertexs[33] =  Vertex(-1.0f,  0.0f,  -1.0f, 0.0f,-1.0f,0.0f);
    vertexs[34] =  Vertex( 1.0f,  0.0f,  -1.0f, 0.0f,-1.0f,0.0f);
    vertexs[35] =  Vertex( 1.0f,  0.0f,   1.0f, 0.0f,-1.0f,0.0f);

    
    //解锁顶点缓冲区
    cube->Unlock();

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        
    //2. (2)访问索引缓存区的内容
    //创建指向索引缓冲区指针对象
    //WORD* indices = NULL;
 //   IB->Lock(0,0,(void**)&indices,0); 

    ////前面
    //indices[0]  = 6; indices[1]  = 1; indices[2]  = 0;
    //indices[3]  = 0; indices[4]  = 5; indices[5]  = 6;

    ////后面
    //indices[6]  = 7; indices[7]  = 2; indices[8]  = 3;
    //indices[9]  = 3; indices[10] = 4; indices[11] = 7;

    ////上面
    //indices[12]  = 5; indices[13]  = 6; indices[14]  = 3;
    //indices[15]  = 3; indices[16]  = 4; indices[17]  = 5;

    ////下面
    //indices[18]  = 0; indices[19]  = 1; indices[20]  = 2;
    //indices[21]  = 2; indices[22] = 7; indices[23] = 0;

    ////左面
    //indices[24]  = 5; indices[25]  = 0; indices[26]  = 7;
    //indices[27]  = 7; indices[28]  = 4; indices[29]  = 5;

    ////右面
    //indices[30]  = 6; indices[31]  = 1; indices[32]  = 2;
    //indices[33]  = 2; indices[34] = 3; indices[35] = 6;

    ////解锁缓冲区
    //IB->Unlock();


    //////////////////////////////////////////////////////////////////////////

    //3.(1) 创建材质对象
    D3DMATERIAL9 mtrl;
    //材质为白色(封装函数)
    mtrl = d3d:: WHITE_MTRL;
//白色材质
const D3DMATERIAL9 WHITE_MTRL  = InitMtrl(WHITE, WHITE, WHITE, BLACK, 2.0f);
// (2) 设置材质
    Device->SetMaterial(&mtrl);
SetMaterial(CONST D3DMATERIAL9 *pMaterial)函数用于指定当前材质。
//创建并设置材质
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;


 D3DMATERIAL9 mtrl;

  mtrl.Ambient = d3d::RED;

  mtrl.Diffuse = d3d::RED;

  mtrl.Specular = d3d::RED;

  mtrl.Emissive = d3d::BLACK;

  mtrl.Power = 5.0f;

  Device->SetMaterial(&mtrl);

//红色材质
const D3DMATERIAL9 RED_MTRL  = InitMtrl(RED, RED, RED, BLACK, 5.0f);

//
4. 光源
//(1)光源对象 D3DLIGHT9 light; //(2)光源的颜色 D3DXCOLOR c = d3d::RED; //3维向量 //(3)方向从下到上 D3DXVECTOR3 direction(0.0f,1.0f,0.0f); //(4)位置 //D3DXVECTOR3 pos(0.0f,0.0f,-1.0f); //(5)方向光 light = d3d::InitDirectionalLight(&direction,&c);
D3DLIGHT9 d3d::InitDirectionalLight(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; }
//(6) 设置0号光
    Device->SetLight(0,&light);
    //(7) 开启0号光(开启光照效果)
    Device->LightEnable(0,true);

    //////////////////////////////////////////////////////////////////////////

//5. 设置取景变换和投影变换、视口变换 //取景变换 D3DXVECTOR3 position(0.0f, 0.0f, -3.0f); D3DXVECTOR3 target(0.0f, 0.0f, 0.0f); D3DXVECTOR3 up(0.0f, 1.0f, 0.0f); D3DXMATRIX V; D3DXMatrixLookAtLH(&V, &position, &target, &up); Device->SetTransform(D3DTS_VIEW, &V); //投影变换 //观察坐标系 -> 投影坐标 //创建一个投影矩阵 D3DXMATRIX proj; D3DXMatrixPerspectiveFovLH(&proj, D3DX_PI * 0.5f, float(640)/float(480),1.0f, 1000.0f); //获得的投影矩阵 、 y轴向上的视角(直角)、前裁剪面的高宽比 、最近的平面(前裁剪面距离) 、最远的平面(后裁剪面距离) Device->SetTransform(D3DTS_PROJECTION, &proj); //投影变换 //视口变换 D3DVIEWPORT9 vp={0,0,Width,Height,0,1}; //左上角为原点(0,0)、屏幕宽|高、最小|最大深度缓冲值 Device->SetViewport(&vp); ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //6. 改变渲染状态 /开启规范化法向量 //使用了自定义的顶点格式中有使用法向量的需要开启 Device->SetRenderState(D3DRS_NORMALIZENORMALS, true); //开启光源 //要为每个顶点设定法线,只有设置了法线,灯光才会起作用 Device->SetRenderState(D3DRS_LIGHTING, true); //镜面光 Device->SetRenderState(D3DRS_SPECULARENABLE, false); //使用顶点颜色进行渲染,如果不禁用的话,将会看到一个黑色的多边形 //Device->SetRenderState(D3DRS_LIGHTING, FALSE); //因为使用顶点颜色渲染,所以要禁用光照处理 //线模式 //Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME); //允许渲染背面 //消隐模式,按照三角形单元的顶点绕序进行背面消隐 //关闭“挑选”功能,允许渲染背面 Device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); /*Device->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT);*/ //平面着色 return true; } //释放存储空间 void Cleanup() { d3d::Release<IDirect3DVertexBuffer9*>(cube); //d3d::Release<ID3DXMesh*>(sphere); }
//图形的渲染
bool Display(float timeDelta) { if( Device ) // Only use Device methods if we have a valid device. { Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0); //绘制目标表面(后台缓存)|深度缓存 黑色 深度缓存值为1.0 //对表面执行清除操作 //开始绘制 Device->BeginScene(); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //1.设置数据流的来源(绘制图形流水线) //指定数据流输入源,将顶点缓存和数据流进行链接 Device->SetStreamSource(0, cube, 0, sizeof(Vertex)); //数据流id、缓冲区接口即与数据流建立链接的顶点缓存的指针、从0号接口开始绑定(传播的顶点数据的起始位置)、顶点缓存中元素的大小 //2.设置索引缓存,指向索引缓存的指针 /*Device->SetIndices(IB);*/ //3.设置顶点格式:D3DFVF_XYZ Device->SetFVF(Vertex::FVF); //4. 绘制图元 Device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 12); //指定所要绘制的图元类型三角形列、索引增加的基数、最小索引值、顶点总数、表示索引的读取其顶点的元素索引、绘制图元的总数) //6. 旋转90度 /*D3DXMATRIX Rx; D3DXMatrixRotationX(&Rx, 3.14/2); Device->SetTransform(D3DTS_WORLD, &Rx);*/ //世界变换 D3DXMATRIX W; D3DXMatrixTranslation(&W,0.0f,-1.0f,0.0f); //Device->SetTransform(D3DTS_WORLD, &W); //旋转45度 D3DXMATRIX Rx; D3DXMatrixRotationX(&Rx,3.14/4); //Device->SetTransform(D3DTS_WORLD, &Rx); //绕Y轴连续旋转 D3DXMATRIX Ry; static float y = 0.0f; D3DXMatrixRotationY(&Ry, y); //Device->SetTransform(D3DTS_WORLD, &Ry); y+=timeDelta; //超过一圈360度 if(y >= 6.28){ y = 0.0f; }
//实现变换 D3DXMATRIX P; P = W * Rx * Ry; Device->SetTransform(D3DTS_WORLD, &P); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //结束绘制 Device->EndScene(); // Swap the back and front buffers. Device->Present(0, 0, 0, 0); } return true; }

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// WndProc //回调函数 WnProc 的函数体 //处理窗口消息的函数 LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) //创建的窗口、接受的消息、w表示word,l表示long,对于32为系统来说,分别是无符号整数(unsigned int)和长整型(long),都是32位整数。 //WndProc的第三个参数类型被定义为WORD,表示一个16位的无符号短整型,而第四个参数被定义为LONG,表示一个32的位有符号长整型,“PARAM”前缀“W”和“L”正是由此而来。 //wParam&MK_SHIFT或MK_CTRL //wParam参数指明移动或者单击鼠标键的非客户区位置 { //参数 msg 的键值判断消息的类型 switch( msg ) { // 如果是关闭窗口的消息,则用 PostQuitMessage() 来退出消息循环 case WM_DESTROY: ::PostQuitMessage(0); break; //如果按下键盘任意一个键 case WM_KEYDOWN: // 如果是 ESC 键则关闭窗口 if( wParam == VK_ESCAPE ) ::DestroyWindow(hwnd); /*if(wParam == 0x41) { D3DXVECTOR3 direction(1.0f,0.0f,0.0f); light = d3d::InitDirectionalLight(&direction, &c); } if(wParam == 0x42) { D3DXVECTOR3 position(0.0f,0.0f,-1.0f); light = d3d::InitPointLight(&position, &c); } if(wParam == 0x43) { D3DXVECTOR3 position(0.0f,0.0f,-1.0f); D3DXVECTOR3 direction(0.0f,0.0f,1.0f); light = d3d::InitSpotLight(&position, &direction,&c); }*/ break; // 如果按下鼠标左键则弹出消息框,这里 WM_LBUTTONDOWN 是鼠标左键的键值 case WM_LBUTTONDOWN: // L"Hello, World" 是消息框中显示的内容 // L"Hello" 是所在父窗口的指针 // MB_OK 表示消息框显示 “确定” 按钮 ::MessageBox(0, L"Hello, World", L"Hello", MB_OK); break; }
return ::DefWindowProc(hwnd, msg, wParam, lParam); //用 DefWindowProc 处理一些默认的消息,比如窗口的最大化、最小化、调整尺寸等
}
// WinMain //程序的入口函数 int WINAPI WinMain(HINSTANCE hinstance,HINSTANCE prevInstance, PSTR cmdLine,int showCmd) //当前实例的句柄、不使用该参数,Win32 该参数始终为 NULL、用于运行程序的命令行参数字符串、指定窗口的显示方式 { // 调用窗口初始化函数,如果调用成功则进入消息循环,否则弹出一个对话框 if(!d3d::InitD3D(hinstance,640, 480, true, D3DDEVTYPE_HAL, &Device)) //当前应用程序实例的句柄、窗口宽640、高480、窗台类型(windowed)、设备类型(HAL)、设备用接口 { ::MessageBoxA(0, "初始化失败!", 0, 0); return 0; } //顶点缓存创建失败 if(!Setup()) { ::MessageBoxA(0, "创建失败!", 0, 0); return 0; } //进入消息循环 -- 函数名调用 d3d::EnterMsgLoop( Display ); Cleanup(); Device->Release(); return 0; }

 

 

 

 

 

 

 

 

 来源:http://www.doc88.com/p-7788454774688.html

 

 来源:https://zhidao.baidu.com/question/686759478766334532.html

1. 如果材质是白色,光照为红色(绿、蓝),看到的是什么颜色的锥体?
//光照在白色的物体表面,会反射所有的光线,视觉上呈现红色(绿、蓝)
//3. (1)材质对象
    D3DMATERIAL9 mtrl;
    //材质颜色:白色
    mtrl = d3d:: WHITE_MTRL;
    //3.  (2)设置材质
    Device->SetMaterial(& mtrl);
//4. 光源
    //(1)光源对象
    D3DLIGHT9 light;

    //(2)光源的颜色:红色
    D3DXCOLOR c = d3d::RED;

    //3维向量
    //(3)方向从下到上
    D3DXVECTOR3 direction(0.0f,1.0f,0.0f);
    //(4)位置
    //D3DXVECTOR3 pos(0.0f,0.0f,-1.0f);

    //(5)方向光
    light = d3d::InitDirectionalLight(&direction,&c);


    //(6) 设置0号光
    Device->SetLight(0,&light);
    //(7) 开启0号光
    Device->LightEnable(0,true);

 

 

 

2. 如果材质是红色,光照为白色呢?
//材质本身的颜色(白色是一种包含光谱中所有颜色光的颜色)
//光被物体吸收,经过反射(混合其他色),呈现红色。
//3. (1)材质对象
    D3DMATERIAL9 mtrl;
    //材质为红色
    mtrl = d3d:: RED_MTRL;
    //3.  (2)设置材质
    Device->SetMaterial(& mtrl);

    
    //4. 光源
    //(1)光源对象
    D3DLIGHT9 light;

    //(2)光源的颜色:白色
    D3DXCOLOR c = d3d::WHITE;

    //3维向量
    //(3)方向从下到上
    D3DXVECTOR3 direction(0.0f,1.0f,0.0f);
    //(4)位置
    //D3DXVECTOR3 pos(0.0f,0.0f,-1.0f);

    //(5)方向光
    light = d3d::InitDirectionalLight(&direction,&c);


    //(6) 设置0号光
    Device->SetLight(0,&light);
    //(7) 开启0号光
    Device->LightEnable(0,true);

 

3. 如果材质是红色,光照是蓝色(绿色)呢?
//吸收蓝光(绿光),不反射任何颜色的光,呈现黑色。
(材质颜色如果吸收光谱内的所有可见光,不反射任何颜色的光,人眼的感觉就是黑色的)

 

4. 如果材质是红色,光照是红色呢?
红色
//吸收红色可见光,反射同色光,视觉上呈现红色。

 

 

 

白色材质反射所有的光;同色材质反射同色的光;其他材质色吸收所有的光,不反射任何光线。

 

推荐阅读