(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. 如果材质是红色,光照是红色呢?
红色
//吸收红色可见光,反射同色光,视觉上呈现红色。
白色材质反射所有的光;同色材质反射同色的光;其他材质色吸收所有的光,不反射任何光线。