Graphics: Remake DepthRender[Queue|Technique]

Former-commit-id: c4d8d4d28d02822273ebe7dca3e468ea156af674
This commit is contained in:
Lynix
2015-07-05 23:43:35 +02:00
parent 6870148314
commit 1f2e810927
4 changed files with 387 additions and 428 deletions

View File

@@ -6,6 +6,7 @@
#include <Nazara/Core/ErrorFlags.hpp>
#include <Nazara/Core/OffsetOf.hpp>
#include <Nazara/Graphics/AbstractBackground.hpp>
#include <Nazara/Graphics/AbstractViewer.hpp>
#include <Nazara/Graphics/Drawable.hpp>
#include <Nazara/Graphics/Light.hpp>
#include <Nazara/Graphics/Material.hpp>
@@ -55,7 +56,7 @@ bool NzDepthRenderTechnique::Draw(const NzSceneData& sceneData) const
if (sceneData.background)
sceneData.background->Draw(sceneData.viewer);
if (!m_renderQueue.meshes.empty())
if (!m_renderQueue.opaqueModels.empty())
DrawOpaqueModels(sceneData);
if (!m_renderQueue.basicSprites.empty())
@@ -78,7 +79,7 @@ NzAbstractRenderQueue* NzDepthRenderTechnique::GetRenderQueue()
nzRenderTechniqueType NzDepthRenderTechnique::GetType() const
{
return nzRenderTechniqueType_BasicForward;
return nzRenderTechniqueType_Depth;
}
bool NzDepthRenderTechnique::Initialize()
@@ -129,11 +130,6 @@ bool NzDepthRenderTechnique::Initialize()
s_billboardInstanceDeclaration.EnableComponent(nzVertexComponent_InstanceData0, nzComponentType_Float3, NzOffsetOf(NzForwardRenderQueue::BillboardData, center));
s_billboardInstanceDeclaration.EnableComponent(nzVertexComponent_InstanceData1, nzComponentType_Float4, NzOffsetOf(NzForwardRenderQueue::BillboardData, size)); // Englobe sincos
s_billboardInstanceDeclaration.EnableComponent(nzVertexComponent_InstanceData2, nzComponentType_Color, NzOffsetOf(NzForwardRenderQueue::BillboardData, color));
// Material
s_material = NzMaterial::New();
s_material->Enable(nzRendererParameter_ColorWrite, false);
s_material->Enable(nzRendererParameter_FaceCulling, false);
}
catch (const std::exception& e)
{
@@ -146,7 +142,6 @@ bool NzDepthRenderTechnique::Initialize()
void NzDepthRenderTechnique::Uninitialize()
{
s_material.Reset();
s_quadIndexBuffer.Reset();
s_quadVertexBuffer.Reset();
}
@@ -155,55 +150,101 @@ void NzDepthRenderTechnique::DrawBasicSprites(const NzSceneData& sceneData) cons
{
NazaraUnused(sceneData);
const NzShader* lastShader = nullptr;
const ShaderUniforms* shaderUniforms = nullptr;
NzRenderer::SetIndexBuffer(&s_quadIndexBuffer);
NzRenderer::SetMatrix(nzMatrixType_World, NzMatrix4f::Identity());
NzRenderer::SetVertexBuffer(&m_spriteBuffer);
auto& spriteChainVector = m_renderQueue.basicSprites;
unsigned int spriteChainCount = spriteChainVector.size();
if (spriteChainCount > 0)
for (auto& matIt : m_renderQueue.basicSprites)
{
s_material->Apply();
const NzMaterial* material = matIt.first;
auto& matEntry = matIt.second;
unsigned int spriteChain = 0; // Quelle chaîne de sprite traitons-nous
unsigned int spriteChainOffset = 0; // À quel offset dans la dernière chaîne nous sommes-nous arrêtés
do
if (matEntry.enabled)
{
// On ouvre le buffer en écriture
NzBufferMapper<NzVertexBuffer> vertexMapper(m_spriteBuffer, nzBufferAccess_DiscardAndWrite);
NzVertexStruct_XYZ_Color_UV* vertices = reinterpret_cast<NzVertexStruct_XYZ_Color_UV*>(vertexMapper.GetPointer());
unsigned int spriteCount = 0;
unsigned int maxSpriteCount = std::min(s_maxQuads, m_spriteBuffer.GetVertexCount()/4);
do
auto& overlayMap = matEntry.overlayMap;
for (auto& overlayIt : overlayMap)
{
NzDepthRenderQueue::SpriteChain_XYZ_Color_UV& currentChain = spriteChainVector[spriteChain];
unsigned int count = std::min(maxSpriteCount - spriteCount, currentChain.spriteCount - spriteChainOffset);
const NzTexture* overlay = overlayIt.first;
auto& spriteChainVector = overlayIt.second.spriteChains;
std::memcpy(vertices, currentChain.vertices + spriteChainOffset*4, 4*count*sizeof(NzVertexStruct_XYZ_Color_UV));
vertices += count*4;
spriteCount += count;
spriteChainOffset += count;
// Avons-nous traité la chaîne entière ?
if (spriteChainOffset == currentChain.spriteCount)
unsigned int spriteChainCount = spriteChainVector.size();
if (spriteChainCount > 0)
{
spriteChain++;
spriteChainOffset = 0;
// On commence par appliquer du matériau (et récupérer le shader ainsi activé)
nzUInt32 flags = nzShaderFlags_VertexColor;
if (overlay)
flags |= nzShaderFlags_TextureOverlay;
nzUInt8 overlayUnit;
const NzShader* shader = material->Apply(flags, 0, &overlayUnit);
if (overlay)
{
overlayUnit++;
NzRenderer::SetTexture(overlayUnit, overlay);
NzRenderer::SetTextureSampler(overlayUnit, material->GetDiffuseSampler());
}
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas
if (shader != lastShader)
{
// Index des uniformes dans le shader
shaderUniforms = GetShaderUniforms(shader);
// Overlay
shader->SendInteger(shaderUniforms->textureOverlay, overlayUnit);
lastShader = shader;
}
unsigned int spriteChain = 0; // Quelle chaîne de sprite traitons-nous
unsigned int spriteChainOffset = 0; // À quel offset dans la dernière chaîne nous sommes-nous arrêtés
do
{
// On ouvre le buffer en écriture
NzBufferMapper<NzVertexBuffer> vertexMapper(m_spriteBuffer, nzBufferAccess_DiscardAndWrite);
NzVertexStruct_XYZ_Color_UV* vertices = reinterpret_cast<NzVertexStruct_XYZ_Color_UV*>(vertexMapper.GetPointer());
unsigned int spriteCount = 0;
unsigned int maxSpriteCount = std::min(s_maxQuads, m_spriteBuffer.GetVertexCount()/4);
do
{
NzForwardRenderQueue::SpriteChain_XYZ_Color_UV& currentChain = spriteChainVector[spriteChain];
unsigned int count = std::min(maxSpriteCount - spriteCount, currentChain.spriteCount - spriteChainOffset);
std::memcpy(vertices, currentChain.vertices + spriteChainOffset*4, 4*count*sizeof(NzVertexStruct_XYZ_Color_UV));
vertices += count*4;
spriteCount += count;
spriteChainOffset += count;
// Avons-nous traité la chaîne entière ?
if (spriteChainOffset == currentChain.spriteCount)
{
spriteChain++;
spriteChainOffset = 0;
}
}
while (spriteCount < maxSpriteCount && spriteChain < spriteChainCount);
vertexMapper.Unmap();
NzRenderer::DrawIndexedPrimitives(nzPrimitiveMode_TriangleList, 0, spriteCount*6);
}
while (spriteChain < spriteChainCount);
spriteChainVector.clear();
}
}
while (spriteCount < maxSpriteCount && spriteChain < spriteChainCount);
vertexMapper.Unmap();
NzRenderer::DrawIndexedPrimitives(nzPrimitiveMode_TriangleList, 0, spriteCount*6);
// On remet à zéro
matEntry.enabled = false;
}
while (spriteChain < spriteChainCount);
spriteChainVector.clear();
}
}
@@ -218,27 +259,34 @@ void NzDepthRenderTechnique::DrawBillboards(const NzSceneData& sceneData) const
NzRenderer::SetVertexBuffer(&s_quadVertexBuffer);
auto& billboardVector = m_renderQueue.billboards;
unsigned int billboardCount = billboardVector.size();
if (billboardCount > 0)
for (auto& matIt : m_renderQueue.billboards)
{
s_material->Apply(nzShaderFlags_Billboard | nzShaderFlags_Instancing);
const NzMaterial* material = matIt.first;
auto& entry = matIt.second;
auto& billboardVector = entry.billboards;
const NzDepthRenderQueue::BillboardData* data = &billboardVector[0];
unsigned int maxBillboardPerDraw = instanceBuffer->GetVertexCount();
do
unsigned int billboardCount = billboardVector.size();
if (billboardCount > 0)
{
unsigned int renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw);
billboardCount -= renderedBillboardCount;
// On commence par appliquer du matériau
material->Apply(nzShaderFlags_Billboard | nzShaderFlags_Instancing | nzShaderFlags_VertexColor);
instanceBuffer->Fill(data, 0, renderedBillboardCount, true);
data += renderedBillboardCount;
const NzForwardRenderQueue::BillboardData* data = &billboardVector[0];
unsigned int maxBillboardPerDraw = instanceBuffer->GetVertexCount();
do
{
unsigned int renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw);
billboardCount -= renderedBillboardCount;
NzRenderer::DrawPrimitivesInstanced(renderedBillboardCount, nzPrimitiveMode_TriangleStrip, 0, 4);
instanceBuffer->Fill(data, 0, renderedBillboardCount, true);
data += renderedBillboardCount;
NzRenderer::DrawPrimitivesInstanced(renderedBillboardCount, nzPrimitiveMode_TriangleStrip, 0, 4);
}
while (billboardCount > 0);
billboardVector.clear();
}
while (billboardCount > 0);
billboardVector.clear();
}
}
else
@@ -246,64 +294,70 @@ void NzDepthRenderTechnique::DrawBillboards(const NzSceneData& sceneData) const
NzRenderer::SetIndexBuffer(&s_quadIndexBuffer);
NzRenderer::SetVertexBuffer(&m_billboardPointBuffer);
auto& billboardVector = m_renderQueue.billboards;
unsigned int billboardCount = billboardVector.size();
if (billboardCount > 0)
for (auto& matIt : m_renderQueue.billboards)
{
s_material->Apply(nzShaderFlags_Billboard);
const NzMaterial* material = matIt.first;
auto& entry = matIt.second;
auto& billboardVector = entry.billboards;
const NzDepthRenderQueue::BillboardData* data = &billboardVector[0];
unsigned int maxBillboardPerDraw = std::min(s_maxQuads, m_billboardPointBuffer.GetVertexCount()/4);
do
unsigned int billboardCount = billboardVector.size();
if (billboardCount > 0)
{
unsigned int renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw);
billboardCount -= renderedBillboardCount;
// On commence par appliquer du matériau
material->Apply(nzShaderFlags_Billboard | nzShaderFlags_VertexColor);
NzBufferMapper<NzVertexBuffer> vertexMapper(m_billboardPointBuffer, nzBufferAccess_DiscardAndWrite, 0, renderedBillboardCount*4);
BillboardPoint* vertices = reinterpret_cast<BillboardPoint*>(vertexMapper.GetPointer());
const NzForwardRenderQueue::BillboardData* data = &billboardVector[0];
unsigned int maxBillboardPerDraw = std::min(s_maxQuads, m_billboardPointBuffer.GetVertexCount()/4);
for (unsigned int i = 0; i < renderedBillboardCount; ++i)
do
{
const NzDepthRenderQueue::BillboardData& billboard = *data++;
unsigned int renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw);
billboardCount -= renderedBillboardCount;
vertices->color = billboard.color;
vertices->position = billboard.center;
vertices->sinCos = billboard.sinCos;
vertices->size = billboard.size;
vertices->uv.Set(0.f, 1.f);
vertices++;
NzBufferMapper<NzVertexBuffer> vertexMapper(m_billboardPointBuffer, nzBufferAccess_DiscardAndWrite, 0, renderedBillboardCount*4);
BillboardPoint* vertices = reinterpret_cast<BillboardPoint*>(vertexMapper.GetPointer());
vertices->color = billboard.color;
vertices->position = billboard.center;
vertices->sinCos = billboard.sinCos;
vertices->size = billboard.size;
vertices->uv.Set(1.f, 1.f);
vertices++;
for (unsigned int i = 0; i < renderedBillboardCount; ++i)
{
const NzForwardRenderQueue::BillboardData& billboard = *data++;
vertices->color = billboard.color;
vertices->position = billboard.center;
vertices->sinCos = billboard.sinCos;
vertices->size = billboard.size;
vertices->uv.Set(0.f, 0.f);
vertices++;
vertices->color = billboard.color;
vertices->position = billboard.center;
vertices->sinCos = billboard.sinCos;
vertices->size = billboard.size;
vertices->uv.Set(0.f, 1.f);
vertices++;
vertices->color = billboard.color;
vertices->position = billboard.center;
vertices->sinCos = billboard.sinCos;
vertices->size = billboard.size;
vertices->uv.Set(1.f, 0.f);
vertices++;
vertices->color = billboard.color;
vertices->position = billboard.center;
vertices->sinCos = billboard.sinCos;
vertices->size = billboard.size;
vertices->uv.Set(1.f, 1.f);
vertices++;
vertices->color = billboard.color;
vertices->position = billboard.center;
vertices->sinCos = billboard.sinCos;
vertices->size = billboard.size;
vertices->uv.Set(0.f, 0.f);
vertices++;
vertices->color = billboard.color;
vertices->position = billboard.center;
vertices->sinCos = billboard.sinCos;
vertices->size = billboard.size;
vertices->uv.Set(1.f, 0.f);
vertices++;
}
vertexMapper.Unmap();
NzRenderer::DrawIndexedPrimitives(nzPrimitiveMode_TriangleList, 0, renderedBillboardCount*6);
}
while (billboardCount > 0);
vertexMapper.Unmap();
NzRenderer::DrawIndexedPrimitives(nzPrimitiveMode_TriangleList, 0, renderedBillboardCount*6);
billboardVector.clear();
}
while (billboardCount > 0);
billboardVector.clear();
}
}
}
@@ -312,55 +366,130 @@ void NzDepthRenderTechnique::DrawOpaqueModels(const NzSceneData& sceneData) cons
{
NazaraUnused(sceneData);
s_material->Apply();
for (auto& meshIt : m_renderQueue.meshes)
for (auto& matIt : m_renderQueue.opaqueModels)
{
const NzMeshData& meshData = meshIt.first;
auto& meshEntry = meshIt.second;
auto& matEntry = matIt.second;
std::vector<NzMatrix4f>& instances = meshEntry.instances;
if (!instances.empty())
if (matEntry.enabled)
{
const NzIndexBuffer* indexBuffer = meshData.indexBuffer;
const NzVertexBuffer* vertexBuffer = meshData.vertexBuffer;
NzForwardRenderQueue::MeshInstanceContainer& meshInstances = matEntry.meshMap;
// Gestion du draw call avant la boucle de rendu
NzRenderer::DrawCall drawFunc;
NzRenderer::DrawCallInstanced instancedDrawFunc;
unsigned int indexCount;
if (!meshInstances.empty())
{
const NzMaterial* material = matIt.first;
if (indexBuffer)
{
drawFunc = NzRenderer::DrawIndexedPrimitives;
instancedDrawFunc = NzRenderer::DrawIndexedPrimitivesInstanced;
indexCount = indexBuffer->GetIndexCount();
}
else
{
drawFunc = NzRenderer::DrawPrimitives;
instancedDrawFunc = NzRenderer::DrawPrimitivesInstanced;
indexCount = vertexBuffer->GetVertexCount();
// Nous utilisons de l'instancing que lorsqu'aucune lumière (autre que directionnelle) n'est active
// Ceci car l'instancing n'est pas compatible avec la recherche des lumières les plus proches
// (Le deferred shading n'a pas ce problème)
bool noPointSpotLight = m_renderQueue.pointLights.empty() && m_renderQueue.spotLights.empty();
bool instancing = m_instancingEnabled && (!material->IsLightingEnabled() || noPointSpotLight) && matEntry.instancingEnabled;
// On commence par appliquer du matériau (et récupérer le shader ainsi activé)
material->Apply((instancing) ? nzShaderFlags_Instancing : 0);
// Meshes
for (auto& meshIt : meshInstances)
{
const NzMeshData& meshData = meshIt.first;
auto& meshEntry = meshIt.second;
std::vector<NzMatrix4f>& instances = meshEntry.instances;
if (!instances.empty())
{
const NzIndexBuffer* indexBuffer = meshData.indexBuffer;
const NzVertexBuffer* vertexBuffer = meshData.vertexBuffer;
// Gestion du draw call avant la boucle de rendu
NzRenderer::DrawCall drawFunc;
NzRenderer::DrawCallInstanced instancedDrawFunc;
unsigned int indexCount;
if (indexBuffer)
{
drawFunc = NzRenderer::DrawIndexedPrimitives;
instancedDrawFunc = NzRenderer::DrawIndexedPrimitivesInstanced;
indexCount = indexBuffer->GetIndexCount();
}
else
{
drawFunc = NzRenderer::DrawPrimitives;
instancedDrawFunc = NzRenderer::DrawPrimitivesInstanced;
indexCount = vertexBuffer->GetVertexCount();
}
NzRenderer::SetIndexBuffer(indexBuffer);
NzRenderer::SetVertexBuffer(vertexBuffer);
if (instancing)
{
// On calcule le nombre d'instances que l'on pourra afficher cette fois-ci (Selon la taille du buffer d'instancing)
NzVertexBuffer* instanceBuffer = NzRenderer::GetInstanceBuffer();
instanceBuffer->SetVertexDeclaration(NzVertexDeclaration::Get(nzVertexLayout_Matrix4));
const NzMatrix4f* instanceMatrices = &instances[0];
unsigned int instanceCount = instances.size();
unsigned int maxInstanceCount = instanceBuffer->GetVertexCount(); // Le nombre maximum d'instances en une fois
while (instanceCount > 0)
{
// On calcule le nombre d'instances que l'on pourra afficher cette fois-ci (Selon la taille du buffer d'instancing)
unsigned int renderedInstanceCount = std::min(instanceCount, maxInstanceCount);
instanceCount -= renderedInstanceCount;
// On remplit l'instancing buffer avec nos matrices world
instanceBuffer->Fill(instanceMatrices, 0, renderedInstanceCount, true);
instanceMatrices += renderedInstanceCount;
// Et on affiche
instancedDrawFunc(renderedInstanceCount, meshData.primitiveMode, 0, indexCount);
}
}
else
{
// Sans instancing, on doit effectuer un draw call pour chaque instance
// Cela reste néanmoins plus rapide que l'instancing en dessous d'un certain nombre d'instances
// À cause du temps de modification du buffer d'instancing
for (const NzMatrix4f& matrix : instances)
{
NzRenderer::SetMatrix(nzMatrixType_World, matrix);
drawFunc(meshData.primitiveMode, 0, indexCount);
}
}
instances.clear();
}
}
}
NzRenderer::SetIndexBuffer(indexBuffer);
NzRenderer::SetVertexBuffer(vertexBuffer);
// Sans instancing, on doit effectuer un draw call pour chaque instance
// Cela reste néanmoins plus rapide que l'instancing en dessous d'un certain nombre d'instances
// À cause du temps de modification du buffer d'instancing
for (const NzMatrix4f& matrix : instances)
{
NzRenderer::SetMatrix(nzMatrixType_World, matrix);
drawFunc(meshData.primitiveMode, 0, indexCount);
}
instances.clear();
// Et on remet à zéro les données
matEntry.enabled = false;
matEntry.instancingEnabled = false;
}
}
}
const NzDepthRenderTechnique::ShaderUniforms* NzDepthRenderTechnique::GetShaderUniforms(const NzShader* shader) const
{
auto it = m_shaderUniforms.find(shader);
if (it == m_shaderUniforms.end())
{
ShaderUniforms uniforms;
uniforms.shaderReleaseSlot.Connect(shader->OnShaderRelease, this, &NzDepthRenderTechnique::OnShaderInvalidated);
uniforms.shaderUniformInvalidatedSlot.Connect(shader->OnShaderUniformInvalidated, this, &NzDepthRenderTechnique::OnShaderInvalidated);
uniforms.textureOverlay = shader->GetUniformLocation("TextureOverlay");
it = m_shaderUniforms.emplace(shader, std::move(uniforms)).first;
}
return &it->second;
}
void NzDepthRenderTechnique::OnShaderInvalidated(const NzShader* shader) const
{
m_shaderUniforms.erase(shader);
}
NzIndexBuffer NzDepthRenderTechnique::s_quadIndexBuffer;
NzMaterialRef NzDepthRenderTechnique::s_material;
NzVertexBuffer NzDepthRenderTechnique::s_quadVertexBuffer;
NzVertexDeclaration NzDepthRenderTechnique::s_billboardInstanceDeclaration;
NzVertexDeclaration NzDepthRenderTechnique::s_billboardVertexDeclaration;