Graphics: Separate pipeline state from Material into a new class, MaterialPipeline
This allows much more efficient batching, along with pipeline reusage and preparation for the Vulkan API Former-commit-id: 4ed2f66567f7da6b6b6ee073e4d855b9a935000d [formerly b540f468fc700a16d5136d4dbb8632e23882fd3d] [formerly 37fff624ec65cc387130875410b6ea35c1a5bcfb [formerly ab9a88f514f46f6596499e285981fa6da588bb03]] Former-commit-id: a2e8859196c0f72b7d7ffd8764a887e6c8173743 [formerly c886cdade14769db243ff993a1741f6052a2eb2a] Former-commit-id: e1d02662fb1ac165c7e888380afee7601350060f
This commit is contained in:
parent
8fbe279a50
commit
87b5047b14
|
|
@ -28,8 +28,8 @@ namespace Ndk
|
|||
m_characterSize(24)
|
||||
{
|
||||
Nz::MaterialRef backgroundMaterial = Nz::Material::New();
|
||||
backgroundMaterial->Enable(Nz::RendererParameter_Blend, true);
|
||||
backgroundMaterial->Enable(Nz::RendererParameter_DepthBuffer, false);
|
||||
backgroundMaterial->EnableBlending(true);
|
||||
backgroundMaterial->EnableDepthBuffer(false);
|
||||
backgroundMaterial->SetDstBlend(Nz::BlendFunc_InvSrcAlpha);
|
||||
backgroundMaterial->SetSrcBlend(Nz::BlendFunc_SrcAlpha);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// This file was automatically generated on 12 Jul 2016 at 17:44:43
|
||||
// This file was automatically generated on 20 Jul 2016 at 13:49:17
|
||||
|
||||
/*
|
||||
Nazara Engine - Graphics module
|
||||
|
|
@ -68,6 +68,7 @@
|
|||
#include <Nazara/Graphics/ParticleRenderer.hpp>
|
||||
#include <Nazara/Graphics/ParticleStruct.hpp>
|
||||
#include <Nazara/Graphics/Renderable.hpp>
|
||||
#include <Nazara/Graphics/MaterialPipeline.hpp>
|
||||
#include <Nazara/Graphics/RenderTechniques.hpp>
|
||||
#include <Nazara/Graphics/SceneData.hpp>
|
||||
#include <Nazara/Graphics/SkeletalModel.hpp>
|
||||
|
|
|
|||
|
|
@ -121,8 +121,7 @@ namespace Nz
|
|||
inline void Billboard::SetDefaultMaterial()
|
||||
{
|
||||
MaterialRef material = Material::New();
|
||||
material->Enable(RendererParameter_FaceCulling, true);
|
||||
material->EnableLighting(false);
|
||||
material->EnableFaceCulling(true);
|
||||
|
||||
SetMaterial(std::move(material));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <Nazara/Core/Color.hpp>
|
||||
#include <Nazara/Graphics/AbstractRenderQueue.hpp>
|
||||
#include <Nazara/Graphics/ForwardRenderQueue.hpp>
|
||||
#include <Nazara/Graphics/Material.hpp>
|
||||
#include <Nazara/Math/Box.hpp>
|
||||
#include <Nazara/Math/Matrix4.hpp>
|
||||
|
|
@ -21,8 +21,6 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
class ForwardRenderQueue;
|
||||
|
||||
class NAZARA_GRAPHICS_API DeferredRenderQueue : public AbstractRenderQueue
|
||||
{
|
||||
public:
|
||||
|
|
@ -43,11 +41,6 @@ namespace Nz
|
|||
|
||||
void Clear(bool fully = false) override;
|
||||
|
||||
struct MeshDataComparator
|
||||
{
|
||||
bool operator()(const MeshData& data1, const MeshData& data2) const;
|
||||
};
|
||||
|
||||
struct MeshInstanceEntry
|
||||
{
|
||||
NazaraSlot(IndexBuffer, OnIndexBufferRelease, indexBufferReleaseSlot);
|
||||
|
|
@ -56,12 +49,7 @@ namespace Nz
|
|||
std::vector<Matrix4f> instances;
|
||||
};
|
||||
|
||||
typedef std::map<MeshData, MeshInstanceEntry, MeshDataComparator> MeshInstanceContainer;
|
||||
|
||||
struct BatchedModelMaterialComparator
|
||||
{
|
||||
bool operator()(const Material* mat1, const Material* mat2) const;
|
||||
};
|
||||
typedef std::map<MeshData, MeshInstanceEntry, ForwardRenderQueue::MeshDataComparator> MeshInstanceContainer;
|
||||
|
||||
struct BatchedModelEntry
|
||||
{
|
||||
|
|
@ -69,14 +57,21 @@ namespace Nz
|
|||
|
||||
MeshInstanceContainer meshMap;
|
||||
bool enabled = false;
|
||||
bool instancingEnabled = false;
|
||||
};
|
||||
|
||||
typedef std::map<const Material*, BatchedModelEntry, BatchedModelMaterialComparator> ModelBatches;
|
||||
typedef std::map<const Material*, BatchedModelEntry, ForwardRenderQueue::MaterialComparator> MeshMaterialBatches;
|
||||
|
||||
struct BatchedMaterialEntry
|
||||
{
|
||||
std::size_t maxInstanceCount = 0;
|
||||
MeshMaterialBatches materialMap;
|
||||
};
|
||||
|
||||
typedef std::map<const MaterialPipeline*, BatchedMaterialEntry, ForwardRenderQueue::MaterialPipelineComparator> MeshPipelineBatches;
|
||||
|
||||
struct Layer
|
||||
{
|
||||
ModelBatches opaqueModels;
|
||||
MeshPipelineBatches opaqueModels;
|
||||
unsigned int clearCount = 0;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ namespace Nz
|
|||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
return material->HasDepthMaterial() || (material->IsEnabled(RendererParameter_DepthBuffer) && material->IsEnabled(RendererParameter_DepthWrite) && material->IsShadowCastingEnabled());
|
||||
return material->HasDepthMaterial() || (material->IsDepthBufferEnabled() && material->IsDepthWriteEnabled() && material->IsShadowCastingEnabled());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ namespace Nz
|
|||
mutable std::unordered_map<const Shader*, ShaderUniforms> m_shaderUniforms;
|
||||
Buffer m_vertexBuffer;
|
||||
mutable DepthRenderQueue m_renderQueue;
|
||||
Texture m_whiteTexture;
|
||||
VertexBuffer m_billboardPointBuffer;
|
||||
VertexBuffer m_spriteBuffer;
|
||||
|
||||
|
|
|
|||
|
|
@ -47,6 +47,16 @@ namespace Nz
|
|||
|
||||
void Sort(const AbstractViewer* viewer);
|
||||
|
||||
struct MaterialComparator
|
||||
{
|
||||
bool operator()(const Material* mat1, const Material* mat2) const;
|
||||
};
|
||||
|
||||
struct MaterialPipelineComparator
|
||||
{
|
||||
bool operator()(const MaterialPipeline* pipeline1, const MaterialPipeline* pipeline2) const;
|
||||
};
|
||||
|
||||
/// Billboards
|
||||
struct BillboardData
|
||||
{
|
||||
|
|
@ -56,11 +66,6 @@ namespace Nz
|
|||
Vector2f sinCos;
|
||||
};
|
||||
|
||||
struct BatchedBillboardComparator
|
||||
{
|
||||
bool operator()(const Material* mat1, const Material* mat2) const;
|
||||
};
|
||||
|
||||
struct BatchedBillboardEntry
|
||||
{
|
||||
NazaraSlot(Material, OnMaterialRelease, materialReleaseSlot);
|
||||
|
|
@ -68,7 +73,15 @@ namespace Nz
|
|||
std::vector<BillboardData> billboards;
|
||||
};
|
||||
|
||||
typedef std::map<const Material*, BatchedBillboardEntry, BatchedBillboardComparator> BatchedBillboardContainer;
|
||||
typedef std::map<const Material*, BatchedBillboardEntry, MaterialComparator> BatchedBillboardContainer;
|
||||
|
||||
struct BatchedBillboardPipelineEntry
|
||||
{
|
||||
BatchedBillboardContainer materialMap;
|
||||
bool enabled = false;
|
||||
};
|
||||
|
||||
typedef std::map<const MaterialPipeline*, BatchedBillboardPipelineEntry, MaterialPipelineComparator> BillboardPipelineBatches;
|
||||
|
||||
/// Sprites
|
||||
struct SpriteChain_XYZ_Color_UV
|
||||
|
|
@ -84,22 +97,25 @@ namespace Nz
|
|||
std::vector<SpriteChain_XYZ_Color_UV> spriteChains;
|
||||
};
|
||||
|
||||
struct BatchedSpriteMaterialComparator
|
||||
{
|
||||
bool operator()(const Material* mat1, const Material* mat2);
|
||||
};
|
||||
|
||||
typedef std::map<const Texture*, BatchedSpriteEntry> BasicSpriteOverlayContainer;
|
||||
typedef std::map<const Texture*, BatchedSpriteEntry> SpriteOverlayBatches;
|
||||
|
||||
struct BatchedBasicSpriteEntry
|
||||
{
|
||||
NazaraSlot(Material, OnMaterialRelease, materialReleaseSlot);
|
||||
|
||||
BasicSpriteOverlayContainer overlayMap;
|
||||
SpriteOverlayBatches overlayMap;
|
||||
bool enabled = false;
|
||||
};
|
||||
|
||||
typedef std::map<const Material*, BatchedBasicSpriteEntry> BasicSpriteBatches;
|
||||
typedef std::map<const Material*, BatchedBasicSpriteEntry, MaterialComparator> SpriteMaterialBatches;
|
||||
|
||||
struct BatchedSpritePipelineEntry
|
||||
{
|
||||
SpriteMaterialBatches materialMap;
|
||||
bool enabled = false;
|
||||
};
|
||||
|
||||
typedef std::map<const MaterialPipeline*, BatchedSpritePipelineEntry, MaterialPipelineComparator> SpritePipelineBatches;
|
||||
|
||||
/// Meshes
|
||||
struct MeshDataComparator
|
||||
|
|
@ -118,21 +134,23 @@ namespace Nz
|
|||
|
||||
typedef std::map<MeshData, MeshInstanceEntry, MeshDataComparator> MeshInstanceContainer;
|
||||
|
||||
struct BatchedModelMaterialComparator
|
||||
{
|
||||
bool operator()(const Material* mat1, const Material* mat2) const;
|
||||
};
|
||||
|
||||
struct BatchedModelEntry
|
||||
{
|
||||
NazaraSlot(Material, OnMaterialRelease, materialReleaseSlot);
|
||||
|
||||
MeshInstanceContainer meshMap;
|
||||
bool enabled = false;
|
||||
bool instancingEnabled = false;
|
||||
};
|
||||
|
||||
typedef std::map<const Material*, BatchedModelEntry, BatchedModelMaterialComparator> ModelBatches;
|
||||
typedef std::map<const Material*, BatchedModelEntry, MaterialComparator> MeshMaterialBatches;
|
||||
|
||||
struct BatchedMaterialEntry
|
||||
{
|
||||
std::size_t maxInstanceCount = 0;
|
||||
MeshMaterialBatches materialMap;
|
||||
};
|
||||
|
||||
typedef std::map<const MaterialPipeline*, BatchedMaterialEntry, MaterialPipelineComparator> MeshPipelineBatches;
|
||||
|
||||
struct TransparentModelData
|
||||
{
|
||||
|
|
@ -146,9 +164,9 @@ namespace Nz
|
|||
|
||||
struct Layer
|
||||
{
|
||||
BatchedBillboardContainer billboards;
|
||||
BasicSpriteBatches basicSprites;
|
||||
ModelBatches opaqueModels;
|
||||
BillboardPipelineBatches billboards;
|
||||
SpritePipelineBatches basicSprites;
|
||||
MeshPipelineBatches opaqueModels;
|
||||
TransparentModelContainer transparentModels;
|
||||
std::vector<TransparentModelData> transparentModelData;
|
||||
std::vector<const Drawable*> otherDrawables;
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ namespace Nz
|
|||
mutable std::vector<LightIndex> m_lights;
|
||||
Buffer m_vertexBuffer;
|
||||
mutable ForwardRenderQueue m_renderQueue;
|
||||
Texture m_whiteTexture;
|
||||
VertexBuffer m_billboardPointBuffer;
|
||||
VertexBuffer m_spriteBuffer;
|
||||
unsigned int m_maxLightPassPerObject;
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
#include <Nazara/Core/String.hpp>
|
||||
#include <Nazara/Graphics/Config.hpp>
|
||||
#include <Nazara/Graphics/Enums.hpp>
|
||||
#include <Nazara/Renderer/RenderStates.hpp>
|
||||
#include <Nazara/Graphics/MaterialPipeline.hpp>
|
||||
#include <Nazara/Renderer/Texture.hpp>
|
||||
#include <Nazara/Renderer/TextureSampler.hpp>
|
||||
#include <Nazara/Renderer/UberShader.hpp>
|
||||
|
|
@ -58,20 +58,33 @@ namespace Nz
|
|||
|
||||
public:
|
||||
inline Material();
|
||||
inline Material(const MaterialPipeline* pipeline);
|
||||
inline Material(const MaterialPipelineInfo& pipelineInfo);
|
||||
inline Material(const String& pipelineName);
|
||||
inline Material(const Material& material);
|
||||
inline ~Material();
|
||||
|
||||
const Shader* Apply(UInt32 shaderFlags = 0, UInt8 textureUnit = 0, UInt8* lastUsedUnit = nullptr) const;
|
||||
void Apply(const MaterialPipeline::Instance& instance, UInt8 textureUnit = 0, UInt8* lastUsedUnit = nullptr) const;
|
||||
|
||||
void BuildFromParameters(const ParameterList& matData, const MaterialParams& matParams = MaterialParams());
|
||||
|
||||
inline void Enable(RendererParameter renderParameter, bool enable);
|
||||
inline void Configure(const MaterialPipeline* pipeline);
|
||||
inline void Configure(const MaterialPipelineInfo& pipelineInfo);
|
||||
inline bool Configure(const String& pipelineName);
|
||||
|
||||
inline void EnableAlphaTest(bool alphaTest);
|
||||
inline void EnableBlending(bool blending);
|
||||
inline void EnableColorWrite(bool colorWrite);
|
||||
inline void EnableDepthBuffer(bool depthBuffer);
|
||||
inline void EnableDepthSorting(bool depthSorting);
|
||||
inline void EnableLighting(bool lighting);
|
||||
inline void EnableDepthWrite(bool depthWrite);
|
||||
inline void EnableFaceCulling(bool faceCulling);
|
||||
inline void EnableScissorTest(bool scissorTest);
|
||||
inline void EnableShadowCasting(bool castShadows);
|
||||
inline void EnableShadowReceive(bool receiveShadows);
|
||||
inline void EnableTransform(bool transform);
|
||||
inline void EnableStencilTest(bool stencilTest);
|
||||
|
||||
inline void EnsurePipelineUpdate() const;
|
||||
|
||||
inline const TextureRef& GetAlphaMap() const;
|
||||
inline float GetAlphaThreshold() const;
|
||||
|
|
@ -87,10 +100,12 @@ namespace Nz
|
|||
inline FaceSide GetFaceCulling() const;
|
||||
inline FaceFilling GetFaceFilling() const;
|
||||
inline const TextureRef& GetHeightMap() const;
|
||||
inline float GetLineWidth() const;
|
||||
inline const TextureRef& GetNormalMap() const;
|
||||
inline const RenderStates& GetRenderStates() const;
|
||||
inline const MaterialPipeline* GetPipeline() const;
|
||||
inline const MaterialPipelineInfo& GetPipelineInfo() const;
|
||||
inline float GetPointSize() const;
|
||||
inline const UberShader* GetShader() const;
|
||||
inline const UberShaderInstance* GetShaderInstance(UInt32 flags = ShaderFlags_None) const;
|
||||
inline float GetShininess() const;
|
||||
inline Color GetSpecularColor() const;
|
||||
inline const TextureRef& GetSpecularMap() const;
|
||||
|
|
@ -107,12 +122,16 @@ namespace Nz
|
|||
inline bool HasSpecularMap() const;
|
||||
|
||||
inline bool IsAlphaTestEnabled() const;
|
||||
inline bool IsBlendingEnabled() const;
|
||||
inline bool IsColorWriteEnabled() const;
|
||||
inline bool IsDepthBufferEnabled() const;
|
||||
inline bool IsDepthSortingEnabled() const;
|
||||
inline bool IsEnabled(RendererParameter renderParameter) const;
|
||||
inline bool IsLightingEnabled() const;
|
||||
inline bool IsDepthWriteEnabled() const;
|
||||
inline bool IsFaceCullingEnabled() const;
|
||||
inline bool IsScissorTestEnabled() const;
|
||||
inline bool IsStencilTestEnabled() const;
|
||||
inline bool IsShadowCastingEnabled() const;
|
||||
inline bool IsShadowReceiveEnabled() const;
|
||||
inline bool IsTransformEnabled() const;
|
||||
|
||||
inline bool LoadFromFile(const String& filePath, const MaterialParams& params = MaterialParams());
|
||||
inline bool LoadFromMemory(const void* data, std::size_t size, const MaterialParams& params = MaterialParams());
|
||||
|
|
@ -139,9 +158,10 @@ namespace Nz
|
|||
inline void SetFaceFilling(FaceFilling filling);
|
||||
inline bool SetHeightMap(const String& textureName);
|
||||
inline void SetHeightMap(TextureRef textureName);
|
||||
inline void SetLineWidth(float lineWidth);
|
||||
inline bool SetNormalMap(const String& textureName);
|
||||
inline void SetNormalMap(TextureRef textureName);
|
||||
inline void SetRenderStates(const RenderStates& states);
|
||||
inline void SetPointSize(float pointSize);
|
||||
inline void SetShader(UberShaderConstRef uberShader);
|
||||
inline bool SetShader(const String& uberShaderName);
|
||||
inline void SetShininess(float shininess);
|
||||
|
|
@ -161,16 +181,9 @@ namespace Nz
|
|||
NazaraSignal(OnMaterialReset, const Material* /*material*/);
|
||||
|
||||
private:
|
||||
struct ShaderInstance
|
||||
{
|
||||
const Shader* shader;
|
||||
UberShaderInstance* uberInstance = nullptr;
|
||||
int uniforms[MaterialUniform_Max + 1];
|
||||
};
|
||||
|
||||
void Copy(const Material& material);
|
||||
void GenerateShader(UInt32 flags) const;
|
||||
inline void InvalidateShaders();
|
||||
inline void InvalidatePipeline();
|
||||
inline void UpdatePipeline() const;
|
||||
|
||||
static bool Initialize();
|
||||
static void Uninitialize();
|
||||
|
|
@ -179,7 +192,8 @@ namespace Nz
|
|||
Color m_diffuseColor;
|
||||
Color m_specularColor;
|
||||
MaterialRef m_depthMaterial; //< Materialception
|
||||
RenderStates m_states;
|
||||
mutable const MaterialPipeline* m_pipeline;
|
||||
MaterialPipelineInfo m_pipelineInfo;
|
||||
TextureSampler m_diffuseSampler;
|
||||
TextureSampler m_specularSampler;
|
||||
TextureRef m_alphaMap;
|
||||
|
|
@ -188,14 +202,8 @@ namespace Nz
|
|||
TextureRef m_heightMap;
|
||||
TextureRef m_normalMap;
|
||||
TextureRef m_specularMap;
|
||||
UberShaderConstRef m_uberShader;
|
||||
mutable ShaderInstance m_shaders[ShaderFlags_Max + 1];
|
||||
bool m_alphaTestEnabled;
|
||||
bool m_depthSortingEnabled;
|
||||
bool m_lightingEnabled;
|
||||
mutable bool m_pipelineUpdated;
|
||||
bool m_shadowCastingEnabled;
|
||||
bool m_shadowReceiveEnabled;
|
||||
bool m_transformEnabled;
|
||||
float m_alphaThreshold;
|
||||
float m_shininess;
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,95 @@
|
|||
// Copyright (C) 2016 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Graphics module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_MATERIALPIPELINE_HPP
|
||||
#define NAZARA_MATERIALPIPELINE_HPP
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <Nazara/Graphics/Config.hpp>
|
||||
#include <Nazara/Graphics/Enums.hpp>
|
||||
#include <Nazara/Renderer/Enums.hpp>
|
||||
#include <Nazara/Renderer/RenderPipeline.hpp>
|
||||
#include <Nazara/Renderer/UberShader.hpp>
|
||||
#include <Nazara/Utility/Enums.hpp>
|
||||
#include <array>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
struct MaterialPipelineInfo : RenderStates
|
||||
{
|
||||
bool alphaTest = false;
|
||||
bool depthSorting = false;
|
||||
bool hasAlphaMap = false;
|
||||
bool hasDiffuseMap = false;
|
||||
bool hasEmissiveMap = false;
|
||||
bool hasHeightMap = false;
|
||||
bool hasNormalMap = false;
|
||||
bool hasSpecularMap = false;
|
||||
bool shadowReceive = true;
|
||||
|
||||
UberShaderConstRef uberShader;
|
||||
};
|
||||
|
||||
inline bool operator==(const MaterialPipelineInfo& lhs, const MaterialPipelineInfo& rhs);
|
||||
inline bool operator!=(const MaterialPipelineInfo& lhs, const MaterialPipelineInfo& rhs);
|
||||
|
||||
class MaterialPipeline;
|
||||
|
||||
using MaterialPipelineConstRef = ObjectRef<const MaterialPipeline>;
|
||||
using MaterialPipelineLibrary = ObjectLibrary<MaterialPipeline>;
|
||||
using MaterialPipelineRef = ObjectRef<MaterialPipeline>;
|
||||
|
||||
class NAZARA_GRAPHICS_API MaterialPipeline : public RefCounted
|
||||
{
|
||||
friend class Graphics;
|
||||
friend MaterialPipelineLibrary;
|
||||
|
||||
public:
|
||||
struct Instance;
|
||||
|
||||
MaterialPipeline(const MaterialPipeline&) = delete;
|
||||
MaterialPipeline(MaterialPipeline&&) = delete;
|
||||
~MaterialPipeline() = default;
|
||||
|
||||
inline const Instance& Apply(UInt32 flags = ShaderFlags_None) const;
|
||||
|
||||
MaterialPipeline& operator=(const MaterialPipeline&) = delete;
|
||||
MaterialPipeline& operator=(MaterialPipeline&&) = delete;
|
||||
|
||||
inline const MaterialPipelineInfo& GetInfo() const;
|
||||
inline const Instance& GetInstance(UInt32 flags = ShaderFlags_None) const;
|
||||
|
||||
static MaterialPipelineRef GetPipeline(const MaterialPipelineInfo& pipelineInfo);
|
||||
|
||||
struct Instance
|
||||
{
|
||||
RenderPipeline renderPipeline;
|
||||
UberShaderInstance* uberInstance = nullptr;
|
||||
std::array<int, MaterialUniform_Max + 1> uniforms;
|
||||
};
|
||||
|
||||
private:
|
||||
inline MaterialPipeline(const MaterialPipelineInfo& pipelineInfo);
|
||||
|
||||
void GenerateRenderPipeline(UInt32 flags) const;
|
||||
|
||||
static bool Initialize();
|
||||
template<typename... Args> static MaterialPipelineRef New(Args&&... args);
|
||||
static void Uninitialize();
|
||||
|
||||
MaterialPipelineInfo m_pipelineInfo;
|
||||
mutable std::array<Instance, ShaderFlags_Max + 1> m_instances;
|
||||
|
||||
using PipelineCache = std::unordered_map<MaterialPipelineInfo, MaterialPipelineRef>;
|
||||
static PipelineCache s_pipelineCache;
|
||||
|
||||
static MaterialPipelineLibrary::LibraryMap s_library;
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/Graphics/MaterialPipeline.inl>
|
||||
|
||||
#endif // NAZARA_MATERIALPIPELINE_HPP
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
// Copyright (C) 2016 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Graphics module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Graphics/MaterialPipeline.hpp>
|
||||
#include <Nazara/Core/Algorithm.hpp>
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
#include <functional>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
inline MaterialPipeline::MaterialPipeline(const MaterialPipelineInfo& pipelineInfo) :
|
||||
m_pipelineInfo(pipelineInfo)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Enable pipeline states for rendering
|
||||
*
|
||||
* \param flags Shader flags
|
||||
*/
|
||||
inline const MaterialPipeline::Instance& MaterialPipeline::Apply(UInt32 flags) const
|
||||
{
|
||||
const Instance& instance = GetInstance(flags);
|
||||
instance.uberInstance->Activate();
|
||||
|
||||
Renderer::SetRenderStates(m_pipelineInfo);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Retrieve a MaterialPipelineInfo object describing this pipeline
|
||||
*
|
||||
* \return Pipeline informations
|
||||
*/
|
||||
const MaterialPipelineInfo& MaterialPipeline::GetInfo() const
|
||||
{
|
||||
return m_pipelineInfo;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Retrieve (and generate if required) a pipeline instance using shader flags without applying it
|
||||
*
|
||||
* \param flags Shader flags
|
||||
*
|
||||
* \return Pipeline instance
|
||||
*/
|
||||
inline const MaterialPipeline::Instance& MaterialPipeline::GetInstance(UInt32 flags) const
|
||||
{
|
||||
const Instance& instance = m_instances[flags];
|
||||
if (!instance.uberInstance)
|
||||
GenerateRenderPipeline(flags);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
bool operator==(const MaterialPipelineInfo& lhs, const MaterialPipelineInfo& rhs)
|
||||
{
|
||||
if (!operator==(static_cast<const RenderStates&>(lhs), static_cast<const RenderStates&>(rhs)))
|
||||
return false;
|
||||
|
||||
#define NazaraPipelineMember(field) if (lhs.##field != rhs.##field) return false
|
||||
#define NazaraPipelineBoolMember NazaraPipelineMember
|
||||
|
||||
NazaraPipelineBoolMember(alphaTest);
|
||||
NazaraPipelineBoolMember(depthSorting);
|
||||
NazaraPipelineBoolMember(hasAlphaMap);
|
||||
NazaraPipelineBoolMember(hasDiffuseMap);
|
||||
NazaraPipelineBoolMember(hasEmissiveMap);
|
||||
NazaraPipelineBoolMember(hasHeightMap);
|
||||
NazaraPipelineBoolMember(hasNormalMap);
|
||||
NazaraPipelineBoolMember(hasSpecularMap);
|
||||
NazaraPipelineBoolMember(shadowReceive);
|
||||
|
||||
NazaraPipelineMember(uberShader);
|
||||
|
||||
#undef NazaraPipelineMember
|
||||
#undef NazaraPipelineBoolMember
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator!=(const MaterialPipelineInfo& lhs, const MaterialPipelineInfo& rhs)
|
||||
{
|
||||
return !operator==(lhs, rhs);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Creates a new MaterialPipeline from the arguments
|
||||
* \return A reference to the newly created material pipeline
|
||||
*
|
||||
* \param args Arguments for the material pipeline
|
||||
*/
|
||||
template<typename... Args>
|
||||
MaterialPipelineRef MaterialPipeline::New(Args&&... args)
|
||||
{
|
||||
std::unique_ptr<MaterialPipeline> object(new MaterialPipeline(std::forward<Args>(args)...));
|
||||
return object.release();
|
||||
}
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<>
|
||||
struct hash<Nz::MaterialPipelineInfo>
|
||||
{
|
||||
size_t operator()(const Nz::MaterialPipelineInfo& pipelineInfo) const
|
||||
{
|
||||
hash<Nz::RenderStates> parentHash;
|
||||
|
||||
std::size_t seed = parentHash(pipelineInfo);
|
||||
|
||||
Nz::UInt16 parameterHash = 0;
|
||||
Nz::UInt16 parameterIndex = 0;
|
||||
|
||||
#define NazaraPipelineMember(member) Nz::HashCombine(seed, pipelineInfo.##member)
|
||||
#define NazaraPipelineBoolMember(member) parameterHash |= ((pipelineInfo.##member) ? 1U : 0U) << (parameterIndex++)
|
||||
|
||||
NazaraPipelineBoolMember(alphaTest);
|
||||
NazaraPipelineBoolMember(depthSorting);
|
||||
NazaraPipelineBoolMember(hasAlphaMap);
|
||||
NazaraPipelineBoolMember(hasDiffuseMap);
|
||||
NazaraPipelineBoolMember(hasEmissiveMap);
|
||||
NazaraPipelineBoolMember(hasHeightMap);
|
||||
NazaraPipelineBoolMember(hasNormalMap);
|
||||
NazaraPipelineBoolMember(hasSpecularMap);
|
||||
NazaraPipelineBoolMember(shadowReceive);
|
||||
|
||||
NazaraPipelineMember(uberShader);
|
||||
|
||||
#undef NazaraPipelineMember
|
||||
#undef NazaraPipelineBoolMember
|
||||
|
||||
Nz::HashCombine(seed, parameterHash);
|
||||
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/Graphics/DebugOff.hpp>
|
||||
|
|
@ -123,8 +123,7 @@ namespace Nz
|
|||
inline void Sprite::SetDefaultMaterial()
|
||||
{
|
||||
MaterialRef material = Material::New();
|
||||
material->Enable(RendererParameter_FaceCulling, false);
|
||||
material->EnableLighting(false);
|
||||
material->EnableFaceCulling(false);
|
||||
|
||||
SetMaterial(std::move(material));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,10 +119,9 @@ namespace Nz
|
|||
inline void TextSprite::SetDefaultMaterial()
|
||||
{
|
||||
MaterialRef material = Material::New();
|
||||
material->Enable(RendererParameter_Blend, true);
|
||||
material->Enable(RendererParameter_DepthWrite, false);
|
||||
material->Enable(RendererParameter_FaceCulling, false);
|
||||
material->EnableLighting(false);
|
||||
material->EnableBlending(true);
|
||||
material->EnableDepthWrite(false);
|
||||
material->EnableFaceCulling(false);
|
||||
material->SetDstBlend(BlendFunc_InvSrcAlpha);
|
||||
material->SetSrcBlend(BlendFunc_SrcAlpha);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright (C) 2016 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_RENDERPIPELINE_HPP
|
||||
#define NAZARA_RENDERPIPELINE_HPP
|
||||
|
||||
#include <Nazara/Utility/Enums.hpp>
|
||||
#include <Nazara/Renderer/RenderStates.hpp>
|
||||
#include <Nazara/Renderer/Shader.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
struct RenderPipelineInfo : RenderStates
|
||||
{
|
||||
ShaderConstRef shader;
|
||||
};
|
||||
|
||||
class RenderPipeline
|
||||
{
|
||||
public:
|
||||
inline RenderPipeline();
|
||||
inline ~RenderPipeline();
|
||||
|
||||
inline bool Create(const RenderPipelineInfo& pipelineInfo);
|
||||
inline void Destroy();
|
||||
|
||||
inline const RenderPipelineInfo& GetInfo() const;
|
||||
|
||||
inline bool IsValid() const;
|
||||
|
||||
private:
|
||||
RenderPipelineInfo m_pipelineInfo;
|
||||
bool m_valid;
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/Renderer/RenderPipeline.inl>
|
||||
|
||||
#endif // NAZARA_RENDERPIPELINE_HPP
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
// Copyright (C) 2016 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/RenderPipeline.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
inline RenderPipeline::RenderPipeline() :
|
||||
m_valid(false)
|
||||
{
|
||||
}
|
||||
|
||||
inline RenderPipeline::~RenderPipeline()
|
||||
{
|
||||
}
|
||||
|
||||
inline bool RenderPipeline::Create(const RenderPipelineInfo& pipelineInfo)
|
||||
{
|
||||
NazaraAssert(pipelineInfo.shader, "Invalid shader");
|
||||
|
||||
m_pipelineInfo = pipelineInfo;
|
||||
m_valid = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void RenderPipeline::Destroy()
|
||||
{
|
||||
m_valid = false;
|
||||
}
|
||||
|
||||
inline const RenderPipelineInfo& RenderPipeline::GetInfo() const
|
||||
{
|
||||
NazaraAssert(m_valid, "Invalid pipeline info");
|
||||
|
||||
return m_pipelineInfo;
|
||||
}
|
||||
|
||||
inline bool RenderPipeline::IsValid() const
|
||||
{
|
||||
return m_valid;
|
||||
}
|
||||
}
|
||||
|
||||
#include <Nazara/Renderer/DebugOff.hpp>
|
||||
|
|
@ -7,8 +7,8 @@
|
|||
#ifndef NAZARA_RENDERSTATES_HPP
|
||||
#define NAZARA_RENDERSTATES_HPP
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <Nazara/Utility/Enums.hpp>
|
||||
#include <Nazara/Renderer/Shader.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
|
|
@ -74,10 +74,7 @@ namespace Nz
|
|||
float pointSize = 1.f;
|
||||
};
|
||||
|
||||
struct RenderPipeline : RenderStates
|
||||
{
|
||||
ShaderConstRef shader;
|
||||
};
|
||||
inline bool operator==(const RenderStates& lhs, const RenderStates& rhs);
|
||||
}
|
||||
|
||||
#include <Nazara/Renderer/RenderStates.inl>
|
||||
|
|
|
|||
|
|
@ -3,11 +3,143 @@
|
|||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/RenderStates.hpp>
|
||||
#include <cstring>
|
||||
#include <Nazara/Core/Algorithm.hpp>
|
||||
#include <Nazara/Math/Algorithm.hpp>
|
||||
#include <functional>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
bool operator==(const RenderStates& lhs, const RenderStates& rhs)
|
||||
{
|
||||
#define NazaraRenderStateMember(field) if (lhs.##field != rhs.##field) return false
|
||||
#define NazaraRenderStateBoolMember NazaraRenderStateMember
|
||||
#define NazaraRenderStateFloatMember(field, maxDiff) if (!NumberEquals(lhs.##field, rhs.##field, maxDiff)) return false
|
||||
|
||||
NazaraRenderStateBoolMember(blending);
|
||||
NazaraRenderStateBoolMember(colorWrite);
|
||||
NazaraRenderStateBoolMember(depthBuffer);
|
||||
NazaraRenderStateBoolMember(faceCulling);
|
||||
NazaraRenderStateBoolMember(scissorTest);
|
||||
NazaraRenderStateBoolMember(stencilTest);
|
||||
|
||||
if (lhs.depthBuffer)
|
||||
NazaraRenderStateBoolMember(depthWrite);
|
||||
|
||||
NazaraRenderStateMember(faceFilling);
|
||||
|
||||
if (lhs.blending) //< Remember, at this time we know lhs.blending == rhs.blending
|
||||
{
|
||||
NazaraRenderStateMember(dstBlend);
|
||||
NazaraRenderStateMember(srcBlend);
|
||||
}
|
||||
|
||||
if (lhs.depthBuffer)
|
||||
NazaraRenderStateMember(depthFunc);
|
||||
|
||||
if (lhs.faceCulling)
|
||||
NazaraRenderStateMember(cullingSide);
|
||||
|
||||
if (lhs.stencilTest)
|
||||
{
|
||||
NazaraRenderStateMember(stencilCompare.back);
|
||||
NazaraRenderStateMember(stencilCompare.front);
|
||||
NazaraRenderStateMember(stencilCompareMask.back);
|
||||
NazaraRenderStateMember(stencilCompareMask.front);
|
||||
NazaraRenderStateMember(stencilDepthFail.back);
|
||||
NazaraRenderStateMember(stencilDepthFail.front);
|
||||
NazaraRenderStateMember(stencilFail.back);
|
||||
NazaraRenderStateMember(stencilFail.front);
|
||||
NazaraRenderStateMember(stencilPass.back);
|
||||
NazaraRenderStateMember(stencilPass.front);
|
||||
NazaraRenderStateMember(stencilReference.back);
|
||||
NazaraRenderStateMember(stencilReference.front);
|
||||
NazaraRenderStateMember(stencilWriteMask.back);
|
||||
NazaraRenderStateMember(stencilWriteMask.front);
|
||||
}
|
||||
|
||||
NazaraRenderStateFloatMember(lineWidth, 0.001f);
|
||||
NazaraRenderStateFloatMember(pointSize, 0.001f);
|
||||
|
||||
#undef NazaraRenderStateMember
|
||||
#undef NazaraRenderStateBoolMember
|
||||
#undef NazaraRenderStateFloatMember
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<>
|
||||
struct hash<Nz::RenderStates>
|
||||
{
|
||||
size_t operator()(const Nz::RenderStates& pipelineInfo) const
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
|
||||
Nz::UInt8 parameterHash = 0;
|
||||
Nz::UInt8 parameterIndex = 0;
|
||||
|
||||
#define NazaraRenderStateMember(member) Nz::HashCombine(seed, pipelineInfo.##member)
|
||||
#define NazaraRenderStateBoolMember(member) parameterHash |= ((pipelineInfo.##member) ? 1U : 0U) << (parameterIndex++)
|
||||
#define NazaraRenderStateBoolMemberDep(dependency, member) parameterHash |= ((pipelineInfo.##dependency && pipelineInfo.##member) ? 1U : 0U) << (parameterIndex++)
|
||||
#define NazaraRenderStateFloatMember(member, maxDiff) Nz::HashCombine(seed, std::floor(pipelineInfo.##member / maxDiff) * maxDiff)
|
||||
|
||||
NazaraRenderStateBoolMember(blending);
|
||||
NazaraRenderStateBoolMember(colorWrite);
|
||||
NazaraRenderStateBoolMember(depthBuffer);
|
||||
NazaraRenderStateBoolMember(faceCulling);
|
||||
NazaraRenderStateBoolMember(scissorTest);
|
||||
NazaraRenderStateBoolMember(stencilTest);
|
||||
|
||||
NazaraRenderStateBoolMemberDep(depthBuffer, depthWrite);
|
||||
|
||||
NazaraRenderStateMember(faceFilling);
|
||||
|
||||
if (pipelineInfo.blending) //< Remember, at this time we know lhs.blending == rhs.blending
|
||||
{
|
||||
NazaraRenderStateMember(dstBlend);
|
||||
NazaraRenderStateMember(srcBlend);
|
||||
}
|
||||
|
||||
if (pipelineInfo.depthBuffer)
|
||||
NazaraRenderStateMember(depthFunc);
|
||||
|
||||
if (pipelineInfo.faceCulling)
|
||||
NazaraRenderStateMember(cullingSide);
|
||||
|
||||
if (pipelineInfo.stencilTest)
|
||||
{
|
||||
NazaraRenderStateMember(stencilCompare.back);
|
||||
NazaraRenderStateMember(stencilCompare.front);
|
||||
NazaraRenderStateMember(stencilCompareMask.back);
|
||||
NazaraRenderStateMember(stencilCompareMask.front);
|
||||
NazaraRenderStateMember(stencilDepthFail.back);
|
||||
NazaraRenderStateMember(stencilDepthFail.front);
|
||||
NazaraRenderStateMember(stencilFail.back);
|
||||
NazaraRenderStateMember(stencilFail.front);
|
||||
NazaraRenderStateMember(stencilPass.back);
|
||||
NazaraRenderStateMember(stencilPass.front);
|
||||
NazaraRenderStateMember(stencilReference.back);
|
||||
NazaraRenderStateMember(stencilReference.front);
|
||||
NazaraRenderStateMember(stencilWriteMask.back);
|
||||
NazaraRenderStateMember(stencilWriteMask.front);
|
||||
}
|
||||
|
||||
NazaraRenderStateFloatMember(lineWidth, 0.001f);
|
||||
NazaraRenderStateFloatMember(pointSize, 0.001f);
|
||||
|
||||
#undef NazaraRenderStateMember
|
||||
#undef NazaraRenderStateBoolMember
|
||||
#undef NazaraRenderStateBoolMemberDep
|
||||
#undef NazaraRenderStateFloatMember
|
||||
|
||||
Nz::HashCombine(seed, parameterHash);
|
||||
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/Renderer/DebugOff.hpp>
|
||||
|
|
|
|||
|
|
@ -73,13 +73,43 @@ namespace Nz
|
|||
const Shader* lastShader = nullptr;
|
||||
const ShaderUniforms* shaderUniforms = nullptr;
|
||||
|
||||
for (auto& pair : m_renderQueue->layers)
|
||||
for (auto& layerPair : m_renderQueue->layers)
|
||||
{
|
||||
DeferredRenderQueue::Layer& layer = pair.second;
|
||||
for (auto& pipelinePair : layerPair.second.opaqueModels)
|
||||
{
|
||||
const MaterialPipeline* pipeline = pipelinePair.first;
|
||||
auto& pipelineEntry = pipelinePair.second;
|
||||
|
||||
for (auto& matIt : layer.opaqueModels)
|
||||
if (pipelineEntry.maxInstanceCount > 0)
|
||||
{
|
||||
auto& matEntry = matIt.second;
|
||||
bool instancing = (pipelineEntry.maxInstanceCount > NAZARA_GRAPHICS_INSTANCING_MIN_INSTANCES_COUNT);
|
||||
|
||||
UInt32 flags = ShaderFlags_Deferred;
|
||||
if (instancing)
|
||||
flags |= ShaderFlags_Instancing;
|
||||
|
||||
const MaterialPipeline::Instance& pipelineInstance = pipeline->Apply(flags);
|
||||
|
||||
const Shader* shader = pipelineInstance.uberInstance->GetShader();
|
||||
|
||||
// Uniforms are conserved in our program, there's no point to send them back until they change
|
||||
if (shader != lastShader)
|
||||
{
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// Ambiant color of the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
||||
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
for (auto& materialPair : pipelineEntry.materialMap)
|
||||
{
|
||||
const Material* material = materialPair.first;
|
||||
auto& matEntry = materialPair.second;
|
||||
|
||||
if (matEntry.enabled)
|
||||
{
|
||||
|
|
@ -87,30 +117,7 @@ namespace Nz
|
|||
|
||||
if (!meshInstances.empty())
|
||||
{
|
||||
const Material* material = matIt.first;
|
||||
|
||||
bool useInstancing = instancingEnabled && matEntry.instancingEnabled;
|
||||
|
||||
// We begin by getting the program for materials
|
||||
UInt32 flags = ShaderFlags_Deferred;
|
||||
if (useInstancing)
|
||||
flags |= ShaderFlags_Instancing;
|
||||
|
||||
const Shader* shader = material->Apply(flags);
|
||||
|
||||
// The uniforms are conserved in our program, there's no point to send them back if they don't change
|
||||
if (shader != lastShader)
|
||||
{
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// Ambient color for the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
||||
|
||||
lastShader = shader;
|
||||
}
|
||||
material->Apply(pipelineInstance);
|
||||
|
||||
// Meshes
|
||||
for (auto& meshIt : meshInstances)
|
||||
|
|
@ -145,7 +152,7 @@ namespace Nz
|
|||
Renderer::SetIndexBuffer(indexBuffer);
|
||||
Renderer::SetVertexBuffer(vertexBuffer);
|
||||
|
||||
if (useInstancing)
|
||||
if (instancing)
|
||||
{
|
||||
// We get the buffer for instance of Renderer and we configure it to work with matrices
|
||||
VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer();
|
||||
|
|
@ -186,9 +193,12 @@ namespace Nz
|
|||
}
|
||||
}
|
||||
|
||||
// Abd we set it back data to zero
|
||||
// And we set it back data to zero
|
||||
matEntry.enabled = false;
|
||||
matEntry.instancingEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
pipelineEntry.maxInstanceCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -191,27 +191,39 @@ namespace Nz
|
|||
|
||||
void DeferredRenderQueue::AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix)
|
||||
{
|
||||
if (material->IsEnabled(RendererParameter_Blend))
|
||||
if (material->IsBlendingEnabled())
|
||||
// One transparent material ? I don't like it, go see if I'm in the forward queue
|
||||
m_forwardQueue->AddMesh(renderOrder, material, meshData, meshAABB, transformMatrix);
|
||||
else
|
||||
{
|
||||
Layer& currentLayer = GetLayer(renderOrder);
|
||||
auto& opaqueModels = currentLayer.opaqueModels;
|
||||
MeshPipelineBatches& opaqueModels = currentLayer.opaqueModels;
|
||||
|
||||
auto it = opaqueModels.find(material);
|
||||
if (it == opaqueModels.end())
|
||||
const MaterialPipeline* materialPipeline = material->GetPipeline();
|
||||
|
||||
auto pipelineIt = opaqueModels.find(materialPipeline);
|
||||
if (pipelineIt == opaqueModels.end())
|
||||
{
|
||||
BatchedMaterialEntry materialEntry;
|
||||
pipelineIt = opaqueModels.insert(MeshPipelineBatches::value_type(materialPipeline, std::move(materialEntry))).first;
|
||||
}
|
||||
|
||||
BatchedMaterialEntry& materialEntry = pipelineIt->second;
|
||||
MeshMaterialBatches& materialMap = materialEntry.materialMap;
|
||||
|
||||
auto materialIt = materialMap.find(material);
|
||||
if (materialIt == materialMap.end())
|
||||
{
|
||||
BatchedModelEntry entry;
|
||||
entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &DeferredRenderQueue::OnMaterialInvalidation);
|
||||
|
||||
it = opaqueModels.insert(std::make_pair(material, std::move(entry))).first;
|
||||
materialIt = materialMap.insert(MeshMaterialBatches::value_type(material, std::move(entry))).first;
|
||||
}
|
||||
|
||||
BatchedModelEntry& entry = it->second;
|
||||
BatchedModelEntry& entry = materialIt->second;
|
||||
entry.enabled = true;
|
||||
|
||||
auto& meshMap = entry.meshMap;
|
||||
MeshInstanceContainer& meshMap = entry.meshMap;
|
||||
|
||||
auto it2 = meshMap.find(meshData);
|
||||
if (it2 == meshMap.end())
|
||||
|
|
@ -225,13 +237,8 @@ namespace Nz
|
|||
it2 = meshMap.insert(std::make_pair(meshData, std::move(instanceEntry))).first;
|
||||
}
|
||||
|
||||
// We add matrices to the list of instances of this object
|
||||
std::vector<Matrix4f>& instances = it2->second.instances;
|
||||
instances.push_back(transformMatrix);
|
||||
|
||||
// Do we have enough instances to perform instancing ?
|
||||
if (instances.size() >= NAZARA_GRAPHICS_INSTANCING_MIN_INSTANCES_COUNT)
|
||||
entry.instancingEnabled = true; // Thus we can activate it
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -306,9 +313,11 @@ namespace Nz
|
|||
{
|
||||
Layer& layer = pair.second;
|
||||
|
||||
for (auto& modelPair : layer.opaqueModels)
|
||||
for (auto& pipelineEntry : layer.opaqueModels)
|
||||
{
|
||||
MeshInstanceContainer& meshes = modelPair.second.meshMap;
|
||||
for (auto& materialEntry : pipelineEntry.second.materialMap)
|
||||
{
|
||||
MeshInstanceContainer& meshes = materialEntry.second.meshMap;
|
||||
for (auto it = meshes.begin(); it != meshes.end();)
|
||||
{
|
||||
const MeshData& renderData = it->first;
|
||||
|
|
@ -320,6 +329,7 @@ namespace Nz
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Handle the invalidation of a material
|
||||
|
|
@ -333,7 +343,8 @@ namespace Nz
|
|||
{
|
||||
Layer& layer = pair.second;
|
||||
|
||||
layer.opaqueModels.erase(material);
|
||||
for (auto& pipelineEntry : layer.opaqueModels)
|
||||
pipelineEntry.second.materialMap.erase(material);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -348,10 +359,11 @@ namespace Nz
|
|||
for (auto& pair : layers)
|
||||
{
|
||||
Layer& layer = pair.second;
|
||||
|
||||
for (auto& modelPair : layer.opaqueModels)
|
||||
for (auto& pipelineEntry : layer.opaqueModels)
|
||||
{
|
||||
MeshInstanceContainer& meshes = modelPair.second.meshMap;
|
||||
for (auto& materialEntry : pipelineEntry.second.materialMap)
|
||||
{
|
||||
MeshInstanceContainer& meshes = materialEntry.second.meshMap;
|
||||
for (auto it = meshes.begin(); it != meshes.end();)
|
||||
{
|
||||
const MeshData& renderData = it->first;
|
||||
|
|
@ -363,58 +375,5 @@ namespace Nz
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Functor to compare two batched model with material
|
||||
* \return true If first material is "smaller" than the second one
|
||||
*
|
||||
* \param mat1 First material to compare
|
||||
* \param mat2 Second material to compare
|
||||
*/
|
||||
|
||||
bool DeferredRenderQueue::BatchedModelMaterialComparator::operator()(const Material* mat1, const Material* mat2) const
|
||||
{
|
||||
const UberShader* uberShader1 = mat1->GetShader();
|
||||
const UberShader* uberShader2 = mat2->GetShader();
|
||||
if (uberShader1 != uberShader2)
|
||||
return uberShader1 < uberShader2;
|
||||
|
||||
const Shader* shader1 = mat1->GetShaderInstance(ShaderFlags_Deferred)->GetShader();
|
||||
const Shader* shader2 = mat2->GetShaderInstance(ShaderFlags_Deferred)->GetShader();
|
||||
if (shader1 != shader2)
|
||||
return shader1 < shader2;
|
||||
|
||||
const Texture* diffuseMap1 = mat1->GetDiffuseMap();
|
||||
const Texture* diffuseMap2 = mat2->GetDiffuseMap();
|
||||
if (diffuseMap1 != diffuseMap2)
|
||||
return diffuseMap1 < diffuseMap2;
|
||||
|
||||
return mat1 < mat2;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Functor to compare two mesh data
|
||||
* \return true If first mesh is "smaller" than the second one
|
||||
*
|
||||
* \param data1 First mesh to compare
|
||||
* \param data2 Second mesh to compare
|
||||
*/
|
||||
|
||||
bool DeferredRenderQueue::MeshDataComparator::operator()(const MeshData& data1, const MeshData& data2) const
|
||||
{
|
||||
const Buffer* buffer1;
|
||||
const Buffer* buffer2;
|
||||
|
||||
buffer1 = (data1.indexBuffer) ? data1.indexBuffer->GetBuffer() : nullptr;
|
||||
buffer2 = (data2.indexBuffer) ? data2.indexBuffer->GetBuffer() : nullptr;
|
||||
if (buffer1 != buffer2)
|
||||
return buffer1 < buffer2;
|
||||
|
||||
buffer1 = data1.vertexBuffer->GetBuffer();
|
||||
buffer2 = data2.vertexBuffer->GetBuffer();
|
||||
if (buffer1 != buffer2)
|
||||
return buffer1 < buffer2;
|
||||
|
||||
return data1.primitiveMode < data2.primitiveMode;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ namespace Nz
|
|||
{
|
||||
// Material
|
||||
m_baseMaterial = Material::New();
|
||||
m_baseMaterial->Enable(RendererParameter_ColorWrite, false);
|
||||
m_baseMaterial->Enable(RendererParameter_FaceCulling, false);
|
||||
m_baseMaterial->EnableColorWrite(false);
|
||||
m_baseMaterial->EnableFaceCulling(false);
|
||||
//m_baseMaterial->SetFaceCulling(FaceSide_Front);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,6 +52,10 @@ namespace Nz
|
|||
{
|
||||
ErrorFlags flags(ErrorFlag_ThrowException, true);
|
||||
|
||||
std::array<UInt8, 4> whitePixel = {255, 255, 255, 255};
|
||||
m_whiteTexture.Create(ImageType_2D, PixelFormatType_RGBA8, 1, 1);
|
||||
m_whiteTexture.Update(whitePixel.data());
|
||||
|
||||
m_vertexBuffer.Create(s_vertexBufferSize, DataStorage_Hardware, BufferUsage_Dynamic);
|
||||
|
||||
m_billboardPointBuffer.Reset(&s_billboardVertexDeclaration, &m_vertexBuffer);
|
||||
|
|
@ -208,6 +212,8 @@ namespace Nz
|
|||
|
||||
void DepthRenderTechnique::DrawBasicSprites(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const
|
||||
{
|
||||
NazaraAssert(sceneData.viewer, "Invalid viewer");
|
||||
|
||||
const Shader* lastShader = nullptr;
|
||||
const ShaderUniforms* shaderUniforms = nullptr;
|
||||
|
||||
|
|
@ -215,13 +221,46 @@ namespace Nz
|
|||
Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity());
|
||||
Renderer::SetVertexBuffer(&m_spriteBuffer);
|
||||
|
||||
for (auto& matIt : layer.basicSprites)
|
||||
for (auto& pipelinePair : layer.basicSprites)
|
||||
{
|
||||
const Material* material = matIt.first;
|
||||
auto& matEntry = matIt.second;
|
||||
const MaterialPipeline* pipeline = pipelinePair.first;
|
||||
auto& pipelineEntry = pipelinePair.second;
|
||||
|
||||
if (pipelineEntry.enabled)
|
||||
{
|
||||
const MaterialPipeline::Instance& pipelineInstance = pipeline->Apply(ShaderFlags_TextureOverlay | ShaderFlags_VertexColor);
|
||||
|
||||
const Shader* shader = pipelineInstance.uberInstance->GetShader();
|
||||
|
||||
// Uniforms are conserved in our program, there's no point to send them back until they change
|
||||
if (shader != lastShader)
|
||||
{
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// Ambiant color of the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
||||
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
for (auto& materialPair : pipelineEntry.materialMap)
|
||||
{
|
||||
const Material* material = materialPair.first;
|
||||
auto& matEntry = materialPair.second;
|
||||
|
||||
if (matEntry.enabled)
|
||||
{
|
||||
UInt8 overlayUnit;
|
||||
material->Apply(pipelineInstance, 0, &overlayUnit);
|
||||
overlayUnit++;
|
||||
|
||||
shader->SendInteger(shaderUniforms->textureOverlay, overlayUnit);
|
||||
|
||||
Renderer::SetTextureSampler(overlayUnit, material->GetDiffuseSampler());
|
||||
|
||||
auto& overlayMap = matEntry.overlayMap;
|
||||
for (auto& overlayIt : overlayMap)
|
||||
{
|
||||
|
|
@ -231,34 +270,7 @@ namespace Nz
|
|||
unsigned int spriteChainCount = spriteChainVector.size();
|
||||
if (spriteChainCount > 0)
|
||||
{
|
||||
// We begin to apply the material (and get the shader activated doing so)
|
||||
UInt32 flags = 0;
|
||||
if (overlay)
|
||||
flags |= ShaderFlags_TextureOverlay;
|
||||
|
||||
UInt8 overlayUnit;
|
||||
const Shader* shader = material->Apply(flags, 0, &overlayUnit);
|
||||
|
||||
if (overlay)
|
||||
{
|
||||
overlayUnit++;
|
||||
Renderer::SetTexture(overlayUnit, overlay);
|
||||
Renderer::SetTextureSampler(overlayUnit, material->GetDiffuseSampler());
|
||||
}
|
||||
|
||||
// Uniforms are conserved in our program, there's no point to send them back until they change
|
||||
if (shader != lastShader)
|
||||
{
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// Overlay
|
||||
shader->SendInteger(shaderUniforms->textureOverlay, overlayUnit);
|
||||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, Renderer::GetMatrix(MatrixType_ViewProj).GetTranslation());
|
||||
|
||||
lastShader = shader;
|
||||
}
|
||||
Renderer::SetTexture(overlayUnit, (overlay) ? overlay : &m_whiteTexture);
|
||||
|
||||
unsigned int spriteChain = 0; // Which chain of sprites are we treating
|
||||
unsigned int spriteChainOffset = 0; // Where was the last offset where we stopped in the last chain
|
||||
|
|
@ -267,7 +279,7 @@ namespace Nz
|
|||
{
|
||||
// We open the buffer in writing mode
|
||||
BufferMapper<VertexBuffer> vertexMapper(m_spriteBuffer, BufferAccess_DiscardAndWrite);
|
||||
VertexStruct_XYZ_Color_UV* vertices = reinterpret_cast<VertexStruct_XYZ_Color_UV*>(vertexMapper.GetPointer());
|
||||
VertexStruct_XYZ_Color_UV* vertices = static_cast<VertexStruct_XYZ_Color_UV*>(vertexMapper.GetPointer());
|
||||
|
||||
unsigned int spriteCount = 0;
|
||||
unsigned int maxSpriteCount = std::min(s_maxQuads, m_spriteBuffer.GetVertexCount() / 4);
|
||||
|
|
@ -289,23 +301,24 @@ namespace Nz
|
|||
spriteChain++;
|
||||
spriteChainOffset = 0;
|
||||
}
|
||||
}
|
||||
while (spriteCount < maxSpriteCount && spriteChain < spriteChainCount);
|
||||
} while (spriteCount < maxSpriteCount && spriteChain < spriteChainCount);
|
||||
|
||||
vertexMapper.Unmap();
|
||||
|
||||
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, spriteCount * 6);
|
||||
}
|
||||
while (spriteChain < spriteChainCount);
|
||||
} while (spriteChain < spriteChainCount);
|
||||
|
||||
spriteChainVector.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// On remet à zéro
|
||||
// We set it back to zero
|
||||
matEntry.enabled = false;
|
||||
}
|
||||
}
|
||||
pipelineEntry.enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -317,6 +330,8 @@ namespace Nz
|
|||
|
||||
void DepthRenderTechnique::DrawBillboards(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const
|
||||
{
|
||||
NazaraAssert(sceneData.viewer, "Invalid viewer");
|
||||
|
||||
const Shader* lastShader = nullptr;
|
||||
const ShaderUniforms* shaderUniforms = nullptr;
|
||||
|
||||
|
|
@ -327,7 +342,32 @@ namespace Nz
|
|||
|
||||
Renderer::SetVertexBuffer(&s_quadVertexBuffer);
|
||||
|
||||
for (auto& matIt : layer.billboards)
|
||||
for (auto& pipelinePair : layer.billboards)
|
||||
{
|
||||
const MaterialPipeline* pipeline = pipelinePair.first;
|
||||
auto& pipelineEntry = pipelinePair.second;
|
||||
|
||||
if (pipelineEntry.enabled)
|
||||
{
|
||||
const MaterialPipeline::Instance& pipelineInstance = pipeline->Apply(ShaderFlags_Billboard | ShaderFlags_Instancing | ShaderFlags_VertexColor);
|
||||
|
||||
const Shader* shader = pipelineInstance.uberInstance->GetShader();
|
||||
|
||||
// Uniforms are conserved in our program, there's no point to send them back until they change
|
||||
if (shader != lastShader)
|
||||
{
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// Ambiant color of the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
||||
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
for (auto& matIt : pipelinePair.second.materialMap)
|
||||
{
|
||||
const Material* material = matIt.first;
|
||||
auto& entry = matIt.second;
|
||||
|
|
@ -337,19 +377,7 @@ namespace Nz
|
|||
if (billboardCount > 0)
|
||||
{
|
||||
// We begin to apply the material (and get the shader activated doing so)
|
||||
const Shader* shader = material->Apply(ShaderFlags_Billboard | ShaderFlags_Instancing | ShaderFlags_VertexColor);
|
||||
|
||||
// Uniforms are conserved in our program, there's no point to send them back until they change
|
||||
if (shader != lastShader)
|
||||
{
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, Renderer::GetMatrix(MatrixType_ViewProj).GetTranslation());
|
||||
|
||||
lastShader = shader;
|
||||
}
|
||||
material->Apply(pipelineInstance);
|
||||
|
||||
const ForwardRenderQueue::BillboardData* data = &billboardVector[0];
|
||||
unsigned int maxBillboardPerDraw = instanceBuffer->GetVertexCount();
|
||||
|
|
@ -369,22 +397,23 @@ namespace Nz
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Renderer::SetIndexBuffer(&s_quadIndexBuffer);
|
||||
Renderer::SetVertexBuffer(&m_billboardPointBuffer);
|
||||
|
||||
for (auto& matIt : layer.billboards)
|
||||
for (auto& pipelinePair : layer.billboards)
|
||||
{
|
||||
const Material* material = matIt.first;
|
||||
auto& entry = matIt.second;
|
||||
auto& billboardVector = entry.billboards;
|
||||
const MaterialPipeline* pipeline = pipelinePair.first;
|
||||
auto& pipelineEntry = pipelinePair.second;
|
||||
|
||||
unsigned int billboardCount = billboardVector.size();
|
||||
if (billboardCount > 0)
|
||||
if (pipelineEntry.enabled)
|
||||
{
|
||||
// We begin to apply the material (and get the shader activated doing so)
|
||||
const Shader* shader = material->Apply(ShaderFlags_Billboard | ShaderFlags_VertexColor);
|
||||
const MaterialPipeline::Instance& pipelineInstance = pipeline->Apply(ShaderFlags_Billboard | ShaderFlags_VertexColor);
|
||||
|
||||
const Shader* shader = pipelineInstance.uberInstance->GetShader();
|
||||
|
||||
// Uniforms are conserved in our program, there's no point to send them back until they change
|
||||
if (shader != lastShader)
|
||||
|
|
@ -392,22 +421,31 @@ namespace Nz
|
|||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// Ambiant color of the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, Renderer::GetMatrix(MatrixType_ViewProj).GetTranslation());
|
||||
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
||||
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
for (auto& matIt : pipelinePair.second.materialMap)
|
||||
{
|
||||
const Material* material = matIt.first;
|
||||
auto& entry = matIt.second;
|
||||
auto& billboardVector = entry.billboards;
|
||||
|
||||
const ForwardRenderQueue::BillboardData* data = &billboardVector[0];
|
||||
unsigned int maxBillboardPerDraw = std::min(s_maxQuads, m_billboardPointBuffer.GetVertexCount() / 4);
|
||||
|
||||
unsigned int billboardCount = billboardVector.size();
|
||||
do
|
||||
{
|
||||
unsigned int renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw);
|
||||
billboardCount -= renderedBillboardCount;
|
||||
|
||||
BufferMapper<VertexBuffer> vertexMapper(m_billboardPointBuffer, BufferAccess_DiscardAndWrite, 0, renderedBillboardCount * 4);
|
||||
BillboardPoint* vertices = reinterpret_cast<BillboardPoint*>(vertexMapper.GetPointer());
|
||||
BillboardPoint* vertices = static_cast<BillboardPoint*>(vertexMapper.GetPointer());
|
||||
|
||||
for (unsigned int i = 0; i < renderedBillboardCount; ++i)
|
||||
{
|
||||
|
|
@ -453,6 +491,7 @@ namespace Nz
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Draws opaques models
|
||||
|
|
@ -463,35 +502,49 @@ namespace Nz
|
|||
|
||||
void DepthRenderTechnique::DrawOpaqueModels(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const
|
||||
{
|
||||
NazaraAssert(sceneData.viewer, "Invalid viewer");
|
||||
|
||||
const Shader* lastShader = nullptr;
|
||||
const ShaderUniforms* shaderUniforms = nullptr;
|
||||
|
||||
for (auto& matIt : layer.opaqueModels)
|
||||
for (auto& pipelinePair : layer.opaqueModels)
|
||||
{
|
||||
auto& matEntry = matIt.second;
|
||||
const MaterialPipeline* pipeline = pipelinePair.first;
|
||||
auto& pipelineEntry = pipelinePair.second;
|
||||
|
||||
if (matEntry.enabled)
|
||||
if (pipelineEntry.maxInstanceCount > 0)
|
||||
{
|
||||
ForwardRenderQueue::MeshInstanceContainer& meshInstances = matEntry.meshMap;
|
||||
bool instancing = (pipelineEntry.maxInstanceCount > NAZARA_GRAPHICS_INSTANCING_MIN_INSTANCES_COUNT);
|
||||
const MaterialPipeline::Instance& pipelineInstance = pipeline->Apply((instancing) ? ShaderFlags_Instancing : 0);
|
||||
|
||||
if (!meshInstances.empty())
|
||||
{
|
||||
const Material* material = matIt.first;
|
||||
|
||||
bool instancing = m_instancingEnabled && matEntry.instancingEnabled;
|
||||
|
||||
// We begin to apply the material (and get the shader activated doing so)
|
||||
UInt8 freeTextureUnit;
|
||||
const Shader* shader = material->Apply((instancing) ? ShaderFlags_Instancing : 0, 0, &freeTextureUnit);
|
||||
const Shader* shader = pipelineInstance.uberInstance->GetShader();
|
||||
|
||||
// Uniforms are conserved in our program, there's no point to send them back until they change
|
||||
if (shader != lastShader)
|
||||
{
|
||||
// Index of uniforms in the shader
|
||||
shaderUniforms = GetShaderUniforms(shader);
|
||||
|
||||
// Ambiant color of the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
||||
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
for (auto& materialPair : pipelineEntry.materialMap)
|
||||
{
|
||||
const Material* material = materialPair.first;
|
||||
auto& matEntry = materialPair.second;
|
||||
|
||||
if (matEntry.enabled)
|
||||
{
|
||||
UInt8 freeTextureUnit;
|
||||
material->Apply(pipelineInstance, 0, &freeTextureUnit);
|
||||
|
||||
ForwardRenderQueue::MeshInstanceContainer& meshInstances = matEntry.meshMap;
|
||||
|
||||
// Meshes
|
||||
for (auto& meshIt : meshInstances)
|
||||
{
|
||||
|
|
@ -535,7 +588,7 @@ namespace Nz
|
|||
|
||||
const Matrix4f* instanceMatrices = &instances[0];
|
||||
unsigned int instanceCount = instances.size();
|
||||
unsigned int maxInstanceCount = instanceBuffer->GetVertexCount(); // The maximum number of instances in one batch
|
||||
unsigned int maxInstanceCount = instanceBuffer->GetVertexCount(); // Maximum number of instance in one batch
|
||||
|
||||
while (instanceCount > 0)
|
||||
{
|
||||
|
|
@ -565,11 +618,12 @@ namespace Nz
|
|||
instances.clear();
|
||||
}
|
||||
}
|
||||
|
||||
matEntry.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
// And we set the data back to zero
|
||||
matEntry.enabled = false;
|
||||
matEntry.instancingEnabled = false;
|
||||
pipelineEntry.maxInstanceCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -372,12 +372,11 @@ namespace Nz
|
|||
*
|
||||
* \remark Produces a NazaraAssert if material is invalid
|
||||
*/
|
||||
|
||||
void ForwardRenderQueue::AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
if (material->IsEnabled(RendererParameter_Blend))
|
||||
if (material->IsBlendingEnabled())
|
||||
{
|
||||
Layer& currentLayer = GetLayer(renderOrder);
|
||||
auto& transparentModels = currentLayer.transparentModels;
|
||||
|
|
@ -398,21 +397,33 @@ namespace Nz
|
|||
else
|
||||
{
|
||||
Layer& currentLayer = GetLayer(renderOrder);
|
||||
auto& opaqueModels = currentLayer.opaqueModels;
|
||||
MeshPipelineBatches& opaqueModels = currentLayer.opaqueModels;
|
||||
|
||||
auto it = opaqueModels.find(material);
|
||||
if (it == opaqueModels.end())
|
||||
const MaterialPipeline* materialPipeline = material->GetPipeline();
|
||||
|
||||
auto pipelineIt = opaqueModels.find(materialPipeline);
|
||||
if (pipelineIt == opaqueModels.end())
|
||||
{
|
||||
BatchedMaterialEntry materialEntry;
|
||||
pipelineIt = opaqueModels.insert(MeshPipelineBatches::value_type(materialPipeline, std::move(materialEntry))).first;
|
||||
}
|
||||
|
||||
BatchedMaterialEntry& materialEntry = pipelineIt->second;
|
||||
MeshMaterialBatches& materialMap = materialEntry.materialMap;
|
||||
|
||||
auto materialIt = materialMap.find(material);
|
||||
if (materialIt == materialMap.end())
|
||||
{
|
||||
BatchedModelEntry entry;
|
||||
entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation);
|
||||
|
||||
it = opaqueModels.insert(std::make_pair(material, std::move(entry))).first;
|
||||
materialIt = materialMap.insert(MeshMaterialBatches::value_type(material, std::move(entry))).first;
|
||||
}
|
||||
|
||||
BatchedModelEntry& entry = it->second;
|
||||
BatchedModelEntry& entry = materialIt->second;
|
||||
entry.enabled = true;
|
||||
|
||||
auto& meshMap = entry.meshMap;
|
||||
MeshInstanceContainer& meshMap = entry.meshMap;
|
||||
|
||||
auto it2 = meshMap.find(meshData);
|
||||
if (it2 == meshMap.end())
|
||||
|
|
@ -431,9 +442,7 @@ namespace Nz
|
|||
std::vector<Matrix4f>& instances = it2->second.instances;
|
||||
instances.push_back(transformMatrix);
|
||||
|
||||
// Do we have enough instances to perform instancing ?
|
||||
if (instances.size() >= NAZARA_GRAPHICS_INSTANCING_MIN_INSTANCES_COUNT)
|
||||
entry.instancingEnabled = true; // Thus we can activate it
|
||||
materialEntry.maxInstanceCount = std::max(materialEntry.maxInstanceCount, instances.size());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -448,21 +457,34 @@ namespace Nz
|
|||
*
|
||||
* \remark Produces a NazaraAssert if material is invalid
|
||||
*/
|
||||
|
||||
void ForwardRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay)
|
||||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
Layer& currentLayer = GetLayer(renderOrder);
|
||||
auto& basicSprites = currentLayer.basicSprites;
|
||||
SpritePipelineBatches& basicSprites = currentLayer.basicSprites;
|
||||
|
||||
auto matIt = basicSprites.find(material);
|
||||
if (matIt == basicSprites.end())
|
||||
const MaterialPipeline* materialPipeline = material->GetPipeline();
|
||||
|
||||
auto pipelineIt = basicSprites.find(materialPipeline);
|
||||
if (pipelineIt == basicSprites.end())
|
||||
{
|
||||
BatchedSpritePipelineEntry materialEntry;
|
||||
pipelineIt = basicSprites.insert(SpritePipelineBatches::value_type(materialPipeline, std::move(materialEntry))).first;
|
||||
}
|
||||
|
||||
BatchedSpritePipelineEntry& pipelineEntry = pipelineIt->second;
|
||||
pipelineEntry.enabled = true;
|
||||
|
||||
SpriteMaterialBatches& materialMap = pipelineEntry.materialMap;
|
||||
|
||||
auto matIt = materialMap.find(material);
|
||||
if (matIt == materialMap.end())
|
||||
{
|
||||
BatchedBasicSpriteEntry entry;
|
||||
entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation);
|
||||
|
||||
matIt = basicSprites.insert(std::make_pair(material, std::move(entry))).first;
|
||||
matIt = materialMap.insert(SpriteMaterialBatches::value_type(material, std::move(entry))).first;
|
||||
}
|
||||
|
||||
BatchedBasicSpriteEntry& entry = matIt->second;
|
||||
|
|
@ -541,13 +563,15 @@ namespace Nz
|
|||
return nearPlane.Distance(position1) > nearPlane.Distance(position2);
|
||||
});
|
||||
|
||||
for (auto& pair : layer.billboards)
|
||||
for (auto& pipelinePair : layer.billboards)
|
||||
{
|
||||
const Material* mat = pair.first;
|
||||
for (auto& matPair : pipelinePair.second.materialMap)
|
||||
{
|
||||
const Material* mat = matPair.first;
|
||||
|
||||
if (mat->IsDepthSortingEnabled())
|
||||
{
|
||||
BatchedBillboardEntry& entry = pair.second;
|
||||
BatchedBillboardEntry& entry = matPair.second;
|
||||
auto& billboardVector = entry.billboards;
|
||||
|
||||
std::sort(billboardVector.begin(), billboardVector.end(), [&viewerPos] (const BillboardData& data1, const BillboardData& data2)
|
||||
|
|
@ -558,6 +582,7 @@ namespace Nz
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the billboard data
|
||||
|
|
@ -571,13 +596,26 @@ namespace Nz
|
|||
{
|
||||
auto& billboards = GetLayer(renderOrder).billboards;
|
||||
|
||||
auto it = billboards.find(material);
|
||||
if (it == billboards.end())
|
||||
const MaterialPipeline* materialPipeline = material->GetPipeline();
|
||||
|
||||
auto pipelineIt = billboards.find(materialPipeline);
|
||||
if (pipelineIt == billboards.end())
|
||||
{
|
||||
BatchedBillboardPipelineEntry pipelineEntry;
|
||||
pipelineIt = billboards.insert(BillboardPipelineBatches::value_type(materialPipeline, std::move(pipelineEntry))).first;
|
||||
}
|
||||
BatchedBillboardPipelineEntry& pipelineEntry = pipelineIt->second;
|
||||
pipelineEntry.enabled = true;
|
||||
|
||||
BatchedBillboardContainer& materialMap = pipelineEntry.materialMap;
|
||||
|
||||
auto it = materialMap.find(material);
|
||||
if (it == materialMap.end())
|
||||
{
|
||||
BatchedBillboardEntry entry;
|
||||
entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation);
|
||||
|
||||
it = billboards.insert(std::make_pair(material, std::move(entry))).first;
|
||||
it = materialMap.insert(BatchedBillboardContainer::value_type(material, std::move(entry))).first;
|
||||
}
|
||||
|
||||
BatchedBillboardEntry& entry = it->second;
|
||||
|
|
@ -620,9 +658,11 @@ namespace Nz
|
|||
{
|
||||
Layer& layer = pair.second;
|
||||
|
||||
for (auto& modelPair : layer.opaqueModels)
|
||||
for (auto& pipelineEntry : layer.opaqueModels)
|
||||
{
|
||||
MeshInstanceContainer& meshes = modelPair.second.meshMap;
|
||||
for (auto& materialEntry : pipelineEntry.second.materialMap)
|
||||
{
|
||||
MeshInstanceContainer& meshes = materialEntry.second.meshMap;
|
||||
for (auto it = meshes.begin(); it != meshes.end();)
|
||||
{
|
||||
const MeshData& renderData = it->first;
|
||||
|
|
@ -634,6 +674,7 @@ namespace Nz
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Handle the invalidation of a material
|
||||
|
|
@ -647,9 +688,14 @@ namespace Nz
|
|||
{
|
||||
Layer& layer = pair.second;
|
||||
|
||||
layer.basicSprites.erase(material);
|
||||
layer.billboards.erase(material);
|
||||
layer.opaqueModels.erase(material);
|
||||
for (auto& pipelineEntry : layer.basicSprites)
|
||||
pipelineEntry.second.materialMap.erase(material);
|
||||
|
||||
for (auto& pipelineEntry : layer.billboards)
|
||||
pipelineEntry.second.materialMap.erase(material);
|
||||
|
||||
for (auto& pipelineEntry : layer.opaqueModels)
|
||||
pipelineEntry.second.materialMap.erase(material);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -664,10 +710,10 @@ namespace Nz
|
|||
for (auto& pair : layers)
|
||||
{
|
||||
Layer& layer = pair.second;
|
||||
for (auto matIt = layer.basicSprites.begin(); matIt != layer.basicSprites.end(); ++matIt)
|
||||
for (auto& pipelineEntry : layer.basicSprites)
|
||||
{
|
||||
auto& overlayMap = matIt->second.overlayMap;
|
||||
overlayMap.erase(texture);
|
||||
for (auto& materialEntry : pipelineEntry.second.materialMap)
|
||||
materialEntry.second.overlayMap.erase(texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -683,9 +729,11 @@ namespace Nz
|
|||
for (auto& pair : layers)
|
||||
{
|
||||
Layer& layer = pair.second;
|
||||
for (auto& modelPair : layer.opaqueModels)
|
||||
for (auto& pipelineEntry : layer.opaqueModels)
|
||||
{
|
||||
MeshInstanceContainer& meshes = modelPair.second.meshMap;
|
||||
for (auto& materialEntry : pipelineEntry.second.materialMap)
|
||||
{
|
||||
MeshInstanceContainer& meshes = materialEntry.second.meshMap;
|
||||
for (auto it = meshes.begin(); it != meshes.end();)
|
||||
{
|
||||
const MeshData& renderData = it->first;
|
||||
|
|
@ -697,27 +745,10 @@ namespace Nz
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Functor to compare two batched billboard with material
|
||||
* \return true If first material is "smaller" than the second one
|
||||
*
|
||||
* \param mat1 First material to compare
|
||||
* \param mat2 Second material to compare
|
||||
*/
|
||||
|
||||
bool ForwardRenderQueue::BatchedBillboardComparator::operator()(const Material* mat1, const Material* mat2) const
|
||||
bool ForwardRenderQueue::MaterialComparator::operator()(const Material* mat1, const Material* mat2) const
|
||||
{
|
||||
const UberShader* uberShader1 = mat1->GetShader();
|
||||
const UberShader* uberShader2 = mat2->GetShader();
|
||||
if (uberShader1 != uberShader2)
|
||||
return uberShader1 < uberShader2;
|
||||
|
||||
const Shader* shader1 = mat1->GetShaderInstance(ShaderFlags_Billboard | ShaderFlags_VertexColor)->GetShader();
|
||||
const Shader* shader2 = mat2->GetShaderInstance(ShaderFlags_Billboard | ShaderFlags_VertexColor)->GetShader();
|
||||
if (shader1 != shader2)
|
||||
return shader1 < shader2;
|
||||
|
||||
const Texture* diffuseMap1 = mat1->GetDiffuseMap();
|
||||
const Texture* diffuseMap2 = mat2->GetDiffuseMap();
|
||||
if (diffuseMap1 != diffuseMap2)
|
||||
|
|
@ -726,60 +757,14 @@ namespace Nz
|
|||
return mat1 < mat2;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Functor to compare two batched model with material
|
||||
* \return true If first material is "smaller" than the second one
|
||||
*
|
||||
* \param mat1 First material to compare
|
||||
* \param mat2 Second material to compare
|
||||
*/
|
||||
|
||||
bool ForwardRenderQueue::BatchedModelMaterialComparator::operator()(const Material* mat1, const Material* mat2) const
|
||||
bool ForwardRenderQueue::MaterialPipelineComparator::operator()(const MaterialPipeline* pipeline1, const MaterialPipeline* pipeline2) const
|
||||
{
|
||||
const UberShader* uberShader1 = mat1->GetShader();
|
||||
const UberShader* uberShader2 = mat2->GetShader();
|
||||
if (uberShader1 != uberShader2)
|
||||
return uberShader1 < uberShader2;
|
||||
|
||||
const Shader* shader1 = mat1->GetShaderInstance()->GetShader();
|
||||
const Shader* shader2 = mat2->GetShaderInstance()->GetShader();
|
||||
const Shader* shader1 = pipeline1->GetInstance().renderPipeline.GetInfo().shader;
|
||||
const Shader* shader2 = pipeline2->GetInstance().renderPipeline.GetInfo().shader;
|
||||
if (shader1 != shader2)
|
||||
return shader1 < shader2;
|
||||
|
||||
const Texture* diffuseMap1 = mat1->GetDiffuseMap();
|
||||
const Texture* diffuseMap2 = mat2->GetDiffuseMap();
|
||||
if (diffuseMap1 != diffuseMap2)
|
||||
return diffuseMap1 < diffuseMap2;
|
||||
|
||||
return mat1 < mat2;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Functor to compare two batched sprites with material
|
||||
* \return true If first material is "smaller" than the second one
|
||||
*
|
||||
* \param mat1 First material to compare
|
||||
* \param mat2 Second material to compare
|
||||
*/
|
||||
|
||||
bool ForwardRenderQueue::BatchedSpriteMaterialComparator::operator()(const Material* mat1, const Material* mat2)
|
||||
{
|
||||
const UberShader* uberShader1 = mat1->GetShader();
|
||||
const UberShader* uberShader2 = mat2->GetShader();
|
||||
if (uberShader1 != uberShader2)
|
||||
return uberShader1 < uberShader2;
|
||||
|
||||
const Shader* shader1 = mat1->GetShaderInstance()->GetShader();
|
||||
const Shader* shader2 = mat2->GetShaderInstance()->GetShader();
|
||||
if (shader1 != shader2)
|
||||
return shader1 < shader2;
|
||||
|
||||
const Texture* diffuseMap1 = mat1->GetDiffuseMap();
|
||||
const Texture* diffuseMap2 = mat2->GetDiffuseMap();
|
||||
if (diffuseMap1 != diffuseMap2)
|
||||
return diffuseMap1 < diffuseMap2;
|
||||
|
||||
return mat1 < mat2;
|
||||
return pipeline1 < pipeline2;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
|
|||
|
|
@ -53,6 +53,10 @@ namespace Nz
|
|||
{
|
||||
ErrorFlags flags(ErrorFlag_ThrowException, true);
|
||||
|
||||
std::array<UInt8, 4> whitePixel = {255, 255, 255, 255};
|
||||
m_whiteTexture.Create(ImageType_2D, PixelFormatType_RGBA8, 1, 1);
|
||||
m_whiteTexture.Update(whitePixel.data());
|
||||
|
||||
m_vertexBuffer.Create(s_vertexBufferSize, DataStorage_Hardware, BufferUsage_Dynamic);
|
||||
|
||||
m_billboardPointBuffer.Reset(&s_billboardVertexDeclaration, &m_vertexBuffer);
|
||||
|
|
@ -297,36 +301,16 @@ namespace Nz
|
|||
Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity());
|
||||
Renderer::SetVertexBuffer(&m_spriteBuffer);
|
||||
|
||||
for (auto& matIt : layer.basicSprites)
|
||||
for (auto& pipelinePair : layer.basicSprites)
|
||||
{
|
||||
const Material* material = matIt.first;
|
||||
auto& matEntry = matIt.second;
|
||||
const MaterialPipeline* pipeline = pipelinePair.first;
|
||||
auto& pipelineEntry = pipelinePair.second;
|
||||
|
||||
if (matEntry.enabled)
|
||||
if (pipelineEntry.enabled)
|
||||
{
|
||||
auto& overlayMap = matEntry.overlayMap;
|
||||
for (auto& overlayIt : overlayMap)
|
||||
{
|
||||
const Texture* overlay = overlayIt.first;
|
||||
auto& spriteChainVector = overlayIt.second.spriteChains;
|
||||
const MaterialPipeline::Instance& pipelineInstance = pipeline->Apply(ShaderFlags_TextureOverlay | ShaderFlags_VertexColor);
|
||||
|
||||
unsigned int spriteChainCount = spriteChainVector.size();
|
||||
if (spriteChainCount > 0)
|
||||
{
|
||||
// We begin to apply the material (and get the shader activated doing so)
|
||||
UInt32 flags = ShaderFlags_VertexColor;
|
||||
if (overlay)
|
||||
flags |= ShaderFlags_TextureOverlay;
|
||||
|
||||
UInt8 overlayUnit;
|
||||
const Shader* shader = material->Apply(flags, 0, &overlayUnit);
|
||||
|
||||
if (overlay)
|
||||
{
|
||||
overlayUnit++;
|
||||
Renderer::SetTexture(overlayUnit, overlay);
|
||||
Renderer::SetTextureSampler(overlayUnit, material->GetDiffuseSampler());
|
||||
}
|
||||
const Shader* shader = pipelineInstance.uberInstance->GetShader();
|
||||
|
||||
// Uniforms are conserved in our program, there's no point to send them back until they change
|
||||
if (shader != lastShader)
|
||||
|
|
@ -336,14 +320,38 @@ namespace Nz
|
|||
|
||||
// Ambiant color of the scene
|
||||
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||
// Overlay
|
||||
shader->SendInteger(shaderUniforms->textureOverlay, overlayUnit);
|
||||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
||||
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
for (auto& materialPair : pipelineEntry.materialMap)
|
||||
{
|
||||
const Material* material = materialPair.first;
|
||||
auto& matEntry = materialPair.second;
|
||||
|
||||
if (matEntry.enabled)
|
||||
{
|
||||
UInt8 overlayUnit;
|
||||
material->Apply(pipelineInstance, 0, &overlayUnit);
|
||||
overlayUnit++;
|
||||
|
||||
shader->SendInteger(shaderUniforms->textureOverlay, overlayUnit);
|
||||
|
||||
Renderer::SetTextureSampler(overlayUnit, material->GetDiffuseSampler());
|
||||
|
||||
auto& overlayMap = matEntry.overlayMap;
|
||||
for (auto& overlayIt : overlayMap)
|
||||
{
|
||||
const Texture* overlay = overlayIt.first;
|
||||
auto& spriteChainVector = overlayIt.second.spriteChains;
|
||||
|
||||
unsigned int spriteChainCount = spriteChainVector.size();
|
||||
if (spriteChainCount > 0)
|
||||
{
|
||||
Renderer::SetTexture(overlayUnit, (overlay) ? overlay : &m_whiteTexture);
|
||||
|
||||
unsigned int spriteChain = 0; // Which chain of sprites are we treating
|
||||
unsigned int spriteChainOffset = 0; // Where was the last offset where we stopped in the last chain
|
||||
|
||||
|
|
@ -373,14 +381,12 @@ namespace Nz
|
|||
spriteChain++;
|
||||
spriteChainOffset = 0;
|
||||
}
|
||||
}
|
||||
while (spriteCount < maxSpriteCount && spriteChain < spriteChainCount);
|
||||
} while (spriteCount < maxSpriteCount && spriteChain < spriteChainCount);
|
||||
|
||||
vertexMapper.Unmap();
|
||||
|
||||
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, spriteCount * 6);
|
||||
}
|
||||
while (spriteChain < spriteChainCount);
|
||||
} while (spriteChain < spriteChainCount);
|
||||
|
||||
spriteChainVector.clear();
|
||||
}
|
||||
|
|
@ -390,6 +396,9 @@ namespace Nz
|
|||
matEntry.enabled = false;
|
||||
}
|
||||
}
|
||||
pipelineEntry.enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -415,17 +424,16 @@ namespace Nz
|
|||
|
||||
Renderer::SetVertexBuffer(&s_quadVertexBuffer);
|
||||
|
||||
for (auto& matIt : layer.billboards)
|
||||
for (auto& pipelinePair : layer.billboards)
|
||||
{
|
||||
const Material* material = matIt.first;
|
||||
auto& entry = matIt.second;
|
||||
auto& billboardVector = entry.billboards;
|
||||
const MaterialPipeline* pipeline = pipelinePair.first;
|
||||
auto& pipelineEntry = pipelinePair.second;
|
||||
|
||||
unsigned int billboardCount = billboardVector.size();
|
||||
if (billboardCount > 0)
|
||||
if (pipelineEntry.enabled)
|
||||
{
|
||||
// We begin to apply the material (and get the shader activated doing so)
|
||||
const Shader* shader = material->Apply(ShaderFlags_Billboard | ShaderFlags_Instancing | ShaderFlags_VertexColor);
|
||||
const MaterialPipeline::Instance& pipelineInstance = pipeline->Apply(ShaderFlags_Billboard | ShaderFlags_Instancing | ShaderFlags_VertexColor);
|
||||
|
||||
const Shader* shader = pipelineInstance.uberInstance->GetShader();
|
||||
|
||||
// Uniforms are conserved in our program, there's no point to send them back until they change
|
||||
if (shader != lastShader)
|
||||
|
|
@ -441,6 +449,18 @@ namespace Nz
|
|||
lastShader = shader;
|
||||
}
|
||||
|
||||
for (auto& matIt : pipelinePair.second.materialMap)
|
||||
{
|
||||
const Material* material = matIt.first;
|
||||
auto& entry = matIt.second;
|
||||
auto& billboardVector = entry.billboards;
|
||||
|
||||
unsigned int billboardCount = billboardVector.size();
|
||||
if (billboardCount > 0)
|
||||
{
|
||||
// We begin to apply the material (and get the shader activated doing so)
|
||||
material->Apply(pipelineInstance);
|
||||
|
||||
const ForwardRenderQueue::BillboardData* data = &billboardVector[0];
|
||||
unsigned int maxBillboardPerDraw = instanceBuffer->GetVertexCount();
|
||||
do
|
||||
|
|
@ -459,22 +479,23 @@ namespace Nz
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Renderer::SetIndexBuffer(&s_quadIndexBuffer);
|
||||
Renderer::SetVertexBuffer(&m_billboardPointBuffer);
|
||||
|
||||
for (auto& matIt : layer.billboards)
|
||||
for (auto& pipelinePair : layer.billboards)
|
||||
{
|
||||
const Material* material = matIt.first;
|
||||
auto& entry = matIt.second;
|
||||
auto& billboardVector = entry.billboards;
|
||||
const MaterialPipeline* pipeline = pipelinePair.first;
|
||||
auto& pipelineEntry = pipelinePair.second;
|
||||
|
||||
unsigned int billboardCount = billboardVector.size();
|
||||
if (billboardCount > 0)
|
||||
if (pipelineEntry.enabled)
|
||||
{
|
||||
// We begin to apply the material (and get the shader activated doing so)
|
||||
const Shader* shader = material->Apply(ShaderFlags_Billboard | ShaderFlags_VertexColor);
|
||||
const MaterialPipeline::Instance& pipelineInstance = pipeline->Apply(ShaderFlags_Billboard | ShaderFlags_VertexColor);
|
||||
|
||||
const Shader* shader = pipelineInstance.uberInstance->GetShader();
|
||||
|
||||
// Uniforms are conserved in our program, there's no point to send them back until they change
|
||||
if (shader != lastShader)
|
||||
|
|
@ -490,9 +511,16 @@ namespace Nz
|
|||
lastShader = shader;
|
||||
}
|
||||
|
||||
for (auto& matIt : pipelinePair.second.materialMap)
|
||||
{
|
||||
const Material* material = matIt.first;
|
||||
auto& entry = matIt.second;
|
||||
auto& billboardVector = entry.billboards;
|
||||
|
||||
const ForwardRenderQueue::BillboardData* data = &billboardVector[0];
|
||||
unsigned int maxBillboardPerDraw = std::min(s_maxQuads, m_billboardPointBuffer.GetVertexCount() / 4);
|
||||
|
||||
unsigned int billboardCount = billboardVector.size();
|
||||
do
|
||||
{
|
||||
unsigned int renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw);
|
||||
|
|
@ -545,6 +573,7 @@ namespace Nz
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Draws opaques models
|
||||
|
|
@ -562,27 +591,17 @@ namespace Nz
|
|||
const Shader* lastShader = nullptr;
|
||||
const ShaderUniforms* shaderUniforms = nullptr;
|
||||
|
||||
for (auto& matIt : layer.opaqueModels)
|
||||
for (auto& pipelinePair : layer.opaqueModels)
|
||||
{
|
||||
auto& matEntry = matIt.second;
|
||||
const MaterialPipeline* pipeline = pipelinePair.first;
|
||||
auto& pipelineEntry = pipelinePair.second;
|
||||
|
||||
if (matEntry.enabled)
|
||||
if (pipelineEntry.maxInstanceCount > 0)
|
||||
{
|
||||
ForwardRenderQueue::MeshInstanceContainer& meshInstances = matEntry.meshMap;
|
||||
bool instancing = (pipelineEntry.maxInstanceCount > NAZARA_GRAPHICS_INSTANCING_MIN_INSTANCES_COUNT);
|
||||
const MaterialPipeline::Instance& pipelineInstance = pipeline->Apply((instancing) ? ShaderFlags_Instancing : 0);
|
||||
|
||||
if (!meshInstances.empty())
|
||||
{
|
||||
const Material* material = matIt.first;
|
||||
|
||||
// We only use instancing when no light (other than directional) is active
|
||||
// This is because instancing is not compatible with the search of nearest lights
|
||||
// Deferred shading does not have this problem
|
||||
bool noPointSpotLight = m_renderQueue.pointLights.empty() && m_renderQueue.spotLights.empty();
|
||||
bool instancing = m_instancingEnabled && (!material->IsLightingEnabled() || noPointSpotLight) && matEntry.instancingEnabled;
|
||||
|
||||
// We begin to apply the material (and get the shader activated doing so)
|
||||
UInt8 freeTextureUnit;
|
||||
const Shader* shader = material->Apply((instancing) ? ShaderFlags_Instancing : 0, 0, &freeTextureUnit);
|
||||
const Shader* shader = pipelineInstance.uberInstance->GetShader();
|
||||
|
||||
// Uniforms are conserved in our program, there's no point to send them back until they change
|
||||
if (shader != lastShader)
|
||||
|
|
@ -598,6 +617,18 @@ namespace Nz
|
|||
lastShader = shader;
|
||||
}
|
||||
|
||||
for (auto& materialPair : pipelineEntry.materialMap)
|
||||
{
|
||||
const Material* material = materialPair.first;
|
||||
auto& matEntry = materialPair.second;
|
||||
|
||||
if (matEntry.enabled)
|
||||
{
|
||||
UInt8 freeTextureUnit;
|
||||
material->Apply(pipelineInstance, 0, &freeTextureUnit);
|
||||
|
||||
ForwardRenderQueue::MeshInstanceContainer& meshInstances = matEntry.meshMap;
|
||||
|
||||
// Meshes
|
||||
for (auto& meshIt : meshInstances)
|
||||
{
|
||||
|
|
@ -667,9 +698,6 @@ namespace Nz
|
|||
// Sends the uniforms
|
||||
for (unsigned int i = 0; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i)
|
||||
SendLightUniforms(shader, shaderUniforms->lightUniforms, lightIndex++, shaderUniforms->lightOffset * i, freeTextureUnit + i);
|
||||
|
||||
// And we give them to draw
|
||||
drawFunc(meshData.primitiveMode, 0, indexCount);
|
||||
}
|
||||
|
||||
const Matrix4f* instanceMatrices = &instances[0];
|
||||
|
|
@ -691,7 +719,7 @@ namespace Nz
|
|||
}
|
||||
}
|
||||
|
||||
// We don't forget to disable the blending to avoid to interfeer with the rest of the rendering
|
||||
// We don't forget to disable the blending to avoid to interferering with the rest of the rendering
|
||||
Renderer::Enable(RendererParameter_Blend, false);
|
||||
Renderer::SetDepthFunc(oldDepthFunc);
|
||||
}
|
||||
|
|
@ -753,11 +781,12 @@ namespace Nz
|
|||
instances.clear();
|
||||
}
|
||||
}
|
||||
|
||||
matEntry.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
// And we set the data back to zero
|
||||
matEntry.enabled = false;
|
||||
matEntry.instancingEnabled = false;
|
||||
pipelineEntry.maxInstanceCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -775,6 +804,8 @@ namespace Nz
|
|||
{
|
||||
NazaraAssert(sceneData.viewer, "Invalid viewer");
|
||||
|
||||
const MaterialPipeline* lastPipeline = nullptr;
|
||||
const MaterialPipeline::Instance* pipelineInstance = nullptr;
|
||||
const Shader* lastShader = nullptr;
|
||||
const ShaderUniforms* shaderUniforms = nullptr;
|
||||
unsigned int lightCount = 0;
|
||||
|
|
@ -786,9 +817,16 @@ namespace Nz
|
|||
// Material
|
||||
const Material* material = modelData.material;
|
||||
|
||||
const MaterialPipeline* pipeline = material->GetPipeline();
|
||||
if (pipeline != lastPipeline)
|
||||
{
|
||||
pipelineInstance = &pipeline->Apply();
|
||||
lastPipeline = pipeline;
|
||||
}
|
||||
|
||||
// We begin to apply the material (and get the shader activated doing so)
|
||||
UInt8 freeTextureUnit;
|
||||
const Shader* shader = material->Apply(0, 0, &freeTextureUnit);
|
||||
const Shader* shader = material->Apply(*pipelineInstance, 0, &freeTextureUnit);
|
||||
|
||||
// Uniforms are conserved in our program, there's no point to send them back until they change
|
||||
if (shader != lastShader)
|
||||
|
|
|
|||
|
|
@ -63,12 +63,20 @@ namespace Nz
|
|||
// Initialisation of the module
|
||||
CallOnExit onExit(Graphics::Uninitialize);
|
||||
|
||||
// Materials
|
||||
if (!MaterialPipeline::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize material pipelines");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Material::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize materials");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Renderables
|
||||
if (!ParticleController::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize particle controllers");
|
||||
|
|
@ -121,7 +129,7 @@ namespace Nz
|
|||
Loaders::RegisterMesh();
|
||||
Loaders::RegisterTexture();
|
||||
|
||||
// RenderTechniques
|
||||
// Render techniques
|
||||
if (!DepthRenderTechnique::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize Depth Rendering");
|
||||
|
|
@ -213,19 +221,25 @@ namespace Nz
|
|||
Loaders::UnregisterMesh();
|
||||
Loaders::UnregisterTexture();
|
||||
|
||||
DeferredRenderTechnique::Uninitialize();
|
||||
DepthRenderTechnique::Uninitialize();
|
||||
ForwardRenderTechnique::Uninitialize();
|
||||
SkinningManager::Uninitialize();
|
||||
// Renderables
|
||||
ParticleRenderer::Uninitialize();
|
||||
ParticleGenerator::Uninitialize();
|
||||
ParticleDeclaration::Uninitialize();
|
||||
ParticleController::Uninitialize();
|
||||
Material::Uninitialize();
|
||||
SkyboxBackground::Uninitialize();
|
||||
Sprite::Uninitialize();
|
||||
TileMap::Uninitialize();
|
||||
|
||||
// Render techniques
|
||||
DeferredRenderTechnique::Uninitialize();
|
||||
DepthRenderTechnique::Uninitialize();
|
||||
ForwardRenderTechnique::Uninitialize();
|
||||
SkinningManager::Uninitialize();
|
||||
|
||||
// Materials
|
||||
Material::Uninitialize();
|
||||
MaterialPipeline::Uninitialize();
|
||||
|
||||
NazaraNotice("Uninitialized: Graphics module");
|
||||
|
||||
// Free of dependances
|
||||
|
|
|
|||
|
|
@ -2,40 +2,15 @@
|
|||
// This file is part of the "Nazara Engine - Graphics module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#ifndef NAZARA_RENDERER_OPENGL
|
||||
#define NAZARA_RENDERER_OPENGL // Mandatory to include the OpenGL headers
|
||||
#endif
|
||||
|
||||
#include <Nazara/Graphics/Material.hpp>
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
#include <Nazara/Renderer/UberShaderPreprocessor.hpp>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace
|
||||
{
|
||||
const UInt8 r_basicFragmentShader[] = {
|
||||
#include <Nazara/Graphics/Resources/Shaders/Basic/core.frag.h>
|
||||
};
|
||||
|
||||
const UInt8 r_basicVertexShader[] = {
|
||||
#include <Nazara/Graphics/Resources/Shaders/Basic/core.vert.h>
|
||||
};
|
||||
|
||||
const UInt8 r_phongLightingFragmentShader[] = {
|
||||
#include <Nazara/Graphics/Resources/Shaders/PhongLighting/core.frag.h>
|
||||
};
|
||||
|
||||
const UInt8 r_phongLightingVertexShader[] = {
|
||||
#include <Nazara/Graphics/Resources/Shaders/PhongLighting/core.vert.h>
|
||||
};
|
||||
}
|
||||
|
||||
/*!
|
||||
* \ingroup graphics
|
||||
* \class Nz::Material
|
||||
|
|
@ -46,7 +21,6 @@ namespace Nz
|
|||
* \brief Checks whether the parameters for the material are correct
|
||||
* \return true If parameters are valid
|
||||
*/
|
||||
|
||||
bool MaterialParams::IsValid() const
|
||||
{
|
||||
if (!UberShaderLibrary::Has(shaderName))
|
||||
|
|
@ -57,41 +31,35 @@ namespace Nz
|
|||
|
||||
/*!
|
||||
* \brief Applies shader to the material
|
||||
* \return Constant pointer to the shader
|
||||
*
|
||||
* \param shaderFlags Flags for the shader
|
||||
* \param instance Pipeline instance to update
|
||||
* \param textureUnit Unit for the texture GL_TEXTURE"i"
|
||||
* \param lastUsedUnit Optional argument to get the last texture unit
|
||||
*/
|
||||
|
||||
const Shader* Material::Apply(UInt32 shaderFlags, UInt8 textureUnit, UInt8* lastUsedUnit) const
|
||||
void Material::Apply(const MaterialPipeline::Instance& instance, UInt8 textureUnit, UInt8* lastUsedUnit) const
|
||||
{
|
||||
const ShaderInstance& instance = m_shaders[shaderFlags];
|
||||
if (!instance.uberInstance)
|
||||
GenerateShader(shaderFlags);
|
||||
|
||||
instance.uberInstance->Activate();
|
||||
const Shader* shader = instance.renderPipeline.GetInfo().shader;
|
||||
|
||||
if (instance.uniforms[MaterialUniform_AlphaThreshold] != -1)
|
||||
instance.shader->SendFloat(instance.uniforms[MaterialUniform_AlphaThreshold], m_alphaThreshold);
|
||||
shader->SendFloat(instance.uniforms[MaterialUniform_AlphaThreshold], m_alphaThreshold);
|
||||
|
||||
if (instance.uniforms[MaterialUniform_Ambient] != -1)
|
||||
instance.shader->SendColor(instance.uniforms[MaterialUniform_Ambient], m_ambientColor);
|
||||
shader->SendColor(instance.uniforms[MaterialUniform_Ambient], m_ambientColor);
|
||||
|
||||
if (instance.uniforms[MaterialUniform_Diffuse] != -1)
|
||||
instance.shader->SendColor(instance.uniforms[MaterialUniform_Diffuse], m_diffuseColor);
|
||||
shader->SendColor(instance.uniforms[MaterialUniform_Diffuse], m_diffuseColor);
|
||||
|
||||
if (instance.uniforms[MaterialUniform_Shininess] != -1)
|
||||
instance.shader->SendFloat(instance.uniforms[MaterialUniform_Shininess], m_shininess);
|
||||
shader->SendFloat(instance.uniforms[MaterialUniform_Shininess], m_shininess);
|
||||
|
||||
if (instance.uniforms[MaterialUniform_Specular] != -1)
|
||||
instance.shader->SendColor(instance.uniforms[MaterialUniform_Specular], m_specularColor);
|
||||
shader->SendColor(instance.uniforms[MaterialUniform_Specular], m_specularColor);
|
||||
|
||||
if (m_alphaMap && instance.uniforms[MaterialUniform_AlphaMap] != -1)
|
||||
{
|
||||
Renderer::SetTexture(textureUnit, m_alphaMap);
|
||||
Renderer::SetTextureSampler(textureUnit, m_diffuseSampler);
|
||||
instance.shader->SendInteger(instance.uniforms[MaterialUniform_AlphaMap], textureUnit);
|
||||
shader->SendInteger(instance.uniforms[MaterialUniform_AlphaMap], textureUnit);
|
||||
textureUnit++;
|
||||
}
|
||||
|
||||
|
|
@ -99,7 +67,7 @@ namespace Nz
|
|||
{
|
||||
Renderer::SetTexture(textureUnit, m_diffuseMap);
|
||||
Renderer::SetTextureSampler(textureUnit, m_diffuseSampler);
|
||||
instance.shader->SendInteger(instance.uniforms[MaterialUniform_DiffuseMap], textureUnit);
|
||||
shader->SendInteger(instance.uniforms[MaterialUniform_DiffuseMap], textureUnit);
|
||||
textureUnit++;
|
||||
}
|
||||
|
||||
|
|
@ -107,7 +75,7 @@ namespace Nz
|
|||
{
|
||||
Renderer::SetTexture(textureUnit, m_emissiveMap);
|
||||
Renderer::SetTextureSampler(textureUnit, m_diffuseSampler);
|
||||
instance.shader->SendInteger(instance.uniforms[MaterialUniform_EmissiveMap], textureUnit);
|
||||
shader->SendInteger(instance.uniforms[MaterialUniform_EmissiveMap], textureUnit);
|
||||
textureUnit++;
|
||||
}
|
||||
|
||||
|
|
@ -115,7 +83,7 @@ namespace Nz
|
|||
{
|
||||
Renderer::SetTexture(textureUnit, m_heightMap);
|
||||
Renderer::SetTextureSampler(textureUnit, m_diffuseSampler);
|
||||
instance.shader->SendInteger(instance.uniforms[MaterialUniform_HeightMap], textureUnit);
|
||||
shader->SendInteger(instance.uniforms[MaterialUniform_HeightMap], textureUnit);
|
||||
textureUnit++;
|
||||
}
|
||||
|
||||
|
|
@ -123,7 +91,7 @@ namespace Nz
|
|||
{
|
||||
Renderer::SetTexture(textureUnit, m_normalMap);
|
||||
Renderer::SetTextureSampler(textureUnit, m_diffuseSampler);
|
||||
instance.shader->SendInteger(instance.uniforms[MaterialUniform_NormalMap], textureUnit);
|
||||
shader->SendInteger(instance.uniforms[MaterialUniform_NormalMap], textureUnit);
|
||||
textureUnit++;
|
||||
}
|
||||
|
||||
|
|
@ -131,25 +99,20 @@ namespace Nz
|
|||
{
|
||||
Renderer::SetTexture(textureUnit, m_specularMap);
|
||||
Renderer::SetTextureSampler(textureUnit, m_specularSampler);
|
||||
instance.shader->SendInteger(instance.uniforms[MaterialUniform_SpecularMap], textureUnit);
|
||||
shader->SendInteger(instance.uniforms[MaterialUniform_SpecularMap], textureUnit);
|
||||
textureUnit++;
|
||||
}
|
||||
|
||||
Renderer::SetRenderStates(m_states);
|
||||
|
||||
if (lastUsedUnit)
|
||||
*lastUsedUnit = textureUnit;
|
||||
|
||||
return instance.shader;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Builds the material from parameters
|
||||
* \brief Builds the material from a parameter list
|
||||
*
|
||||
* \param matData Data information for the material
|
||||
* \param matParams Parameters for the material
|
||||
* \param matParams Additional parameters for the material
|
||||
*/
|
||||
|
||||
void Material::BuildFromParameters(const ParameterList& matData, const MaterialParams& matParams)
|
||||
{
|
||||
Color color;
|
||||
|
|
@ -160,7 +123,6 @@ namespace Nz
|
|||
|
||||
ErrorFlags errFlags(ErrorFlag_Silent | ErrorFlag_ThrowExceptionDisabled, true);
|
||||
|
||||
|
||||
if (matData.GetFloatParameter(MaterialData::AlphaThreshold, &fValue))
|
||||
SetAlphaThreshold(fValue);
|
||||
|
||||
|
|
@ -188,14 +150,11 @@ namespace Nz
|
|||
if (matData.GetIntegerParameter(MaterialData::FaceFilling, &iValue))
|
||||
SetFaceFilling(static_cast<FaceFilling>(iValue));
|
||||
|
||||
if (matData.GetBooleanParameter(MaterialData::Lighting, &isEnabled))
|
||||
EnableLighting(isEnabled);
|
||||
|
||||
if (matData.GetFloatParameter(MaterialData::LineWidth, &fValue))
|
||||
m_states.lineWidth = fValue;
|
||||
SetLineWidth(fValue);
|
||||
|
||||
if (matData.GetFloatParameter(MaterialData::PointSize, &fValue))
|
||||
m_states.pointSize = fValue;
|
||||
SetPointSize(fValue);
|
||||
|
||||
if (matData.GetColorParameter(MaterialData::SpecularColor, &color))
|
||||
SetSpecularColor(color);
|
||||
|
|
@ -206,30 +165,27 @@ namespace Nz
|
|||
if (matData.GetIntegerParameter(MaterialData::SrcBlend, &iValue))
|
||||
SetSrcBlend(static_cast<BlendFunc>(iValue));
|
||||
|
||||
if (matData.GetBooleanParameter(MaterialData::Transform, &isEnabled))
|
||||
EnableTransform(isEnabled);
|
||||
|
||||
// RendererParameter
|
||||
if (matData.GetBooleanParameter(MaterialData::Blending, &isEnabled))
|
||||
Enable(RendererParameter_Blend, isEnabled);
|
||||
EnableBlending(isEnabled);
|
||||
|
||||
if (matData.GetBooleanParameter(MaterialData::ColorWrite, &isEnabled))
|
||||
Enable(RendererParameter_ColorWrite, isEnabled);
|
||||
EnableColorWrite(isEnabled);
|
||||
|
||||
if (matData.GetBooleanParameter(MaterialData::DepthBuffer, &isEnabled))
|
||||
Enable(RendererParameter_DepthBuffer, isEnabled);
|
||||
EnableDepthBuffer(isEnabled);
|
||||
|
||||
if (matData.GetBooleanParameter(MaterialData::DepthWrite, &isEnabled))
|
||||
Enable(RendererParameter_DepthWrite, isEnabled);
|
||||
EnableDepthWrite(isEnabled);
|
||||
|
||||
if (matData.GetBooleanParameter(MaterialData::FaceCulling, &isEnabled))
|
||||
Enable(RendererParameter_FaceCulling, isEnabled);
|
||||
EnableFaceCulling(isEnabled);
|
||||
|
||||
if (matData.GetBooleanParameter(MaterialData::ScissorTest, &isEnabled))
|
||||
Enable(RendererParameter_ScissorTest, isEnabled);
|
||||
EnableScissorTest(isEnabled);
|
||||
|
||||
if (matData.GetBooleanParameter(MaterialData::StencilTest, &isEnabled))
|
||||
Enable(RendererParameter_StencilTest, isEnabled);
|
||||
EnableStencilTest(isEnabled);
|
||||
|
||||
// Samplers
|
||||
if (matData.GetIntegerParameter(MaterialData::DiffuseAnisotropyLevel, &iValue))
|
||||
|
|
@ -252,41 +208,43 @@ namespace Nz
|
|||
|
||||
// Stencil
|
||||
if (matData.GetIntegerParameter(MaterialData::StencilCompare, &iValue))
|
||||
m_states.stencilCompare.front = static_cast<RendererComparison>(iValue);
|
||||
m_pipelineInfo.stencilCompare.front = static_cast<RendererComparison>(iValue);
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::StencilFail, &iValue))
|
||||
m_states.stencilFail.front = static_cast<StencilOperation>(iValue);
|
||||
m_pipelineInfo.stencilFail.front = static_cast<StencilOperation>(iValue);
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::StencilPass, &iValue))
|
||||
m_states.stencilPass.front = static_cast<StencilOperation>(iValue);
|
||||
m_pipelineInfo.stencilPass.front = static_cast<StencilOperation>(iValue);
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::StencilZFail, &iValue))
|
||||
m_states.stencilDepthFail.front = static_cast<StencilOperation>(iValue);
|
||||
m_pipelineInfo.stencilDepthFail.front = static_cast<StencilOperation>(iValue);
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::StencilMask, &iValue))
|
||||
m_states.stencilWriteMask.front = static_cast<UInt32>(iValue);
|
||||
m_pipelineInfo.stencilWriteMask.front = static_cast<UInt32>(iValue);
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::StencilReference, &iValue))
|
||||
m_states.stencilReference.front = static_cast<unsigned int>(iValue);
|
||||
m_pipelineInfo.stencilReference.front = static_cast<unsigned int>(iValue);
|
||||
|
||||
// Stencil (back)
|
||||
if (matData.GetIntegerParameter(MaterialData::BackFaceStencilCompare, &iValue))
|
||||
m_states.stencilCompare.back = static_cast<RendererComparison>(iValue);
|
||||
m_pipelineInfo.stencilCompare.back = static_cast<RendererComparison>(iValue);
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::BackFaceStencilFail, &iValue))
|
||||
m_states.stencilFail.back = static_cast<StencilOperation>(iValue);
|
||||
m_pipelineInfo.stencilFail.back = static_cast<StencilOperation>(iValue);
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::BackFaceStencilPass, &iValue))
|
||||
m_states.stencilPass.back = static_cast<StencilOperation>(iValue);
|
||||
m_pipelineInfo.stencilPass.back = static_cast<StencilOperation>(iValue);
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::BackFaceStencilZFail, &iValue))
|
||||
m_states.stencilDepthFail.back = static_cast<StencilOperation>(iValue);
|
||||
m_pipelineInfo.stencilDepthFail.back = static_cast<StencilOperation>(iValue);
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::BackFaceStencilMask, &iValue))
|
||||
m_states.stencilWriteMask.back = static_cast<UInt32>(iValue);
|
||||
m_pipelineInfo.stencilWriteMask.back = static_cast<UInt32>(iValue);
|
||||
|
||||
if (matData.GetIntegerParameter(MaterialData::BackFaceStencilReference, &iValue))
|
||||
m_states.stencilReference.back = static_cast<unsigned int>(iValue);
|
||||
m_pipelineInfo.stencilReference.back = static_cast<unsigned int>(iValue);
|
||||
|
||||
InvalidatePipeline();
|
||||
|
||||
// Textures
|
||||
if (matParams.loadAlphaMap && matData.GetStringParameter(MaterialData::AlphaTexturePath, &path))
|
||||
|
|
@ -310,6 +268,11 @@ namespace Nz
|
|||
SetShader(matParams.shaderName);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Builds a ParameterList with material data
|
||||
*
|
||||
* \param matData Destination parameter list which will receive material data
|
||||
*/
|
||||
void Material::SaveToParameters(ParameterList* matData)
|
||||
{
|
||||
NazaraAssert(matData, "Invalid ParameterList");
|
||||
|
|
@ -323,22 +286,20 @@ namespace Nz
|
|||
matData->SetParameter(MaterialData::DiffuseColor, GetDiffuseColor());
|
||||
matData->SetParameter(MaterialData::DstBlend, int(GetDstBlend()));
|
||||
matData->SetParameter(MaterialData::FaceFilling, int(GetFaceFilling()));
|
||||
matData->SetParameter(MaterialData::Lighting, IsLightingEnabled());
|
||||
matData->SetParameter(MaterialData::LineWidth, GetRenderStates().lineWidth);
|
||||
matData->SetParameter(MaterialData::PointSize, GetRenderStates().pointSize);
|
||||
matData->SetParameter(MaterialData::LineWidth, GetLineWidth());
|
||||
matData->SetParameter(MaterialData::PointSize, GetPointSize());
|
||||
matData->SetParameter(MaterialData::Shininess, GetShininess());
|
||||
matData->SetParameter(MaterialData::SpecularColor, GetSpecularColor());
|
||||
matData->SetParameter(MaterialData::SrcBlend, int(GetSrcBlend()));
|
||||
matData->SetParameter(MaterialData::Transform, IsTransformEnabled());
|
||||
|
||||
// RendererParameter
|
||||
matData->SetParameter(MaterialData::Blending, GetRenderStates().blending);
|
||||
matData->SetParameter(MaterialData::ColorWrite, GetRenderStates().colorWrite);
|
||||
matData->SetParameter(MaterialData::DepthBuffer, GetRenderStates().depthBuffer);
|
||||
matData->SetParameter(MaterialData::DepthWrite, GetRenderStates().depthWrite);
|
||||
matData->SetParameter(MaterialData::FaceCulling, GetRenderStates().faceCulling);
|
||||
matData->SetParameter(MaterialData::ScissorTest, GetRenderStates().scissorTest);
|
||||
matData->SetParameter(MaterialData::StencilTest, GetRenderStates().stencilTest);
|
||||
matData->SetParameter(MaterialData::Blending, IsBlendingEnabled());
|
||||
matData->SetParameter(MaterialData::ColorWrite, IsColorWriteEnabled());
|
||||
matData->SetParameter(MaterialData::DepthBuffer, IsDepthBufferEnabled());
|
||||
matData->SetParameter(MaterialData::DepthWrite, IsDepthWriteEnabled());
|
||||
matData->SetParameter(MaterialData::FaceCulling, IsFaceCullingEnabled());
|
||||
matData->SetParameter(MaterialData::ScissorTest, IsScissorTestEnabled());
|
||||
matData->SetParameter(MaterialData::StencilTest, IsStencilTestEnabled());
|
||||
|
||||
// Samplers
|
||||
matData->SetParameter(MaterialData::DiffuseAnisotropyLevel, int(GetDiffuseSampler().GetAnisotropicLevel()));
|
||||
|
|
@ -350,20 +311,20 @@ namespace Nz
|
|||
matData->SetParameter(MaterialData::SpecularWrap, int(GetSpecularSampler().GetWrapMode()));
|
||||
|
||||
// Stencil
|
||||
matData->SetParameter(MaterialData::StencilCompare, int(GetRenderStates().stencilCompare.front));
|
||||
matData->SetParameter(MaterialData::StencilFail, int(GetRenderStates().stencilFail.front));
|
||||
matData->SetParameter(MaterialData::StencilPass, int(GetRenderStates().stencilPass.front));
|
||||
matData->SetParameter(MaterialData::StencilZFail, int(GetRenderStates().stencilDepthFail.front));
|
||||
matData->SetParameter(MaterialData::StencilMask, int(GetRenderStates().stencilWriteMask.front));
|
||||
matData->SetParameter(MaterialData::StencilReference, int(GetRenderStates().stencilReference.front));
|
||||
matData->SetParameter(MaterialData::StencilCompare, int(GetPipelineInfo().stencilCompare.front));
|
||||
matData->SetParameter(MaterialData::StencilFail, int(GetPipelineInfo().stencilFail.front));
|
||||
matData->SetParameter(MaterialData::StencilPass, int(GetPipelineInfo().stencilPass.front));
|
||||
matData->SetParameter(MaterialData::StencilZFail, int(GetPipelineInfo().stencilDepthFail.front));
|
||||
matData->SetParameter(MaterialData::StencilMask, int(GetPipelineInfo().stencilWriteMask.front));
|
||||
matData->SetParameter(MaterialData::StencilReference, int(GetPipelineInfo().stencilReference.front));
|
||||
|
||||
// Stencil (back)
|
||||
matData->SetParameter(MaterialData::BackFaceStencilCompare, int(GetRenderStates().stencilCompare.back));
|
||||
matData->SetParameter(MaterialData::BackFaceStencilFail, int(GetRenderStates().stencilFail.back));
|
||||
matData->SetParameter(MaterialData::BackFaceStencilPass, int(GetRenderStates().stencilPass.back));
|
||||
matData->SetParameter(MaterialData::BackFaceStencilZFail, int(GetRenderStates().stencilDepthFail.back));
|
||||
matData->SetParameter(MaterialData::BackFaceStencilMask, int(GetRenderStates().stencilWriteMask.back));
|
||||
matData->SetParameter(MaterialData::BackFaceStencilReference, int(GetRenderStates().stencilReference.back));
|
||||
matData->SetParameter(MaterialData::BackFaceStencilCompare, int(GetPipelineInfo().stencilCompare.back));
|
||||
matData->SetParameter(MaterialData::BackFaceStencilFail, int(GetPipelineInfo().stencilFail.back));
|
||||
matData->SetParameter(MaterialData::BackFaceStencilPass, int(GetPipelineInfo().stencilPass.back));
|
||||
matData->SetParameter(MaterialData::BackFaceStencilZFail, int(GetPipelineInfo().stencilDepthFail.back));
|
||||
matData->SetParameter(MaterialData::BackFaceStencilMask, int(GetPipelineInfo().stencilWriteMask.back));
|
||||
matData->SetParameter(MaterialData::BackFaceStencilReference, int(GetPipelineInfo().stencilReference.back));
|
||||
|
||||
// Textures
|
||||
if (HasAlphaMap())
|
||||
|
|
@ -411,6 +372,8 @@ namespace Nz
|
|||
|
||||
/*!
|
||||
* \brief Resets the material, cleans everything
|
||||
*
|
||||
* \remark Invalidates the pipeline
|
||||
*/
|
||||
void Material::Reset()
|
||||
{
|
||||
|
|
@ -423,29 +386,22 @@ namespace Nz
|
|||
m_heightMap.Reset();
|
||||
m_normalMap.Reset();
|
||||
m_specularMap.Reset();
|
||||
m_uberShader.Reset();
|
||||
|
||||
for (ShaderInstance& instance : m_shaders)
|
||||
instance.uberInstance = nullptr;
|
||||
|
||||
m_alphaThreshold = 0.2f;
|
||||
m_alphaTestEnabled = false;
|
||||
m_ambientColor = Color(128, 128, 128);
|
||||
m_depthSortingEnabled = false;
|
||||
m_diffuseColor = Color::White;
|
||||
m_diffuseSampler = TextureSampler();
|
||||
m_lightingEnabled = true;
|
||||
m_shadowCastingEnabled = true;
|
||||
m_shadowReceiveEnabled = true;
|
||||
m_shininess = 50.f;
|
||||
m_specularColor = Color::White;
|
||||
m_specularSampler = TextureSampler();
|
||||
m_states = RenderStates();
|
||||
m_states.depthBuffer = true;
|
||||
m_states.faceCulling = true;
|
||||
m_transformEnabled = true;
|
||||
m_pipelineInfo = MaterialPipelineInfo();
|
||||
m_pipelineInfo.depthBuffer = true;
|
||||
m_pipelineInfo.faceCulling = true;
|
||||
|
||||
SetShader("Basic");
|
||||
|
||||
InvalidatePipeline();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -453,24 +409,18 @@ namespace Nz
|
|||
*
|
||||
* \param material Material to copy into this
|
||||
*/
|
||||
|
||||
void Material::Copy(const Material& material)
|
||||
{
|
||||
// Copy of base states
|
||||
m_alphaTestEnabled = material.m_alphaTestEnabled;
|
||||
m_alphaThreshold = material.m_alphaThreshold;
|
||||
m_ambientColor = material.m_ambientColor;
|
||||
m_depthSortingEnabled = material.m_depthSortingEnabled;
|
||||
m_diffuseColor = material.m_diffuseColor;
|
||||
m_diffuseSampler = material.m_diffuseSampler;
|
||||
m_lightingEnabled = material.m_lightingEnabled;
|
||||
m_pipelineInfo = material.m_pipelineInfo;
|
||||
m_shininess = material.m_shininess;
|
||||
m_shadowCastingEnabled = material.m_shadowCastingEnabled;
|
||||
m_shadowReceiveEnabled = material.m_shadowReceiveEnabled;
|
||||
m_specularColor = material.m_specularColor;
|
||||
m_specularSampler = material.m_specularSampler;
|
||||
m_states = material.m_states;
|
||||
m_transformEnabled = material.m_transformEnabled;
|
||||
|
||||
// Copy of reference to the textures
|
||||
m_alphaMap = material.m_alphaMap;
|
||||
|
|
@ -480,61 +430,8 @@ namespace Nz
|
|||
m_heightMap = material.m_heightMap;
|
||||
m_normalMap = material.m_normalMap;
|
||||
m_specularMap = material.m_specularMap;
|
||||
m_uberShader = material.m_uberShader;
|
||||
|
||||
// We copy the instances of the shader too
|
||||
std::memcpy(&m_shaders[0], &material.m_shaders[0], (ShaderFlags_Max + 1) * sizeof(ShaderInstance));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Generates the shader based on flag
|
||||
*
|
||||
* \param flags Flag for the shaer
|
||||
*/
|
||||
|
||||
void Material::GenerateShader(UInt32 flags) const
|
||||
{
|
||||
ParameterList list;
|
||||
list.SetParameter("ALPHA_MAPPING", m_alphaMap.IsValid());
|
||||
list.SetParameter("ALPHA_TEST", m_alphaTestEnabled);
|
||||
list.SetParameter("COMPUTE_TBNMATRIX", m_normalMap.IsValid() || m_heightMap.IsValid());
|
||||
list.SetParameter("DIFFUSE_MAPPING", m_diffuseMap.IsValid());
|
||||
list.SetParameter("EMISSIVE_MAPPING", m_emissiveMap.IsValid());
|
||||
list.SetParameter("LIGHTING", m_lightingEnabled);
|
||||
list.SetParameter("NORMAL_MAPPING", m_normalMap.IsValid());
|
||||
list.SetParameter("PARALLAX_MAPPING", m_heightMap.IsValid());
|
||||
list.SetParameter("SHADOW_MAPPING", m_shadowReceiveEnabled);
|
||||
list.SetParameter("SPECULAR_MAPPING", m_specularMap.IsValid());
|
||||
list.SetParameter("TEXTURE_MAPPING", m_alphaMap.IsValid() || m_diffuseMap.IsValid() || m_emissiveMap.IsValid() ||
|
||||
m_normalMap.IsValid() || m_heightMap.IsValid() || m_specularMap.IsValid() ||
|
||||
flags & ShaderFlags_TextureOverlay);
|
||||
list.SetParameter("TRANSFORM", m_transformEnabled);
|
||||
|
||||
list.SetParameter("FLAG_BILLBOARD", static_cast<bool>((flags & ShaderFlags_Billboard) != 0));
|
||||
list.SetParameter("FLAG_DEFERRED", static_cast<bool>((flags & ShaderFlags_Deferred) != 0));
|
||||
list.SetParameter("FLAG_INSTANCING", static_cast<bool>((flags & ShaderFlags_Instancing) != 0));
|
||||
list.SetParameter("FLAG_TEXTUREOVERLAY", static_cast<bool>((flags & ShaderFlags_TextureOverlay) != 0));
|
||||
list.SetParameter("FLAG_VERTEXCOLOR", static_cast<bool>((flags & ShaderFlags_VertexColor) != 0));
|
||||
|
||||
ShaderInstance& instance = m_shaders[flags];
|
||||
instance.uberInstance = m_uberShader->Get(list);
|
||||
instance.shader = instance.uberInstance->GetShader();
|
||||
|
||||
#define CacheUniform(name) instance.uniforms[MaterialUniform_##name] = instance.shader->GetUniformLocation("Material" #name)
|
||||
|
||||
CacheUniform(AlphaMap);
|
||||
CacheUniform(AlphaThreshold);
|
||||
CacheUniform(Ambient);
|
||||
CacheUniform(Diffuse);
|
||||
CacheUniform(DiffuseMap);
|
||||
CacheUniform(EmissiveMap);
|
||||
CacheUniform(HeightMap);
|
||||
CacheUniform(NormalMap);
|
||||
CacheUniform(Shininess);
|
||||
CacheUniform(Specular);
|
||||
CacheUniform(SpecularMap);
|
||||
|
||||
#undef CacheUniform
|
||||
InvalidatePipeline();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -543,7 +440,6 @@ namespace Nz
|
|||
*
|
||||
* \remark Produces a NazaraError if the material library failed to be initialized
|
||||
*/
|
||||
|
||||
bool Material::Initialize()
|
||||
{
|
||||
if (!MaterialLibrary::Initialize())
|
||||
|
|
@ -558,67 +454,21 @@ namespace Nz
|
|||
return false;
|
||||
}
|
||||
|
||||
// Basic shader
|
||||
{
|
||||
UberShaderPreprocessorRef uberShader = UberShaderPreprocessor::New();
|
||||
|
||||
String fragmentShader(reinterpret_cast<const char*>(r_basicFragmentShader), sizeof(r_basicFragmentShader));
|
||||
String vertexShader(reinterpret_cast<const char*>(r_basicVertexShader), sizeof(r_basicVertexShader));
|
||||
|
||||
uberShader->SetShader(ShaderStageType_Fragment, fragmentShader, "FLAG_TEXTUREOVERLAY ALPHA_MAPPING ALPHA_TEST AUTO_TEXCOORDS DIFFUSE_MAPPING");
|
||||
uberShader->SetShader(ShaderStageType_Vertex, vertexShader, "FLAG_BILLBOARD FLAG_INSTANCING FLAG_VERTEXCOLOR TEXTURE_MAPPING TRANSFORM UNIFORM_VERTEX_DEPTH");
|
||||
|
||||
UberShaderLibrary::Register("Basic", uberShader);
|
||||
}
|
||||
|
||||
// PhongLighting shader
|
||||
{
|
||||
UberShaderPreprocessorRef uberShader = UberShaderPreprocessor::New();
|
||||
|
||||
String fragmentShader(reinterpret_cast<const char*>(r_phongLightingFragmentShader), sizeof(r_phongLightingFragmentShader));
|
||||
String vertexShader(reinterpret_cast<const char*>(r_phongLightingVertexShader), sizeof(r_phongLightingVertexShader));
|
||||
|
||||
uberShader->SetShader(ShaderStageType_Fragment, fragmentShader, "FLAG_DEFERRED FLAG_TEXTUREOVERLAY ALPHA_MAPPING ALPHA_TEST AUTO_TEXCOORDS DIFFUSE_MAPPING EMISSIVE_MAPPING LIGHTING NORMAL_MAPPING PARALLAX_MAPPING SHADOW_MAPPING SPECULAR_MAPPING");
|
||||
uberShader->SetShader(ShaderStageType_Vertex, vertexShader, "FLAG_BILLBOARD FLAG_DEFERRED FLAG_INSTANCING FLAG_VERTEXCOLOR COMPUTE_TBNMATRIX LIGHTING PARALLAX_MAPPING SHADOW_MAPPING TEXTURE_MAPPING TRANSFORM UNIFORM_VERTEX_DEPTH");
|
||||
|
||||
UberShaderLibrary::Register("PhongLighting", uberShader);
|
||||
}
|
||||
|
||||
// Once the base shaders are registered, we can now set some default materials
|
||||
s_defaultMaterial = New();
|
||||
s_defaultMaterial->Enable(RendererParameter_FaceCulling, false);
|
||||
s_defaultMaterial->EnableFaceCulling(false);
|
||||
s_defaultMaterial->SetFaceFilling(FaceFilling_Line);
|
||||
MaterialLibrary::Register("Default", s_defaultMaterial);
|
||||
|
||||
MaterialRef mat;
|
||||
|
||||
mat = New();
|
||||
mat->Enable(RendererParameter_DepthWrite, false);
|
||||
mat->Enable(RendererParameter_FaceCulling, false);
|
||||
mat->EnableLighting(false);
|
||||
MaterialLibrary::Register("Basic2D", std::move(mat));
|
||||
|
||||
mat = New();
|
||||
mat->Enable(RendererParameter_Blend, true);
|
||||
mat->Enable(RendererParameter_DepthWrite, false);
|
||||
mat->Enable(RendererParameter_FaceCulling, false);
|
||||
mat->EnableLighting(false);
|
||||
mat->SetDstBlend(BlendFunc_InvSrcAlpha);
|
||||
mat->SetSrcBlend(BlendFunc_SrcAlpha);
|
||||
MaterialLibrary::Register("Translucent2D", std::move(mat));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Uninitializes the material librairies
|
||||
*/
|
||||
|
||||
void Material::Uninitialize()
|
||||
{
|
||||
s_defaultMaterial.Reset();
|
||||
UberShaderLibrary::Unregister("PhongLighting");
|
||||
UberShaderLibrary::Unregister("Basic");
|
||||
|
||||
MaterialManager::Uninitialize();
|
||||
MaterialLibrary::Uninitialize();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,168 @@
|
|||
// Copyright (C) 2016 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Graphics module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Graphics/MaterialPipeline.hpp>
|
||||
|
||||
#ifndef NAZARA_RENDERER_OPENGL
|
||||
#define NAZARA_RENDERER_OPENGL // Mandatory to include the OpenGL headers
|
||||
#endif
|
||||
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Renderer/UberShaderPreprocessor.hpp>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace
|
||||
{
|
||||
const UInt8 r_basicFragmentShader[] = {
|
||||
#include <Nazara/Graphics/Resources/Shaders/Basic/core.frag.h>
|
||||
};
|
||||
|
||||
const UInt8 r_basicVertexShader[] = {
|
||||
#include <Nazara/Graphics/Resources/Shaders/Basic/core.vert.h>
|
||||
};
|
||||
|
||||
const UInt8 r_phongLightingFragmentShader[] = {
|
||||
#include <Nazara/Graphics/Resources/Shaders/PhongLighting/core.frag.h>
|
||||
};
|
||||
|
||||
const UInt8 r_phongLightingVertexShader[] = {
|
||||
#include <Nazara/Graphics/Resources/Shaders/PhongLighting/core.vert.h>
|
||||
};
|
||||
}
|
||||
|
||||
/*!
|
||||
* \ingroup graphics
|
||||
* \class Nz::MaterialPipeline
|
||||
*
|
||||
* \brief Graphics class used to contains all rendering states that are not allowed to change individually on rendering devices
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Returns a reference to a MaterialPipeline built with MaterialPipelineInfo
|
||||
*
|
||||
* This function is using a cache, calling it multiples times with the same MaterialPipelineInfo will returns references to a single MaterialPipeline
|
||||
*
|
||||
* \param pipelineInfo Pipeline informations used to build/retrieve a MaterialPipeline object
|
||||
*/
|
||||
MaterialPipelineRef MaterialPipeline::GetPipeline(const MaterialPipelineInfo& pipelineInfo)
|
||||
{
|
||||
auto it = s_pipelineCache.lower_bound(pipelineInfo);
|
||||
if (it == s_pipelineCache.end() || it->first != pipelineInfo)
|
||||
it = s_pipelineCache.insert(it, PipelineCache::value_type(pipelineInfo, New(pipelineInfo)));
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void MaterialPipeline::GenerateRenderPipeline(UInt32 flags) const
|
||||
{
|
||||
ParameterList list;
|
||||
list.SetParameter("ALPHA_MAPPING", m_pipelineInfo.hasAlphaMap);
|
||||
list.SetParameter("ALPHA_TEST", m_pipelineInfo.alphaTest);
|
||||
list.SetParameter("COMPUTE_TBNMATRIX", m_pipelineInfo.hasNormalMap || m_pipelineInfo.hasHeightMap);
|
||||
list.SetParameter("DIFFUSE_MAPPING", m_pipelineInfo.hasDiffuseMap);
|
||||
list.SetParameter("EMISSIVE_MAPPING", m_pipelineInfo.hasEmissiveMap);
|
||||
list.SetParameter("NORMAL_MAPPING", m_pipelineInfo.hasNormalMap);
|
||||
list.SetParameter("PARALLAX_MAPPING", m_pipelineInfo.hasHeightMap);
|
||||
list.SetParameter("SHADOW_MAPPING", m_pipelineInfo.shadowReceive);
|
||||
list.SetParameter("SPECULAR_MAPPING", m_pipelineInfo.hasSpecularMap);
|
||||
list.SetParameter("TEXTURE_MAPPING", m_pipelineInfo.hasAlphaMap || m_pipelineInfo.hasDiffuseMap || m_pipelineInfo.hasEmissiveMap ||
|
||||
m_pipelineInfo.hasNormalMap || m_pipelineInfo.hasHeightMap || m_pipelineInfo.hasSpecularMap ||
|
||||
flags & ShaderFlags_TextureOverlay);
|
||||
list.SetParameter("TRANSFORM", true);
|
||||
|
||||
list.SetParameter("FLAG_BILLBOARD", static_cast<bool>((flags & ShaderFlags_Billboard) != 0));
|
||||
list.SetParameter("FLAG_DEFERRED", static_cast<bool>((flags & ShaderFlags_Deferred) != 0));
|
||||
list.SetParameter("FLAG_INSTANCING", static_cast<bool>((flags & ShaderFlags_Instancing) != 0));
|
||||
list.SetParameter("FLAG_TEXTUREOVERLAY", static_cast<bool>((flags & ShaderFlags_TextureOverlay) != 0));
|
||||
list.SetParameter("FLAG_VERTEXCOLOR", static_cast<bool>((flags & ShaderFlags_VertexColor) != 0));
|
||||
|
||||
Instance& instance = m_instances[flags];
|
||||
instance.uberInstance = m_pipelineInfo.uberShader->Get(list);
|
||||
|
||||
RenderPipelineInfo renderPipelineInfo;
|
||||
static_cast<RenderStates&>(renderPipelineInfo).operator=(m_pipelineInfo); // Not my proudest line
|
||||
|
||||
renderPipelineInfo.shader = instance.uberInstance->GetShader();
|
||||
|
||||
instance.renderPipeline.Create(renderPipelineInfo);
|
||||
|
||||
#define CacheUniform(name) instance.uniforms[MaterialUniform_##name] = renderPipelineInfo.shader->GetUniformLocation("Material" #name)
|
||||
|
||||
CacheUniform(AlphaMap);
|
||||
CacheUniform(AlphaThreshold);
|
||||
CacheUniform(Ambient);
|
||||
CacheUniform(Diffuse);
|
||||
CacheUniform(DiffuseMap);
|
||||
CacheUniform(EmissiveMap);
|
||||
CacheUniform(HeightMap);
|
||||
CacheUniform(NormalMap);
|
||||
CacheUniform(Shininess);
|
||||
CacheUniform(Specular);
|
||||
CacheUniform(SpecularMap);
|
||||
|
||||
#undef CacheUniform
|
||||
}
|
||||
|
||||
bool MaterialPipeline::Initialize()
|
||||
{
|
||||
// Basic shader
|
||||
{
|
||||
UberShaderPreprocessorRef uberShader = UberShaderPreprocessor::New();
|
||||
|
||||
String fragmentShader(reinterpret_cast<const char*>(r_basicFragmentShader), sizeof(r_basicFragmentShader));
|
||||
String vertexShader(reinterpret_cast<const char*>(r_basicVertexShader), sizeof(r_basicVertexShader));
|
||||
|
||||
uberShader->SetShader(ShaderStageType_Fragment, fragmentShader, "FLAG_TEXTUREOVERLAY ALPHA_MAPPING ALPHA_TEST AUTO_TEXCOORDS DIFFUSE_MAPPING");
|
||||
uberShader->SetShader(ShaderStageType_Vertex, vertexShader, "FLAG_BILLBOARD FLAG_INSTANCING FLAG_VERTEXCOLOR TEXTURE_MAPPING TRANSFORM UNIFORM_VERTEX_DEPTH");
|
||||
|
||||
UberShaderLibrary::Register("Basic", uberShader);
|
||||
}
|
||||
|
||||
// PhongLighting shader
|
||||
{
|
||||
UberShaderPreprocessorRef uberShader = UberShaderPreprocessor::New();
|
||||
|
||||
String fragmentShader(reinterpret_cast<const char*>(r_phongLightingFragmentShader), sizeof(r_phongLightingFragmentShader));
|
||||
String vertexShader(reinterpret_cast<const char*>(r_phongLightingVertexShader), sizeof(r_phongLightingVertexShader));
|
||||
|
||||
uberShader->SetShader(ShaderStageType_Fragment, fragmentShader, "FLAG_DEFERRED FLAG_TEXTUREOVERLAY ALPHA_MAPPING ALPHA_TEST AUTO_TEXCOORDS DIFFUSE_MAPPING EMISSIVE_MAPPING NORMAL_MAPPING PARALLAX_MAPPING SHADOW_MAPPING SPECULAR_MAPPING");
|
||||
uberShader->SetShader(ShaderStageType_Vertex, vertexShader, "FLAG_BILLBOARD FLAG_DEFERRED FLAG_INSTANCING FLAG_VERTEXCOLOR COMPUTE_TBNMATRIX PARALLAX_MAPPING SHADOW_MAPPING TEXTURE_MAPPING TRANSFORM UNIFORM_VERTEX_DEPTH");
|
||||
|
||||
UberShaderLibrary::Register("PhongLighting", uberShader);
|
||||
}
|
||||
|
||||
// Once the base shaders are registered, we can now set some default materials
|
||||
MaterialPipelineInfo pipelineInfo;
|
||||
|
||||
// Basic 2D - No depth write/face culling
|
||||
pipelineInfo.depthWrite = false;
|
||||
pipelineInfo.faceCulling = false;
|
||||
|
||||
MaterialPipelineLibrary::Register("Basic2D", GetPipeline(pipelineInfo));
|
||||
|
||||
// Translucent 2D - Alpha blending with no depth write/face culling
|
||||
pipelineInfo.blending = false;
|
||||
pipelineInfo.depthWrite = false;
|
||||
pipelineInfo.faceCulling = false;
|
||||
pipelineInfo.dstBlend = BlendFunc_InvSrcAlpha;
|
||||
pipelineInfo.srcBlend = BlendFunc_SrcAlpha;
|
||||
|
||||
MaterialPipelineLibrary::Register("Translucent2D", GetPipeline(pipelineInfo));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MaterialPipeline::Uninitialize()
|
||||
{
|
||||
s_pipelineCache.clear();
|
||||
UberShaderLibrary::Unregister("PhongLighting");
|
||||
UberShaderLibrary::Unregister("Basic");
|
||||
MaterialPipelineLibrary::Uninitialize();
|
||||
}
|
||||
|
||||
MaterialPipelineLibrary::LibraryMap MaterialPipeline::s_library;
|
||||
MaterialPipeline::PipelineCache MaterialPipeline::s_pipelineCache;
|
||||
}
|
||||
|
|
@ -132,7 +132,7 @@ void main()
|
|||
vec2 texCoord = vTexCoord;
|
||||
#endif
|
||||
|
||||
#if LIGHTING && PARALLAX_MAPPING
|
||||
#if PARALLAX_MAPPING
|
||||
float height = texture(MaterialHeightMap, texCoord).r;
|
||||
float v = height*ParallaxScale + ParallaxBias;
|
||||
|
||||
|
|
@ -159,7 +159,6 @@ void main()
|
|||
discard;
|
||||
#endif // ALPHA_TEST
|
||||
|
||||
#if LIGHTING
|
||||
#if NORMAL_MAPPING
|
||||
vec3 normal = normalize(vLightToWorld * (2.0 * vec3(texture(MaterialNormalMap, texCoord)) - 1.0));
|
||||
#else
|
||||
|
|
@ -179,9 +178,6 @@ void main()
|
|||
RenderTarget0 = vec4(diffuseColor.rgb, dot(specularColor, vec3(0.3, 0.59, 0.11)));
|
||||
RenderTarget1 = vec4(EncodeNormal(normal));
|
||||
RenderTarget2 = vec4(FloatToColor(gl_FragCoord.z), (MaterialShininess == 0.0) ? 0.0 : max(log2(MaterialShininess), 0.1)/10.5); // http://www.guerrilla-games.com/publications/dr_kz2_rsx_dev07.pdf
|
||||
#else // LIGHTING
|
||||
RenderTarget0 = vec4(diffuseColor.rgb, 0.0);
|
||||
#endif
|
||||
#else // FLAG_DEFERRED
|
||||
#if ALPHA_MAPPING
|
||||
diffuseColor.a *= texture(MaterialAlphaMap, texCoord).r;
|
||||
|
|
@ -192,7 +188,6 @@ void main()
|
|||
discard;
|
||||
#endif
|
||||
|
||||
#if LIGHTING
|
||||
vec3 lightAmbient = vec3(0.0);
|
||||
vec3 lightDiffuse = vec3(0.0);
|
||||
vec3 lightSpecular = vec3(0.0);
|
||||
|
|
@ -474,9 +469,6 @@ void main()
|
|||
#else
|
||||
RenderTarget0 = fragmentColor;
|
||||
#endif // EMISSIVE_MAPPING
|
||||
#else
|
||||
RenderTarget0 = diffuseColor;
|
||||
#endif // LIGHTING
|
||||
#endif // FLAG_DEFERRED
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -12,6 +12,7 @@ in vec3 VertexPosition;
|
|||
in vec3 VertexNormal;
|
||||
in vec3 VertexTangent;
|
||||
in vec2 VertexTexCoord;
|
||||
in vec4 VertexUserdata0;
|
||||
|
||||
/********************Sortant********************/
|
||||
out vec4 vColor;
|
||||
|
|
@ -27,6 +28,7 @@ uniform vec3 EyePosition;
|
|||
uniform mat4 InvViewMatrix;
|
||||
uniform mat4 LightViewProjMatrix[3];
|
||||
uniform float VertexDepth;
|
||||
uniform mat4 ViewMatrix;
|
||||
uniform mat4 ViewProjMatrix;
|
||||
uniform mat4 WorldMatrix;
|
||||
uniform mat4 WorldViewProjMatrix;
|
||||
|
|
@ -107,7 +109,6 @@ void main()
|
|||
|
||||
vColor = color;
|
||||
|
||||
#if LIGHTING
|
||||
#if FLAG_INSTANCING
|
||||
mat3 rotationMatrix = mat3(InstanceData0);
|
||||
#else
|
||||
|
|
@ -122,7 +123,6 @@ void main()
|
|||
#else
|
||||
vNormal = normalize(rotationMatrix * VertexNormal);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SHADOW_MAPPING
|
||||
for (int i = 0; i < 3; ++i)
|
||||
|
|
@ -133,12 +133,12 @@ void main()
|
|||
vTexCoord = VertexTexCoord;
|
||||
#endif
|
||||
|
||||
#if LIGHTING && PARALLAX_MAPPING
|
||||
#if PARALLAX_MAPPING
|
||||
vViewDir = EyePosition - VertexPosition;
|
||||
vViewDir *= vLightToWorld;
|
||||
#endif
|
||||
|
||||
#if LIGHTING && !FLAG_DEFERRED
|
||||
#if !FLAG_DEFERRED
|
||||
#if FLAG_INSTANCING
|
||||
vWorldPos = vec3(InstanceData0 * vec4(VertexPosition, 1.0));
|
||||
#else
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue