Deferred Shading update

-Deferred Shading now use a dynamics pass system
-Forward Shading is now capable of rendering more than three lights
(Multipass)


Former-commit-id: 74ed0b998d72aa9eb3bd2aab938a75985ebb2bf6
This commit is contained in:
Lynix
2013-12-28 10:22:03 +01:00
parent 6568cc7995
commit a332579c80
31 changed files with 2431 additions and 1354 deletions

View File

@@ -21,7 +21,7 @@
namespace
{
static NzIndexBuffer* s_indexBuffer = nullptr;
unsigned int maxLightCount = 3; ///TODO: Constante sur le nombre maximum de lumières
unsigned int s_maxLightPerPass = 3; ///TODO: Constante sur le nombre maximum de lumières
unsigned int s_maxSprites = 8192;
NzIndexBuffer* BuildIndexBuffer()
@@ -49,7 +49,7 @@ namespace
NzForwardRenderTechnique::NzForwardRenderTechnique() :
m_spriteBuffer(NzVertexDeclaration::Get(nzVertexLayout_XYZ_UV), s_maxSprites*4, nzBufferStorage_Hardware, nzBufferUsage_Dynamic),
m_maxLightsPerObject(maxLightCount)
m_maxLightPassPerObject(3)
{
if (!s_indexBuffer)
s_indexBuffer = BuildIndexBuffer();
@@ -63,7 +63,7 @@ NzForwardRenderTechnique::~NzForwardRenderTechnique()
s_indexBuffer = nullptr;
}
void NzForwardRenderTechnique::Clear(const NzScene* scene)
void NzForwardRenderTechnique::Clear(const NzScene* scene) const
{
NzRenderer::Enable(nzRendererParameter_DepthBuffer, true);
NzRenderer::Enable(nzRendererParameter_DepthWrite, true);
@@ -74,7 +74,7 @@ void NzForwardRenderTechnique::Clear(const NzScene* scene)
background->Draw(scene);
}
bool NzForwardRenderTechnique::Draw(const NzScene* scene)
bool NzForwardRenderTechnique::Draw(const NzScene* scene) const
{
m_directionalLights.SetLights(&m_renderQueue.directionalLights[0], m_renderQueue.directionalLights.size());
m_lights.SetLights(&m_renderQueue.lights[0], m_renderQueue.lights.size());
@@ -141,9 +141,9 @@ bool NzForwardRenderTechnique::Draw(const NzScene* scene)
}*/
}
unsigned int NzForwardRenderTechnique::GetMaxLightsPerObject() const
unsigned int NzForwardRenderTechnique::GetMaxLightPassPerObject() const
{
return m_maxLightsPerObject;
return m_maxLightPassPerObject;
}
NzAbstractRenderQueue* NzForwardRenderTechnique::GetRenderQueue()
@@ -156,26 +156,16 @@ nzRenderTechniqueType NzForwardRenderTechnique::GetType() const
return nzRenderTechniqueType_BasicForward;
}
void NzForwardRenderTechnique::SetMaxLightsPerObject(unsigned int lightCount)
void NzForwardRenderTechnique::SetMaxLightPassPerObject(unsigned int passCount)
{
#if NAZARA_GRAPHICS_SAFE
if (lightCount > maxLightCount)
{
NazaraError("Light count is over maximum light count (" + NzString::Number(lightCount) + " > " + NzString::Number(lightCount) + ')');
return;
}
#endif
m_maxLightsPerObject = lightCount;
m_maxLightPassPerObject = passCount;
}
void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene)
void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const
{
NzAbstractViewer* viewer = scene->GetViewer();
const NzShaderProgram* lastProgram = nullptr;
unsigned int lightCount = 0;
for (auto& matIt : m_renderQueue.opaqueModels)
{
bool& used = std::get<0>(matIt.second);
@@ -207,11 +197,6 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene)
// Position de la caméra
program->SendVector(program->GetUniformLocation(nzShaderUniform_EyePosition), viewer->GetEyePosition());
// On envoie les lumières directionnelles s'il y a (Les mêmes pour tous)
lightCount = std::min(m_directionalLights.GetLightCount(), 3U);
for (unsigned int i = 0; i < lightCount; ++i)
m_directionalLights.GetLight(i)->Enable(program, i);
lastProgram = program;
}
@@ -269,51 +254,110 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene)
unsigned int stride = instanceBuffer->GetStride();
const NzForwardRenderQueue::StaticData* data = &staticData[0];
unsigned int instanceCount = staticData.size();
unsigned int maxInstanceCount = instanceBuffer->GetVertexCount();
// Avec l'instancing, impossible de sélectionner les lumières pour chaque objet
// Du coup, il n'est activé que pour les lumières directionnelles
unsigned int lightCount = m_directionalLights.GetLightCount();
unsigned int lightIndex = 0;
nzRendererComparison oldDepthFunc = NzRenderer::GetDepthFunc();
while (instanceCount > 0)
unsigned int passCount = (lightCount == 0) ? 1 : (lightCount-1)/s_maxLightPerPass + 1;
for (unsigned int pass = 0; pass < passCount; ++pass)
{
unsigned int renderedInstanceCount = std::min(instanceCount, maxInstanceCount);
instanceCount -= renderedInstanceCount;
unsigned int renderedLightCount = std::min(lightCount, s_maxLightPerPass);
lightCount -= renderedLightCount;
NzBufferMapper<NzVertexBuffer> mapper(instanceBuffer, nzBufferAccess_DiscardAndWrite, 0, renderedInstanceCount);
nzUInt8* ptr = reinterpret_cast<nzUInt8*>(mapper.GetPointer());
for (unsigned int i = 0; i < renderedInstanceCount; ++i)
if (pass == 1)
{
std::memcpy(ptr, data->transformMatrix, sizeof(float)*16);
data++;
ptr += stride;
// Pour additionner le résultat des calculs de lumière
// Aucune chance d'interférer avec les paramètres du matériau car nous ne rendons que les objets opaques
// (Autrement dit, sans blending)
// Quant à la fonction de profondeur, elle ne doit être appliquée que la première fois
NzRenderer::Enable(nzRendererParameter_Blend, true);
NzRenderer::SetBlendFunc(nzBlendFunc_One, nzBlendFunc_One);
NzRenderer::SetDepthFunc(nzRendererComparison_Equal);
}
mapper.Unmap();
for (unsigned int i = 0; i < renderedLightCount; ++i)
m_directionalLights.GetLight(lightIndex++)->Enable(program, i);
InstancedDrawFunc(renderedInstanceCount, primitiveMode, 0, indexCount);
for (unsigned int i = renderedLightCount; i < s_maxLightPerPass; ++i)
NzLight::Disable(program, i);
const NzForwardRenderQueue::StaticData* data = &staticData[0];
unsigned int instanceCount = staticData.size();
unsigned int maxInstanceCount = instanceBuffer->GetVertexCount();
while (instanceCount > 0)
{
unsigned int renderedInstanceCount = std::min(instanceCount, maxInstanceCount);
instanceCount -= renderedInstanceCount;
NzBufferMapper<NzVertexBuffer> mapper(instanceBuffer, nzBufferAccess_DiscardAndWrite, 0, renderedInstanceCount);
nzUInt8* ptr = reinterpret_cast<nzUInt8*>(mapper.GetPointer());
for (unsigned int i = 0; i < renderedInstanceCount; ++i)
{
std::memcpy(ptr, data->transformMatrix, sizeof(float)*16);
data++;
ptr += stride;
}
mapper.Unmap();
InstancedDrawFunc(renderedInstanceCount, primitiveMode, 0, indexCount);
}
}
NzRenderer::Enable(nzRendererParameter_Blend, false);
NzRenderer::SetDepthFunc(oldDepthFunc);
}
else
{
unsigned int originalLightCount = lightCount;
for (const NzForwardRenderQueue::StaticData& data : staticData)
{
// Calcul des lumières les plus proches
if (lightCount < m_maxLightsPerObject && !m_lights.IsEmpty())
unsigned int directionalLightCount = m_directionalLights.GetLightCount();
unsigned int otherLightCount = m_lights.ComputeClosestLights(data.transformMatrix.GetTranslation() + boundingSphere.GetPosition(), boundingSphere.radius, m_maxLightPassPerObject*s_maxLightPerPass - directionalLightCount);
unsigned int lightCount = directionalLightCount + otherLightCount;
NzRenderer::SetMatrix(nzMatrixType_World, data.transformMatrix);
unsigned int directionalLightIndex = 0;
unsigned int otherLightIndex = 0;
nzRendererComparison oldDepthFunc = NzRenderer::GetDepthFunc();
unsigned int passCount = (lightCount == 0) ? 1 : (lightCount-1)/s_maxLightPerPass + 1;
for (unsigned int pass = 0; pass < passCount; ++pass)
{
unsigned int count = std::min(m_maxLightsPerObject-lightCount, m_lights.ComputeClosestLights(data.transformMatrix.GetTranslation() + boundingSphere.GetPosition(), boundingSphere.radius, maxLightCount));
for (unsigned int i = 0; i < count; ++i)
m_lights.GetResult(i)->Enable(program, lightCount++);
unsigned int renderedLightCount = std::min(lightCount, s_maxLightPerPass);
lightCount -= renderedLightCount;
if (pass == 1)
{
// Pour additionner le résultat des calculs de lumière
// Aucune chance d'interférer avec les paramètres du matériau car nous ne rendons que les objets opaques
// (Autrement dit, sans blending)
// Quant à la fonction de profondeur, elle ne doit être appliquée que la première fois
NzRenderer::Enable(nzRendererParameter_Blend, true);
NzRenderer::SetBlendFunc(nzBlendFunc_One, nzBlendFunc_One);
NzRenderer::SetDepthFunc(nzRendererComparison_Equal);
}
for (unsigned int i = 0; i < renderedLightCount; ++i)
{
if (directionalLightIndex >= directionalLightCount)
m_lights.GetResult(otherLightIndex++)->Enable(program, i);
else
m_directionalLights.GetLight(directionalLightIndex++)->Enable(program, i);
}
for (unsigned int i = renderedLightCount; i < s_maxLightPerPass; ++i)
NzLight::Disable(program, i);
DrawFunc(primitiveMode, 0, indexCount);
}
for (unsigned int i = lightCount; i < maxLightCount; ++i)
NzLight::Disable(program, i);
NzRenderer::SetMatrix(nzMatrixType_World, data.transformMatrix);
DrawFunc(primitiveMode, 0, indexCount);
lightCount = originalLightCount;
NzRenderer::Enable(nzRendererParameter_Blend, false);
NzRenderer::SetDepthFunc(oldDepthFunc);
}
}
staticData.clear();
@@ -328,7 +372,7 @@ void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene)
}
}
void NzForwardRenderTechnique::DrawSprites(const NzScene* scene)
void NzForwardRenderTechnique::DrawSprites(const NzScene* scene) const
{
NzAbstractViewer* viewer = scene->GetViewer();
const NzShaderProgram* lastProgram = nullptr;
@@ -408,7 +452,7 @@ void NzForwardRenderTechnique::DrawSprites(const NzScene* scene)
}
}
void NzForwardRenderTechnique::DrawTransparentModels(const NzScene* scene)
void NzForwardRenderTechnique::DrawTransparentModels(const NzScene* scene) const
{
NzAbstractViewer* viewer = scene->GetViewer();
const NzShaderProgram* lastProgram = nullptr;
@@ -474,14 +518,14 @@ void NzForwardRenderTechnique::DrawTransparentModels(const NzScene* scene)
NzRenderer::SetVertexBuffer(vertexBuffer);
// Calcul des lumières les plus proches
if (lightCount < m_maxLightsPerObject && !m_lights.IsEmpty())
if (lightCount < s_maxLightPerPass && !m_lights.IsEmpty())
{
unsigned int count = std::min(m_maxLightsPerObject-lightCount, m_lights.ComputeClosestLights(matrix.GetTranslation() + staticModel.boundingSphere.GetPosition(), staticModel.boundingSphere.radius, maxLightCount));
unsigned int count = std::min(s_maxLightPerPass - lightCount, m_lights.ComputeClosestLights(matrix.GetTranslation() + staticModel.boundingSphere.GetPosition(), staticModel.boundingSphere.radius, s_maxLightPerPass));
for (unsigned int i = 0; i < count; ++i)
m_lights.GetResult(i)->Enable(program, lightCount++);
}
for (unsigned int i = lightCount; i < maxLightCount; ++i)
for (unsigned int i = lightCount; i < s_maxLightPerPass; ++i)
NzLight::Disable(program, i);
NzRenderer::SetMatrix(nzMatrixType_World, matrix);