Added support for billboads

Improved ForwardRenderTechnique code


Former-commit-id: 2386de85c26839565f087885ffcb098ef263bdfa
This commit is contained in:
Lynix 2014-09-03 13:16:56 +02:00
parent aeec8ee0f4
commit 659eb31757
8 changed files with 375 additions and 53 deletions

View File

@ -8,7 +8,9 @@
#define NAZARA_ABSTRACTRENDERQUEUE_HPP
#include <Nazara/Prerequesites.hpp>
#include <Nazara/Core/Color.hpp>
#include <Nazara/Core/NonCopyable.hpp>
#include <Nazara/Core/SparsePtr.hpp>
#include <Nazara/Math/Box.hpp>
#include <Nazara/Math/Matrix4.hpp>
#include <Nazara/Utility/Enums.hpp>
@ -25,6 +27,8 @@ class NAZARA_API NzAbstractRenderQueue : NzNonCopyable
NzAbstractRenderQueue() = default;
virtual ~NzAbstractRenderQueue();
virtual void AddBillboard(const NzMaterial* material, const NzVector3f& position, const NzVector2f& size, const NzVector2f& sinCos = NzVector2f(0.f, 1.f), const NzColor& color = NzColor::White) = 0;
virtual void AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const NzVector2f> sizePtr, NzSparsePtr<const NzVector2f> sinCosPtr = nullptr, NzSparsePtr<const NzColor> colorPtr = nullptr) = 0;
virtual void AddDrawable(const NzDrawable* drawable) = 0;
virtual void AddLight(const NzLight* light) = 0;
virtual void AddMesh(const NzMaterial* material, const NzMeshData& meshData, const NzBoxf& meshAABB, const NzMatrix4f& transformMatrix) = 0;

View File

@ -28,6 +28,8 @@ class NAZARA_API NzDeferredRenderQueue : public NzAbstractRenderQueue, NzResourc
NzDeferredRenderQueue(NzForwardRenderQueue* forwardQueue);
~NzDeferredRenderQueue();
void AddBillboard(const NzMaterial* material, const NzVector3f& position, const NzVector2f& size, const NzVector2f& sinCos = NzVector2f(0.f, 1.f), const NzColor& color = NzColor::White) override;
void AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const NzVector2f> sizePtr, NzSparsePtr<const NzVector2f> sinCosPtr = nullptr, NzSparsePtr<const NzColor> colorPtr = nullptr) override;
void AddDrawable(const NzDrawable* drawable) override;
void AddLight(const NzLight* light) override;
void AddMesh(const NzMaterial* material, const NzMeshData& meshData, const NzBoxf& meshAABB, const NzMatrix4f& transformMatrix) override;

View File

@ -30,6 +30,8 @@ class NAZARA_API NzForwardRenderQueue : public NzAbstractRenderQueue, NzResource
NzForwardRenderQueue() = default;
~NzForwardRenderQueue();
void AddBillboard(const NzMaterial* material, const NzVector3f& position, const NzVector2f& size, const NzVector2f& sinCos = NzVector2f(0.f, 1.f), const NzColor& color = NzColor::White) override;
void AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const NzVector2f> sizePtr, NzSparsePtr<const NzVector2f> sinCosPtr = nullptr, NzSparsePtr<const NzColor> colorPtr = nullptr) override;
void AddDrawable(const NzDrawable* drawable) override;
void AddLight(const NzLight* light) override;
void AddMesh(const NzMaterial* material, const NzMeshData& meshData, const NzBoxf& meshAABB, const NzMatrix4f& transformMatrix) override;
@ -43,6 +45,14 @@ class NAZARA_API NzForwardRenderQueue : public NzAbstractRenderQueue, NzResource
bool OnResourceDestroy(const NzResource* resource, int index) override;
void OnResourceReleased(const NzResource* resource, int index) override;
struct BillboardData
{
NzColor color;
NzVector3f center;
NzVector2f size;
NzVector2f sinCos;
};
struct TransparentModelData
{
NzMatrix4f transformMatrix;
@ -68,11 +78,13 @@ class NAZARA_API NzForwardRenderQueue : public NzAbstractRenderQueue, NzResource
typedef std::map<NzMeshData, std::pair<NzSpheref, std::vector<NzMatrix4f>>, MeshDataComparator> MeshInstanceContainer;
typedef std::map<const NzMaterial*, std::tuple<bool, bool, MeshInstanceContainer>, BatchedModelMaterialComparator> ModelBatches;
typedef std::map<const NzMaterial*, std::vector<BillboardData>> BatchedBillboardContainer;
typedef std::map<const NzMaterial*, std::vector<const NzSprite*>> BatchedSpriteContainer;
typedef std::vector<const NzLight*> LightContainer;
typedef std::vector<unsigned int> TransparentModelContainer;
ModelBatches opaqueModels;
BatchedBillboardContainer billboards;
BatchedSpriteContainer sprites;
TransparentModelContainer transparentModels;
std::vector<TransparentModelData> transparentModelData;

View File

@ -20,7 +20,7 @@ class NAZARA_API NzForwardRenderTechnique : public NzAbstractRenderTechnique, Nz
{
public:
NzForwardRenderTechnique();
~NzForwardRenderTechnique();
~NzForwardRenderTechnique() = default;
void Clear(const NzScene* scene) const;
bool Draw(const NzScene* scene) const;
@ -31,9 +31,13 @@ class NAZARA_API NzForwardRenderTechnique : public NzAbstractRenderTechnique, Nz
void SetMaxLightPassPerObject(unsigned int passCount);
static bool Initialize();
static void Uninitialize();
private:
struct LightUniforms;
void DrawBillboards(const NzScene* scene) const;
void DrawOpaqueModels(const NzScene* scene) const;
void DrawSprites(const NzScene* scene) const;
void DrawTransparentModels(const NzScene* scene) const;
@ -49,12 +53,19 @@ class NAZARA_API NzForwardRenderTechnique : public NzAbstractRenderTechnique, Nz
};
mutable std::unordered_map<const NzShader*, LightUniforms> m_lightUniforms;
NzBuffer m_vertexBuffer;
mutable NzForwardRenderQueue m_renderQueue;
NzIndexBufferRef m_indexBuffer;
mutable NzLightManager m_directionalLights;
mutable NzLightManager m_lights;
NzVertexBuffer m_billboardPointBuffer;
NzVertexBuffer m_spriteBuffer;
unsigned int m_maxLightPassPerObject;
static NzIndexBuffer s_quadIndexBuffer;
static NzVertexBuffer s_quadVertexBuffer;
static NzVertexDeclaration s_billboardInstanceDeclaration;
static NzVertexDeclaration s_billboardVertexDeclaration;
static NzVertexDeclaration s_spriteDeclaration;
};
#endif // NAZARA_FORWARDRENDERTECHNIQUE_HPP

View File

@ -31,6 +31,18 @@ NzDeferredRenderQueue::~NzDeferredRenderQueue()
Clear(true);
}
void NzDeferredRenderQueue::AddBillboard(const NzMaterial* material, const NzVector3f& position, const NzVector2f& size, const NzVector2f& sinCos, const NzColor& color)
{
///TODO: Rendre les billboards via Deferred Shading si possible
m_forwardQueue->AddBillboard(material, position, size, sinCos, color);
}
void NzDeferredRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const NzVector2f> sizePtr, NzSparsePtr<const NzVector2f> sinCosPtr, NzSparsePtr<const NzColor> colorPtr)
{
///TODO: Rendre les billboards via Deferred Shading si possible
m_forwardQueue->AddBillboards(material, count, positionPtr, sizePtr, sinCosPtr, colorPtr);
}
void NzDeferredRenderQueue::AddDrawable(const NzDrawable* drawable)
{
m_forwardQueue->AddDrawable(drawable);
@ -81,8 +93,10 @@ void NzDeferredRenderQueue::AddMesh(const NzMaterial* material, const NzMeshData
bool& enableInstancing = std::get<1>(it->second);
MeshInstanceContainer& meshMap = std::get<2>(it->second);
// On indique la présence de modèles dans cette partie de la map
used = true;
// Si nous insérons ce mesh pour la première fois, nous ajoutons des listeners sur ses buffers
MeshInstanceContainer::iterator it2 = meshMap.find(meshData);
if (it2 == meshMap.end())
{
@ -94,6 +108,7 @@ void NzDeferredRenderQueue::AddMesh(const NzMaterial* material, const NzMeshData
meshData.vertexBuffer->AddResourceListener(this, ResourceType_VertexBuffer);
}
// On ajoute la matrice à la liste des instances de cet objet
std::vector<NzMatrix4f>& instances = it2->second;
instances.push_back(transformMatrix);

View File

@ -27,6 +27,37 @@ NzForwardRenderQueue::~NzForwardRenderQueue()
Clear(true);
}
void NzForwardRenderQueue::AddBillboard(const NzMaterial* material, const NzVector3f& position, const NzVector2f& size, const NzVector2f& sinCos, const NzColor& color)
{
billboards[material].push_back(BillboardData{color, position, size, sinCos});
}
void NzForwardRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const NzVector2f> sizePtr, NzSparsePtr<const NzVector2f> sinCosPtr, NzSparsePtr<const NzColor> colorPtr)
{
///DOC: sinCosPtr et colorPtr peuvent être nuls, ils seont remplacés respectivement par Vector2f(0.f, 1.f) et Color::White
NzVector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1
if (!sinCosPtr)
sinCosPtr.Reset(&defaultSinCos, 0); // L'astuce ici est de mettre le stride sur zéro, rendant le pointeur immobile
if (!colorPtr)
colorPtr.Reset(&NzColor::White, 0); // Pareil
std::vector<BillboardData>& billboardVec = billboards[material];
unsigned int prevSize = billboardVec.size();
billboardVec.resize(prevSize + count);
BillboardData* billboardData = &billboardVec[prevSize];
for (unsigned int i = 0; i < count; ++i)
{
billboardData->center = *positionPtr++;
billboardData->color = *colorPtr++;
billboardData->sinCos = *sinCosPtr++;
billboardData->size = *sizePtr++;
billboardData++;
}
}
void NzForwardRenderQueue::AddDrawable(const NzDrawable* drawable)
{
#if NAZARA_GRAPHICS_SAFE
@ -72,6 +103,7 @@ void NzForwardRenderQueue::AddMesh(const NzMaterial* material, const NzMeshData&
{
if (material->IsEnabled(nzRendererParameter_Blend))
{
// Le matériau est transparent, nous devons rendre ce mesh d'une autre façon (après le rendu des objets opaques et en les triant)
unsigned int index = transparentModelData.size();
transparentModelData.resize(index+1);
@ -88,6 +120,7 @@ void NzForwardRenderQueue::AddMesh(const NzMaterial* material, const NzMeshData&
ModelBatches::iterator it = opaqueModels.find(material);
if (it == opaqueModels.end())
{
// Première utilisation du matériau, ajoutons-nous comme listener
it = opaqueModels.insert(std::make_pair(material, ModelBatches::mapped_type())).first;
material->AddResourceListener(this, ResourceType_Material);
}
@ -166,6 +199,8 @@ void NzForwardRenderQueue::Clear(bool fully)
renderData.vertexBuffer->RemoveResourceListener(this);
}
}
billboards.clear();
opaqueModels.clear();
sprites.clear();
}
@ -174,6 +209,7 @@ void NzForwardRenderQueue::Clear(bool fully)
void NzForwardRenderQueue::Sort(const NzAbstractViewer* viewer)
{
NzPlanef nearPlane = viewer->GetFrustum().GetPlane(nzFrustumPlane_Near);
NzVector3f viewerPos = viewer->GetEyePosition();
NzVector3f viewerNormal = viewer->GetForward();
std::sort(transparentModels.begin(), transparentModels.end(), [this, &nearPlane, &viewerNormal](unsigned int index1, unsigned int index2)
@ -186,6 +222,20 @@ void NzForwardRenderQueue::Sort(const NzAbstractViewer* viewer)
return nearPlane.Distance(position1) > nearPlane.Distance(position2);
});
for (auto& pair : billboards)
{
const NzMaterial* mat = pair.first;
auto& container = pair.second;
if (mat->IsEnabled(nzRendererParameter_Blend))
{
std::sort(container.begin(), container.end(), [&viewerPos](const BillboardData& data1, const BillboardData& data2)
{
return viewerPos.SquaredDistance(data1.center) > viewerPos.SquaredDistance(data2.center);
});
}
}
}
bool NzForwardRenderQueue::OnResourceDestroy(const NzResource* resource, int index)
@ -210,8 +260,13 @@ bool NzForwardRenderQueue::OnResourceDestroy(const NzResource* resource, int ind
}
case ResourceType_Material:
opaqueModels.erase(static_cast<const NzMaterial*>(resource));
{
const NzMaterial* material = static_cast<const NzMaterial*>(resource);
billboards.erase(material);
opaqueModels.erase(material);
break;
}
case ResourceType_VertexBuffer:
{
@ -299,7 +354,6 @@ bool NzForwardRenderQueue::BatchedModelMaterialComparator::operator()(const NzMa
const NzShader* shader1 = mat1->GetShaderInstance()->GetShader();
const NzShader* shader2 = mat2->GetShaderInstance()->GetShader();
if (shader1 != shader2)
return shader1 < shader2;
@ -320,7 +374,6 @@ bool NzForwardRenderQueue::BatchedSpriteMaterialComparator::operator()(const NzM
const NzShader* shader1 = mat1->GetShaderInstance()->GetShader();
const NzShader* shader2 = mat2->GetShaderInstance()->GetShader();
if (shader1 != shader2)
return shader1 < shader2;

View File

@ -3,6 +3,8 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/ForwardRenderTechnique.hpp>
#include <Nazara/Core/ErrorFlags.hpp>
#include <Nazara/Core/OffsetOf.hpp>
#include <Nazara/Graphics/AbstractBackground.hpp>
#include <Nazara/Graphics/Camera.hpp>
#include <Nazara/Graphics/Drawable.hpp>
@ -22,46 +24,36 @@
namespace
{
static NzIndexBuffer* s_indexBuffer = nullptr;
unsigned int s_maxSprites = 8192;
NzIndexBuffer* BuildIndexBuffer()
struct BillboardPoint
{
std::unique_ptr<NzIndexBuffer> indexBuffer(new NzIndexBuffer(false, s_maxSprites*6, nzBufferStorage_Hardware, nzBufferUsage_Static));
indexBuffer->SetPersistent(false);
NzColor color;
NzVector3f position;
NzVector2f size;
NzVector2f sinCos; // doit suivre size
NzVector2f uv;
};
NzBufferMapper<NzIndexBuffer> mapper(indexBuffer.get(), nzBufferAccess_WriteOnly);
nzUInt16* indices = static_cast<nzUInt16*>(mapper.GetPointer());
struct SpriteVertex
{
NzColor color;
NzVector3f position;
NzVector2f uv;
};
for (unsigned int i = 0; i < s_maxSprites; ++i)
{
*indices++ = i*4 + 0;
*indices++ = i*4 + 2;
*indices++ = i*4 + 1;
*indices++ = i*4 + 2;
*indices++ = i*4 + 3;
*indices++ = i*4 + 1;
}
return indexBuffer.release();
}
unsigned int s_maxBillboardSprites = std::numeric_limits<nzUInt16>::max()/6;
unsigned int s_vertexBufferSize = 1024*1024; // 1 MB
}
NzForwardRenderTechnique::NzForwardRenderTechnique() :
m_spriteBuffer(NzVertexDeclaration::Get(nzVertexLayout_XYZ_UV), s_maxSprites*4, nzBufferStorage_Hardware, nzBufferUsage_Dynamic),
m_vertexBuffer(nzBufferType_Vertex),
m_maxLightPassPerObject(3)
{
if (!s_indexBuffer)
s_indexBuffer = BuildIndexBuffer();
NzErrorFlags flags(nzErrorFlag_ThrowException, true);
m_indexBuffer = s_indexBuffer;
}
m_vertexBuffer.Create(s_vertexBufferSize, nzBufferStorage_Hardware, nzBufferUsage_Dynamic);
NzForwardRenderTechnique::~NzForwardRenderTechnique()
{
if (m_indexBuffer.Reset())
s_indexBuffer = nullptr;
m_billboardPointBuffer.Reset(&s_billboardVertexDeclaration, &m_vertexBuffer);
m_spriteBuffer.Reset(&s_spriteDeclaration, &m_vertexBuffer);
}
void NzForwardRenderTechnique::Clear(const NzScene* scene) const
@ -87,6 +79,9 @@ bool NzForwardRenderTechnique::Draw(const NzScene* scene) const
if (!m_renderQueue.transparentModels.empty())
DrawTransparentModels(scene);
if (!m_renderQueue.billboards.empty())
DrawBillboards(scene);
if (!m_renderQueue.sprites.empty())
DrawSprites(scene);
@ -162,6 +157,208 @@ void NzForwardRenderTechnique::SetMaxLightPassPerObject(unsigned int passCount)
m_maxLightPassPerObject = passCount;
}
bool NzForwardRenderTechnique::Initialize()
{
try
{
NzErrorFlags flags(nzErrorFlag_ThrowException, true);
s_quadIndexBuffer.Reset(false, s_maxBillboardSprites*6, nzBufferStorage_Hardware, nzBufferUsage_Static);
NzBufferMapper<NzIndexBuffer> mapper(s_quadIndexBuffer, nzBufferAccess_WriteOnly);
nzUInt16* indices = static_cast<nzUInt16*>(mapper.GetPointer());
for (unsigned int i = 0; i < s_maxBillboardSprites; ++i)
{
*indices++ = i*4 + 0;
*indices++ = i*4 + 2;
*indices++ = i*4 + 1;
*indices++ = i*4 + 2;
*indices++ = i*4 + 3;
*indices++ = i*4 + 1;
}
mapper.Unmap(); // Inutile de garder le buffer ouvert plus longtemps
// Quad buffer (utilisé pour l'instancing de billboard et de sprites)
//Note: Les UV sont calculés dans le shader
s_quadVertexBuffer.Reset(NzVertexDeclaration::Get(nzVertexLayout_XY), 4, nzBufferStorage_Hardware, nzBufferUsage_Static);
float vertices[2*4] = {
-0.5f, -0.5f,
0.5f, -0.5f,
-0.5f, 0.5f,
0.5f, 0.5f,
};
s_quadVertexBuffer.FillRaw(vertices, 0, sizeof(vertices));
// Déclaration lors du rendu des billboards par sommet
s_billboardVertexDeclaration.EnableComponent(nzVertexComponent_Color, nzComponentType_Color, NzOffsetOf(BillboardPoint, color));
s_billboardVertexDeclaration.EnableComponent(nzVertexComponent_Position, nzComponentType_Float3, NzOffsetOf(BillboardPoint, position));
s_billboardVertexDeclaration.EnableComponent(nzVertexComponent_TexCoord, nzComponentType_Float2, NzOffsetOf(BillboardPoint, uv));
s_billboardVertexDeclaration.EnableComponent(nzVertexComponent_Userdata0, nzComponentType_Float4, NzOffsetOf(BillboardPoint, size)); // Englobe sincos
// Declaration utilisée lors du rendu des billboards par instancing
// L'avantage ici est la copie directe (std::memcpy) des données de la RenderQueue vers le buffer GPU
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));
s_spriteDeclaration.EnableComponent(nzVertexComponent_Color, nzComponentType_Color, NzOffsetOf(SpriteVertex, color));
s_spriteDeclaration.EnableComponent(nzVertexComponent_Position, nzComponentType_Float3, NzOffsetOf(SpriteVertex, position));
s_spriteDeclaration.EnableComponent(nzVertexComponent_TexCoord, nzComponentType_Float2, NzOffsetOf(SpriteVertex, uv));
}
catch (const std::exception& e)
{
NazaraError("Failed to initialise: " + NzString(e.what()));
return false;
}
return true;
}
void NzForwardRenderTechnique::Uninitialize()
{
s_quadIndexBuffer.Reset();
}
void NzForwardRenderTechnique::DrawBillboards(const NzScene* scene) const
{
NzAbstractViewer* viewer = scene->GetViewer();
const NzShader* lastShader = nullptr;
if (NzRenderer::HasCapability(nzRendererCap_Instancing))
{
NzVertexBuffer* instanceBuffer = NzRenderer::GetInstanceBuffer();
instanceBuffer->SetVertexDeclaration(&s_billboardInstanceDeclaration);
NzRenderer::SetVertexBuffer(&s_quadVertexBuffer);
for (auto& matIt : m_renderQueue.billboards)
{
const NzMaterial* material = matIt.first;
auto& billboardVector = matIt.second;
unsigned int billboardCount = billboardVector.size();
if (billboardCount > 0)
{
// On commence par appliquer du matériau (et récupérer le shader ainsi activé)
const NzShader* shader = material->Apply(nzShaderFlags_Billboard | nzShaderFlags_Instancing | nzShaderFlags_VertexColor);
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas
if (shader != lastShader)
{
// Couleur ambiante de la scène
shader->SendColor(shader->GetUniformLocation(nzShaderUniform_SceneAmbient), scene->GetAmbientColor());
// Position de la caméra
shader->SendVector(shader->GetUniformLocation(nzShaderUniform_EyePosition), viewer->GetEyePosition());
lastShader = shader;
}
const NzForwardRenderQueue::BillboardData* data = &billboardVector[0];
unsigned int maxBillboardPerDraw = instanceBuffer->GetVertexCount();
do
{
unsigned int renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw);
billboardCount -= renderedBillboardCount;
instanceBuffer->Fill(data, 0, renderedBillboardCount, true);
data += renderedBillboardCount;
NzRenderer::DrawPrimitivesInstanced(renderedBillboardCount, nzPrimitiveMode_TriangleStrip, 0, 4);
}
while (billboardCount > 0);
billboardVector.clear();
}
}
}
else
{
NzRenderer::SetIndexBuffer(&s_quadIndexBuffer);
NzRenderer::SetVertexBuffer(&m_billboardPointBuffer);
for (auto& matIt : m_renderQueue.billboards)
{
const NzMaterial* material = matIt.first;
auto& billboardVector = matIt.second;
unsigned int billboardCount = billboardVector.size();
if (billboardCount > 0)
{
// On commence par appliquer du matériau (et récupérer le shader ainsi activé)
const NzShader* shader = material->Apply(nzShaderFlags_Billboard | nzShaderFlags_VertexColor);
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas
if (shader != lastShader)
{
// Couleur ambiante de la scène
shader->SendColor(shader->GetUniformLocation(nzShaderUniform_SceneAmbient), scene->GetAmbientColor());
// Position de la caméra
shader->SendVector(shader->GetUniformLocation(nzShaderUniform_EyePosition), viewer->GetEyePosition());
lastShader = shader;
}
const NzForwardRenderQueue::BillboardData* data = &billboardVector[0];
unsigned int maxBillboardPerDraw = std::min(s_maxBillboardSprites, m_billboardPointBuffer.GetVertexCount()/4);
do
{
unsigned int renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw);
billboardCount -= renderedBillboardCount;
NzBufferMapper<NzVertexBuffer> vertexMapper(m_billboardPointBuffer, nzBufferAccess_DiscardAndWrite, 0, renderedBillboardCount*4);
BillboardPoint* vertices = reinterpret_cast<BillboardPoint*>(vertexMapper.GetPointer());
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, 1.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);
billboardVector.clear();
}
}
}
}
void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene) const
{
NzAbstractViewer* viewer = scene->GetViewer();
@ -378,7 +575,7 @@ void NzForwardRenderTechnique::DrawSprites(const NzScene* scene) const
NzAbstractViewer* viewer = scene->GetViewer();
const NzShader* lastShader = nullptr;
NzRenderer::SetIndexBuffer(m_indexBuffer);
NzRenderer::SetIndexBuffer(&s_quadIndexBuffer);
NzRenderer::SetMatrix(nzMatrixType_World, NzMatrix4f::Identity());
NzRenderer::SetVertexBuffer(&m_spriteBuffer);
@ -391,7 +588,7 @@ void NzForwardRenderTechnique::DrawSprites(const NzScene* scene) const
if (spriteCount > 0)
{
// On commence par appliquer du matériau (et récupérer le shader ainsi activé)
const NzShader* shader = material->Apply();
const NzShader* shader = material->Apply(nzShaderFlags_VertexColor);
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas
if (shader != lastShader)
@ -405,36 +602,47 @@ void NzForwardRenderTechnique::DrawSprites(const NzScene* scene) const
}
const NzSprite** spritePtr = &spriteVector[0];
unsigned int maxSpritePerDraw = std::min(s_maxBillboardSprites, m_spriteBuffer.GetVertexCount()/4);
do
{
unsigned int renderedSpriteCount = std::min(spriteCount, 64U);
unsigned int renderedSpriteCount = std::min(spriteCount, maxSpritePerDraw);
spriteCount -= renderedSpriteCount;
NzBufferMapper<NzVertexBuffer> vertexMapper(m_spriteBuffer, nzBufferAccess_DiscardAndWrite, 0, renderedSpriteCount*4);
NzVertexStruct_XYZ_UV* vertices = reinterpret_cast<NzVertexStruct_XYZ_UV*>(vertexMapper.GetPointer());
SpriteVertex* vertices = reinterpret_cast<SpriteVertex*>(vertexMapper.GetPointer());
for (unsigned int i = 0; i < renderedSpriteCount; ++i)
{
const NzSprite* sprite = *spritePtr++;
const NzColor& color = sprite->GetColor();
const NzRectf& textureCoords = sprite->GetTextureCoords();
const NzVector2f& halfSize = sprite->GetSize()*0.5f;
NzVector3f center = sprite->GetPosition();
NzVector2f size = sprite->GetSize();
NzVector3f origin = sprite->GetPosition();
NzVector3f scale = sprite->GetScale();
NzQuaternionf rotation = sprite->GetRotation();
vertices->position = center + rotation * NzVector3f(-halfSize.x, -halfSize.y, 0.f);
vertices->uv.Set(textureCoords.x, textureCoords.y + textureCoords.height);
vertices++;
size.x *= scale.x;
size.y *= scale.y;
vertices->position = center + rotation * NzVector3f(halfSize.x, -halfSize.y, 0.f);
vertices->uv.Set(textureCoords.width, textureCoords.y + textureCoords.height);
vertices++;
vertices->position = center + rotation * NzVector3f(-halfSize.x, halfSize.y, 0.f);
vertices->color = color;
vertices->position = origin;
vertices->uv.Set(textureCoords.x, textureCoords.y);
vertices++;
vertices->position = center + rotation * NzVector3f(halfSize.x, halfSize.y, 0.f);
vertices->uv.Set(textureCoords.width, textureCoords.y);
vertices->color = color;
vertices->position = origin + rotation * NzVector3f(size.x, 0.f, 0.f);
vertices->uv.Set(textureCoords.x + textureCoords.width, textureCoords.y);
vertices++;
vertices->color = color;
vertices->position = origin + rotation * NzVector3f(0.f, size.y, 0.f);
vertices->uv.Set(textureCoords.x, textureCoords.y + textureCoords.height);
vertices++;
vertices->color = color;
vertices->position = origin + rotation * NzVector3f(size.x, size.y, 0.f);
vertices->uv.Set(textureCoords.x + textureCoords.width, textureCoords.y + textureCoords.height);
vertices++;
}
@ -557,3 +765,9 @@ const NzForwardRenderTechnique::LightUniforms* NzForwardRenderTechnique::GetLigh
return &(pair.first->second);
}
}
NzIndexBuffer NzForwardRenderTechnique::s_quadIndexBuffer;
NzVertexBuffer NzForwardRenderTechnique::s_quadVertexBuffer;
NzVertexDeclaration NzForwardRenderTechnique::s_billboardInstanceDeclaration;
NzVertexDeclaration NzForwardRenderTechnique::s_billboardVertexDeclaration;
NzVertexDeclaration NzForwardRenderTechnique::s_spriteDeclaration;

View File

@ -65,12 +65,22 @@ bool NzGraphics::Initialize()
NzLoaders_Texture_Register();
// RenderTechniques
if (!NzForwardRenderTechnique::Initialize())
{
NazaraError("Failed to initialize Forward Rendering");
return false;
}
NzRenderTechniques::Register(NzRenderTechniques::ToString(nzRenderTechniqueType_BasicForward), 0, []() -> NzAbstractRenderTechnique* { return new NzForwardRenderTechnique; });
if (NzDeferredRenderTechnique::IsSupported())
{
NzDeferredRenderTechnique::Initialize();
NzRenderTechniques::Register(NzRenderTechniques::ToString(nzRenderTechniqueType_DeferredShading), 20, []() -> NzAbstractRenderTechnique* { return new NzDeferredRenderTechnique; });
if (NzDeferredRenderTechnique::Initialize())
NzRenderTechniques::Register(NzRenderTechniques::ToString(nzRenderTechniqueType_DeferredShading), 20, []() -> NzAbstractRenderTechnique* { return new NzDeferredRenderTechnique; });
else
{
NazaraWarning("Failed to initialize Deferred Rendering");
}
}
onExit.Reset();
@ -104,6 +114,7 @@ void NzGraphics::Uninitialize()
NzLoaders_Texture_Unregister();
NzDeferredRenderTechnique::Uninitialize();
NzForwardRenderTechnique::Uninitialize();
NzMaterial::Uninitialize();
NzParticleDeclaration::Uninitialize();
NzSkinningManager::Uninitialize();