粒子系统类,粒子系统是游戏里细小元素的控制系统,虽然感觉上它对游戏的影响不大,但是其实有了它能给游戏增色不少。粒子系统控制着细小元素的生死,运动,纹理。对它的编写让我知道,游戏里的这一片从天空飘落的雪花其实是之前那一朵已经融化在地上的雪花。
这个类我还没有编写完整,因为我发现如果要真正实现那种很美的效果我还要多加学习啊。使用广告版技术让人觉得它真的是个粒子,开启alpha通道能让粒子与背景融为一体,开启光照能让粒子煜煜生辉,给纹理混合上颜色才能让粒子真正的变幻幻幻(不是打错字)起来。
particleSysclass.h
1 #pragma once 2 #include <d3d11.h> 3 #include <d3dcompiler.h> 4 #include <D3DX11.h> 5 #include <xnamath.h> 6 #include<time.h> 7 #pragma comment(lib,"d3dx11.lib") 8 #pragma comment(lib,"d3d11.lib") 9 #pragma comment(lib,"d3dcompiler.lib") 10 class particleSysclass 11 { 12 public: 13 particleSysclass(); 14 ~particleSysclass(); 15 16 private: 17 ID3D11ShaderResourceView* m_texture; 18 struct vertex 19 { 20 XMFLOAT3 pos; 21 XMFLOAT2 tex; 22 }; 23 struct particle 24 { 25 XMFLOAT3 pos; 26 float size; 27 bool alive; 28 }; 29 struct constantBuffer 30 { 31 XMMATRIX world; 32 XMMATRIX view; 33 XMMATRIX pro; 34 }; 35 36 vertex *m_vertexarray; 37 particle *m_particlearray; 38 int m_particlecountMAX; 39 int m_particlecountCUR; 40 XMFLOAT3 m_sourcepos; 41 42 ID3D11Buffer *m_vertexBuffer, *m_indexBuffer; 43 ID3D11Buffer *m_constantBuffer; 44 int m_vertexCount, m_indexCount; 45 ID3D11SamplerState *m_samplerstate; 46 XMMATRIX m_worldMatrix; 47 48 public: 49 bool Initialize(ID3D11Device* device, LPCWSTR texture, int maxcount); 50 void Render(ID3D11DeviceContext* context, XMMATRIX& viewmatrix, XMMATRIX& pro, 51 ID3D11VertexShader* vertexshader, ID3D11PixelShader* pixelshader); 52 void Shutdown(); 53 54 private: 55 void Emitparticle(); 56 void Killparticle(); 57 void Updatebuffer(ID3D11DeviceContext* context); 58 void ChangeparticlePos(); 59 bool Initbuffer(ID3D11Device* device); 60 void Loadtexture(ID3D11Device* device,LPCWSTR texture); 61 };
可以看到,粒子系统类与之前的模型类非常相像只是多了:
- 粒子数据结构,粒子数组指针,粒子最大数量,粒子当前数量(m_particlecountCUR)
- 私有方法:生成粒子,粒子湮灭,更新缓存,改变例子位置(运动),初始化缓存
particleSysclass.cpp
1 #include "particleSysclass.h" 2 3 4 particleSysclass::particleSysclass() 5 { 6 m_worldMatrix = XMMatrixIdentity(); 7 } 8 9 10 particleSysclass::~particleSysclass() 11 { 12 } 13 14 15 bool particleSysclass::Initialize(ID3D11Device* device, LPCWSTR texture, int maxcount) 16 { 17 m_particlecountMAX = maxcount; 18 19 Loadtexture(device,texture); 20 21 Initbuffer(device); 22 23 m_particlearray = new particle[m_particlecountMAX]; 24 25 srand((unsigned)time(NULL)); 26 for (int i = 0; i < m_particlecountMAX; i++) 27 { 28 m_particlearray[i].alive = true; 29 m_particlearray[i].pos.x = (((float)rand() - (float)rand()) / RAND_MAX) * 5; 30 m_particlearray[i].pos.y = (((float)rand() - (float)rand()) / RAND_MAX) * 5; 31 m_particlearray[i].pos.z = (((float)rand() - (float)rand()) / RAND_MAX) * 3; 32 33 m_particlearray[i].size = 0.05; 34 } 35 36 return false; 37 } 38 39 40 void particleSysclass::Shutdown() 41 { 42 if (m_particlearray) 43 { 44 delete m_particlearray; 45 } 46 if (m_samplerstate) 47 { 48 m_samplerstate->Release(); 49 } 50 if (m_constantBuffer) 51 { 52 m_constantBuffer->Release(); 53 } 54 if (m_indexBuffer) 55 { 56 m_indexBuffer->Release(); 57 } 58 if (m_vertexBuffer) 59 { 60 m_vertexBuffer->Release(); 61 } 62 if (m_vertexarray) 63 { 64 delete[] m_vertexarray; 65 } 66 if (m_texture) 67 { 68 m_texture->Release(); 69 } 70 } 71 72 73 void particleSysclass::Emitparticle() 74 { 75 76 } 77 78 79 void particleSysclass::Killparticle() 80 { 81 } 82 83 84 void particleSysclass::Updatebuffer(ID3D11DeviceContext* context) 85 { 86 HRESULT hr = S_OK; 87 88 memset(m_vertexarray, 0, sizeof(vertex)*m_particlecountMAX*6); 89 for (int i = 0; i < m_particlecountMAX; i++) 90 { 91 m_vertexarray[i * 6].pos.x = m_particlearray[i].pos.x - m_particlearray[i].size; 92 m_vertexarray[i * 6].pos.y = m_particlearray[i].pos.y - m_particlearray[i].size; 93 m_vertexarray[i * 6].pos.z = m_particlearray[i].pos.z; 94 m_vertexarray[i * 6].tex.x = 0; 95 m_vertexarray[i * 6].tex.y = 1; 96 97 m_vertexarray[i * 6 + 1].pos.x = m_particlearray[i].pos.x - m_particlearray[i].size; 98 m_vertexarray[i * 6 + 1].pos.y = m_particlearray[i].pos.y + m_particlearray[i].size; 99 m_vertexarray[i * 6 + 1].pos.z = m_particlearray[i].pos.z; 100 m_vertexarray[i * 6 + 1].tex.x = 0; 101 m_vertexarray[i * 6 + 1].tex.y = 0; 102 103 m_vertexarray[i * 6 + 2].pos.x = m_particlearray[i].pos.x + m_particlearray[i].size; 104 m_vertexarray[i * 6 + 2].pos.y = m_particlearray[i].pos.y - m_particlearray[i].size; 105 m_vertexarray[i * 6 + 2].pos.z = m_particlearray[i].pos.z; 106 m_vertexarray[i * 6 + 2].tex.x = 1; 107 m_vertexarray[i * 6 + 2].tex.y = 1; 108 109 m_vertexarray[i * 6 + 3].pos.x = m_particlearray[i].pos.x - m_particlearray[i].size; 110 m_vertexarray[i * 6 + 3].pos.y = m_particlearray[i].pos.y + m_particlearray[i].size; 111 m_vertexarray[i * 6 + 3].pos.z = m_particlearray[i].pos.z; 112 m_vertexarray[i * 6 + 3].tex.x = 0; 113 m_vertexarray[i * 6 + 3].tex.y = 0; 114 115 m_vertexarray[i * 6 + 4].pos.x = m_particlearray[i].pos.x + m_particlearray[i].size; 116 m_vertexarray[i * 6 + 4].pos.y = m_particlearray[i].pos.y + m_particlearray[i].size; 117 m_vertexarray[i * 6 + 4].pos.z = m_particlearray[i].pos.z; 118 m_vertexarray[i * 6 + 4].tex.x = 1; 119 m_vertexarray[i * 6 + 4].tex.y = 0; 120 121 m_vertexarray[i * 6 + 5].pos.x = m_particlearray[i].pos.x + m_particlearray[i].size; 122 m_vertexarray[i * 6 + 5].pos.y = m_particlearray[i].pos.y - m_particlearray[i].size; 123 m_vertexarray[i * 6 + 5].pos.z = m_particlearray[i].pos.z; 124 m_vertexarray[i * 6 + 5].tex.x = 1; 125 m_vertexarray[i * 6 + 5].tex.y = 1; 126 } 127 128 D3D11_MAPPED_SUBRESOURCE mappedResource; 129 130 hr = context->Map(m_vertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); 131 if (FAILED(hr)) 132 { 133 return; 134 } 135 136 vertex* verticesPtr = (vertex*)mappedResource.pData; 137 138 memcpy(verticesPtr, (void*)m_vertexarray, (sizeof(vertex)* m_vertexCount)); 139 140 context->Unmap(m_vertexBuffer, 0); 141 } 142 143 144 void particleSysclass::ChangeparticlePos() 145 { 146 147 for (int i = 0; i < m_particlecountMAX; i++) 148 { 149 static bool flag = true; 150 if (m_particlearray[i].pos.y < -5) 151 { 152 flag = true; 153 } 154 if (m_particlearray[i].pos.y > 5) 155 { 156 flag = false; 157 } 158 if (flag) 159 { 160 m_particlearray[i].pos.y += 0.0001; 161 } 162 else 163 { 164 m_particlearray[i].pos.y -= 0.0001; 165 } 166 } 167 } 168 169 170 void particleSysclass::Render(ID3D11DeviceContext* context, XMMATRIX& viewmatrix, XMMATRIX& pro, 171 ID3D11VertexShader* vertexshader, ID3D11PixelShader* pixelshader) 172 { 173 174 Killparticle(); 175 176 Emitparticle(); 177 178 Updatebuffer(context); 179 180 ChangeparticlePos(); 181 182 UINT stride = sizeof(vertex); 183 UINT offset = 0; 184 context->IASetVertexBuffers(0, 1, &m_vertexBuffer, &stride, &offset); 185 context->IASetIndexBuffer(m_indexBuffer, DXGI_FORMAT_R16_UINT, 0); 186 context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); 187 188 context->VSSetShader(vertexshader, NULL, 0); 189 190 191 D3D11_MAPPED_SUBRESOURCE mappedResource; 192 HRESULT hr = S_OK; 193 194 hr = context->Map(m_constantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); 195 if (FAILED(hr)) 196 { 197 return; 198 } 199 constantBuffer* dataPtr = (constantBuffer*)mappedResource.pData; 200 201 XMMATRIX worldmatrix = m_worldMatrix; 202 XMMATRIX promatrix = pro; 203 dataPtr->world = XMMatrixTranspose(worldmatrix); 204 dataPtr->view = XMMatrixTranspose(viewmatrix); 205 dataPtr->pro = XMMatrixTranspose(promatrix); 206 207 context->Unmap(m_constantBuffer, 0); 208 209 210 context->VSSetConstantBuffers(0, 1, &m_constantBuffer); 211 context->PSSetShader(pixelshader, NULL, 0); 212 context->PSSetShaderResources(0, 1, &m_texture); 213 context->PSSetSamplers(0, 1, &m_samplerstate); 214 context->DrawIndexed(m_vertexCount, 0, 0); 215 } 216 217 218 bool particleSysclass::Initbuffer(ID3D11Device* device) 219 { 220 m_vertexCount = m_indexCount = m_particlecountMAX * 6; 221 222 m_vertexarray = new vertex[m_vertexCount]; 223 224 WORD *indices = new WORD[m_indexCount]; 225 for (int i = 0; i < m_indexCount; i++) 226 { 227 indices[i] = i; 228 } 229 230 D3D11_BUFFER_DESC vertexbd, indexbd, constantbd; 231 D3D11_SUBRESOURCE_DATA vertexdata, indexdata; 232 HRESULT hr = S_OK; 233 234 vertexbd.Usage = D3D11_USAGE_DYNAMIC; 235 vertexbd.ByteWidth = sizeof(vertex)* m_vertexCount; 236 vertexbd.BindFlags = D3D11_BIND_VERTEX_BUFFER; 237 vertexbd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; 238 vertexbd.MiscFlags = 0; 239 vertexbd.StructureByteStride = 0; 240 241 vertexdata.pSysMem = m_vertexarray; 242 vertexdata.SysMemPitch = 0; 243 vertexdata.SysMemSlicePitch = 0; 244 245 hr = device->CreateBuffer(&vertexbd, &vertexdata, &m_vertexBuffer); 246 if (FAILED(hr)) 247 { 248 return false; 249 } 250 251 indexbd.Usage = D3D11_USAGE_DEFAULT; 252 indexbd.ByteWidth = sizeof(WORD)* m_indexCount; 253 indexbd.BindFlags = D3D11_BIND_INDEX_BUFFER; 254 indexbd.CPUAccessFlags = 0; 255 indexbd.MiscFlags = 0; 256 indexbd.StructureByteStride = 0; 257 258 indexdata.pSysMem = indices; 259 indexdata.SysMemPitch = 0; 260 indexdata.SysMemSlicePitch = 0; 261 262 hr = device->CreateBuffer(&indexbd, &indexdata, &m_indexBuffer); 263 if (FAILED(hr)) 264 { 265 return false; 266 } 267 268 constantbd.Usage = D3D11_USAGE_DYNAMIC; 269 constantbd.ByteWidth = sizeof(constantBuffer); 270 constantbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; 271 constantbd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; 272 constantbd.MiscFlags = 0; 273 constantbd.StructureByteStride = 0; 274 hr = device->CreateBuffer(&constantbd, NULL, &m_constantBuffer); 275 if (FAILED(hr)) 276 { 277 return false; 278 } 279 280 D3D11_SAMPLER_DESC sampDesc; 281 ZeroMemory(&sampDesc, sizeof(sampDesc)); 282 sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; 283 sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; 284 sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; 285 sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; 286 sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; 287 sampDesc.MinLOD = 0; 288 sampDesc.MaxLOD = D3D11_FLOAT32_MAX; 289 device->CreateSamplerState(&sampDesc, &m_samplerstate); 290 291 delete[] indices; 292 indices = 0; 293 294 return false; 295 } 296 297 298 void particleSysclass::Loadtexture(ID3D11Device*device, LPCWSTR texture) 299 { 300 D3DX11CreateShaderResourceViewFromFile(device, texture, NULL, NULL, &m_texture, NULL); 301 }
Initialize(): 与前不同,这里创建缓存的工作交给了私有方法Initbuffer(),从参数获得最大粒子数量,创建并随机给他们设置位置和大小
Emitparticle(),Killparticle():偷懒还没写、、
Updatebuffer():根据粒子位置,粒子大小更改顶点的位置纹理坐标,更改好后再更新到顶点缓存里
ChangeparticlePos():更改粒子位置,即使粒子做运动,对每个粒子做位置判断,使之在-5<y<5的范围内移动,如果到了边界就往回移动
Render():渲染,与之前的model类的渲染函数类似
- 产生粒子
- 杀死粒子
- 更改顶点缓存
- 更改粒子位置
- 设置顶点缓存
- 设置索引缓存
- 设置绘制方式
- 设置顶点着色器
- 更改常量缓存,这里需要使用动态的更改方式
- 设置常量缓存
- 设置像素着色器
- 设置纹理源
- 设置取样器取样方式
- 绘制各个顶点
Initbuffer():其实这才是与之前model类最为不一样的地方,他创建的顶点缓存,常量缓存都是动态的
- 填充顶点描述结构,usage字段设置为D3D11_USAGE_DYNAMIC,CPUAccessFlags字段设置为D3D11_CPU_ACCESS_WRITE,创建顶点缓存
- 填充索引描述结构,创建索引缓存
- 填充常量缓存描述结构,usage字段设置为D3D11_USAGE_DYNAMIC,CPUAccessFlags字段设置为D3D11_CPU_ACCESS_WRITE,创建常量缓存
- 填充取样器描述,创建取样器状态。
这就是粒子系统的实现方式了,总的来说是根据1个粒子位置设置6个顶点(两个三角形)位置,更新顶点缓存,再像渲染模型一样渲染就好了。我们其实也很容易想到,粒子就是微小的、结构更加简单、数量更为庞大的模型。不过虽说如此,要实现非常漂亮的图形学程序,还是需要对高级着色语言,directx的各种功能做深入的了解。