Так, ігровий двигун взагалі матиме безліч різних шейдерів. Типовою схемою є:
Під час ініціалізації двигуна та завантаження ігрового світу підготуйте всі шейдери, які ви будете використовувати для візуалізації. Під «підготовкою» я маю на увазі завантаження їх у пам’ять, компілюйте їх за необхідності та виконайте всі ID3D11Device::CreatePixelShader
подібні дзвінки, щоб отримати виділені та готові до роботи об’єкти шейдерів D3D. Зберігайте об'єкти в масиві чи іншій структурі даних.
Зазвичай у вас буде взаємозв'язок між вершинами шейдерами та піксельними шейдерами, які призначені для спільної роботи. Я думаю про них як про єдиний об'єкт, який я просто називаю "шейдером", навіть якщо він дійсно містить шейдер вершини та піксельний шейдер (а може бути, також шейдери геометрії / корпусу / домену).
Кожен кадр, знайшовши список об'єктів (сіток) для відтворення, сортуйте їх за шейдером. Ідея полягає в тому, щоб мінімізувати кількість разів перемикання шейдерів у кадрі, шляхом складання всіх об'єктів із заданим шейдером разом. Це відбувається тому , що перемикання шейдери є кілька дорогою операцією (хоча можна , звичайно , зробити це кілька сотень або тисяч разів за кадр, так що це на самому ділі не що дорого).
Насправді ви можете піти на крок далі і сортувати сітки за першим шейдером та другим матеріалом. Під матеріалом я маю на увазі поєднання шейдера та набору текстур та параметрів для нього. Шейдери зазвичай мають деякі текстури та числові параметри (зберігаються в постійних буферах), які подаються в них, тому, наприклад, цегляний матеріал та матеріал асфальту можуть використовувати один і той же шейдерний код, лише з різними текстурами.
Щоб намалювати, просто переведіть петлю на шейдери, встановіть кожен шейдер у ID3D11DeviceContext
, встановіть будь-які параметри (постійні буфери, текстури тощо), а потім намалюйте об'єкти. У псевдокоді, включаючи відмінність шейдерів / матеріалів, я згадував:
for each shader:
// Set the device context to use this shader
pContext->VSSetShader(shader.pVertexShader);
pContext->PSSetShader(shader.pPixelShader);
for each material that uses this shader:
// Set the device context to use any constant buffers, textures, samplers,
// etc. needed for this material
pContext->VSSetConstantBuffers(...);
pContext->PSSetConstantBuffers(...);
pContext->PSSetShaderResources(...);
pContext->PSSetSamplers(...);
for each mesh that uses this material:
// Set any constant buffers containing parameters specific to the mesh
// (e.g. world matrix)
pContext->VSSetConstantBuffers(...);
// Set the context to use the vertex & index buffers for this mesh
pContext->IASetInputLayout(mesh.pInputLayout);
pContext->IASetVertexBuffers(...);
pContext->IASetIndexBuffer(...);
pContext->IASetPrimitiveTopology(...)
// Draw it
pContext->DrawIndexed(...)
Існує набагато більше, що можна сказати про керування об'єктами, сітками, шейдерами, макетами вводу, постійними буферами тощо, але цього має бути достатньо для початку роботи. :)