这个程序是基于上个程序修改而来,为每一个面贴图。但是之前一直有问题,纹理一直不能正确显示
1.不显示纹理。如下图所示
经排查,问题出在Render函数里面设置顶点格式d3dDevice->SetFVF(D3DFVF_XYZ).然后我就修改成了自定义的格式Vertex::FVF。
2.上面修改完成后,纹理显示不正常,并不是每个面分别一个贴图。而是贴图混乱。如下图所示:
最后参考了http://blog.youkuaiyun.com/poem_qianmo/article/details/8523341这篇博文,发现自定义的顶点格式有问题
const DWORD Vertex::FVF=D3DFVF_XYZ | D3DFVF_TEX1 | D3DFVF_NORMAL;
去掉D3DFVF_NORMAL程序运行就正常了。如下图所示
至于原因,我google了一下,D3DFVF_NORMAL的定义是这样的:
还是不明白为什么它影响纹理贴图。
下面是源代码
1 #include <Windows.h> 2 #include <d3d9.h> 3 #include <D3DX9math.h> 4 #include <strsafe.h> 5 #include <d3dx9tex.h> 6 //全局变量 7 8 LPDIRECT3D9 d3D9 = NULL; // IDirect3D9接口指针,用于获得物理设备信息和创建IDirect3DDeivce9接口。 9 LPDIRECT3DDEVICE9 d3dDevice = NULL; // 代表显示3d图形的物理设备的C++对象。 10 LPDIRECT3DVERTEXBUFFER9 vertexBuffer = NULL; // 顶点缓存,用于存储顶点坐标。 11 LPDIRECT3DINDEXBUFFER9 indexBuffer = NULL; // 索引缓存,用于存储组成各个三角形的顶点的索引 12 LPDIRECT3DTEXTURE9 tex = NULL; // 材质 13 struct Vertex // 三维中顶点结构 14 { 15 float x, y, z; 16 float _u, _v; //texture coordinates 17 static const DWORD FVF; 18 }; 19 const DWORD Vertex::FVF=D3DFVF_XYZ | D3DFVF_TEX1; 20 21 //初始化 Direct3D 22 BOOL InitD3D(HWND hwnd) 23 { 24 if( NULL == (d3D9 = Direct3DCreate9(D3D_SDK_VERSION))) // 该初始化函数保证应用程序通过正确的头文件被生成。 25 return E_FAIL; 26 27 28 29 D3DCAPS9 caps; //device capabilitites 30 d3D9->GetDeviceCaps( // 获取设备信息 31 D3DADAPTER_DEFAULT, //Adapter 指定获取哪个显示适配器的特性 32 D3DDEVTYPE_HAL, // 设备类型 硬件设备:D3DDEVTYPE_HAL 软件设备:D3DDEVTYPE_REF 33 &caps); //返回填充后的D3DCAPS9结构。 34 35 int vp = 0; //代表是否支持硬件顶点处理 36 if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) //显卡是否支持硬件几何转换和光源计算 37 { 38 vp = D3DCREATE_HARDWARE_VERTEXPROCESSING; //支持,硬件方式处理顶点 39 } 40 else 41 { 42 vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING; //软件方式处理顶点 43 } 44 45 D3DPRESENT_PARAMETERS d3dparam; // 这个结构用于设定我们将要创建的IDirect3DDevice9对象的一些特性 46 ZeroMemory(&d3dparam, sizeof(d3dparam)); 47 d3dparam.BackBufferWidth = 800; //后备缓冲表面的宽度 48 d3dparam.BackBufferHeight = 600; //后备缓冲表面的高度 49 d3dparam.BackBufferFormat = D3DFMT_A8R8G8B8; //后备缓冲表面的像素格式 50 d3dparam.BackBufferCount = 1; // 后备表面的个数 51 d3dparam.MultiSampleType = D3DMULTISAMPLE_NONE; //全屏抗锯齿的类型 52 d3dparam.MultiSampleQuality = 0; //全屏抗锯齿的质量等级 53 d3dparam.SwapEffect = D3DSWAPEFFECT_DISCARD; // 指定表面在交换链中是如何被交换的 54 d3dparam.hDeviceWindow = hwnd; // 窗口句柄 55 d3dparam.Windowed = true; //是否窗口模式 56 d3dparam.EnableAutoDepthStencil = true; // 深度/模板缓冲 57 d3dparam.AutoDepthStencilFormat = D3DFMT_D24S8; //深度/模板缓冲的等级 58 d3dparam.Flags = 0; // 一些附加特性 59 d3dparam.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; //刷新率 60 d3dparam.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; //属于D3DPRESENT 成员,又有两个常用标志,其余请查SDK: 61 62 //创建IDirect3DDevcie9对象 63 if(FAILED(d3D9->CreateDevice( 64 D3DADAPTER_DEFAULT, //adapter 65 D3DDEVTYPE_HAL, //设备类型 66 hwnd, //窗口句柄 67 vp, //顶点处理方式 68 &d3dparam, &d3dDevice))) 69 { 70 return E_FAIL; 71 } 72 return true; 73 } 74 75 // 创建顶点缓存 76 bool InitVertexBuffer() 77 { 78 79 // 初始化正方体的24顶点 80 Vertex vertex[] = 81 { //正面 82 {-1.0f, 1.0f, -1.0f, 0.0f, 0.0f}, 83 {1.0f, 1.0f, -1.0f, 1.0f, 0.0f}, 84 {1.0f, -1.0f, -1.0f, 1.0f, 1.0f}, 85 {-1.0f, -1.0f, -1.0f, 0.0f, 1.0f}, 86 //背面 87 {1.0f, 1.0f, 1.0f,0.0f, 0.0f}, 88 {-1.0f, 1.0f, 1.0f, 1.0f, 0.0f}, 89 {-1.0f, -1.0f, 1.0f, 1.0f, 1.0f}, 90 {1.0f, -1.0f, 1.0f, 0.0f, 1.0f}, 91 //左面 92 {-1.0f, 1.0f, 1.0f, 0.0f, 0.0f}, 93 {-1.0f, 1.0f, -1.0f,1.0f, 0.0f}, 94 {-1.0f, -1.0f, -1.0f, 1.0f, 1.0f}, 95 {-1.0f, -1.0f, 1.0f, 0.0f, 1.0f}, 96 //右面 97 {1.0f, 1.0f, -1.0f, 0.0f, 0.0f}, 98 {1.0f, 1.0f, 1.0f, 1.0f, 0.0f}, 99 {1.0f, -1.0f, 1.0f, 1.0f, 1.0f}, 100 {1.0f, -1.0f, -1.0f, 0.0f, 1.0f}, 101 //底面 102 {-1.0f, -1.0f, -1.0f, 0.0f, 0.0f}, 103 {1.0f, -1.0f, -1.0f, 1.0f, 0.0f}, 104 {1.0f, -1.0f, 1.0f, 1.0f, 1.0f}, 105 {-1.0f, -1.0f, 1.0f, 0.0f, 1.0f}, 106 //上面 107 {-1.0f, 1.0f, 1.0f, 0.0f, 0.0f}, 108 {1.0f, 1.0f, 1.0f, 1.0f, 0.0f}, 109 {1.0f, 1.0f, -1.0f, 1.0f, 1.0f}, 110 {-1.0f, 1.0f, -1.0f, 0.0f, 1.0f} 111 112 }; 113 if(FAILED(d3dDevice->CreateVertexBuffer( //创建顶点缓存 114 24*sizeof(Vertex), // 分配给缓存的字节大小 115 0, //指定关于怎样使用缓存的额外信息 116 Vertex::FVF, // 存储杂牌缓存中的顶点格式 117 D3DPOOL_DEFAULT, //缓存放置在哪一个内存池中 118 &vertexBuffer, //返回创建好的顶点缓存的指针 119 NULL))) // 没有使用 120 { 121 return false; 122 } 123 Vertex *vetices; 124 vertexBuffer->Lock(0, 0, (void**)&vetices, 0); //锁存整个缓存 125 memcpy(vetices, vertex, sizeof(vertex)); //想缓存里写顶点 126 vertexBuffer->Unlock(); //解锁缓存 127 return true; 128 } 129 130 //设置照相机和投影 131 void SetupMatrices() 132 { 133 D3DXMATRIX matWorld, Rx, Ry, Rz; 134 D3DXMatrixIdentity(&matWorld); // 单位化世界矩阵 135 D3DXMatrixRotationX(&Rx, D3DX_PI *(::timeGetTime() / 1000.0f)); // 绕X轴旋转 136 D3DXMatrixRotationY(&Ry, D3DX_PI *( ::timeGetTime() / 1000.0f/2)); // 绕Y轴旋转 137 D3DXMatrixRotationZ(&Rz, D3DX_PI *( ::timeGetTime() / 1000.0f/3)); // 绕Z轴旋转 138 matWorld = Rx * Ry * Rz * matWorld; // 得到最终的组合矩阵 139 d3dDevice->SetTransform(D3DTS_WORLD, &matWorld); //设置世界变换矩阵 140 141 D3DXVECTOR3 position(3.0f, 3.0f, 3.0f); //虚拟照相机坐标 142 D3DXVECTOR3 target(0.0f, 0.0f, 0.0f); // 目标物体坐标 143 D3DXVECTOR3 up(0.0f, 1.0f, 0.0f); //正上方坐标 144 D3DXMATRIX v; 145 D3DXMatrixLookAtLH(&v, &position, &target, &up); //计算视图坐标系的变换矩阵 146 147 d3dDevice->SetTransform(D3DTS_VIEW, &v); //视图坐标系变换 148 149 D3DXMATRIX proj; //投影矩阵 150 //计算投影矩阵 151 D3DXMatrixPerspectiveFovLH(&proj, 152 D3DX_PI*0.5f, //视野角度 153 800.0/600.0, //宽高比 154 1.0f, //前裁剪面距离 155 1000.0f); //后裁剪面距离 156 d3dDevice->SetTransform(D3DTS_PROJECTION, &proj); //设置投影变换 157 158 } 159 160 void InitTexture() 161 { 162 D3DXCreateTextureFromFile(d3dDevice, L"texture.bmp", &tex); // 创建纹理 163 d3dDevice->SetTexture(0, tex); 164 165 //设置过滤器 166 d3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); 167 d3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); 168 d3dDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT); 169 170 d3dDevice->SetRenderState(D3DRS_LIGHTING, false); //关闭灯光 171 } 172 //初始化索引缓存 173 bool InitIntextBuffer() 174 { 175 d3dDevice->CreateIndexBuffer(36*sizeof(WORD), 176 D3DUSAGE_WRITEONLY, 177 D3DFMT_INDEX16, //指定索引的大小 178 D3DPOOL_MANAGED, 179 &indexBuffer, 180 0); 181 WORD* indices = 0; 182 indexBuffer->Lock(0, 0, (void**)&indices, 0); 183 //前面 184 indices[0] = 0; indices[1] = 1; indices[2] = 2; 185 indices[3] = 0; indices[4] = 2; indices[5] = 3; 186 // 背面 187 indices[6] = 4; indices[7] = 5; indices[8] = 6; 188 indices[9] = 4; indices[10] = 6; indices[11] = 7; 189 // 左面 190 indices[12] =8; indices[13] =9; indices[14] = 10; 191 indices[15] = 8; indices[16] = 10; indices[17] = 11; 192 // 右面 193 indices[18] = 12; indices[19] = 13; indices[20] =14; 194 indices[21] = 12; indices[22] = 14; indices[23] =15; 195 //底面 196 indices[24] = 16; indices[25] = 17; indices[26] =18; 197 indices[27] = 16; indices[28] = 18; indices[29] = 19; 198 //顶面 199 indices[30] =20; indices[31] = 21; indices[32] =22; 200 indices[33] = 20; indices[34] = 22; indices[35] = 23; 201 202 indexBuffer->Unlock(); 203 return true; 204 } 205 //释放COM资源 206 bool CleanUp() 207 { 208 if(indexBuffer != NULL) 209 indexBuffer->Release(); 210 if(vertexBuffer != NULL) 211 vertexBuffer->Release(); 212 if(d3dDevice != NULL) 213 d3dDevice->Release(); 214 if(d3D9 != NULL) 215 d3D9->Release(); 216 return true; 217 } 218 //渲染 219 bool Render() 220 { 221 d3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xff000000, 1.0f, 0); 222 if(SUCCEEDED(d3dDevice->BeginScene())) //开始场景绘制 223 { 224 SetupMatrices(); //设置照相机和投影 225 226 // 设置资源流与一个顶点缓存挂钩 227 d3dDevice->SetStreamSource(0, vertexBuffer, 0, sizeof(Vertex)); 228 d3dDevice->SetIndices(indexBuffer); //设置索引缓存 229 d3dDevice->SetFVF(Vertex::FVF); //设置顶点格式 230 231 //使用索引来绘制图元 232 d3dDevice->DrawIndexedPrimitive( 233 D3DPT_TRIANGLELIST, //图元类型 234 0, //一个基本数字,在调用中用它去加上索引 235 0, //将被引用的最小索引值 236 24, //顶点数 237 0, //开始渲染的开始索引点 238 12); //绘制图元的个数 239 d3dDevice->EndScene(); //结束场景绘制 240 } 241 d3dDevice->Present(NULL, NULL, NULL, NULL); //翻转表面 242 return true; 243 } 244 //消息处理函数 245 LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 246 { 247 switch( msg ) 248 { 249 case WM_DESTROY: 250 CleanUp(); 251 PostQuitMessage( 0 ); 252 return 0; 253 } 254 return DefWindowProc( hwnd, msg, wParam, lParam ); 255 } 256 257 //main函数 258 INT WINAPI wWinMain( __in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in LPWSTR lpCmdLine, __in int nShowCmd ) 259 { 260 UNREFERENCED_PARAMETER(hInstance); 261 WNDCLASSEX wc = { 262 sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L, 263 GetModuleHandle(NULL), NULL, NULL, NULL, NULL, 264 L"Cubedemo", NULL 265 }; 266 RegisterClassEx(&wc); 267 268 HWND hwnd = CreateWindow(L"CubeDemo", L"CubeDemo", 269 WS_OVERLAPPEDWINDOW, 100, 100, 800, 600, NULL, NULL, hInstance, NULL); 270 271 if(InitD3D(hwnd)) 272 { 273 if(InitVertexBuffer() && InitIntextBuffer()) 274 { 275 InitTexture(); 276 ShowWindow(hwnd, SW_SHOWDEFAULT); 277 UpdateWindow(hwnd); 278 MSG msg; 279 ZeroMemory(&msg, sizeof(msg)); 280 while(msg.message != WM_QUIT) 281 { 282 if(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE)) 283 { 284 TranslateMessage(&msg); 285 DispatchMessage(&msg); 286 } 287 else 288 { 289 Render(); 290 } 291 } 292 293 } 294 } 295 UnregisterClass(L"CubeDemo", wc.hInstance); 296 return 0; 297 298 }