Switch from Nz prefix to namespace Nz
What a huge commit Former-commit-id: 38ac5eebf70adc1180f571f6006192d28fb99897
This commit is contained in:
@@ -16,244 +16,247 @@
|
||||
#include <memory>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
NzDeferredGeometryPass::NzDeferredGeometryPass()
|
||||
namespace Nz
|
||||
{
|
||||
m_clearShader = NzShaderLibrary::Get("DeferredGBufferClear");
|
||||
m_clearStates.parameters[nzRendererParameter_DepthBuffer] = true;
|
||||
m_clearStates.parameters[nzRendererParameter_FaceCulling] = true;
|
||||
m_clearStates.parameters[nzRendererParameter_StencilTest] = true;
|
||||
m_clearStates.depthFunc = nzRendererComparison_Always;
|
||||
m_clearStates.frontFace.stencilCompare = nzRendererComparison_Always;
|
||||
m_clearStates.frontFace.stencilPass = nzStencilOperation_Zero;
|
||||
}
|
||||
|
||||
NzDeferredGeometryPass::~NzDeferredGeometryPass() = default;
|
||||
|
||||
bool NzDeferredGeometryPass::Process(const NzSceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const
|
||||
{
|
||||
NazaraAssert(sceneData.viewer, "Invalid viewer");
|
||||
NazaraUnused(firstWorkTexture);
|
||||
NazaraUnused(secondWorkTexture);
|
||||
|
||||
bool instancingEnabled = m_deferredTechnique->IsInstancingEnabled();
|
||||
|
||||
m_GBufferRTT->SetColorTargets({0, 1, 2}); // G-Buffer
|
||||
NzRenderer::SetTarget(m_GBufferRTT);
|
||||
NzRenderer::SetViewport(NzRecti(0, 0, m_dimensions.x, m_dimensions.y));
|
||||
|
||||
NzRenderer::SetRenderStates(m_clearStates);
|
||||
NzRenderer::SetShader(m_clearShader);
|
||||
NzRenderer::DrawFullscreenQuad();
|
||||
|
||||
|
||||
NzRenderer::SetMatrix(nzMatrixType_Projection, sceneData.viewer->GetProjectionMatrix());
|
||||
NzRenderer::SetMatrix(nzMatrixType_View, sceneData.viewer->GetViewMatrix());
|
||||
|
||||
const NzShader* lastShader = nullptr;
|
||||
const ShaderUniforms* shaderUniforms = nullptr;
|
||||
|
||||
for (auto& matIt : m_renderQueue->opaqueModels)
|
||||
DeferredGeometryPass::DeferredGeometryPass()
|
||||
{
|
||||
auto& matEntry = matIt.second;
|
||||
m_clearShader = ShaderLibrary::Get("DeferredGBufferClear");
|
||||
m_clearStates.parameters[RendererParameter_DepthBuffer] = true;
|
||||
m_clearStates.parameters[RendererParameter_FaceCulling] = true;
|
||||
m_clearStates.parameters[RendererParameter_StencilTest] = true;
|
||||
m_clearStates.depthFunc = RendererComparison_Always;
|
||||
m_clearStates.frontFace.stencilCompare = RendererComparison_Always;
|
||||
m_clearStates.frontFace.stencilPass = nzStencilOperation_Zero;
|
||||
}
|
||||
|
||||
if (matEntry.enabled)
|
||||
DeferredGeometryPass::~DeferredGeometryPass() = default;
|
||||
|
||||
bool DeferredGeometryPass::Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const
|
||||
{
|
||||
NazaraAssert(sceneData.viewer, "Invalid viewer");
|
||||
NazaraUnused(firstWorkTexture);
|
||||
NazaraUnused(secondWorkTexture);
|
||||
|
||||
bool instancingEnabled = m_deferredTechnique->IsInstancingEnabled();
|
||||
|
||||
m_GBufferRTT->SetColorTargets({0, 1, 2}); // G-Buffer
|
||||
Renderer::SetTarget(m_GBufferRTT);
|
||||
Renderer::SetViewport(Recti(0, 0, m_dimensions.x, m_dimensions.y));
|
||||
|
||||
Renderer::SetRenderStates(m_clearStates);
|
||||
Renderer::SetShader(m_clearShader);
|
||||
Renderer::DrawFullscreenQuad();
|
||||
|
||||
|
||||
Renderer::SetMatrix(MatrixType_Projection, sceneData.viewer->GetProjectionMatrix());
|
||||
Renderer::SetMatrix(MatrixType_View, sceneData.viewer->GetViewMatrix());
|
||||
|
||||
const Shader* lastShader = nullptr;
|
||||
const ShaderUniforms* shaderUniforms = nullptr;
|
||||
|
||||
for (auto& matIt : m_renderQueue->opaqueModels)
|
||||
{
|
||||
NzDeferredRenderQueue::MeshInstanceContainer& meshInstances = matEntry.meshMap;
|
||||
auto& matEntry = matIt.second;
|
||||
|
||||
if (!meshInstances.empty())
|
||||
if (matEntry.enabled)
|
||||
{
|
||||
const NzMaterial* material = matIt.first;
|
||||
DeferredRenderQueue::MeshInstanceContainer& meshInstances = matEntry.meshMap;
|
||||
|
||||
bool useInstancing = instancingEnabled && matEntry.instancingEnabled;
|
||||
|
||||
// On commence par récupérer le programme du matériau
|
||||
nzUInt32 flags = nzShaderFlags_Deferred;
|
||||
if (useInstancing)
|
||||
flags |= nzShaderFlags_Instancing;
|
||||
|
||||
const NzShader* shader = material->Apply(flags);
|
||||
|
||||
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas
|
||||
if (shader != lastShader)
|
||||
if (!meshInstances.empty())
|
||||
{
|
||||
// Index des uniformes dans le shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
const Material* material = matIt.first;
|
||||
|
||||
// Couleur ambiante de la scène
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
// Position de la caméra
|
||||
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
||||
bool useInstancing = instancingEnabled && matEntry.instancingEnabled;
|
||||
|
||||
lastShader = shader;
|
||||
}
|
||||
// On commence par récupérer le programme du matériau
|
||||
UInt32 flags = ShaderFlags_Deferred;
|
||||
if (useInstancing)
|
||||
flags |= ShaderFlags_Instancing;
|
||||
|
||||
// Meshes
|
||||
for (auto& meshIt : meshInstances)
|
||||
{
|
||||
const NzMeshData& meshData = meshIt.first;
|
||||
auto& meshEntry = meshIt.second;
|
||||
const Shader* shader = material->Apply(flags);
|
||||
|
||||
std::vector<NzMatrix4f>& instances = meshEntry.instances;
|
||||
if (!instances.empty())
|
||||
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas
|
||||
if (shader != lastShader)
|
||||
{
|
||||
const NzIndexBuffer* indexBuffer = meshData.indexBuffer;
|
||||
const NzVertexBuffer* vertexBuffer = meshData.vertexBuffer;
|
||||
// Index des uniformes dans le shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// Gestion du draw call avant la boucle de rendu
|
||||
NzRenderer::DrawCall drawFunc;
|
||||
NzRenderer::DrawCallInstanced instancedDrawFunc;
|
||||
unsigned int indexCount;
|
||||
// Couleur ambiante de la scène
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
// Position de la caméra
|
||||
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
||||
|
||||
if (indexBuffer)
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
// Meshes
|
||||
for (auto& meshIt : meshInstances)
|
||||
{
|
||||
const MeshData& meshData = meshIt.first;
|
||||
auto& meshEntry = meshIt.second;
|
||||
|
||||
std::vector<Matrix4f>& instances = meshEntry.instances;
|
||||
if (!instances.empty())
|
||||
{
|
||||
drawFunc = NzRenderer::DrawIndexedPrimitives;
|
||||
instancedDrawFunc = NzRenderer::DrawIndexedPrimitivesInstanced;
|
||||
indexCount = indexBuffer->GetIndexCount();
|
||||
}
|
||||
else
|
||||
{
|
||||
drawFunc = NzRenderer::DrawPrimitives;
|
||||
instancedDrawFunc = NzRenderer::DrawPrimitivesInstanced;
|
||||
indexCount = vertexBuffer->GetVertexCount();
|
||||
}
|
||||
const IndexBuffer* indexBuffer = meshData.indexBuffer;
|
||||
const VertexBuffer* vertexBuffer = meshData.vertexBuffer;
|
||||
|
||||
NzRenderer::SetIndexBuffer(indexBuffer);
|
||||
NzRenderer::SetVertexBuffer(vertexBuffer);
|
||||
// Gestion du draw call avant la boucle de rendu
|
||||
Renderer::DrawCall drawFunc;
|
||||
Renderer::DrawCallInstanced instancedDrawFunc;
|
||||
unsigned int indexCount;
|
||||
|
||||
if (useInstancing)
|
||||
{
|
||||
// On récupère le buffer d'instancing du Renderer et on le configure pour fonctionner avec des matrices
|
||||
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 de matrices que peut contenir le buffer
|
||||
|
||||
while (instanceCount > 0)
|
||||
if (indexBuffer)
|
||||
{
|
||||
// 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);
|
||||
drawFunc = Renderer::DrawIndexedPrimitives;
|
||||
instancedDrawFunc = Renderer::DrawIndexedPrimitivesInstanced;
|
||||
indexCount = indexBuffer->GetIndexCount();
|
||||
}
|
||||
}
|
||||
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)
|
||||
else
|
||||
{
|
||||
NzRenderer::SetMatrix(nzMatrixType_World, matrix);
|
||||
drawFunc(meshData.primitiveMode, 0, indexCount);
|
||||
drawFunc = Renderer::DrawPrimitives;
|
||||
instancedDrawFunc = Renderer::DrawPrimitivesInstanced;
|
||||
indexCount = vertexBuffer->GetVertexCount();
|
||||
}
|
||||
}
|
||||
|
||||
instances.clear();
|
||||
Renderer::SetIndexBuffer(indexBuffer);
|
||||
Renderer::SetVertexBuffer(vertexBuffer);
|
||||
|
||||
if (useInstancing)
|
||||
{
|
||||
// On récupère le buffer d'instancing du Renderer et on le configure pour fonctionner avec des matrices
|
||||
VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer();
|
||||
instanceBuffer->SetVertexDeclaration(VertexDeclaration::Get(VertexLayout_Matrix4));
|
||||
|
||||
const Matrix4f* instanceMatrices = &instances[0];
|
||||
unsigned int instanceCount = instances.size();
|
||||
unsigned int maxInstanceCount = instanceBuffer->GetVertexCount(); // Le nombre de matrices que peut contenir le buffer
|
||||
|
||||
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 Matrix4f& matrix : instances)
|
||||
{
|
||||
Renderer::SetMatrix(MatrixType_World, matrix);
|
||||
drawFunc(meshData.primitiveMode, 0, indexCount);
|
||||
}
|
||||
}
|
||||
|
||||
instances.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Et on remet à zéro les données
|
||||
matEntry.enabled = false;
|
||||
matEntry.instancingEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
return false; // On ne fait que remplir le G-Buffer, les work texture ne sont pas affectées
|
||||
}
|
||||
|
||||
bool DeferredGeometryPass::Resize(const Vector2ui& dimensions)
|
||||
{
|
||||
DeferredRenderPass::Resize(dimensions);
|
||||
|
||||
/*
|
||||
G-Buffer:
|
||||
Texture0: Diffuse Color + Flags
|
||||
Texture1: Encoded normal
|
||||
Texture2: Specular value + Shininess
|
||||
Texture3: N/A
|
||||
*/
|
||||
|
||||
try
|
||||
{
|
||||
ErrorFlags errFlags(ErrorFlag_ThrowException);
|
||||
|
||||
unsigned int width = dimensions.x;
|
||||
unsigned int height = dimensions.y;
|
||||
|
||||
m_depthStencilBuffer->Create(PixelFormatType_Depth24Stencil8, width, height);
|
||||
|
||||
m_GBuffer[0]->Create(ImageType_2D, PixelFormatType_RGBA8, width, height); // Texture 0 : Diffuse Color + Specular
|
||||
m_GBuffer[1]->Create(ImageType_2D, PixelFormatType_RG16F, width, height); // Texture 1 : Encoded normal
|
||||
m_GBuffer[2]->Create(ImageType_2D, PixelFormatType_RGBA8, width, height); // Texture 2 : Depth (24bits) + Shininess
|
||||
|
||||
m_GBufferRTT->Create(true);
|
||||
|
||||
m_GBufferRTT->AttachTexture(AttachmentPoint_Color, 0, m_GBuffer[0]);
|
||||
m_GBufferRTT->AttachTexture(AttachmentPoint_Color, 1, m_GBuffer[1]);
|
||||
m_GBufferRTT->AttachTexture(AttachmentPoint_Color, 2, m_GBuffer[2]);
|
||||
|
||||
// Texture 3 : Emission map ?
|
||||
|
||||
m_GBufferRTT->AttachBuffer(AttachmentPoint_DepthStencil, 0, m_depthStencilBuffer);
|
||||
|
||||
m_GBufferRTT->Unlock();
|
||||
|
||||
m_workRTT->Create(true);
|
||||
|
||||
for (unsigned int i = 0; i < 2; ++i)
|
||||
{
|
||||
m_workTextures[i]->Create(ImageType_2D, PixelFormatType_RGBA8, width, height);
|
||||
m_workRTT->AttachTexture(AttachmentPoint_Color, i, m_workTextures[i]);
|
||||
}
|
||||
|
||||
// Et on remet à zéro les données
|
||||
matEntry.enabled = false;
|
||||
matEntry.instancingEnabled = false;
|
||||
m_workRTT->AttachBuffer(AttachmentPoint_DepthStencil, 0, m_depthStencilBuffer);
|
||||
|
||||
m_workRTT->Unlock();
|
||||
|
||||
if (!m_workRTT->IsComplete() || !m_GBufferRTT->IsComplete())
|
||||
{
|
||||
NazaraError("Incomplete RTT");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false; // On ne fait que remplir le G-Buffer, les work texture ne sont pas affectées
|
||||
}
|
||||
|
||||
bool NzDeferredGeometryPass::Resize(const NzVector2ui& dimensions)
|
||||
{
|
||||
NzDeferredRenderPass::Resize(dimensions);
|
||||
|
||||
/*
|
||||
G-Buffer:
|
||||
Texture0: Diffuse Color + Flags
|
||||
Texture1: Encoded normal
|
||||
Texture2: Specular value + Shininess
|
||||
Texture3: N/A
|
||||
*/
|
||||
|
||||
try
|
||||
{
|
||||
NzErrorFlags errFlags(nzErrorFlag_ThrowException);
|
||||
|
||||
unsigned int width = dimensions.x;
|
||||
unsigned int height = dimensions.y;
|
||||
|
||||
m_depthStencilBuffer->Create(nzPixelFormat_Depth24Stencil8, width, height);
|
||||
|
||||
m_GBuffer[0]->Create(nzImageType_2D, nzPixelFormat_RGBA8, width, height); // Texture 0 : Diffuse Color + Specular
|
||||
m_GBuffer[1]->Create(nzImageType_2D, nzPixelFormat_RG16F, width, height); // Texture 1 : Encoded normal
|
||||
m_GBuffer[2]->Create(nzImageType_2D, nzPixelFormat_RGBA8, width, height); // Texture 2 : Depth (24bits) + Shininess
|
||||
|
||||
m_GBufferRTT->Create(true);
|
||||
|
||||
m_GBufferRTT->AttachTexture(nzAttachmentPoint_Color, 0, m_GBuffer[0]);
|
||||
m_GBufferRTT->AttachTexture(nzAttachmentPoint_Color, 1, m_GBuffer[1]);
|
||||
m_GBufferRTT->AttachTexture(nzAttachmentPoint_Color, 2, m_GBuffer[2]);
|
||||
|
||||
// Texture 3 : Emission map ?
|
||||
|
||||
m_GBufferRTT->AttachBuffer(nzAttachmentPoint_DepthStencil, 0, m_depthStencilBuffer);
|
||||
|
||||
m_GBufferRTT->Unlock();
|
||||
|
||||
m_workRTT->Create(true);
|
||||
|
||||
for (unsigned int i = 0; i < 2; ++i)
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
m_workTextures[i]->Create(nzImageType_2D, nzPixelFormat_RGBA8, width, height);
|
||||
m_workRTT->AttachTexture(nzAttachmentPoint_Color, i, m_workTextures[i]);
|
||||
}
|
||||
|
||||
m_workRTT->AttachBuffer(nzAttachmentPoint_DepthStencil, 0, m_depthStencilBuffer);
|
||||
|
||||
m_workRTT->Unlock();
|
||||
|
||||
if (!m_workRTT->IsComplete() || !m_GBufferRTT->IsComplete())
|
||||
{
|
||||
NazaraError("Incomplete RTT");
|
||||
NazaraError("Failed to create G-Buffer RTT: " + String(e.what()));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
|
||||
const DeferredGeometryPass::ShaderUniforms* DeferredGeometryPass::GetShaderUniforms(const Shader* shader) const
|
||||
{
|
||||
NazaraError("Failed to create G-Buffer RTT: " + NzString(e.what()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
auto it = m_shaderUniforms.find(shader);
|
||||
if (it == m_shaderUniforms.end())
|
||||
{
|
||||
ShaderUniforms uniforms;
|
||||
uniforms.shaderReleaseSlot.Connect(shader->OnShaderRelease, this, &DeferredGeometryPass::OnShaderInvalidated);
|
||||
uniforms.shaderUniformInvalidatedSlot.Connect(shader->OnShaderUniformInvalidated, this, &DeferredGeometryPass::OnShaderInvalidated);
|
||||
|
||||
const NzDeferredGeometryPass::ShaderUniforms* NzDeferredGeometryPass::GetShaderUniforms(const NzShader* shader) const
|
||||
{
|
||||
auto it = m_shaderUniforms.find(shader);
|
||||
if (it == m_shaderUniforms.end())
|
||||
uniforms.eyePosition = shader->GetUniformLocation("EyePosition");
|
||||
uniforms.sceneAmbient = shader->GetUniformLocation("SceneAmbient");
|
||||
uniforms.textureOverlay = shader->GetUniformLocation("TextureOverlay");
|
||||
|
||||
it = m_shaderUniforms.emplace(shader, std::move(uniforms)).first;
|
||||
}
|
||||
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
void DeferredGeometryPass::OnShaderInvalidated(const Shader* shader) const
|
||||
{
|
||||
ShaderUniforms uniforms;
|
||||
uniforms.shaderReleaseSlot.Connect(shader->OnShaderRelease, this, &NzDeferredGeometryPass::OnShaderInvalidated);
|
||||
uniforms.shaderUniformInvalidatedSlot.Connect(shader->OnShaderUniformInvalidated, this, &NzDeferredGeometryPass::OnShaderInvalidated);
|
||||
|
||||
uniforms.eyePosition = shader->GetUniformLocation("EyePosition");
|
||||
uniforms.sceneAmbient = shader->GetUniformLocation("SceneAmbient");
|
||||
uniforms.textureOverlay = shader->GetUniformLocation("TextureOverlay");
|
||||
|
||||
it = m_shaderUniforms.emplace(shader, std::move(uniforms)).first;
|
||||
m_shaderUniforms.erase(shader);
|
||||
}
|
||||
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
void NzDeferredGeometryPass::OnShaderInvalidated(const NzShader* shader) const
|
||||
{
|
||||
m_shaderUniforms.erase(shader);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user