Merge branch 'Graphics-Update'

Former-commit-id: 9855f235dd21d47d1cd9da8c3c0b4ede41e74472
This commit is contained in:
Lynix 2013-08-21 20:05:50 +02:00
commit 6556acfa32
39 changed files with 1772 additions and 554 deletions

View File

@ -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();

View File

@ -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

View File

@ -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;
};

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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;
};

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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;
};

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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,

View File

@ -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;

View File

@ -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;
};
};

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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
{
public:
LightManager() = default;
~LightManager() = default;
static NzIndexBuffer* s_indexBuffer = nullptr;
unsigned int maxLightCount = 3; ///TODO: Constante sur le nombre maximum de lumières
unsigned int s_maxSprites = 8192;
unsigned int FindClosestLights(const NzLight** lights, unsigned int lightCount, const NzVector3f& position, float squaredRadius)
NzIndexBuffer* BuildIndexBuffer()
{
for (Light& light : m_lights)
std::unique_ptr<NzIndexBuffer> indexBuffer(new NzIndexBuffer(false, s_maxSprites*6, nzBufferStorage_Hardware, nzBufferUsage_Static));
indexBuffer->SetPersistent(false);
NzBufferMapper<NzIndexBuffer> mapper(indexBuffer.get(), nzBufferAccess_WriteOnly);
nzUInt16* indices = static_cast<nzUInt16*>(mapper.GetPointer());
for (unsigned int i = 0; i < s_maxSprites; ++i)
{
light.light = nullptr;
light.score = std::numeric_limits<unsigned int>::max(); // Nous jouons au Golf
*indices++ = i*4 + 0;
*indices++ = i*4 + 2;
*indices++ = i*4 + 1;
*indices++ = i*4 + 2;
*indices++ = i*4 + 3;
*indices++ = i*4 + 1;
}
for (unsigned int i = 0; i < lightCount; ++i)
{
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;
return indexBuffer.release();
}
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
};
}
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
}
}
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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
}

View File

@ -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);

View File

@ -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()
{
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -310,3 +310,9 @@ void NzRenderWindow::OnWindowDestroy()
m_context = nullptr;
}
}
void NzRenderWindow::OnWindowResized()
{
NotifySizeChange();
}

View File

@ -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>
@ -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;
}