Merge branch 'Graphics-Update'
Former-commit-id: 9855f235dd21d47d1cd9da8c3c0b4ede41e74472
This commit is contained in:
commit
6556acfa32
|
|
@ -149,6 +149,9 @@ int main()
|
|||
// La distance entre l'oeil et le plan rapproché (0 est une valeur interdite car la division par zéro l'est également)
|
||||
camera.SetZNear(0.1f);
|
||||
|
||||
// On indique à la scène que le viewer (Le point de vue) sera la caméra
|
||||
scene.SetViewer(&camera);
|
||||
|
||||
// Attention que le ratio entre les deux (zFar/zNear) doit rester raisonnable, dans le cas contraire vous risquez un phénomène
|
||||
// de "Z-Fighting" (Impossibilité de déduire quelle surface devrait apparaître en premier) sur les surfaces éloignées.
|
||||
|
||||
|
|
@ -326,14 +329,10 @@ int main()
|
|||
updateClock.Restart();
|
||||
}
|
||||
|
||||
// Rendu de la scène
|
||||
|
||||
// On active la caméra (Qui s'occupera de préparer la fenêtre au rendu)
|
||||
camera.Activate();
|
||||
|
||||
// Rendu de la scène:
|
||||
// On procède maintenant au rendu de la scène en elle-même, celui-ci se décompose en quatre étapes distinctes
|
||||
|
||||
// Pour commencer, on mets à jour la scène, ceci appelle la méthode Update de tous les SceneNode enregistrés
|
||||
// Pour commencer, on met à jour la scène, ceci appelle la méthode Update de tous les SceneNode enregistrés
|
||||
// pour la mise à jour globale (Scene::RegisterForUpdate)
|
||||
scene.Update();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// This file was automatically generated on 09 Jun 2013 at 11:23:10
|
||||
// This file was automatically generated on 21 Aug 2013 at 19:43:23
|
||||
|
||||
/*
|
||||
Nazara Engine - Graphics module
|
||||
|
|
@ -32,6 +32,7 @@
|
|||
#include <Nazara/Graphics/AbstractBackground.hpp>
|
||||
#include <Nazara/Graphics/AbstractRenderQueue.hpp>
|
||||
#include <Nazara/Graphics/AbstractRenderTechnique.hpp>
|
||||
#include <Nazara/Graphics/AbstractViewer.hpp>
|
||||
#include <Nazara/Graphics/Camera.hpp>
|
||||
#include <Nazara/Graphics/ColorBackground.hpp>
|
||||
#include <Nazara/Graphics/Config.hpp>
|
||||
|
|
@ -41,11 +42,16 @@
|
|||
#include <Nazara/Graphics/ForwardRenderTechnique.hpp>
|
||||
#include <Nazara/Graphics/Graphics.hpp>
|
||||
#include <Nazara/Graphics/Light.hpp>
|
||||
#include <Nazara/Graphics/LightManager.hpp>
|
||||
#include <Nazara/Graphics/Model.hpp>
|
||||
#include <Nazara/Graphics/Scene.hpp>
|
||||
#include <Nazara/Graphics/SceneLayer.hpp>
|
||||
#include <Nazara/Graphics/SceneNode.hpp>
|
||||
#include <Nazara/Graphics/SceneRoot.hpp>
|
||||
#include <Nazara/Graphics/ScreenNode.hpp>
|
||||
#include <Nazara/Graphics/SkyboxBackground.hpp>
|
||||
#include <Nazara/Graphics/Sprite.hpp>
|
||||
#include <Nazara/Graphics/TextureBackground.hpp>
|
||||
#include <Nazara/Graphics/View.hpp>
|
||||
|
||||
#endif // NAZARA_GLOBAL_GRAPHICS_HPP
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
class NzDrawable;
|
||||
class NzLight;
|
||||
class NzModel;
|
||||
class NzSprite;
|
||||
|
||||
class NAZARA_API NzAbstractRenderQueue : NzNonCopyable
|
||||
{
|
||||
|
|
@ -23,6 +24,7 @@ class NAZARA_API NzAbstractRenderQueue : NzNonCopyable
|
|||
virtual void AddDrawable(const NzDrawable* drawable) = 0;
|
||||
virtual void AddLight(const NzLight* light) = 0;
|
||||
virtual void AddModel(const NzModel* model) = 0;
|
||||
virtual void AddSprite(const NzSprite* sprite) = 0;
|
||||
|
||||
virtual void Clear(bool fully) = 0;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
// Copyright (C) 2013 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_ABSTRACTVIEWER_HPP
|
||||
#define NAZARA_ABSTRACTVIEWER_HPP
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <Nazara/Graphics/Enums.hpp>
|
||||
#include <Nazara/Math/Frustum.hpp>
|
||||
#include <Nazara/Math/Matrix4.hpp>
|
||||
#include <Nazara/Math/Rect.hpp>
|
||||
|
||||
class NzRenderTarget;
|
||||
class NzScene;
|
||||
|
||||
class NAZARA_API NzAbstractViewer
|
||||
{
|
||||
public:
|
||||
NzAbstractViewer() = default;
|
||||
virtual ~NzAbstractViewer();
|
||||
|
||||
virtual void ApplyView() const = 0;
|
||||
|
||||
virtual float GetAspectRatio() const = 0;
|
||||
virtual NzVector3f GetEyePosition() const = 0;
|
||||
virtual const NzFrustumf& GetFrustum() const = 0;
|
||||
virtual const NzMatrix4f& GetProjectionMatrix() const = 0;
|
||||
virtual const NzRenderTarget* GetTarget() const = 0;
|
||||
virtual const NzMatrix4f& GetViewMatrix() const = 0;
|
||||
virtual const NzRectui& GetViewport() const = 0;
|
||||
virtual float GetZFar() const = 0;
|
||||
virtual float GetZNear() const = 0;
|
||||
};
|
||||
|
||||
#endif // NAZARA_ABSTRACTVIEWER_HPP
|
||||
|
|
@ -8,6 +8,7 @@
|
|||
#define NAZARA_CAMERA_HPP
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <Nazara/Graphics/AbstractViewer.hpp>
|
||||
#include <Nazara/Graphics/SceneNode.hpp>
|
||||
#include <Nazara/Math/Frustum.hpp>
|
||||
#include <Nazara/Math/Matrix4.hpp>
|
||||
|
|
@ -15,24 +16,22 @@
|
|||
#include <Nazara/Math/Vector3.hpp>
|
||||
#include <Nazara/Renderer/RenderTarget.hpp>
|
||||
|
||||
class NAZARA_API NzCamera : public NzSceneNode, NzRenderTarget::Listener
|
||||
class NAZARA_API NzCamera : public NzAbstractViewer, public NzNode, NzRenderTarget::Listener
|
||||
{
|
||||
public:
|
||||
NzCamera();
|
||||
~NzCamera();
|
||||
|
||||
void Activate();
|
||||
|
||||
void EnsureFrustumUpdate() const;
|
||||
void EnsureProjectionMatrixUpdate() const;
|
||||
void EnsureViewMatrixUpdate() const;
|
||||
void EnsureViewportUpdate() const;
|
||||
|
||||
float GetAspectRatio() const;
|
||||
const NzBoundingVolumef& GetBoundingVolume() const override;
|
||||
NzVector3f GetEyePosition() const;
|
||||
float GetFOV() const;
|
||||
const NzFrustumf& GetFrustum() const;
|
||||
const NzMatrix4f& GetProjectionMatrix() const;
|
||||
nzSceneNodeType GetSceneNodeType() const override;
|
||||
const NzRenderTarget* GetTarget() const;
|
||||
const NzRectf& GetTargetRegion() const;
|
||||
const NzMatrix4f& GetViewMatrix() const;
|
||||
|
|
@ -49,22 +48,17 @@ class NAZARA_API NzCamera : public NzSceneNode, NzRenderTarget::Listener
|
|||
void SetZNear(float zNear);
|
||||
|
||||
private:
|
||||
void AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const override;
|
||||
void Invalidate();
|
||||
void ApplyView() const override;
|
||||
void Invalidate() override;
|
||||
|
||||
void OnRenderTargetReleased(const NzRenderTarget* renderTarget, void* userdata) override;
|
||||
bool OnRenderTargetSizeChange(const NzRenderTarget* renderTarget, void* userdata) override;
|
||||
|
||||
void Register() override;
|
||||
void Unregister() override;
|
||||
|
||||
void UpdateFrustum() const;
|
||||
void UpdateProjectionMatrix() const;
|
||||
void UpdateViewMatrix() const;
|
||||
void UpdateViewport() const;
|
||||
|
||||
bool VisibilityTest(const NzCamera* camera) override;
|
||||
|
||||
mutable NzFrustumf m_frustum;
|
||||
mutable NzMatrix4f m_projectionMatrix;
|
||||
mutable NzMatrix4f m_viewMatrix;
|
||||
|
|
|
|||
|
|
@ -28,10 +28,10 @@ enum nzLightType
|
|||
|
||||
enum nzSceneNodeType
|
||||
{
|
||||
nzSceneNodeType_Camera, // NzCamera
|
||||
nzSceneNodeType_Light, // NzLight
|
||||
nzSceneNodeType_Model, // NzModel
|
||||
nzSceneNodeType_Root, // NzSceneRoot
|
||||
nzSceneNodeType_Sprite, // NzSprite
|
||||
nzSceneNodeType_User,
|
||||
|
||||
nzSceneNodeType_Max = nzSceneNodeType_User
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ class NAZARA_API NzForwardRenderQueue : public NzAbstractRenderQueue, NzResource
|
|||
void AddDrawable(const NzDrawable* drawable);
|
||||
void AddLight(const NzLight* light);
|
||||
void AddModel(const NzModel* model);
|
||||
void AddSprite(const NzSprite* sprite);
|
||||
|
||||
void Clear(bool fully);
|
||||
|
||||
|
|
@ -40,32 +41,17 @@ class NAZARA_API NzForwardRenderQueue : public NzAbstractRenderQueue, NzResource
|
|||
private:
|
||||
bool OnResourceDestroy(const NzResource* resource, int index) override;
|
||||
|
||||
struct ModelMaterialComparator
|
||||
{
|
||||
bool operator()(const NzMaterial* mat1, const NzMaterial* mat2);
|
||||
};
|
||||
|
||||
struct SkeletalData
|
||||
{
|
||||
///TODO
|
||||
NzMatrix4f transformMatrix;
|
||||
};
|
||||
|
||||
struct SkeletalMeshComparator
|
||||
{
|
||||
bool operator()(const NzSkeletalMesh* subMesh1, const NzSkeletalMesh* subMesh2);
|
||||
};
|
||||
|
||||
struct StaticData
|
||||
{
|
||||
NzMatrix4f transformMatrix;
|
||||
};
|
||||
|
||||
struct StaticMeshComparator
|
||||
{
|
||||
bool operator()(const NzStaticMesh* subMesh1, const NzStaticMesh* subMesh2);
|
||||
};
|
||||
|
||||
struct TransparentModel
|
||||
{
|
||||
NzMatrix4f transformMatrix;
|
||||
|
|
@ -83,17 +69,42 @@ class NAZARA_API NzForwardRenderQueue : public NzAbstractRenderQueue, NzResource
|
|||
NzStaticMesh* mesh;
|
||||
};
|
||||
|
||||
typedef std::map<const NzSkeletalMesh*, std::vector<SkeletalData>, SkeletalMeshComparator> SkeletalMeshContainer;
|
||||
typedef std::map<const NzStaticMesh*, std::pair<NzSpheref, std::vector<StaticData>>, StaticMeshComparator> StaticMeshContainer;
|
||||
typedef std::map<const NzMaterial*, std::tuple<bool, SkeletalMeshContainer, StaticMeshContainer>, ModelMaterialComparator> MeshContainer;
|
||||
|
||||
MeshContainer opaqueModels;
|
||||
std::vector<std::pair<unsigned int, bool>> transparentsModels;
|
||||
struct BatchedModelMaterialComparator
|
||||
{
|
||||
bool operator()(const NzMaterial* mat1, const NzMaterial* mat2);
|
||||
};
|
||||
|
||||
struct BatchedSpriteMaterialComparator
|
||||
{
|
||||
bool operator()(const NzMaterial* mat1, const NzMaterial* mat2);
|
||||
};
|
||||
|
||||
struct BatchedSkeletalMeshComparator
|
||||
{
|
||||
bool operator()(const NzSkeletalMesh* subMesh1, const NzSkeletalMesh* subMesh2);
|
||||
};
|
||||
|
||||
struct BatchedStaticMeshComparator
|
||||
{
|
||||
bool operator()(const NzStaticMesh* subMesh1, const NzStaticMesh* subMesh2);
|
||||
};
|
||||
|
||||
typedef std::map<const NzSkeletalMesh*, std::vector<SkeletalData>, BatchedSkeletalMeshComparator> BatchedSkeletalMeshContainer;
|
||||
typedef std::map<const NzStaticMesh*, std::pair<NzSpheref, std::vector<StaticData>>, BatchedStaticMeshComparator> BatchedStaticMeshContainer;
|
||||
typedef std::map<const NzMaterial*, std::tuple<bool, bool, BatchedSkeletalMeshContainer, BatchedStaticMeshContainer>, BatchedModelMaterialComparator> BatchedModelContainer;
|
||||
typedef std::map<const NzMaterial*, std::vector<const NzSprite*>> BatchedSpriteContainer;
|
||||
typedef std::vector<const NzLight*> LightContainer;
|
||||
typedef std::vector<std::pair<unsigned int, bool>> TransparentModelContainer;
|
||||
|
||||
BatchedModelContainer opaqueModels;
|
||||
BatchedSpriteContainer sprites;
|
||||
TransparentModelContainer transparentsModels;
|
||||
std::vector<TransparentSkeletalModel> transparentSkeletalModels;
|
||||
std::vector<TransparentStaticModel> transparentStaticModels;
|
||||
std::vector<const NzDrawable*> otherDrawables;
|
||||
std::vector<const NzLight*> directionnalLights;
|
||||
std::vector<const NzLight*> lights;
|
||||
LightContainer directionnalLights;
|
||||
LightContainer lights;
|
||||
};
|
||||
|
||||
#endif // NAZARA_FORWARDRENDERQUEUE_HPP
|
||||
|
|
|
|||
|
|
@ -10,12 +10,17 @@
|
|||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <Nazara/Graphics/AbstractRenderTechnique.hpp>
|
||||
#include <Nazara/Graphics/ForwardRenderQueue.hpp>
|
||||
#include <Nazara/Graphics/LightManager.hpp>
|
||||
#include <Nazara/Utility/IndexBuffer.hpp>
|
||||
#include <Nazara/Utility/VertexBuffer.hpp>
|
||||
|
||||
class NzLightManager;
|
||||
|
||||
class NAZARA_API NzForwardRenderTechnique : public NzAbstractRenderTechnique
|
||||
{
|
||||
public:
|
||||
NzForwardRenderTechnique();
|
||||
~NzForwardRenderTechnique() = default;
|
||||
~NzForwardRenderTechnique();
|
||||
|
||||
void Clear(const NzScene* scene);
|
||||
void Draw(const NzScene* scene);
|
||||
|
|
@ -26,7 +31,15 @@ class NAZARA_API NzForwardRenderTechnique : public NzAbstractRenderTechnique
|
|||
void SetMaxLightsPerObject(unsigned int lightCount);
|
||||
|
||||
private:
|
||||
void DrawOpaqueModels(const NzScene* scene, NzForwardRenderQueue::BatchedModelContainer& opaqueModels);
|
||||
void DrawSprites(const NzScene* scene, NzForwardRenderQueue::BatchedSpriteContainer& sprites);
|
||||
void DrawTransparentModels(const NzScene* scene, NzForwardRenderQueue::TransparentModelContainer& transparentModels);
|
||||
|
||||
NzForwardRenderQueue m_renderQueue;
|
||||
NzIndexBufferRef m_indexBuffer;
|
||||
NzLightManager m_directionnalLights;
|
||||
NzLightManager m_lights;
|
||||
NzVertexBuffer m_spriteBuffer;
|
||||
unsigned int m_maxLightsPerObject;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -49,11 +49,11 @@ class NAZARA_API NzLight : public NzSceneNode
|
|||
static void Disable(const NzShaderProgram* program, unsigned int lightUnit);
|
||||
|
||||
private:
|
||||
void Invalidate();
|
||||
void Register();
|
||||
void Unregister();
|
||||
bool FrustumCull(const NzFrustumf& frustum) override;
|
||||
void Invalidate() override;
|
||||
void Register() override;
|
||||
void Unregister() override;
|
||||
void UpdateBoundingVolume() const;
|
||||
bool VisibilityTest(const NzCamera* camera) override;
|
||||
|
||||
nzLightType m_type;
|
||||
mutable NzBoundingVolumef m_boundingVolume;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
// Copyright (C) 2013 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_LIGHTMANAGER_HPP
|
||||
#define NAZARA_LIGHTMANAGER_HPP
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <Nazara/Math/Vector3.hpp>
|
||||
|
||||
class NzLight;
|
||||
|
||||
class NAZARA_API NzLightManager
|
||||
{
|
||||
public:
|
||||
NzLightManager();
|
||||
NzLightManager(const NzLight** lights, unsigned int lightCount);
|
||||
~NzLightManager() = default;
|
||||
|
||||
void AddLights(const NzLight** lights, unsigned int lightCount);
|
||||
|
||||
void Clear();
|
||||
|
||||
unsigned int ComputeClosestLights(const NzVector3f& position, float squaredRadius, unsigned int maxResults);
|
||||
|
||||
const NzLight* GetLight(unsigned int index) const;
|
||||
unsigned int GetLightCount() const;
|
||||
const NzLight* GetResult(unsigned int i) const;
|
||||
|
||||
bool IsEmpty() const;
|
||||
|
||||
void SetLights(const NzLight** lights, unsigned int lightCount);
|
||||
|
||||
private:
|
||||
struct Light
|
||||
{
|
||||
const NzLight* light;
|
||||
unsigned int score;
|
||||
};
|
||||
|
||||
std::vector<std::pair<const NzLight**, unsigned int>> m_lights;
|
||||
std::vector<Light> m_results;
|
||||
unsigned int m_lightCount;
|
||||
};
|
||||
|
||||
#endif // NAZARA_LIGHTMANAGER_HPP
|
||||
|
|
@ -88,12 +88,12 @@ class NAZARA_API NzModel : public NzSceneNode, public NzUpdatable
|
|||
NzModel& operator=(NzModel&& node);
|
||||
|
||||
private:
|
||||
bool FrustumCull(const NzFrustumf& frustum) override;
|
||||
void Invalidate() override;
|
||||
void Register() override;
|
||||
void Unregister() override;
|
||||
void Update() override;
|
||||
void UpdateBoundingVolume() const;
|
||||
bool VisibilityTest(const NzCamera* camera) override;
|
||||
|
||||
std::vector<NzMaterialRef> m_materials;
|
||||
NzAnimationRef m_animation;
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include <Nazara/Math/Frustum.hpp>
|
||||
|
||||
class NzAbstractRenderQueue;
|
||||
class NzAbstractViewer;
|
||||
class NzCamera;
|
||||
class NzLight;
|
||||
class NzModel;
|
||||
|
|
@ -36,11 +37,11 @@ class NAZARA_API NzScene
|
|||
void Cull();
|
||||
void Draw();
|
||||
|
||||
NzCamera* GetActiveCamera() const;
|
||||
NzColor GetAmbientColor() const;
|
||||
NzAbstractBackground* GetBackground() const;
|
||||
NzAbstractRenderTechnique* GetRenderTechnique() const;
|
||||
NzSceneNode& GetRoot() const;
|
||||
NzAbstractViewer* GetViewer() const;
|
||||
float GetUpdateTime() const;
|
||||
unsigned int GetUpdatePerSecond() const;
|
||||
|
||||
|
|
@ -49,6 +50,7 @@ class NAZARA_API NzScene
|
|||
void SetAmbientColor(const NzColor& color);
|
||||
void SetBackground(NzAbstractBackground* background);
|
||||
void SetRenderTechnique(NzAbstractRenderTechnique* renderTechnique);
|
||||
void SetViewer(NzAbstractViewer* viewer);
|
||||
void SetUpdatePerSecond(unsigned int updatePerSecond);
|
||||
|
||||
void UnregisterForUpdate(NzUpdatable* object);
|
||||
|
|
@ -59,8 +61,7 @@ class NAZARA_API NzScene
|
|||
operator const NzSceneNode&() const;
|
||||
|
||||
private:
|
||||
void RecursiveCameraCull(NzAbstractRenderQueue* renderQueue, const NzCamera* camera, NzNode* node);
|
||||
void SetActiveCamera(NzCamera* camera);
|
||||
void RecursiveFrustumCull(NzAbstractRenderQueue* renderQueue, const NzFrustumf& frustum, NzNode* node);
|
||||
|
||||
NzSceneImpl* m_impl;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright (C) 2013 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_SCENELAYER_HPP
|
||||
#define NAZARA_SCENELAYER_HPP
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
|
||||
class NzAbstractRenderTechnique;
|
||||
class NzAbstractViewer;
|
||||
|
||||
class NAZARA_API NzSceneLayer
|
||||
{
|
||||
public:
|
||||
NzSceneLayer();
|
||||
~NzSceneLayer();
|
||||
|
||||
void Draw();
|
||||
|
||||
nzUInt32 GetBufferClearFlags() const;
|
||||
NzAbstractRenderQueue* GetRenderQueue() const;
|
||||
NzAbstractRenderTechnique* GetRenderTechnique() const;
|
||||
NzScene* GetScene() const;
|
||||
NzAbstractViewer* GetViewer() const;
|
||||
|
||||
void SetBufferClearFlags(nzUInt32 flags);
|
||||
void SetRenderTechnique(NzAbstractRenderTechnique* renderTechnique);
|
||||
void SetViewer(NzAbstractViewer* viewer);
|
||||
};
|
||||
|
||||
#endif // NAZARA_SCENELAYER_HPP
|
||||
|
|
@ -35,18 +35,18 @@ class NAZARA_API NzSceneNode : public NzNode
|
|||
protected:
|
||||
virtual void OnParenting(const NzNode* parent) override;
|
||||
virtual void OnVisibilityChange(bool visibility);
|
||||
virtual bool FrustumCull(const NzFrustumf& frustum) = 0;
|
||||
void RecursiveSetScene(NzScene* scene, NzNode* node);
|
||||
virtual void Register();
|
||||
void SetScene(NzScene* scene);
|
||||
virtual void Unregister();
|
||||
virtual void Update();
|
||||
virtual bool VisibilityTest(const NzCamera* camera) = 0;
|
||||
|
||||
NzScene* m_scene;
|
||||
bool m_visible;
|
||||
|
||||
private:
|
||||
void UpdateVisibility(const NzCamera* camera);
|
||||
void UpdateVisibility(const NzFrustumf& frustum);
|
||||
};
|
||||
|
||||
#endif // NAZARA_SCENENODE_HPP
|
||||
|
|
|
|||
|
|
@ -24,9 +24,9 @@ class NAZARA_API NzSceneRoot : public NzSceneNode
|
|||
NzSceneRoot(NzScene* scene);
|
||||
virtual ~NzSceneRoot();
|
||||
|
||||
bool FrustumCull(const NzFrustumf& frustum) override;
|
||||
void Register();
|
||||
void Unregister();
|
||||
bool VisibilityTest(const NzCamera* camera) override;
|
||||
};
|
||||
|
||||
#endif // NAZARA_SCENEROOT_HPP
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
// Copyright (C) 2013 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_SCENENODE_HPP
|
||||
#define NAZARA_SCENENODE_HPP
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <Nazara/Graphics/Enums.hpp>
|
||||
#include <Nazara/Graphics/Scene.hpp>
|
||||
#include <Nazara/Math/BoundingVolume.hpp>
|
||||
#include <Nazara/Math/Frustum.hpp>
|
||||
#include <Nazara/Utility/Node.hpp>
|
||||
|
||||
class NAZARA_API NzSceneNode : public NzNode
|
||||
{
|
||||
friend class NzScene;
|
||||
|
||||
public:
|
||||
NzSceneNode();
|
||||
NzSceneNode(const NzSceneNode& node);
|
||||
virtual ~NzSceneNode();
|
||||
|
||||
virtual void AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const = 0;
|
||||
|
||||
virtual const NzBoundingVolumef& GetBoundingVolume() const = 0;
|
||||
nzNodeType GetNodeType() const final;
|
||||
NzScene* GetScene() const;
|
||||
virtual nzSceneNodeType GetSceneNodeType() const = 0;
|
||||
|
||||
bool IsVisible() const;
|
||||
|
||||
protected:
|
||||
virtual void OnParenting(const NzNode* parent) override;
|
||||
virtual void OnVisibilityChange(bool visibility);
|
||||
void RecursiveSetScene(NzScene* scene, NzNode* node);
|
||||
virtual void Register();
|
||||
void SetScene(NzScene* scene);
|
||||
virtual void Unregister();
|
||||
virtual void Update();
|
||||
virtual bool VisibilityTest(const NzCamera* camera) = 0;
|
||||
|
||||
NzScene* m_scene;
|
||||
bool m_visible;
|
||||
|
||||
private:
|
||||
void UpdateVisibility(const NzCamera& camera);
|
||||
};
|
||||
|
||||
#endif // NAZARA_SCENENODE_HPP
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
// Copyright (C) 2013 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_SPRITE_HPP
|
||||
#define NAZARA_SPRITE_HPP
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <Nazara/Graphics/SceneNode.hpp>
|
||||
#include <Nazara/Renderer/Material.hpp>
|
||||
|
||||
class NAZARA_API NzSprite : public NzSceneNode
|
||||
{
|
||||
public:
|
||||
NzSprite();
|
||||
NzSprite(const NzSprite& sprite);
|
||||
NzSprite(NzSprite&& sprite);
|
||||
~NzSprite();
|
||||
|
||||
void AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const override;
|
||||
|
||||
const NzBoundingVolumef& GetBoundingVolume() const override;
|
||||
NzMaterial* GetMaterial() const;
|
||||
nzSceneNodeType GetSceneNodeType() const override;
|
||||
const NzVector2f& GetSize() const;
|
||||
const NzRectf& GetTextureCoords() const;
|
||||
|
||||
void SetMaterial(NzMaterial* material);
|
||||
void SetSize(const NzVector2f& size);
|
||||
void SetTextureCoords(const NzRectf& coords);
|
||||
void SetTextureRect(const NzRectui& rect);
|
||||
|
||||
private:
|
||||
bool FrustumCull(const NzFrustumf& frustum) override;
|
||||
void Register() override;
|
||||
void Unregister() override;
|
||||
|
||||
NzRectf m_textureCoords;
|
||||
NzVector2f m_size;
|
||||
NzMaterialRef m_material;
|
||||
};
|
||||
|
||||
#endif // NAZARA_SPRITE_HPP
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
// Copyright (C) 2013 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_VIEW_HPP
|
||||
#define NAZARA_VIEW_HPP
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <Nazara/Graphics/AbstractViewer.hpp>
|
||||
#include <Nazara/Graphics/SceneNode.hpp>
|
||||
#include <Nazara/Math/Frustum.hpp>
|
||||
#include <Nazara/Math/Matrix4.hpp>
|
||||
#include <Nazara/Math/Rect.hpp>
|
||||
#include <Nazara/Math/Vector3.hpp>
|
||||
#include <Nazara/Renderer/RenderTarget.hpp>
|
||||
|
||||
class NAZARA_API NzView : public NzAbstractViewer, public NzNode, NzRenderTarget::Listener
|
||||
{
|
||||
public:
|
||||
NzView();
|
||||
~NzView();
|
||||
|
||||
void EnsureFrustumUpdate() const;
|
||||
void EnsureProjectionMatrixUpdate() const;
|
||||
void EnsureViewMatrixUpdate() const;
|
||||
void EnsureViewportUpdate() const;
|
||||
|
||||
float GetAspectRatio() const;
|
||||
NzVector3f GetEyePosition() const;
|
||||
const NzFrustumf& GetFrustum() const;
|
||||
const NzMatrix4f& GetProjectionMatrix() const;
|
||||
const NzRenderTarget* GetTarget() const;
|
||||
const NzRectf& GetTargetRegion() const;
|
||||
const NzMatrix4f& GetViewMatrix() const;
|
||||
const NzRectui& GetViewport() const;
|
||||
float GetZFar() const;
|
||||
float GetZNear() const;
|
||||
|
||||
void SetTarget(const NzRenderTarget* renderTarget);
|
||||
void SetTarget(const NzRenderTarget& renderTarget);
|
||||
void SetTargetRegion(const NzRectf& region);
|
||||
void SetViewport(const NzRectui& viewport);
|
||||
void SetZFar(float zFar);
|
||||
void SetZNear(float zNear);
|
||||
|
||||
private:
|
||||
void ApplyView() const override;
|
||||
void Invalidate() override;
|
||||
|
||||
void OnRenderTargetReleased(const NzRenderTarget* renderTarget, void* userdata) override;
|
||||
bool OnRenderTargetSizeChange(const NzRenderTarget* renderTarget, void* userdata) override;
|
||||
|
||||
void UpdateFrustum() const;
|
||||
void UpdateProjectionMatrix() const;
|
||||
void UpdateViewMatrix() const;
|
||||
void UpdateViewport() const;
|
||||
|
||||
mutable NzFrustumf m_frustum;
|
||||
mutable NzMatrix4f m_projectionMatrix;
|
||||
mutable NzMatrix4f m_viewMatrix;
|
||||
NzRectf m_targetRegion;
|
||||
mutable NzRectui m_viewport;
|
||||
const NzRenderTarget* m_target;
|
||||
mutable bool m_frustumUpdated;
|
||||
mutable bool m_projectionMatrixUpdated;
|
||||
mutable bool m_viewMatrixUpdated;
|
||||
mutable bool m_viewportUpdated;
|
||||
float m_zFar;
|
||||
float m_zNear;
|
||||
};
|
||||
|
||||
#endif // NAZARA_VIEW_HPP
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// This file was automatically generated on 13 Mar 2013 at 23:20:31
|
||||
// This file was automatically generated on 21 Aug 2013 at 19:43:23
|
||||
|
||||
/*
|
||||
Nazara Engine - Renderer module
|
||||
|
|
@ -38,12 +38,14 @@
|
|||
#include <Nazara/Renderer/OcclusionQuery.hpp>
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
#include <Nazara/Renderer/RenderStates.hpp>
|
||||
#include <Nazara/Renderer/RenderTarget.hpp>
|
||||
#include <Nazara/Renderer/RenderTargetParameters.hpp>
|
||||
#include <Nazara/Renderer/RenderTexture.hpp>
|
||||
#include <Nazara/Renderer/RenderWindow.hpp>
|
||||
#include <Nazara/Renderer/ShaderProgram.hpp>
|
||||
#include <Nazara/Renderer/ShaderProgramManager.hpp>
|
||||
#include <Nazara/Renderer/ShaderProgramManagerParams.hpp>
|
||||
#include <Nazara/Renderer/Texture.hpp>
|
||||
#include <Nazara/Renderer/TextureSampler.hpp>
|
||||
|
||||
|
|
|
|||
|
|
@ -179,13 +179,14 @@ enum nzShaderTarget
|
|||
nzShaderTarget_FullscreenQuad,
|
||||
nzShaderTarget_Model,
|
||||
nzShaderTarget_None,
|
||||
nzShaderTarget_Sprite,
|
||||
|
||||
nzShaderTarget_Max = nzShaderTarget_None
|
||||
nzShaderTarget_Max = nzShaderTarget_Sprite
|
||||
};
|
||||
|
||||
enum nzShaderUniform
|
||||
{
|
||||
nzShaderUniform_CameraPosition,
|
||||
nzShaderUniform_EyePosition,
|
||||
nzShaderUniform_InvTargetSize,
|
||||
nzShaderUniform_MaterialAlphaMap,
|
||||
nzShaderUniform_MaterialAlphaThreshold,
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ class NAZARA_API NzRenderWindow : public NzRenderTarget, public NzWindow
|
|||
private:
|
||||
bool OnWindowCreated() override;
|
||||
void OnWindowDestroy() override;
|
||||
void OnWindowResized() override;
|
||||
|
||||
NzClock m_clock;
|
||||
NzContextParameters m_parameters;
|
||||
|
|
|
|||
|
|
@ -30,6 +30,13 @@ struct NzShaderProgramManagerParams
|
|||
bool specularMapping;
|
||||
};
|
||||
|
||||
struct Sprite
|
||||
{
|
||||
bool alphaMapping;
|
||||
bool alphaTest;
|
||||
bool diffuseMapping;
|
||||
};
|
||||
|
||||
nzShaderTarget target;
|
||||
nzUInt32 flags;
|
||||
|
||||
|
|
@ -37,6 +44,7 @@ struct NzShaderProgramManagerParams
|
|||
{
|
||||
FullscreenQuad fullscreenQuad;
|
||||
Model model;
|
||||
Sprite sprite;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
// Copyright (C) 2013 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/AbstractViewer.hpp>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
NzAbstractViewer::~NzAbstractViewer() = default;
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
NzCamera::NzCamera() :
|
||||
m_viewport(0.f, 0.f, 1.f, 1.f),
|
||||
m_targetRegion(0.f, 0.f, 1.f, 1.f),
|
||||
m_target(nullptr),
|
||||
m_frustumUpdated(false),
|
||||
m_projectionMatrixUpdated(false),
|
||||
|
|
@ -28,26 +28,6 @@ NzCamera::~NzCamera()
|
|||
m_target->RemoveListener(this);
|
||||
}
|
||||
|
||||
void NzCamera::Activate()
|
||||
{
|
||||
#ifdef NAZARA_GRAPHICS_SAFE
|
||||
if (!m_target)
|
||||
{
|
||||
NazaraError("Camera has no render target");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!m_viewportUpdated)
|
||||
UpdateViewport();
|
||||
|
||||
NzRenderer::SetTarget(m_target);
|
||||
NzRenderer::SetViewport(m_viewport);
|
||||
|
||||
if (m_scene)
|
||||
m_scene->SetActiveCamera(this);
|
||||
}
|
||||
|
||||
void NzCamera::EnsureFrustumUpdate() const
|
||||
{
|
||||
if (!m_frustumUpdated)
|
||||
|
|
@ -66,16 +46,20 @@ void NzCamera::EnsureViewMatrixUpdate() const
|
|||
UpdateViewMatrix();
|
||||
}
|
||||
|
||||
void NzCamera::EnsureViewportUpdate() const
|
||||
{
|
||||
if (!m_viewportUpdated)
|
||||
UpdateViewport();
|
||||
}
|
||||
|
||||
float NzCamera::GetAspectRatio() const
|
||||
{
|
||||
return m_aspectRatio;
|
||||
}
|
||||
|
||||
const NzBoundingVolumef& NzCamera::GetBoundingVolume() const
|
||||
NzVector3f NzCamera::GetEyePosition() const
|
||||
{
|
||||
///TODO: Remplacer par le bounding volume du Frustum ?
|
||||
static NzBoundingVolumef dummy(nzExtend_Null);
|
||||
return dummy;
|
||||
return GetPosition(nzCoordSys_Global);
|
||||
}
|
||||
|
||||
float NzCamera::GetFOV() const
|
||||
|
|
@ -99,11 +83,6 @@ const NzMatrix4f& NzCamera::GetProjectionMatrix() const
|
|||
return m_projectionMatrix;
|
||||
}
|
||||
|
||||
nzSceneNodeType NzCamera::GetSceneNodeType() const
|
||||
{
|
||||
return nzSceneNodeType_Camera;
|
||||
}
|
||||
|
||||
const NzRenderTarget* NzCamera::GetTarget() const
|
||||
{
|
||||
return m_target;
|
||||
|
|
@ -174,6 +153,9 @@ void NzCamera::SetTarget(const NzRenderTarget& renderTarget)
|
|||
void NzCamera::SetTargetRegion(const NzRectf& region)
|
||||
{
|
||||
m_targetRegion = region;
|
||||
|
||||
m_frustumUpdated = false;
|
||||
m_projectionMatrixUpdated = false;
|
||||
m_viewportUpdated = false;
|
||||
}
|
||||
|
||||
|
|
@ -210,16 +192,33 @@ void NzCamera::SetZNear(float zNear)
|
|||
m_projectionMatrixUpdated = false;
|
||||
}
|
||||
|
||||
void NzCamera::AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const
|
||||
void NzCamera::ApplyView() const
|
||||
{
|
||||
NazaraUnused(renderQueue);
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
if (!m_target)
|
||||
{
|
||||
NazaraError("Camera has no render target");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
NazaraInternalError("SceneNode::AddToRenderQueue() called on Camera");
|
||||
if (!m_projectionMatrixUpdated)
|
||||
UpdateProjectionMatrix();
|
||||
|
||||
if (!m_viewMatrixUpdated)
|
||||
UpdateViewMatrix();
|
||||
|
||||
if (!m_viewportUpdated)
|
||||
UpdateViewport();
|
||||
|
||||
NzRenderer::SetMatrix(nzMatrixType_Projection, m_projectionMatrix);
|
||||
NzRenderer::SetMatrix(nzMatrixType_View, m_viewMatrix);
|
||||
NzRenderer::SetViewport(m_viewport);
|
||||
}
|
||||
|
||||
void NzCamera::Invalidate()
|
||||
{
|
||||
NzSceneNode::Invalidate();
|
||||
NzNode::Invalidate();
|
||||
|
||||
// Le frustum et la view matrix dépendent des paramètres du node, invalidons-les
|
||||
m_frustumUpdated = false;
|
||||
|
|
@ -241,21 +240,17 @@ bool NzCamera::OnRenderTargetSizeChange(const NzRenderTarget* renderTarget, void
|
|||
NazaraUnused(userdata);
|
||||
|
||||
if (renderTarget == m_target)
|
||||
{
|
||||
m_frustumUpdated = false;
|
||||
m_projectionMatrixUpdated = false;
|
||||
m_viewportUpdated = false;
|
||||
}
|
||||
else
|
||||
NazaraInternalError("Not listening to " + NzString::Pointer(renderTarget));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzCamera::Register()
|
||||
{
|
||||
}
|
||||
|
||||
void NzCamera::Unregister()
|
||||
{
|
||||
}
|
||||
|
||||
void NzCamera::UpdateFrustum() const
|
||||
{
|
||||
if (!m_projectionMatrixUpdated)
|
||||
|
|
@ -270,6 +265,9 @@ void NzCamera::UpdateFrustum() const
|
|||
|
||||
void NzCamera::UpdateProjectionMatrix() const
|
||||
{
|
||||
if (!m_viewportUpdated)
|
||||
UpdateViewport(); // Peut affecter l'aspect ratio
|
||||
|
||||
m_projectionMatrix.MakePerspective(m_fov, m_aspectRatio, m_zNear, m_zFar);
|
||||
m_projectionMatrixUpdated = true;
|
||||
}
|
||||
|
|
@ -288,8 +286,8 @@ void NzCamera::UpdateViewport() const
|
|||
unsigned int width = m_target->GetWidth();
|
||||
unsigned int height = std::max(m_target->GetHeight(), 1U);
|
||||
|
||||
float vWidth = width * m_viewport.width;
|
||||
float vHeight = height * m_viewport.height;
|
||||
float vWidth = width * m_targetRegion.width;
|
||||
float vHeight = height * m_targetRegion.height;
|
||||
float aspectRatio = vWidth/vHeight;
|
||||
|
||||
if (!NzNumberEquals(m_aspectRatio, aspectRatio, 0.001f))
|
||||
|
|
@ -305,10 +303,3 @@ void NzCamera::UpdateViewport() const
|
|||
m_viewport.height = vHeight;
|
||||
m_viewportUpdated = true;
|
||||
}
|
||||
|
||||
bool NzCamera::VisibilityTest(const NzCamera* camera)
|
||||
{
|
||||
NazaraUnused(camera);
|
||||
//NazaraInternalError("SceneNode::IsVisible() called on Camera");
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <Nazara/Graphics/Camera.hpp>
|
||||
#include <Nazara/Graphics/Light.hpp>
|
||||
#include <Nazara/Graphics/Model.hpp>
|
||||
#include <Nazara/Graphics/Sprite.hpp>
|
||||
#include <Nazara/Renderer/Material.hpp>
|
||||
#include <Nazara/Utility/SkeletalMesh.hpp>
|
||||
#include <Nazara/Utility/StaticMesh.hpp>
|
||||
|
|
@ -131,13 +132,18 @@ void NzForwardRenderQueue::AddModel(const NzModel* model)
|
|||
}
|
||||
else
|
||||
{
|
||||
auto pair = opaqueModels.insert(std::make_pair(material, MeshContainer::mapped_type()));
|
||||
auto pair = opaqueModels.insert(std::make_pair(material, BatchedModelContainer::mapped_type()));
|
||||
if (pair.second)
|
||||
material->AddResourceListener(this, ResourceType_Material);
|
||||
|
||||
auto& meshMap = std::get<2>(pair.first->second);
|
||||
bool& used = std::get<0>(pair.first->second);
|
||||
bool& enableInstancing = std::get<1>(pair.first->second);
|
||||
|
||||
auto pair2 = meshMap.insert(std::make_pair(staticMesh, StaticMeshContainer::mapped_type()));
|
||||
used = true;
|
||||
|
||||
auto& meshMap = std::get<3>(pair.first->second);
|
||||
|
||||
auto pair2 = meshMap.insert(std::make_pair(staticMesh, BatchedStaticMeshContainer::mapped_type()));
|
||||
if (pair2.second)
|
||||
{
|
||||
staticMesh->AddResourceListener(this, ResourceType_StaticMesh);
|
||||
|
|
@ -153,7 +159,7 @@ void NzForwardRenderQueue::AddModel(const NzModel* model)
|
|||
|
||||
// As-t-on suffisamment d'instances pour que le coût d'utilisation de l'instancing soit payé ?
|
||||
if (instanceCount >= NAZARA_GRAPHICS_INSTANCING_MIN_INSTANCES_COUNT)
|
||||
std::get<0>(pair.first->second) = true; // Apparemment oui, activons l'instancing avec ce matériau
|
||||
enableInstancing = true; // Apparemment oui, activons l'instancing avec ce matériau
|
||||
|
||||
staticDataContainer.resize(instanceCount);
|
||||
StaticData& data = staticDataContainer.back();
|
||||
|
|
@ -166,6 +172,19 @@ void NzForwardRenderQueue::AddModel(const NzModel* model)
|
|||
}
|
||||
}
|
||||
|
||||
void NzForwardRenderQueue::AddSprite(const NzSprite* sprite)
|
||||
{
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
if (!sprite)
|
||||
{
|
||||
NazaraError("Invalid sprite");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
sprites[sprite->GetMaterial()].push_back(sprite);
|
||||
}
|
||||
|
||||
void NzForwardRenderQueue::Clear(bool fully)
|
||||
{
|
||||
directionnalLights.clear();
|
||||
|
|
@ -176,7 +195,10 @@ void NzForwardRenderQueue::Clear(bool fully)
|
|||
transparentStaticModels.clear();
|
||||
|
||||
if (fully)
|
||||
{
|
||||
opaqueModels.clear();
|
||||
sprites.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void NzForwardRenderQueue::Sort(const NzCamera& camera)
|
||||
|
|
@ -219,7 +241,7 @@ bool NzForwardRenderQueue::OnResourceDestroy(const NzResource* resource, int ind
|
|||
case ResourceType_SkeletalMesh:
|
||||
{
|
||||
for (auto& pair : opaqueModels)
|
||||
std::get<1>(pair.second).erase(static_cast<const NzSkeletalMesh*>(resource));
|
||||
std::get<2>(pair.second).erase(static_cast<const NzSkeletalMesh*>(resource));
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
@ -227,7 +249,7 @@ bool NzForwardRenderQueue::OnResourceDestroy(const NzResource* resource, int ind
|
|||
case ResourceType_StaticMesh:
|
||||
{
|
||||
for (auto& pair : opaqueModels)
|
||||
std::get<2>(pair.second).erase(static_cast<const NzStaticMesh*>(resource));
|
||||
std::get<3>(pair.second).erase(static_cast<const NzStaticMesh*>(resource));
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
@ -236,7 +258,7 @@ bool NzForwardRenderQueue::OnResourceDestroy(const NzResource* resource, int ind
|
|||
return false; // Nous ne voulons plus recevoir d'évènement de cette ressource
|
||||
}
|
||||
|
||||
bool NzForwardRenderQueue::ModelMaterialComparator::operator()(const NzMaterial* mat1, const NzMaterial* mat2)
|
||||
bool NzForwardRenderQueue::BatchedModelMaterialComparator::operator()(const NzMaterial* mat1, const NzMaterial* mat2)
|
||||
{
|
||||
for (unsigned int i = 0; i <= nzShaderFlags_Max; ++i)
|
||||
{
|
||||
|
|
@ -255,7 +277,26 @@ bool NzForwardRenderQueue::ModelMaterialComparator::operator()(const NzMaterial*
|
|||
return mat1 < mat2;
|
||||
}
|
||||
|
||||
bool NzForwardRenderQueue::SkeletalMeshComparator::operator()(const NzSkeletalMesh* subMesh1, const NzSkeletalMesh* subMesh2)
|
||||
bool NzForwardRenderQueue::BatchedSpriteMaterialComparator::operator()(const NzMaterial* mat1, const NzMaterial* mat2)
|
||||
{
|
||||
for (unsigned int i = 0; i <= nzShaderFlags_Max; ++i)
|
||||
{
|
||||
const NzShaderProgram* program1 = mat1->GetShaderProgram(nzShaderTarget_Sprite, i);
|
||||
const NzShaderProgram* program2 = mat2->GetShaderProgram(nzShaderTarget_Sprite, i);
|
||||
|
||||
if (program1 != program2)
|
||||
return program1 < program2;
|
||||
}
|
||||
|
||||
const NzTexture* diffuseMap1 = mat1->GetDiffuseMap();
|
||||
const NzTexture* diffuseMap2 = mat2->GetDiffuseMap();
|
||||
if (diffuseMap1 != diffuseMap2)
|
||||
return diffuseMap1 < diffuseMap2;
|
||||
|
||||
return mat1 < mat2;
|
||||
}
|
||||
|
||||
bool NzForwardRenderQueue::BatchedSkeletalMeshComparator::operator()(const NzSkeletalMesh* subMesh1, const NzSkeletalMesh* subMesh2)
|
||||
{
|
||||
const NzIndexBuffer* iBuffer1 = subMesh1->GetIndexBuffer();
|
||||
const NzBuffer* buffer1 = (iBuffer1) ? iBuffer1->GetBuffer() : nullptr;
|
||||
|
|
@ -269,7 +310,7 @@ bool NzForwardRenderQueue::SkeletalMeshComparator::operator()(const NzSkeletalMe
|
|||
return buffer2 < buffer2;
|
||||
}
|
||||
|
||||
bool NzForwardRenderQueue::StaticMeshComparator::operator()(const NzStaticMesh* subMesh1, const NzStaticMesh* subMesh2)
|
||||
bool NzForwardRenderQueue::BatchedStaticMeshComparator::operator()(const NzStaticMesh* subMesh1, const NzStaticMesh* subMesh2)
|
||||
{
|
||||
const NzIndexBuffer* iBuffer1 = subMesh1->GetIndexBuffer();
|
||||
const NzBuffer* buffer1 = (iBuffer1) ? iBuffer1->GetBuffer() : nullptr;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <Nazara/Graphics/Camera.hpp>
|
||||
#include <Nazara/Graphics/Drawable.hpp>
|
||||
#include <Nazara/Graphics/Light.hpp>
|
||||
#include <Nazara/Graphics/Sprite.hpp>
|
||||
#include <Nazara/Renderer/Config.hpp>
|
||||
#include <Nazara/Renderer/Material.hpp>
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
|
|
@ -19,106 +20,47 @@
|
|||
|
||||
namespace
|
||||
{
|
||||
class LightManager
|
||||
static NzIndexBuffer* s_indexBuffer = nullptr;
|
||||
unsigned int maxLightCount = 3; ///TODO: Constante sur le nombre maximum de lumières
|
||||
unsigned int s_maxSprites = 8192;
|
||||
|
||||
NzIndexBuffer* BuildIndexBuffer()
|
||||
{
|
||||
public:
|
||||
LightManager() = default;
|
||||
~LightManager() = default;
|
||||
std::unique_ptr<NzIndexBuffer> indexBuffer(new NzIndexBuffer(false, s_maxSprites*6, nzBufferStorage_Hardware, nzBufferUsage_Static));
|
||||
indexBuffer->SetPersistent(false);
|
||||
|
||||
unsigned int FindClosestLights(const NzLight** lights, unsigned int lightCount, const NzVector3f& position, float squaredRadius)
|
||||
{
|
||||
for (Light& light : m_lights)
|
||||
{
|
||||
light.light = nullptr;
|
||||
light.score = std::numeric_limits<unsigned int>::max(); // Nous jouons au Golf
|
||||
}
|
||||
NzBufferMapper<NzIndexBuffer> mapper(indexBuffer.get(), nzBufferAccess_WriteOnly);
|
||||
nzUInt16* indices = static_cast<nzUInt16*>(mapper.GetPointer());
|
||||
|
||||
for (unsigned int i = 0; i < lightCount; ++i)
|
||||
{
|
||||
const NzLight* light = *lights;
|
||||
for (unsigned int i = 0; i < s_maxSprites; ++i)
|
||||
{
|
||||
*indices++ = i*4 + 0;
|
||||
*indices++ = i*4 + 2;
|
||||
*indices++ = i*4 + 1;
|
||||
|
||||
unsigned int score = std::numeric_limits<unsigned int>::max();
|
||||
switch (light->GetLightType())
|
||||
{
|
||||
case nzLightType_Directional:
|
||||
score = 0; // Lumière choisie d'office
|
||||
break;
|
||||
*indices++ = i*4 + 2;
|
||||
*indices++ = i*4 + 3;
|
||||
*indices++ = i*4 + 1;
|
||||
}
|
||||
|
||||
case nzLightType_Point:
|
||||
{
|
||||
float lightRadius = light->GetRadius();
|
||||
|
||||
float squaredDistance = position.SquaredDistance(light->GetPosition());
|
||||
if (squaredDistance - squaredRadius <= lightRadius*lightRadius)
|
||||
score = static_cast<unsigned int>(squaredDistance*1000.f);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case nzLightType_Spot:
|
||||
{
|
||||
float lightRadius = light->GetRadius();
|
||||
|
||||
///TODO: Attribuer bonus/malus selon l'angle du spot ?
|
||||
float squaredDistance = position.SquaredDistance(light->GetPosition());
|
||||
if (squaredDistance - squaredRadius <= lightRadius*lightRadius)
|
||||
score = static_cast<unsigned int>(squaredDistance*1000.f);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (score < m_lights[0].score)
|
||||
{
|
||||
unsigned int j;
|
||||
for (j = 1; j < 3; ++j) ///TODO: Constante
|
||||
{
|
||||
if (score > m_lights[j].score)
|
||||
break;
|
||||
}
|
||||
|
||||
j--; // Position de la nouvelle lumière
|
||||
|
||||
// Décalage
|
||||
std::memcpy(&m_lights[0], &m_lights[1], j*sizeof(Light));
|
||||
|
||||
m_lights[j].light = light;
|
||||
m_lights[j].score = score;
|
||||
}
|
||||
|
||||
lights++;
|
||||
}
|
||||
|
||||
unsigned int i;
|
||||
for (i = 0; i < 3; ++i) ///TODO: Constante
|
||||
{
|
||||
if (m_lights[i].light)
|
||||
break;
|
||||
}
|
||||
|
||||
return 3-i; ///TODO: Constante
|
||||
}
|
||||
|
||||
const NzLight* GetLight(unsigned int i) const
|
||||
{
|
||||
///TODO: Constante
|
||||
return m_lights[3-i-1].light; // Les lumières sont stockées dans l'ordre inverse (De la plus éloignée à la plus proche)
|
||||
}
|
||||
|
||||
private:
|
||||
struct Light
|
||||
{
|
||||
const NzLight* light;
|
||||
unsigned int score;
|
||||
};
|
||||
|
||||
Light m_lights[3]; ///TODO: Constante
|
||||
};
|
||||
return indexBuffer.release();
|
||||
}
|
||||
}
|
||||
|
||||
NzForwardRenderTechnique::NzForwardRenderTechnique() :
|
||||
m_maxLightsPerObject(3) // Valeur totalement arbitraire
|
||||
m_spriteBuffer(NzVertexDeclaration::Get(nzVertexLayout_XYZ_UV), s_maxSprites*4, nzBufferStorage_Hardware, nzBufferUsage_Dynamic),
|
||||
m_maxLightsPerObject(maxLightCount)
|
||||
{
|
||||
if (!s_indexBuffer)
|
||||
s_indexBuffer = BuildIndexBuffer();
|
||||
|
||||
m_indexBuffer = s_indexBuffer;
|
||||
}
|
||||
|
||||
NzForwardRenderTechnique::~NzForwardRenderTechnique()
|
||||
{
|
||||
if (m_indexBuffer.Reset())
|
||||
s_indexBuffer = nullptr;
|
||||
}
|
||||
|
||||
void NzForwardRenderTechnique::Clear(const NzScene* scene)
|
||||
|
|
@ -134,247 +76,22 @@ void NzForwardRenderTechnique::Clear(const NzScene* scene)
|
|||
|
||||
void NzForwardRenderTechnique::Draw(const NzScene* scene)
|
||||
{
|
||||
///TODO: Regrouper les activations par méthode
|
||||
LightManager lightManager;
|
||||
// Rendu en projection perspective (3D)
|
||||
m_directionnalLights.SetLights(&m_renderQueue.directionnalLights[0], m_renderQueue.directionnalLights.size());
|
||||
m_lights.SetLights(&m_renderQueue.lights[0], m_renderQueue.lights.size());
|
||||
|
||||
const NzCamera* camera = scene->GetActiveCamera();
|
||||
const NzShaderProgram* lastProgram = nullptr;
|
||||
if (!m_renderQueue.opaqueModels.empty())
|
||||
DrawOpaqueModels(scene, m_renderQueue.opaqueModels);
|
||||
|
||||
NzRenderer::SetMatrix(nzMatrixType_Projection, camera->GetProjectionMatrix());
|
||||
NzRenderer::SetMatrix(nzMatrixType_View, camera->GetViewMatrix());
|
||||
if (!m_renderQueue.sprites.empty())
|
||||
DrawSprites(scene, m_renderQueue.sprites);
|
||||
|
||||
// Rendu des modèles opaques
|
||||
for (auto& matIt : m_renderQueue.opaqueModels)
|
||||
{
|
||||
NzForwardRenderQueue::SkeletalMeshContainer& skeletalContainer = std::get<1>(matIt.second);
|
||||
NzForwardRenderQueue::StaticMeshContainer& staticContainer = std::get<2>(matIt.second);
|
||||
if (!m_renderQueue.transparentsModels.empty())
|
||||
DrawTransparentModels(scene, m_renderQueue.transparentsModels);
|
||||
|
||||
if (!skeletalContainer.empty() || !staticContainer.empty())
|
||||
{
|
||||
const NzMaterial* material = matIt.first;
|
||||
|
||||
// La RenderQueue active ou non l'instancing selon le nombre d'instances
|
||||
bool renderQueueInstancing = std::get<0>(matIt.second);
|
||||
|
||||
// Nous utilisons de l'instancing que lorsqu'aucune lumière (autre que directionnelle) n'est active
|
||||
// Ceci car l'instancing n'est pas compatible avec la recherche des lumières les plus proches
|
||||
// (Le deferred shading n'a pas ce problème)
|
||||
bool instancing = m_instancingEnabled && m_renderQueue.lights.empty() && renderQueueInstancing;
|
||||
|
||||
// On commence par récupérer le programme du matériau
|
||||
const NzShaderProgram* program = material->GetShaderProgram(nzShaderTarget_Model, (instancing) ? nzShaderFlags_Instancing : 0);
|
||||
|
||||
unsigned int lightCount = 0;
|
||||
|
||||
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas
|
||||
if (program != lastProgram)
|
||||
{
|
||||
NzRenderer::SetShaderProgram(program);
|
||||
|
||||
// Couleur ambiante de la scène
|
||||
program->SendColor(program->GetUniformLocation(nzShaderUniform_SceneAmbient), scene->GetAmbientColor());
|
||||
// Position de la caméra
|
||||
program->SendVector(program->GetUniformLocation(nzShaderUniform_CameraPosition), camera->GetPosition());
|
||||
|
||||
// On envoie les lumières directionnelles s'il y a (Les mêmes pour tous)
|
||||
lightCount = m_renderQueue.directionnalLights.size();
|
||||
for (unsigned int i = 0; i < lightCount; ++i)
|
||||
m_renderQueue.directionnalLights[i]->Enable(program, i);
|
||||
|
||||
lastProgram = program;
|
||||
}
|
||||
|
||||
material->Apply(program);
|
||||
|
||||
// Meshs squelettiques
|
||||
/*if (!skeletalContainer.empty())
|
||||
{
|
||||
NzRenderer::SetVertexBuffer(m_skinningBuffer); // Vertex buffer commun
|
||||
for (auto& subMeshIt : container)
|
||||
{
|
||||
///TODO
|
||||
}
|
||||
}*/
|
||||
|
||||
// Meshs statiques
|
||||
for (auto& subMeshIt : staticContainer)
|
||||
{
|
||||
const NzSpheref& boundingSphere = subMeshIt.second.first;
|
||||
const NzStaticMesh* mesh = subMeshIt.first;
|
||||
std::vector<NzForwardRenderQueue::StaticData>& staticData = subMeshIt.second.second;
|
||||
|
||||
if (!staticData.empty())
|
||||
{
|
||||
const NzIndexBuffer* indexBuffer = mesh->GetIndexBuffer();
|
||||
const NzVertexBuffer* vertexBuffer = mesh->GetVertexBuffer();
|
||||
|
||||
// Gestion du draw call avant la boucle de rendu
|
||||
std::function<void(nzPrimitiveMode, unsigned int, unsigned int)> drawFunc;
|
||||
std::function<void(unsigned int, nzPrimitiveMode, unsigned int, unsigned int)> instancedDrawFunc;
|
||||
unsigned int indexCount;
|
||||
|
||||
if (indexBuffer)
|
||||
{
|
||||
drawFunc = NzRenderer::DrawIndexedPrimitives;
|
||||
indexCount = indexBuffer->GetIndexCount();
|
||||
instancedDrawFunc = NzRenderer::DrawIndexedPrimitivesInstanced;
|
||||
}
|
||||
else
|
||||
{
|
||||
drawFunc = NzRenderer::DrawPrimitives;
|
||||
indexCount = vertexBuffer->GetVertexCount();
|
||||
instancedDrawFunc = NzRenderer::DrawPrimitivesInstanced;
|
||||
}
|
||||
|
||||
NzRenderer::SetIndexBuffer(indexBuffer);
|
||||
NzRenderer::SetVertexBuffer(vertexBuffer);
|
||||
|
||||
nzPrimitiveMode primitiveMode = mesh->GetPrimitiveMode();
|
||||
if (instancing)
|
||||
{
|
||||
NzVertexBuffer* instanceBuffer = NzRenderer::GetInstanceBuffer();
|
||||
|
||||
instanceBuffer->SetVertexDeclaration(NzVertexDeclaration::Get(nzVertexLayout_Matrix4));
|
||||
|
||||
unsigned int stride = instanceBuffer->GetStride();
|
||||
|
||||
const NzForwardRenderQueue::StaticData* data = &staticData[0];
|
||||
unsigned int instanceCount = staticData.size();
|
||||
unsigned int maxInstanceCount = instanceBuffer->GetVertexCount();
|
||||
|
||||
while (instanceCount > 0)
|
||||
{
|
||||
unsigned int renderedInstanceCount = std::min(instanceCount, maxInstanceCount);
|
||||
instanceCount -= renderedInstanceCount;
|
||||
|
||||
NzBufferMapper<NzVertexBuffer> mapper(instanceBuffer, nzBufferAccess_DiscardAndWrite, 0, renderedInstanceCount);
|
||||
nzUInt8* ptr = reinterpret_cast<nzUInt8*>(mapper.GetPointer());
|
||||
|
||||
for (unsigned int i = 0; i < renderedInstanceCount; ++i)
|
||||
{
|
||||
std::memcpy(ptr, data->transformMatrix, sizeof(float)*16);
|
||||
|
||||
data++;
|
||||
ptr += stride;
|
||||
}
|
||||
|
||||
mapper.Unmap();
|
||||
|
||||
instancedDrawFunc(renderedInstanceCount, primitiveMode, 0, indexCount);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const NzForwardRenderQueue::StaticData& data : staticData)
|
||||
{
|
||||
// Calcul des lumières les plus proches
|
||||
if (lightCount < m_maxLightsPerObject && !m_renderQueue.lights.empty())
|
||||
{
|
||||
unsigned int count = lightManager.FindClosestLights(&m_renderQueue.lights[0], m_renderQueue.lights.size(), data.transformMatrix.GetTranslation() + boundingSphere.GetPosition(), boundingSphere.radius);
|
||||
count -= lightCount;
|
||||
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
lightManager.GetLight(i)->Enable(program, lightCount++);
|
||||
}
|
||||
|
||||
for (unsigned int i = lightCount; i < 3; ++i) ///TODO: Constante sur le nombre maximum de lumières
|
||||
NzLight::Disable(program, i);
|
||||
|
||||
NzRenderer::SetMatrix(nzMatrixType_World, data.transformMatrix);
|
||||
drawFunc(primitiveMode, 0, indexCount);
|
||||
}
|
||||
}
|
||||
staticData.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Et on remet à zéro l'instancing
|
||||
std::get<0>(matIt.second) = false;
|
||||
}
|
||||
|
||||
for (const std::pair<unsigned int, bool>& pair : m_renderQueue.transparentsModels)
|
||||
{
|
||||
// Matériau
|
||||
NzMaterial* material = (pair.second) ?
|
||||
m_renderQueue.transparentStaticModels[pair.first].material :
|
||||
m_renderQueue.transparentSkeletalModels[pair.first].material;
|
||||
|
||||
// On commence par récupérer le shader du matériau
|
||||
const NzShaderProgram* program = material->GetShaderProgram(nzShaderTarget_Model, 0);
|
||||
|
||||
unsigned int lightCount = 0;
|
||||
|
||||
// Les uniformes sont conservées au sein du shader, inutile de les renvoyer tant que le shader reste le même
|
||||
if (program != lastProgram)
|
||||
{
|
||||
NzRenderer::SetShaderProgram(program);
|
||||
|
||||
// Couleur ambiante de la scène
|
||||
program->SendColor(program->GetUniformLocation(nzShaderUniform_SceneAmbient), scene->GetAmbientColor());
|
||||
// Position de la caméra
|
||||
program->SendVector(program->GetUniformLocation(nzShaderUniform_CameraPosition), camera->GetPosition());
|
||||
|
||||
// On envoie les lumières directionnelles s'il y a (Les mêmes pour tous)
|
||||
lightCount = m_renderQueue.directionnalLights.size();
|
||||
for (unsigned int i = 0; i < lightCount; ++i)
|
||||
m_renderQueue.directionnalLights[i]->Enable(program, i);
|
||||
|
||||
lastProgram = program;
|
||||
}
|
||||
|
||||
material->Apply(program);
|
||||
|
||||
// Mesh
|
||||
if (pair.second)
|
||||
{
|
||||
NzForwardRenderQueue::TransparentStaticModel& staticModel = m_renderQueue.transparentStaticModels[pair.first];
|
||||
|
||||
const NzMatrix4f& matrix = staticModel.transformMatrix;
|
||||
NzStaticMesh* mesh = staticModel.mesh;
|
||||
|
||||
const NzIndexBuffer* indexBuffer = mesh->GetIndexBuffer();
|
||||
const NzVertexBuffer* vertexBuffer = mesh->GetVertexBuffer();
|
||||
|
||||
// Gestion du draw call avant la boucle de rendu
|
||||
std::function<void(nzPrimitiveMode, unsigned int, unsigned int)> drawFunc;
|
||||
unsigned int indexCount;
|
||||
|
||||
if (indexBuffer)
|
||||
{
|
||||
drawFunc = NzRenderer::DrawIndexedPrimitives;
|
||||
indexCount = indexBuffer->GetIndexCount();
|
||||
}
|
||||
else
|
||||
{
|
||||
drawFunc = NzRenderer::DrawPrimitives;
|
||||
indexCount = vertexBuffer->GetVertexCount();
|
||||
}
|
||||
|
||||
NzRenderer::SetIndexBuffer(indexBuffer);
|
||||
NzRenderer::SetVertexBuffer(vertexBuffer);
|
||||
|
||||
// Calcul des lumières les plus proches
|
||||
if (lightCount < m_maxLightsPerObject && !m_renderQueue.lights.empty())
|
||||
{
|
||||
unsigned int count = lightManager.FindClosestLights(&m_renderQueue.lights[0], m_renderQueue.lights.size(), matrix.GetTranslation() + staticModel.boundingSphere.GetPosition(), staticModel.boundingSphere.radius);
|
||||
count -= lightCount;
|
||||
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
lightManager.GetLight(i)->Enable(program, lightCount++);
|
||||
}
|
||||
|
||||
for (unsigned int i = lightCount; i < 3; ++i) ///TODO: Constante sur le nombre maximum de lumières
|
||||
NzLight::Disable(program, i);
|
||||
|
||||
NzRenderer::SetMatrix(nzMatrixType_World, matrix);
|
||||
drawFunc(mesh->GetPrimitiveMode(), 0, indexCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
///TODO
|
||||
}
|
||||
}
|
||||
// Les autres drawables (Exemple: Terrain)
|
||||
for (const NzDrawable* drawable : m_renderQueue.otherDrawables)
|
||||
drawable->Draw();
|
||||
|
||||
// Les billboards
|
||||
/*if (!m_renderQueue.billboards.empty())
|
||||
|
|
@ -420,10 +137,6 @@ void NzForwardRenderTechnique::Draw(const NzScene* scene)
|
|||
billboards.clear();
|
||||
}
|
||||
}*/
|
||||
|
||||
// Les autres drawables (Exemple: Terrain)
|
||||
for (const NzDrawable* drawable : m_renderQueue.otherDrawables)
|
||||
drawable->Draw();
|
||||
}
|
||||
|
||||
unsigned int NzForwardRenderTechnique::GetMaxLightsPerObject() const
|
||||
|
|
@ -438,5 +151,340 @@ NzAbstractRenderQueue* NzForwardRenderTechnique::GetRenderQueue()
|
|||
|
||||
void NzForwardRenderTechnique::SetMaxLightsPerObject(unsigned int lightCount)
|
||||
{
|
||||
m_maxLightsPerObject = lightCount; ///TODO: Vérifier par rapport à la constante
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
if (lightCount > maxLightCount)
|
||||
{
|
||||
NazaraError("Light count is over maximum light count (" + NzString::Number(lightCount) + " > " + NzString::Number(lightCount) + ')');
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_maxLightsPerObject = lightCount;
|
||||
}
|
||||
|
||||
void NzForwardRenderTechnique::DrawOpaqueModels(const NzScene* scene, NzForwardRenderQueue::BatchedModelContainer& opaqueModels)
|
||||
{
|
||||
NzAbstractViewer* viewer = scene->GetViewer();
|
||||
const NzShaderProgram* lastProgram = nullptr;
|
||||
|
||||
for (auto& matIt : opaqueModels)
|
||||
{
|
||||
bool& used = std::get<0>(matIt.second);
|
||||
if (used)
|
||||
{
|
||||
bool& renderQueueInstancing = std::get<1>(matIt.second);
|
||||
NzForwardRenderQueue::BatchedSkeletalMeshContainer& skeletalContainer = std::get<2>(matIt.second);
|
||||
NzForwardRenderQueue::BatchedStaticMeshContainer& staticContainer = std::get<3>(matIt.second);
|
||||
|
||||
if (!skeletalContainer.empty() || !staticContainer.empty())
|
||||
{
|
||||
const NzMaterial* material = matIt.first;
|
||||
|
||||
// Nous utilisons de l'instancing que lorsqu'aucune lumière (autre que directionnelle) n'est active
|
||||
// Ceci car l'instancing n'est pas compatible avec la recherche des lumières les plus proches
|
||||
// (Le deferred shading n'a pas ce problème)
|
||||
bool instancing = m_instancingEnabled && m_lights.IsEmpty() && renderQueueInstancing;
|
||||
|
||||
// On commence par récupérer le programme du matériau
|
||||
const NzShaderProgram* program = material->GetShaderProgram(nzShaderTarget_Model, (instancing) ? nzShaderFlags_Instancing : 0);
|
||||
|
||||
unsigned int lightCount = 0;
|
||||
|
||||
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas
|
||||
if (program != lastProgram)
|
||||
{
|
||||
NzRenderer::SetShaderProgram(program);
|
||||
|
||||
// Couleur ambiante de la scène
|
||||
program->SendColor(program->GetUniformLocation(nzShaderUniform_SceneAmbient), scene->GetAmbientColor());
|
||||
// Position de la caméra
|
||||
program->SendVector(program->GetUniformLocation(nzShaderUniform_EyePosition), viewer->GetEyePosition());
|
||||
|
||||
// On envoie les lumières directionnelles s'il y a (Les mêmes pour tous)
|
||||
lightCount = std::min(m_directionnalLights.GetLightCount(), 3U);
|
||||
for (unsigned int i = 0; i < lightCount; ++i)
|
||||
m_directionnalLights.GetLight(i)->Enable(program, i);
|
||||
|
||||
lastProgram = program;
|
||||
}
|
||||
|
||||
material->Apply(program);
|
||||
|
||||
// Meshs squelettiques
|
||||
/*if (!skeletalContainer.empty())
|
||||
{
|
||||
NzRenderer::SetVertexBuffer(m_skinningBuffer); // Vertex buffer commun
|
||||
for (auto& subMeshIt : container)
|
||||
{
|
||||
///TODO
|
||||
}
|
||||
}*/
|
||||
|
||||
// Meshs statiques
|
||||
for (auto& subMeshIt : staticContainer)
|
||||
{
|
||||
const NzSpheref& boundingSphere = subMeshIt.second.first;
|
||||
const NzStaticMesh* mesh = subMeshIt.first;
|
||||
std::vector<NzForwardRenderQueue::StaticData>& staticData = subMeshIt.second.second;
|
||||
|
||||
if (!staticData.empty())
|
||||
{
|
||||
const NzIndexBuffer* indexBuffer = mesh->GetIndexBuffer();
|
||||
const NzVertexBuffer* vertexBuffer = mesh->GetVertexBuffer();
|
||||
|
||||
// Gestion du draw call avant la boucle de rendu
|
||||
std::function<void(nzPrimitiveMode, unsigned int, unsigned int)> DrawFunc;
|
||||
std::function<void(unsigned int, nzPrimitiveMode, unsigned int, unsigned int)> InstancedDrawFunc;
|
||||
unsigned int indexCount;
|
||||
|
||||
if (indexBuffer)
|
||||
{
|
||||
DrawFunc = NzRenderer::DrawIndexedPrimitives;
|
||||
InstancedDrawFunc = NzRenderer::DrawIndexedPrimitivesInstanced;
|
||||
indexCount = indexBuffer->GetIndexCount();
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawFunc = NzRenderer::DrawPrimitives;
|
||||
InstancedDrawFunc = NzRenderer::DrawPrimitivesInstanced;
|
||||
indexCount = vertexBuffer->GetVertexCount();
|
||||
}
|
||||
|
||||
NzRenderer::SetIndexBuffer(indexBuffer);
|
||||
NzRenderer::SetVertexBuffer(vertexBuffer);
|
||||
|
||||
nzPrimitiveMode primitiveMode = mesh->GetPrimitiveMode();
|
||||
if (instancing)
|
||||
{
|
||||
NzVertexBuffer* instanceBuffer = NzRenderer::GetInstanceBuffer();
|
||||
|
||||
instanceBuffer->SetVertexDeclaration(NzVertexDeclaration::Get(nzVertexLayout_Matrix4));
|
||||
|
||||
unsigned int stride = instanceBuffer->GetStride();
|
||||
|
||||
const NzForwardRenderQueue::StaticData* data = &staticData[0];
|
||||
unsigned int instanceCount = staticData.size();
|
||||
unsigned int maxInstanceCount = instanceBuffer->GetVertexCount();
|
||||
|
||||
while (instanceCount > 0)
|
||||
{
|
||||
unsigned int renderedInstanceCount = std::min(instanceCount, maxInstanceCount);
|
||||
instanceCount -= renderedInstanceCount;
|
||||
|
||||
NzBufferMapper<NzVertexBuffer> mapper(instanceBuffer, nzBufferAccess_DiscardAndWrite, 0, renderedInstanceCount);
|
||||
nzUInt8* ptr = reinterpret_cast<nzUInt8*>(mapper.GetPointer());
|
||||
|
||||
for (unsigned int i = 0; i < renderedInstanceCount; ++i)
|
||||
{
|
||||
std::memcpy(ptr, data->transformMatrix, sizeof(float)*16);
|
||||
|
||||
data++;
|
||||
ptr += stride;
|
||||
}
|
||||
|
||||
mapper.Unmap();
|
||||
|
||||
InstancedDrawFunc(renderedInstanceCount, primitiveMode, 0, indexCount);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const NzForwardRenderQueue::StaticData& data : staticData)
|
||||
{
|
||||
// Calcul des lumières les plus proches
|
||||
if (lightCount < m_maxLightsPerObject && !m_lights.IsEmpty())
|
||||
{
|
||||
unsigned int count = m_lights.ComputeClosestLights(data.transformMatrix.GetTranslation() + boundingSphere.GetPosition(), boundingSphere.radius, maxLightCount);
|
||||
count -= lightCount;
|
||||
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
m_lights.GetResult(i)->Enable(program, lightCount++);
|
||||
}
|
||||
|
||||
for (unsigned int i = lightCount; i < maxLightCount; ++i)
|
||||
NzLight::Disable(program, i);
|
||||
|
||||
NzRenderer::SetMatrix(nzMatrixType_World, data.transformMatrix);
|
||||
DrawFunc(primitiveMode, 0, indexCount);
|
||||
}
|
||||
}
|
||||
staticData.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Et on remet à zéro les données
|
||||
renderQueueInstancing = false;
|
||||
used = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NzForwardRenderTechnique::DrawSprites(const NzScene* scene, NzForwardRenderQueue::BatchedSpriteContainer& sprites)
|
||||
{
|
||||
NzAbstractViewer* viewer = scene->GetViewer();
|
||||
const NzShaderProgram* lastProgram = nullptr;
|
||||
|
||||
NzRenderer::SetIndexBuffer(m_indexBuffer);
|
||||
NzRenderer::SetMatrix(nzMatrixType_World, NzMatrix4f::Identity());
|
||||
NzRenderer::SetVertexBuffer(&m_spriteBuffer);
|
||||
|
||||
for (auto& matIt : sprites)
|
||||
{
|
||||
const NzMaterial* material = matIt.first;
|
||||
auto& spriteVector = matIt.second;
|
||||
|
||||
unsigned int spriteCount = spriteVector.size();
|
||||
if (spriteCount > 0)
|
||||
{
|
||||
// On commence par récupérer le programme du matériau
|
||||
const NzShaderProgram* program = material->GetShaderProgram(nzShaderTarget_Sprite, 0);
|
||||
|
||||
// Les uniformes sont conservées au sein du shader, inutile de les renvoyer tant que le shader reste le même
|
||||
if (program != lastProgram)
|
||||
{
|
||||
NzRenderer::SetShaderProgram(program);
|
||||
|
||||
// Couleur ambiante de la scène
|
||||
program->SendColor(program->GetUniformLocation(nzShaderUniform_SceneAmbient), scene->GetAmbientColor());
|
||||
// Position de la caméra
|
||||
program->SendVector(program->GetUniformLocation(nzShaderUniform_EyePosition), viewer->GetEyePosition());
|
||||
|
||||
lastProgram = program;
|
||||
}
|
||||
|
||||
material->Apply(program);
|
||||
|
||||
const NzSprite** spritePtr = &spriteVector[0];
|
||||
do
|
||||
{
|
||||
unsigned int renderedSpriteCount = std::min(spriteCount, 64U);
|
||||
spriteCount -= renderedSpriteCount;
|
||||
|
||||
NzBufferMapper<NzVertexBuffer> vertexMapper(m_spriteBuffer, nzBufferAccess_DiscardAndWrite, 0, renderedSpriteCount*4);
|
||||
NzVertexStruct_XYZ_UV* vertices = reinterpret_cast<NzVertexStruct_XYZ_UV*>(vertexMapper.GetPointer());
|
||||
|
||||
for (unsigned int i = 0; i < renderedSpriteCount; ++i)
|
||||
{
|
||||
const NzSprite* sprite = *spritePtr++;
|
||||
const NzRectf& textureCoords = sprite->GetTextureCoords();
|
||||
const NzVector2f& halfSize = sprite->GetSize()*0.5f;
|
||||
NzVector3f center = sprite->GetPosition();
|
||||
NzQuaternionf rotation = sprite->GetRotation();
|
||||
|
||||
vertices->position = center + rotation * NzVector3f(-halfSize.x, -halfSize.y, 0.f);
|
||||
vertices->uv.Set(textureCoords.x, textureCoords.y + textureCoords.height);
|
||||
vertices++;
|
||||
|
||||
vertices->position = center + rotation * NzVector3f(halfSize.x, -halfSize.y, 0.f);
|
||||
vertices->uv.Set(textureCoords.width, textureCoords.y + textureCoords.height);
|
||||
vertices++;
|
||||
|
||||
vertices->position = center + rotation * NzVector3f(-halfSize.x, halfSize.y, 0.f);
|
||||
vertices->uv.Set(textureCoords.x, textureCoords.y);
|
||||
vertices++;
|
||||
|
||||
vertices->position = center + rotation * NzVector3f(halfSize.x, halfSize.y, 0.f);
|
||||
vertices->uv.Set(textureCoords.width, textureCoords.y);
|
||||
vertices++;
|
||||
}
|
||||
|
||||
vertexMapper.Unmap();
|
||||
|
||||
NzRenderer::DrawIndexedPrimitives(nzPrimitiveMode_TriangleList, 0, renderedSpriteCount*6);
|
||||
}
|
||||
while (spriteCount > 0);
|
||||
|
||||
spriteVector.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NzForwardRenderTechnique::DrawTransparentModels(const NzScene* scene, NzForwardRenderQueue::TransparentModelContainer& transparentModels)
|
||||
{
|
||||
NzAbstractViewer* viewer = scene->GetViewer();
|
||||
const NzShaderProgram* lastProgram = nullptr;
|
||||
|
||||
for (const std::pair<unsigned int, bool>& pair : transparentModels)
|
||||
{
|
||||
// Matériau
|
||||
NzMaterial* material = (pair.second) ?
|
||||
m_renderQueue.transparentStaticModels[pair.first].material :
|
||||
m_renderQueue.transparentSkeletalModels[pair.first].material;
|
||||
|
||||
// On commence par récupérer le shader du matériau
|
||||
const NzShaderProgram* program = material->GetShaderProgram(nzShaderTarget_Model, 0);
|
||||
|
||||
unsigned int lightCount = 0;
|
||||
|
||||
// Les uniformes sont conservées au sein du shader, inutile de les renvoyer tant que le shader reste le même
|
||||
if (program != lastProgram)
|
||||
{
|
||||
NzRenderer::SetShaderProgram(program);
|
||||
|
||||
// Couleur ambiante de la scène
|
||||
program->SendColor(program->GetUniformLocation(nzShaderUniform_SceneAmbient), scene->GetAmbientColor());
|
||||
// Position de la caméra
|
||||
program->SendVector(program->GetUniformLocation(nzShaderUniform_EyePosition), viewer->GetEyePosition());
|
||||
|
||||
// On envoie les lumières directionnelles s'il y a (Les mêmes pour tous)
|
||||
lightCount = std::min(m_directionnalLights.GetLightCount(), 3U);
|
||||
for (unsigned int i = 0; i < lightCount; ++i)
|
||||
m_directionnalLights.GetLight(i)->Enable(program, i);
|
||||
|
||||
lastProgram = program;
|
||||
}
|
||||
|
||||
material->Apply(program);
|
||||
|
||||
// Mesh
|
||||
if (pair.second)
|
||||
{
|
||||
NzForwardRenderQueue::TransparentStaticModel& staticModel = m_renderQueue.transparentStaticModels[pair.first];
|
||||
|
||||
const NzMatrix4f& matrix = staticModel.transformMatrix;
|
||||
NzStaticMesh* mesh = staticModel.mesh;
|
||||
|
||||
const NzIndexBuffer* indexBuffer = mesh->GetIndexBuffer();
|
||||
const NzVertexBuffer* vertexBuffer = mesh->GetVertexBuffer();
|
||||
|
||||
// Gestion du draw call avant la boucle de rendu
|
||||
std::function<void(nzPrimitiveMode, unsigned int, unsigned int)> DrawFunc;
|
||||
unsigned int indexCount;
|
||||
|
||||
if (indexBuffer)
|
||||
{
|
||||
DrawFunc = NzRenderer::DrawIndexedPrimitives;
|
||||
indexCount = indexBuffer->GetIndexCount();
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawFunc = NzRenderer::DrawPrimitives;
|
||||
indexCount = vertexBuffer->GetVertexCount();
|
||||
}
|
||||
|
||||
NzRenderer::SetIndexBuffer(indexBuffer);
|
||||
NzRenderer::SetVertexBuffer(vertexBuffer);
|
||||
|
||||
// Calcul des lumières les plus proches
|
||||
if (lightCount < m_maxLightsPerObject && !m_lights.IsEmpty())
|
||||
{
|
||||
unsigned int count = m_lights.ComputeClosestLights(matrix.GetTranslation() + staticModel.boundingSphere.GetPosition(), staticModel.boundingSphere.radius, maxLightCount);
|
||||
count -= lightCount;
|
||||
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
m_lights.GetResult(i)->Enable(program, lightCount++);
|
||||
}
|
||||
|
||||
for (unsigned int i = lightCount; i < maxLightCount; ++i)
|
||||
NzLight::Disable(program, i);
|
||||
|
||||
NzRenderer::SetMatrix(nzMatrixType_World, matrix);
|
||||
DrawFunc(mesh->GetPrimitiveMode(), 0, indexCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
///TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -225,6 +225,31 @@ void NzLight::Disable(const NzShaderProgram* program, unsigned int lightUnit)
|
|||
program->SendInteger(program->GetUniformLocation("Lights[" + NzString::Number(lightUnit) + "].type"), -1);
|
||||
}
|
||||
|
||||
bool NzLight::FrustumCull(const NzFrustumf& frustum)
|
||||
{
|
||||
switch (m_type)
|
||||
{
|
||||
case nzLightType_Directional:
|
||||
return true; // Toujours visible
|
||||
|
||||
case nzLightType_Point:
|
||||
if (!m_derivedUpdated)
|
||||
UpdateDerived();
|
||||
|
||||
// Un test sphérique est bien plus rapide et précis que celui de la bounding box
|
||||
return frustum.Contains(NzSpheref(m_derivedPosition, m_radius));
|
||||
|
||||
case nzLightType_Spot:
|
||||
if (!m_boundingVolumeUpdated)
|
||||
UpdateBoundingVolume();
|
||||
|
||||
return frustum.Contains(m_boundingVolume);
|
||||
}
|
||||
|
||||
NazaraError("Invalid light type (0x" + NzString::Number(m_type, 16) + ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
void NzLight::Invalidate()
|
||||
{
|
||||
NzSceneNode::Invalidate();
|
||||
|
|
@ -307,28 +332,3 @@ void NzLight::UpdateBoundingVolume() const
|
|||
|
||||
m_boundingVolumeUpdated = true;
|
||||
}
|
||||
|
||||
bool NzLight::VisibilityTest(const NzCamera* camera)
|
||||
{
|
||||
switch (m_type)
|
||||
{
|
||||
case nzLightType_Directional:
|
||||
return true; // Toujours visible
|
||||
|
||||
case nzLightType_Point:
|
||||
if (!m_derivedUpdated)
|
||||
UpdateDerived();
|
||||
|
||||
// Un test sphérique est bien plus rapide et précis que celui de la bounding box
|
||||
return camera->GetFrustum().Contains(NzSpheref(m_derivedPosition, m_radius));
|
||||
|
||||
case nzLightType_Spot:
|
||||
if (!m_boundingVolumeUpdated)
|
||||
UpdateBoundingVolume();
|
||||
|
||||
return camera->GetFrustum().Contains(m_boundingVolume);
|
||||
}
|
||||
|
||||
NazaraError("Invalid light type (0x" + NzString::Number(m_type, 16) + ')');
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,160 @@
|
|||
// Copyright (C) 2013 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/LightManager.hpp>
|
||||
#include <Nazara/Graphics/Light.hpp>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
NzLightManager::NzLightManager() :
|
||||
m_lightCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
NzLightManager::NzLightManager(const NzLight** lights, unsigned int lightCount)
|
||||
{
|
||||
SetLights(lights, lightCount);
|
||||
}
|
||||
|
||||
void NzLightManager::AddLights(const NzLight** lights, unsigned int lightCount)
|
||||
{
|
||||
m_lights.push_back(std::make_pair(lights, lightCount));
|
||||
m_lightCount += lightCount;
|
||||
}
|
||||
|
||||
void NzLightManager::Clear()
|
||||
{
|
||||
m_lights.clear();
|
||||
m_lightCount = 0;
|
||||
}
|
||||
|
||||
unsigned int NzLightManager::ComputeClosestLights(const NzVector3f& position, float squaredRadius, unsigned int maxResults)
|
||||
{
|
||||
m_results.resize(maxResults);
|
||||
for (Light& light : m_results)
|
||||
{
|
||||
light.light = nullptr;
|
||||
light.score = std::numeric_limits<unsigned int>::max(); // Nous jouons au Golf
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < m_lights.size(); ++i)
|
||||
{
|
||||
const NzLight** lights = m_lights[i].first;
|
||||
unsigned int lightCount = m_lights[i].second;
|
||||
|
||||
for (unsigned int j = 0; j < lightCount; ++j)
|
||||
{
|
||||
const NzLight* light = *lights++;
|
||||
|
||||
unsigned int score = std::numeric_limits<unsigned int>::max();
|
||||
switch (light->GetLightType())
|
||||
{
|
||||
case nzLightType_Directional:
|
||||
score = 0; // Lumière choisie d'office
|
||||
break;
|
||||
|
||||
case nzLightType_Point:
|
||||
{
|
||||
float lightRadius = light->GetRadius();
|
||||
|
||||
float squaredDistance = position.SquaredDistance(light->GetPosition());
|
||||
if (squaredDistance - squaredRadius <= lightRadius*lightRadius)
|
||||
score = static_cast<unsigned int>(squaredDistance*1000.f);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case nzLightType_Spot:
|
||||
{
|
||||
float lightRadius = light->GetRadius();
|
||||
|
||||
///TODO: Attribuer bonus/malus selon l'angle du spot ?
|
||||
float squaredDistance = position.SquaredDistance(light->GetPosition());
|
||||
if (squaredDistance - squaredRadius <= lightRadius*lightRadius)
|
||||
score = static_cast<unsigned int>(squaredDistance*1000.f);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (score < m_results[0].score)
|
||||
{
|
||||
unsigned int k;
|
||||
for (k = 1; k < maxResults; ++k)
|
||||
{
|
||||
if (score > m_results[k].score)
|
||||
break;
|
||||
}
|
||||
|
||||
k--; // Position de la nouvelle lumière
|
||||
|
||||
// Décalage
|
||||
std::memcpy(&m_results[0], &m_results[1], k*sizeof(Light));
|
||||
|
||||
m_results[k].light = light;
|
||||
m_results[k].score = score;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int i;
|
||||
for (i = 0; i < maxResults; ++i)
|
||||
{
|
||||
if (m_results[i].light)
|
||||
break;
|
||||
}
|
||||
|
||||
return maxResults-i;
|
||||
}
|
||||
|
||||
const NzLight* NzLightManager::GetLight(unsigned int index) const
|
||||
{
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
if (index >= m_lightCount)
|
||||
{
|
||||
NazaraError("Light index out of range (" + NzString::Number(index) + " >= " + NzString::Number(m_lightCount) + ')');
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (unsigned int i = 0; i < m_lights.size(); ++i)
|
||||
{
|
||||
unsigned int lightCount = m_lights[i].second;
|
||||
if (index > lightCount)
|
||||
index -= lightCount;
|
||||
else
|
||||
{
|
||||
const NzLight** lights = m_lights[i].first;
|
||||
return lights[i];
|
||||
}
|
||||
}
|
||||
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
NazaraInternalError("Light not found");
|
||||
#else
|
||||
NazaraError("Light not found");
|
||||
#endif
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unsigned int NzLightManager::GetLightCount() const
|
||||
{
|
||||
return m_lightCount;
|
||||
}
|
||||
|
||||
const NzLight* NzLightManager::GetResult(unsigned int i) const
|
||||
{
|
||||
return m_results[i].light;
|
||||
}
|
||||
|
||||
bool NzLightManager::IsEmpty() const
|
||||
{
|
||||
return m_lightCount == 0;
|
||||
}
|
||||
|
||||
void NzLightManager::SetLights(const NzLight** lights, unsigned int lightCount)
|
||||
{
|
||||
Clear();
|
||||
AddLights(lights, lightCount);
|
||||
}
|
||||
|
|
@ -630,6 +630,25 @@ NzModel& NzModel::operator=(NzModel&& node)
|
|||
return *this;
|
||||
}
|
||||
|
||||
bool NzModel::FrustumCull(const NzFrustumf& frustum)
|
||||
{
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
if (!IsDrawable())
|
||||
{
|
||||
NazaraError("Model is not drawable");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!m_drawEnabled)
|
||||
return false;
|
||||
|
||||
if (!m_boundingVolumeUpdated)
|
||||
UpdateBoundingVolume();
|
||||
|
||||
return frustum.Contains(m_boundingVolume);
|
||||
}
|
||||
|
||||
void NzModel::Invalidate()
|
||||
{
|
||||
NzSceneNode::Invalidate();
|
||||
|
|
@ -671,23 +690,4 @@ void NzModel::UpdateBoundingVolume() const
|
|||
m_boundingVolumeUpdated = true;
|
||||
}
|
||||
|
||||
bool NzModel::VisibilityTest(const NzCamera* camera)
|
||||
{
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
if (!IsDrawable())
|
||||
{
|
||||
NazaraError("Model is not drawable");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!m_drawEnabled)
|
||||
return false;
|
||||
|
||||
if (!m_boundingVolumeUpdated)
|
||||
UpdateBoundingVolume();
|
||||
|
||||
return camera->GetFrustum().Contains(m_boundingVolume);
|
||||
}
|
||||
|
||||
NzModelLoader::LoaderList NzModel::s_loaders;
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ struct NzSceneImpl
|
|||
NzClock updateClock;
|
||||
NzColor ambientColor = NzColor(25,25,25);
|
||||
NzSceneRoot root;
|
||||
NzCamera* activeCamera;
|
||||
NzAbstractViewer* viewer;
|
||||
bool update;
|
||||
float frameTime;
|
||||
float updateTime;
|
||||
|
|
@ -64,9 +64,9 @@ void NzScene::AddToVisibilityList(NzUpdatable* object)
|
|||
void NzScene::Cull()
|
||||
{
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
if (!m_impl->activeCamera)
|
||||
if (!m_impl->viewer)
|
||||
{
|
||||
NazaraError("No active camera");
|
||||
NazaraError("No viewer");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -76,8 +76,8 @@ void NzScene::Cull()
|
|||
|
||||
m_impl->visibleUpdateList.clear();
|
||||
|
||||
// Frustum culling/Viewport culling
|
||||
RecursiveCameraCull(m_impl->renderTechnique->GetRenderQueue(), m_impl->activeCamera, &m_impl->root);
|
||||
// Frustum culling
|
||||
RecursiveFrustumCull(m_impl->renderTechnique->GetRenderQueue(), m_impl->viewer->GetFrustum(), &m_impl->root);
|
||||
|
||||
///TODO: Occlusion culling
|
||||
|
||||
|
|
@ -87,22 +87,18 @@ void NzScene::Cull()
|
|||
void NzScene::Draw()
|
||||
{
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
if (!m_impl->activeCamera)
|
||||
if (!m_impl->viewer)
|
||||
{
|
||||
NazaraError("No active camera");
|
||||
NazaraError("No viewer");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->renderTechnique->Clear(this);
|
||||
m_impl->viewer->ApplyView();
|
||||
m_impl->renderTechnique->Draw(this);
|
||||
}
|
||||
|
||||
NzCamera* NzScene::GetActiveCamera() const
|
||||
{
|
||||
return m_impl->activeCamera;
|
||||
}
|
||||
|
||||
NzColor NzScene::GetAmbientColor() const
|
||||
{
|
||||
return m_impl->ambientColor;
|
||||
|
|
@ -123,6 +119,11 @@ NzSceneNode& NzScene::GetRoot() const
|
|||
return m_impl->root;
|
||||
}
|
||||
|
||||
NzAbstractViewer* NzScene::GetViewer() const
|
||||
{
|
||||
return m_impl->viewer;
|
||||
}
|
||||
|
||||
float NzScene::GetUpdateTime() const
|
||||
{
|
||||
return m_impl->updateTime;
|
||||
|
|
@ -161,6 +162,11 @@ void NzScene::SetRenderTechnique(NzAbstractRenderTechnique* renderTechnique)
|
|||
m_impl->renderTechnique.reset(renderTechnique);
|
||||
}
|
||||
|
||||
void NzScene::SetViewer(NzAbstractViewer* viewer)
|
||||
{
|
||||
m_impl->viewer = viewer;
|
||||
}
|
||||
|
||||
void NzScene::SetUpdatePerSecond(unsigned int updatePerSecond)
|
||||
{
|
||||
m_impl->updatePerSecond = updatePerSecond;
|
||||
|
|
@ -209,7 +215,7 @@ NzScene::operator const NzSceneNode&() const
|
|||
return m_impl->root;
|
||||
}
|
||||
|
||||
void NzScene::RecursiveCameraCull(NzAbstractRenderQueue* renderQueue, const NzCamera* camera, NzNode* node)
|
||||
void NzScene::RecursiveFrustumCull(NzAbstractRenderQueue* renderQueue, const NzFrustumf& frustum, NzNode* node)
|
||||
{
|
||||
for (NzNode* child : node->GetChilds())
|
||||
{
|
||||
|
|
@ -218,17 +224,12 @@ void NzScene::RecursiveCameraCull(NzAbstractRenderQueue* renderQueue, const NzCa
|
|||
NzSceneNode* sceneNode = static_cast<NzSceneNode*>(child);
|
||||
|
||||
///TODO: Empêcher le rendu des enfants si le parent est cullé selon un flag
|
||||
sceneNode->UpdateVisibility(camera);
|
||||
sceneNode->UpdateVisibility(frustum);
|
||||
if (sceneNode->IsVisible())
|
||||
sceneNode->AddToRenderQueue(renderQueue);
|
||||
}
|
||||
|
||||
if (child->HasChilds())
|
||||
RecursiveCameraCull(renderQueue, camera, child);
|
||||
RecursiveFrustumCull(renderQueue, frustum, child);
|
||||
}
|
||||
}
|
||||
|
||||
void NzScene::SetActiveCamera(NzCamera* camera)
|
||||
{
|
||||
m_impl->activeCamera = camera;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,11 +97,11 @@ void NzSceneNode::Update()
|
|||
{
|
||||
}
|
||||
|
||||
void NzSceneNode::UpdateVisibility(const NzCamera* camera)
|
||||
void NzSceneNode::UpdateVisibility(const NzFrustumf& frustum)
|
||||
{
|
||||
bool wasVisible = m_visible;
|
||||
|
||||
m_visible = VisibilityTest(camera);
|
||||
m_visible = FrustumCull(frustum);
|
||||
|
||||
if (m_visible != wasVisible)
|
||||
OnVisibilityChange(m_visible);
|
||||
|
|
|
|||
|
|
@ -31,6 +31,13 @@ nzSceneNodeType NzSceneRoot::GetSceneNodeType() const
|
|||
return nzSceneNodeType_Root;
|
||||
}
|
||||
|
||||
bool NzSceneRoot::FrustumCull(const NzFrustumf& frustum)
|
||||
{
|
||||
NazaraUnused(frustum);
|
||||
|
||||
return true; // Toujours visible
|
||||
}
|
||||
|
||||
void NzSceneRoot::Register()
|
||||
{
|
||||
NazaraInternalError("SceneNode::Register() called on SceneRoot");
|
||||
|
|
@ -40,10 +47,3 @@ void NzSceneRoot::Unregister()
|
|||
{
|
||||
NazaraInternalError("SceneNode::Unregister() called on SceneRoot");
|
||||
}
|
||||
|
||||
bool NzSceneRoot::VisibilityTest(const NzCamera* camera)
|
||||
{
|
||||
NazaraUnused(camera);
|
||||
|
||||
return true; // Toujours visible
|
||||
}
|
||||
|
|
|
|||
|
|
@ -198,15 +198,15 @@ void NzSkyboxBackground::Draw(const NzScene* scene) const
|
|||
|
||||
s_program->SendInteger(s_skyboxLocation, 0);
|
||||
|
||||
NzCamera* camera = scene->GetActiveCamera();
|
||||
NzAbstractViewer* viewer = scene->GetViewer();
|
||||
|
||||
NzMatrix4f skyboxMatrix(camera->GetViewMatrix());
|
||||
NzMatrix4f skyboxMatrix(viewer->GetViewMatrix());
|
||||
skyboxMatrix.SetTranslation(NzVector3f::Zero());
|
||||
|
||||
NzRenderer::SetIndexBuffer(m_indexBuffer);
|
||||
NzRenderer::SetMatrix(nzMatrixType_Projection, camera->GetProjectionMatrix());
|
||||
NzRenderer::SetMatrix(nzMatrixType_Projection, viewer->GetProjectionMatrix());
|
||||
NzRenderer::SetMatrix(nzMatrixType_View, skyboxMatrix);
|
||||
NzRenderer::SetMatrix(nzMatrixType_World, NzMatrix4f::Scale(NzVector3f(camera->GetZNear())));
|
||||
NzRenderer::SetMatrix(nzMatrixType_World, NzMatrix4f::Scale(NzVector3f(viewer->GetZNear())));
|
||||
NzRenderer::SetRenderStates(states);
|
||||
NzRenderer::SetShaderProgram(s_program);
|
||||
NzRenderer::SetTexture(0, m_texture);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,114 @@
|
|||
// Copyright (C) 2013 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/Sprite.hpp>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
NzSprite::NzSprite() :
|
||||
m_textureCoords(0.f, 0.f, 1.f, 1.f),
|
||||
m_size(64.f, 64.f)
|
||||
{
|
||||
}
|
||||
|
||||
NzSprite::NzSprite(const NzSprite& sprite) :
|
||||
NzSceneNode(sprite),
|
||||
m_textureCoords(sprite.m_textureCoords),
|
||||
m_size(sprite.m_size),
|
||||
m_material(sprite.m_material)
|
||||
{
|
||||
}
|
||||
|
||||
NzSprite::NzSprite(NzSprite&& sprite) :
|
||||
NzSceneNode(sprite),
|
||||
m_textureCoords(sprite.m_textureCoords),
|
||||
m_size(sprite.m_size),
|
||||
m_material(std::move(sprite.m_material))
|
||||
{
|
||||
}
|
||||
|
||||
NzSprite::~NzSprite() = default;
|
||||
|
||||
void NzSprite::AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const
|
||||
{
|
||||
renderQueue->AddSprite(this);
|
||||
}
|
||||
|
||||
const NzBoundingVolumef& NzSprite::GetBoundingVolume() const
|
||||
{
|
||||
static NzBoundingVolumef infinity(NzBoundingVolumef::Infinite());
|
||||
return infinity;
|
||||
}
|
||||
|
||||
NzMaterial* NzSprite::GetMaterial() const
|
||||
{
|
||||
return m_material;
|
||||
}
|
||||
|
||||
nzSceneNodeType NzSprite::GetSceneNodeType() const
|
||||
{
|
||||
return nzSceneNodeType_Sprite;
|
||||
}
|
||||
|
||||
const NzVector2f& NzSprite::GetSize() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
const NzRectf& NzSprite::GetTextureCoords() const
|
||||
{
|
||||
return m_textureCoords;
|
||||
}
|
||||
|
||||
void NzSprite::SetMaterial(NzMaterial* material)
|
||||
{
|
||||
m_material = material;
|
||||
}
|
||||
|
||||
void NzSprite::SetSize(const NzVector2f& size)
|
||||
{
|
||||
m_size = size;
|
||||
}
|
||||
|
||||
void NzSprite::SetTextureCoords(const NzRectf& coords)
|
||||
{
|
||||
m_textureCoords = coords;
|
||||
}
|
||||
|
||||
void NzSprite::SetTextureRect(const NzRectui& rect)
|
||||
{
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
if (!m_material)
|
||||
{
|
||||
NazaraError("Sprite has no material");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_material->HasDiffuseMap())
|
||||
{
|
||||
NazaraError("Sprite material has no diffuse map");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
NzTexture* diffuseMap = m_material->GetDiffuseMap();
|
||||
|
||||
float invWidth = 1.f/diffuseMap->GetWidth();
|
||||
float invHeight = 1.f/diffuseMap->GetHeight();
|
||||
|
||||
SetTextureCoords(NzRectf(invWidth*rect.x, invHeight*rect.y, invWidth*rect.width, invHeight*rect.height));
|
||||
}
|
||||
|
||||
bool NzSprite::FrustumCull(const NzFrustumf& frustum)
|
||||
{
|
||||
///TODO: Effectuer un vrai test
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzSprite::Register()
|
||||
{
|
||||
}
|
||||
|
||||
void NzSprite::Unregister()
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,279 @@
|
|||
// Copyright (C) 2013 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/View.hpp>
|
||||
#include <Nazara/Graphics/Scene.hpp>
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
#include <Nazara/Renderer/RenderTarget.hpp>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
NzView::NzView() :
|
||||
m_targetRegion(0.f, 0.f, 1.f, 1.f),
|
||||
m_target(nullptr),
|
||||
m_frustumUpdated(false),
|
||||
m_projectionMatrixUpdated(false),
|
||||
m_viewMatrixUpdated(false),
|
||||
m_viewportUpdated(false),
|
||||
m_zFar(1.f),
|
||||
m_zNear(-1.f)
|
||||
{
|
||||
}
|
||||
|
||||
NzView::~NzView()
|
||||
{
|
||||
if (m_target)
|
||||
m_target->RemoveListener(this);
|
||||
}
|
||||
|
||||
void NzView::EnsureFrustumUpdate() const
|
||||
{
|
||||
if (!m_frustumUpdated)
|
||||
UpdateFrustum();
|
||||
}
|
||||
|
||||
void NzView::EnsureProjectionMatrixUpdate() const
|
||||
{
|
||||
if (!m_projectionMatrixUpdated)
|
||||
UpdateProjectionMatrix();
|
||||
}
|
||||
|
||||
void NzView::EnsureViewMatrixUpdate() const
|
||||
{
|
||||
if (!m_viewMatrixUpdated)
|
||||
UpdateViewMatrix();
|
||||
}
|
||||
|
||||
void NzView::EnsureViewportUpdate() const
|
||||
{
|
||||
if (!m_viewportUpdated)
|
||||
UpdateViewport();
|
||||
}
|
||||
|
||||
float NzView::GetAspectRatio() const
|
||||
{
|
||||
return 1.f;
|
||||
}
|
||||
|
||||
NzVector3f NzView::GetEyePosition() const
|
||||
{
|
||||
return GetPosition(nzCoordSys_Global);
|
||||
}
|
||||
|
||||
const NzFrustumf& NzView::GetFrustum() const
|
||||
{
|
||||
if (!m_frustumUpdated)
|
||||
UpdateFrustum();
|
||||
|
||||
return m_frustum;
|
||||
}
|
||||
|
||||
const NzMatrix4f& NzView::GetProjectionMatrix() const
|
||||
{
|
||||
if (!m_projectionMatrixUpdated)
|
||||
UpdateProjectionMatrix();
|
||||
|
||||
return m_projectionMatrix;
|
||||
}
|
||||
|
||||
const NzRenderTarget* NzView::GetTarget() const
|
||||
{
|
||||
return m_target;
|
||||
}
|
||||
|
||||
const NzRectf& NzView::GetTargetRegion() const
|
||||
{
|
||||
return m_targetRegion;
|
||||
}
|
||||
|
||||
const NzMatrix4f& NzView::GetViewMatrix() const
|
||||
{
|
||||
if (!m_viewMatrixUpdated)
|
||||
UpdateViewMatrix();
|
||||
|
||||
return m_viewMatrix;
|
||||
}
|
||||
|
||||
const NzRectui& NzView::GetViewport() const
|
||||
{
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
if (!m_target)
|
||||
{
|
||||
NazaraError("Camera has no render target");
|
||||
return m_viewport;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!m_viewportUpdated)
|
||||
UpdateViewport();
|
||||
|
||||
return m_viewport;
|
||||
}
|
||||
|
||||
float NzView::GetZFar() const
|
||||
{
|
||||
return m_zFar;
|
||||
}
|
||||
|
||||
float NzView::GetZNear() const
|
||||
{
|
||||
return m_zNear;
|
||||
}
|
||||
|
||||
void NzView::SetTarget(const NzRenderTarget* renderTarget)
|
||||
{
|
||||
if (m_target)
|
||||
m_target->RemoveListener(this);
|
||||
|
||||
m_target = renderTarget;
|
||||
if (m_target)
|
||||
m_target->AddListener(this);
|
||||
}
|
||||
|
||||
void NzView::SetTarget(const NzRenderTarget& renderTarget)
|
||||
{
|
||||
SetTarget(&renderTarget);
|
||||
}
|
||||
|
||||
void NzView::SetTargetRegion(const NzRectf& region)
|
||||
{
|
||||
m_targetRegion = region;
|
||||
|
||||
m_frustumUpdated = false;
|
||||
m_projectionMatrixUpdated = false;
|
||||
m_viewportUpdated = false;
|
||||
}
|
||||
|
||||
void NzView::SetViewport(const NzRectui& viewport)
|
||||
{
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
if (!m_target)
|
||||
{
|
||||
NazaraError("Camera has no render target");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// On calcule la région nécessaire pour produire ce viewport avec la taille actuelle de la cible
|
||||
float invWidth = 1.f/m_target->GetWidth();
|
||||
float invHeight = 1.f/m_target->GetHeight();
|
||||
|
||||
SetTargetRegion(NzRectf(invWidth * viewport.x, invHeight * viewport.y, invWidth * viewport.width, invHeight * viewport.height));
|
||||
}
|
||||
|
||||
void NzView::SetZFar(float zFar)
|
||||
{
|
||||
m_zFar = zFar;
|
||||
|
||||
m_frustumUpdated = false;
|
||||
m_projectionMatrixUpdated = false;
|
||||
}
|
||||
|
||||
void NzView::SetZNear(float zNear)
|
||||
{
|
||||
m_zNear = zNear;
|
||||
|
||||
m_frustumUpdated = false;
|
||||
m_projectionMatrixUpdated = false;
|
||||
}
|
||||
|
||||
void NzView::ApplyView() const
|
||||
{
|
||||
#if NAZARA_GRAPHICS_SAFE
|
||||
if (!m_target)
|
||||
{
|
||||
NazaraError("Camera has no render target");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!m_projectionMatrixUpdated)
|
||||
UpdateProjectionMatrix();
|
||||
|
||||
if (!m_viewMatrixUpdated)
|
||||
UpdateViewMatrix();
|
||||
|
||||
if (!m_viewportUpdated)
|
||||
UpdateViewport();
|
||||
|
||||
NzRenderer::SetMatrix(nzMatrixType_Projection, m_projectionMatrix);
|
||||
NzRenderer::SetMatrix(nzMatrixType_View, m_viewMatrix);
|
||||
NzRenderer::SetViewport(m_viewport);
|
||||
}
|
||||
|
||||
void NzView::Invalidate()
|
||||
{
|
||||
NzNode::Invalidate();
|
||||
|
||||
// Le frustum et la view matrix dépendent des paramètres du node, invalidons-les
|
||||
m_frustumUpdated = false;
|
||||
m_viewMatrixUpdated = false;
|
||||
}
|
||||
|
||||
void NzView::OnRenderTargetReleased(const NzRenderTarget* renderTarget, void* userdata)
|
||||
{
|
||||
NazaraUnused(userdata);
|
||||
|
||||
if (renderTarget == m_target)
|
||||
m_target = nullptr;
|
||||
else
|
||||
NazaraInternalError("Not listening to " + NzString::Pointer(renderTarget));
|
||||
}
|
||||
|
||||
bool NzView::OnRenderTargetSizeChange(const NzRenderTarget* renderTarget, void* userdata)
|
||||
{
|
||||
NazaraUnused(userdata);
|
||||
|
||||
if (renderTarget == m_target)
|
||||
{
|
||||
m_frustumUpdated = false;
|
||||
m_projectionMatrixUpdated = false;
|
||||
m_viewportUpdated = false;
|
||||
}
|
||||
else
|
||||
NazaraInternalError("Not listening to " + NzString::Pointer(renderTarget));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzView::UpdateFrustum() const
|
||||
{
|
||||
if (!m_projectionMatrixUpdated)
|
||||
UpdateProjectionMatrix();
|
||||
|
||||
if (!m_viewMatrixUpdated)
|
||||
UpdateViewMatrix();
|
||||
|
||||
m_frustum.Extract(m_viewMatrix, m_projectionMatrix);
|
||||
m_frustumUpdated = true;
|
||||
}
|
||||
|
||||
void NzView::UpdateProjectionMatrix() const
|
||||
{
|
||||
if (!m_viewportUpdated)
|
||||
UpdateViewport();
|
||||
|
||||
m_projectionMatrix.MakeOrtho(m_viewport.x, m_viewport.x + m_viewport.width, m_viewport.y, m_viewport.y + m_viewport.height, m_zNear, m_zFar);
|
||||
m_projectionMatrixUpdated = true;
|
||||
}
|
||||
|
||||
void NzView::UpdateViewMatrix() const
|
||||
{
|
||||
if (!m_derivedUpdated)
|
||||
UpdateDerived();
|
||||
|
||||
m_viewMatrix.MakeViewMatrix(m_derivedPosition, m_derivedRotation);
|
||||
m_viewMatrixUpdated = true;
|
||||
}
|
||||
|
||||
void NzView::UpdateViewport() const
|
||||
{
|
||||
unsigned int width = m_target->GetWidth();
|
||||
unsigned int height = std::max(m_target->GetHeight(), 1U);
|
||||
|
||||
m_viewport.x = width * m_targetRegion.x;
|
||||
m_viewport.y = height * m_targetRegion.y;
|
||||
m_viewport.width = width * m_targetRegion.width;
|
||||
m_viewport.height = height * m_targetRegion.height;
|
||||
m_viewportUpdated = true;
|
||||
}
|
||||
|
|
@ -605,7 +605,7 @@ bool NzGLSLProgram::PostLinkage()
|
|||
// Pour éviter de se tromper entre le nom et la constante
|
||||
#define CacheUniform(name) m_uniformLocations[nzShaderUniform_##name] = GetUniformLocation(#name)
|
||||
|
||||
CacheUniform(CameraPosition);
|
||||
CacheUniform(EyePosition);
|
||||
CacheUniform(InvTargetSize);
|
||||
CacheUniform(MaterialAlphaMap);
|
||||
CacheUniform(MaterialAlphaThreshold);
|
||||
|
|
|
|||
|
|
@ -163,11 +163,17 @@ void NzMaterial::Enable(nzRendererParameter renderParameter, bool enable)
|
|||
void NzMaterial::EnableAlphaTest(bool alphaTest)
|
||||
{
|
||||
m_alphaTestEnabled = alphaTest;
|
||||
|
||||
InvalidatePrograms(nzShaderTarget_FullscreenQuad);
|
||||
InvalidatePrograms(nzShaderTarget_Model);
|
||||
InvalidatePrograms(nzShaderTarget_Sprite);
|
||||
}
|
||||
|
||||
void NzMaterial::EnableLighting(bool lighting)
|
||||
{
|
||||
m_lightingEnabled = lighting;
|
||||
|
||||
InvalidatePrograms(nzShaderTarget_Model);
|
||||
}
|
||||
|
||||
NzTexture* NzMaterial::GetAlphaMap() const
|
||||
|
|
@ -410,7 +416,9 @@ void NzMaterial::SetAlphaMap(NzTexture* map)
|
|||
{
|
||||
m_alphaMap = map;
|
||||
|
||||
InvalidatePrograms(nzShaderTarget_FullscreenQuad);
|
||||
InvalidatePrograms(nzShaderTarget_Model);
|
||||
InvalidatePrograms(nzShaderTarget_Sprite);
|
||||
}
|
||||
|
||||
void NzMaterial::SetAlphaThreshold(float alphaThreshold)
|
||||
|
|
@ -454,7 +462,9 @@ void NzMaterial::SetDiffuseMap(NzTexture* map)
|
|||
{
|
||||
m_diffuseMap = map;
|
||||
|
||||
InvalidatePrograms(nzShaderTarget_FullscreenQuad);
|
||||
InvalidatePrograms(nzShaderTarget_Model);
|
||||
InvalidatePrograms(nzShaderTarget_Sprite);
|
||||
}
|
||||
|
||||
void NzMaterial::SetDiffuseSampler(const NzTextureSampler& sampler)
|
||||
|
|
@ -706,6 +716,12 @@ void NzMaterial::GenerateProgram(nzShaderTarget target, nzUInt32 flags) const
|
|||
|
||||
case nzShaderTarget_None:
|
||||
break;
|
||||
|
||||
case nzShaderTarget_Sprite:
|
||||
params.sprite.alphaMapping = m_alphaMap.IsValid();
|
||||
params.sprite.alphaTest = m_alphaTestEnabled;
|
||||
params.sprite.diffuseMapping = m_diffuseMap.IsValid();
|
||||
break;
|
||||
}
|
||||
|
||||
m_programs[target][flags].program = NzShaderProgramManager::Get(params);
|
||||
|
|
|
|||
|
|
@ -310,3 +310,9 @@ void NzRenderWindow::OnWindowDestroy()
|
|||
m_context = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void NzRenderWindow::OnWindowResized()
|
||||
{
|
||||
NotifySizeChange();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@
|
|||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Core/Log.hpp>
|
||||
#include <Nazara/Core/Clock.hpp>
|
||||
#include <Nazara/Core/Directory.hpp>
|
||||
#include <Nazara/Core/File.hpp>
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Renderer/ShaderProgramManager.hpp>
|
||||
#include <cstring>
|
||||
|
|
@ -24,9 +27,9 @@ namespace
|
|||
switch (params.target)
|
||||
{
|
||||
case nzShaderTarget_FullscreenQuad:
|
||||
h |= (params.fullscreenQuad.alphaMapping << 10) | // 1 bit
|
||||
(params.fullscreenQuad.alphaTest << 11) | // 1 bit
|
||||
(params.fullscreenQuad.diffuseMapping << 12); // 1 bit
|
||||
h |= (params.fullscreenQuad.alphaMapping << 10) | // 1 bit
|
||||
(params.fullscreenQuad.alphaTest << 11) | // 1 bit
|
||||
(params.fullscreenQuad.diffuseMapping << 12); // 1 bit
|
||||
break;
|
||||
|
||||
case nzShaderTarget_Model:
|
||||
|
|
@ -42,6 +45,12 @@ namespace
|
|||
|
||||
case nzShaderTarget_None:
|
||||
break;
|
||||
|
||||
case nzShaderTarget_Sprite:
|
||||
h |= (params.sprite.alphaMapping << 10) | // 1 bit
|
||||
(params.sprite.alphaTest << 11) | // 1 bit
|
||||
(params.sprite.diffuseMapping << 12); // 1 bit
|
||||
break;
|
||||
}
|
||||
|
||||
return h;
|
||||
|
|
@ -65,6 +74,9 @@ namespace
|
|||
|
||||
case nzShaderTarget_None:
|
||||
return true;
|
||||
|
||||
case nzShaderTarget_Sprite:
|
||||
return std::memcmp(&first.sprite, &second.sprite, sizeof(NzShaderProgramManagerParams::Sprite)) == 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
@ -72,12 +84,15 @@ namespace
|
|||
};
|
||||
|
||||
std::unordered_map<NzShaderProgramManagerParams, NzShaderProgramRef, ParamsHash, ParamsEquality> s_programs;
|
||||
NzString s_cacheDirectory("shaderCache");
|
||||
NzString s_inKW;
|
||||
NzString s_outKW;
|
||||
NzString s_fragmentColorKW;
|
||||
NzString s_textureLookupKW;
|
||||
bool s_cacheEnabled = false;
|
||||
bool s_earlyFragmentTest;
|
||||
bool s_glsl140;
|
||||
//bool s_loadCachedPrograms = true;
|
||||
unsigned int s_glslVersion;
|
||||
}
|
||||
|
||||
|
|
@ -86,8 +101,68 @@ const NzShaderProgram* NzShaderProgramManager::Get(const NzShaderProgramManagerP
|
|||
auto it = s_programs.find(params);
|
||||
if (it == s_programs.end())
|
||||
{
|
||||
// Alors nous gébérons le programme
|
||||
NzShaderProgram* program = GenerateProgram(params);
|
||||
// Alors nous générons le programme
|
||||
std::unique_ptr<NzShaderProgram> program;
|
||||
|
||||
if (s_cacheEnabled)
|
||||
{
|
||||
NzString programFileName = NzNumberToString(ParamsHash()(params), 36) + ".nsb"; // Nazara Shader Binary, très original, je sais
|
||||
NazaraDebug("Checking cache for program file \"" + programFileName + "\"...");
|
||||
|
||||
NzFile shaderFile(s_cacheDirectory + NAZARA_DIRECTORY_SEPARATOR + programFileName);
|
||||
if (shaderFile.Open(NzFile::ReadOnly))
|
||||
{
|
||||
NazaraDebug("File found");
|
||||
|
||||
unsigned int size = shaderFile.GetSize();
|
||||
|
||||
NzByteArray binary;
|
||||
binary.Resize(size);
|
||||
|
||||
if (shaderFile.Read(&binary[0], size) != size)
|
||||
{
|
||||
NazaraError("Failed to read program binary");
|
||||
return false;
|
||||
}
|
||||
|
||||
shaderFile.Close();
|
||||
|
||||
program.reset(new NzShaderProgram);
|
||||
if (!program->LoadFromBinary(binary))
|
||||
{
|
||||
NazaraWarning("Program \"" + programFileName + "\" loading failed, this is mostly due to a driver/video card "
|
||||
"update or a file corruption, regenerating program...");
|
||||
|
||||
program.reset(GenerateProgram(params));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (shaderFile.Exists())
|
||||
NazaraWarning("Program file exists but couldn't be opened");
|
||||
|
||||
program.reset(GenerateProgram(params));
|
||||
if (program)
|
||||
{
|
||||
if (program->IsBinaryRetrievable())
|
||||
{
|
||||
NazaraDebug("Program \"" + programFileName + "\" (re)generated, saving it into program cache directory...");
|
||||
|
||||
NzByteArray programBinary = program->GetBinary();
|
||||
if (!programBinary.IsEmpty())
|
||||
{
|
||||
if (!shaderFile.Open(NzFile::Truncate | NzFile::WriteOnly) || !shaderFile.Write(programBinary))
|
||||
NazaraWarning("Failed to save program binary to file \"" + programFileName + "\": " + NzGetLastSystemError());
|
||||
}
|
||||
else
|
||||
NazaraWarning("Failed to retrieve shader program binary");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
program.reset(GenerateProgram(params));
|
||||
|
||||
if (!program)
|
||||
{
|
||||
NazaraWarning("Failed to build program, using default one...");
|
||||
|
|
@ -96,12 +171,10 @@ const NzShaderProgram* NzShaderProgramManager::Get(const NzShaderProgramManagerP
|
|||
defaultParams.flags = params.flags;
|
||||
defaultParams.target = nzShaderTarget_None;
|
||||
|
||||
program = s_programs[defaultParams]; // Shader par défaut
|
||||
program.reset(s_programs[defaultParams]); // Shader par défaut
|
||||
}
|
||||
|
||||
s_programs[params] = program;
|
||||
|
||||
return program;
|
||||
return program.release();
|
||||
}
|
||||
else
|
||||
return it->second;
|
||||
|
|
@ -125,13 +198,14 @@ NzString NzShaderProgramManager::BuildFragmentCode(const NzShaderProgramManagerP
|
|||
source += NzString::Number(s_glslVersion);
|
||||
source += "\n\n";
|
||||
|
||||
if (s_earlyFragmentTest)
|
||||
source += "layout(early_fragment_tests) in;" "\n\n";
|
||||
|
||||
switch (params.target)
|
||||
{
|
||||
case nzShaderTarget_FullscreenQuad:
|
||||
{
|
||||
// "discard" ne s'entend pas bien avec les early fragment tests
|
||||
if (s_earlyFragmentTest && !params.fullscreenQuad.alphaMapping)
|
||||
source += "layout(early_fragment_tests) in;" "\n\n";
|
||||
|
||||
/********************Entrant********************/
|
||||
if (params.fullscreenQuad.alphaMapping || params.fullscreenQuad.diffuseMapping)
|
||||
source += s_inKW + " vec2 vTexCoord;" "\n\n";
|
||||
|
|
@ -162,23 +236,17 @@ NzString NzShaderProgramManager::BuildFragmentCode(const NzShaderProgramManagerP
|
|||
if (params.fullscreenQuad.diffuseMapping)
|
||||
source += '*' + s_textureLookupKW + "(MaterialDiffuseMap, vTexCoord)";
|
||||
|
||||
source += ";" "\n"
|
||||
"\t" "float fragmentAlpha = ";
|
||||
|
||||
if (params.fullscreenQuad.diffuseMapping)
|
||||
source += "fragmentColor.a";
|
||||
else
|
||||
source += "MaterialDiffuse.a";
|
||||
source += ";" "\n";
|
||||
|
||||
if (params.fullscreenQuad.alphaMapping)
|
||||
source += '*' + s_textureLookupKW + "(MaterialAlphaMap, vTexCoord).r";
|
||||
source += "fragmentColor.a *= " + s_textureLookupKW + "(MaterialAlphaMap, vTexCoord).r";
|
||||
|
||||
source += ";" "\n";
|
||||
|
||||
if (params.fullscreenQuad.alphaMapping)
|
||||
{
|
||||
source += "if (fragmentAlpha < MaterialAlphaThreshold)" "\n"
|
||||
"\t" "discard;" "\n";
|
||||
source += "\t" "if (fragmentColor.a < MaterialAlphaThreshold)" "\n"
|
||||
"\t\t" "discard;" "\n";
|
||||
}
|
||||
|
||||
source += "\t" "RenderTarget0 = fragmentColor;" "\n"
|
||||
|
|
@ -191,6 +259,10 @@ NzString NzShaderProgramManager::BuildFragmentCode(const NzShaderProgramManagerP
|
|||
//bool parallaxMapping = (params.model.lighting && params.model.parallaxMapping);
|
||||
bool uvMapping = (params.model.alphaMapping || params.model.diffuseMapping || params.model.normalMapping || params.model.specularMapping);
|
||||
|
||||
// "discard" ne s'entend pas bien avec les early fragment tests
|
||||
if (s_earlyFragmentTest && !params.model.alphaMapping)
|
||||
source += "layout(early_fragment_tests) in;" "\n\n";
|
||||
|
||||
if (params.model.lighting)
|
||||
{
|
||||
source += "#define LIGHT_DIRECTIONAL 0" "\n"
|
||||
|
|
@ -235,7 +307,7 @@ NzString NzShaderProgramManager::BuildFragmentCode(const NzShaderProgramManagerP
|
|||
"\t" "vec2 parameters3;" "\n"
|
||||
"};" "\n\n"
|
||||
|
||||
"uniform vec3 CameraPosition;" "\n"
|
||||
"uniform vec3 EyePosition;" "\n"
|
||||
"uniform Light Lights[3];" "\n"
|
||||
"uniform vec4 MaterialAmbient;" "\n";
|
||||
}
|
||||
|
|
@ -298,8 +370,8 @@ NzString NzShaderProgramManager::BuildFragmentCode(const NzShaderProgramManagerP
|
|||
|
||||
if (params.model.alphaTest)
|
||||
{
|
||||
source += "if (diffuseColor.a < MaterialAlphaThreshold)" "\n"
|
||||
"\t" "discard;" "\n";
|
||||
source += "\t" "if (fragmentColor.a < MaterialAlphaThreshold)" "\n"
|
||||
"\t\t" "discard;" "\n";
|
||||
}
|
||||
|
||||
if (params.model.lighting)
|
||||
|
|
@ -318,7 +390,7 @@ NzString NzShaderProgramManager::BuildFragmentCode(const NzShaderProgramManagerP
|
|||
|
||||
source += "\t" "if (MaterialShininess > 0.0)" "\n"
|
||||
"\t" "{" "\n"
|
||||
"\t\t" "vec3 eyeVec = normalize(CameraPosition - vWorldPos);" "\n\n"
|
||||
"\t\t" "vec3 eyeVec = normalize(EyePosition - vWorldPos);" "\n\n"
|
||||
|
||||
"\t\t" "for (int i = 0; i < 3; ++i)" "\n"
|
||||
"\t\t" "{" "\n";
|
||||
|
|
@ -551,6 +623,9 @@ NzString NzShaderProgramManager::BuildFragmentCode(const NzShaderProgramManagerP
|
|||
|
||||
case nzShaderTarget_None:
|
||||
{
|
||||
if (s_earlyFragmentTest)
|
||||
source += "layout(early_fragment_tests) in;" "\n\n";
|
||||
|
||||
/********************Sortant********************/
|
||||
if (s_glsl140)
|
||||
source += "out vec4 RenderTarget0;" "\n\n";
|
||||
|
|
@ -565,6 +640,60 @@ NzString NzShaderProgramManager::BuildFragmentCode(const NzShaderProgramManagerP
|
|||
source += "}" "\n";
|
||||
break;
|
||||
}
|
||||
|
||||
case nzShaderTarget_Sprite:
|
||||
{
|
||||
// "discard" ne s'entend pas bien avec les early fragment tests
|
||||
if (s_earlyFragmentTest && !params.sprite.alphaMapping)
|
||||
source += "layout(early_fragment_tests) in;" "\n\n";
|
||||
|
||||
/********************Entrant********************/
|
||||
if (params.sprite.alphaMapping || params.sprite.diffuseMapping)
|
||||
source += s_inKW + " vec2 vTexCoord;" "\n\n";
|
||||
|
||||
/********************Sortant********************/
|
||||
if (s_glsl140)
|
||||
source += "out vec4 RenderTarget0;" "\n\n";
|
||||
|
||||
/********************Uniformes********************/
|
||||
if (params.sprite.alphaMapping)
|
||||
source += "uniform sampler2D MaterialAlphaMap;" "\n";
|
||||
|
||||
if (params.sprite.alphaTest)
|
||||
source += "uniform float MaterialAlphaThreshold;" "\n";
|
||||
|
||||
source += "uniform vec4 MaterialDiffuse;" "\n";
|
||||
|
||||
if (params.sprite.diffuseMapping)
|
||||
source += "uniform sampler2D MaterialDiffuseMap;" "\n";
|
||||
|
||||
source += '\n';
|
||||
|
||||
/********************Fonctions********************/
|
||||
source += "void main()" "\n"
|
||||
"{" "\n";
|
||||
|
||||
source += "\t" "vec4 fragmentColor = MaterialDiffuse";
|
||||
if (params.sprite.diffuseMapping)
|
||||
source += '*' + s_textureLookupKW + "(MaterialDiffuseMap, vTexCoord)";
|
||||
|
||||
source += ";" "\n";
|
||||
|
||||
if (params.sprite.alphaMapping)
|
||||
source += "fragmentColor.a *= " + s_textureLookupKW + "(MaterialAlphaMap, vTexCoord).r";
|
||||
|
||||
source += ";" "\n";
|
||||
|
||||
if (params.sprite.alphaMapping)
|
||||
{
|
||||
source += "\t" "if (fragmentColor.a < MaterialAlphaThreshold)" "\n"
|
||||
"\t\t" "discard;" "\n";
|
||||
}
|
||||
|
||||
source += "\t" "RenderTarget0 = fragmentColor;" "\n"
|
||||
"}" "\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return source;
|
||||
|
|
@ -754,6 +883,54 @@ NzString NzShaderProgramManager::BuildVertexCode(const NzShaderProgramManagerPar
|
|||
source += "}" "\n";
|
||||
break;
|
||||
}
|
||||
|
||||
case nzShaderTarget_Sprite:
|
||||
{
|
||||
bool uvMapping = (params.fullscreenQuad.alphaMapping || params.fullscreenQuad.diffuseMapping);
|
||||
|
||||
/********************Entrant********************/
|
||||
if (params.flags & nzShaderFlags_Instancing)
|
||||
source += s_inKW + " mat4 InstanceData0;" "\n";
|
||||
|
||||
source += s_inKW + " vec3 VertexPosition;" "\n";
|
||||
|
||||
if (uvMapping)
|
||||
source += s_inKW + " vec2 VertexTexCoord;" "\n";
|
||||
|
||||
source += '\n';
|
||||
|
||||
/********************Sortant********************/
|
||||
if (uvMapping)
|
||||
source += s_outKW + " vec2 vTexCoord;" "\n\n";
|
||||
|
||||
/********************Uniformes********************/
|
||||
if (params.flags & nzShaderFlags_Instancing)
|
||||
source += "uniform mat4 ViewProjMatrix;" "\n";
|
||||
else
|
||||
source += "uniform mat4 WorldViewProjMatrix;" "\n";
|
||||
|
||||
source += '\n';
|
||||
|
||||
/********************Code********************/
|
||||
source += "void main()" "\n"
|
||||
"{" "\n";
|
||||
|
||||
if (params.flags & nzShaderFlags_Instancing)
|
||||
source += "\t" "gl_Position = ViewProjMatrix * InstanceData0 * vec4(VertexPosition, 1.0);" "\n";
|
||||
else
|
||||
source += "\t" "gl_Position = WorldViewProjMatrix * vec4(VertexPosition, 1.0);" "\n";
|
||||
|
||||
if (uvMapping)
|
||||
{
|
||||
if (params.flags & nzShaderFlags_FlipUVs)
|
||||
source += "\t" "vTexCoord = vec2(VertexTexCoord.x, 1.0 - VertexTexCoord.y);" "\n";
|
||||
else
|
||||
source += "\t" "vTexCoord = VertexTexCoord;" "\n";
|
||||
}
|
||||
|
||||
source += "}" "\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return source;
|
||||
|
|
@ -825,6 +1002,54 @@ bool NzShaderProgramManager::Initialize()
|
|||
s_programs[params] = program;
|
||||
}
|
||||
|
||||
/*if (s_loadCachedPrograms)
|
||||
{
|
||||
NzDirectory cacheDirectory(s_cacheDirectory);
|
||||
cacheDirectory.SetPattern("*.nsb");
|
||||
|
||||
if (cacheDirectory.Open())
|
||||
{
|
||||
while (cacheDirectory.NextResult(true))
|
||||
{
|
||||
long long hash;
|
||||
if (cacheDirectory.GetResultName().SubStringTo(".nsb", -1, true, false).ToInteger(&hash, 32))
|
||||
{
|
||||
std::size_t hashCode = static_cast<std::size_t>(hash);
|
||||
|
||||
if (s_programs.find(hashCode) == s_programs.end())
|
||||
{
|
||||
NzFile shaderFile(cacheDirectory.GetResultPath());
|
||||
if (shaderFile.Open(NzFile::ReadOnly))
|
||||
{
|
||||
unsigned int size = cacheDirectory.GetResultSize();
|
||||
|
||||
NzByteArray binary;
|
||||
binary.Resize(size);
|
||||
|
||||
if (shaderFile.Read(&binary[0], size) != size)
|
||||
{
|
||||
NazaraError("Failed to read program binary");
|
||||
return false;
|
||||
}
|
||||
|
||||
shaderFile.Close();
|
||||
|
||||
std::unique_ptr<NzShaderProgram> program(new NzShaderProgram);
|
||||
if (program->LoadFromBinary(binary))
|
||||
s_programs[hashCode] = binary.release();
|
||||
else
|
||||
NazaraWarning("Program binary \"" + cacheDirectory.GetResultName() + "\" loading failed, this is mostly due to a driver/video card "
|
||||
"update or a file corruption, regenerating program..."); }
|
||||
}
|
||||
}
|
||||
else
|
||||
NazaraWarning("Failed to parse program file name (" + cacheDirectory.GetResultName() + ')');
|
||||
}
|
||||
}
|
||||
else if (cacheDirectory.Exists())
|
||||
NazaraWarning("Failed to open shader cache directory");
|
||||
}*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue