//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#pragma once
#ifndef RENDER_PROBE_MGR_H
#define RENDER_PROBE_MGR_H
#ifndef _RENDERBINMANAGER_H_
#include "renderInstance/renderBinManager.h"
#endif
#ifndef _MATINSTANCE_H_
#include "materials/matInstance.h"
#endif
#ifndef _MATTEXTURETARGET_H_
#include "materials/matTextureTarget.h"
#endif
#ifndef _GFXPRIMITIVEBUFFER_H_
#include "gfx/gfxPrimitiveBuffer.h"
#endif
#ifndef _GFXVERTEXBUFFER_H_
#include "gfx/gfxVertexBuffer.h"
#endif
//#include "core/util/systemInterfaceList.h"
#ifndef _MATERIALS_PROCESSEDSHADERMATERIAL_H_
#include "materials/processedShaderMaterial.h"
#endif
#ifndef _POSTEFFECTCOMMON_H_
#include "postFx/postEffectCommon.h"
#endif
#ifndef _REFLECTOR_H_
#include "scene/reflector.h"
#endif
#ifndef REFLECTIONPROBE_H
#include "T3D/lighting/reflectionProbe.h"
#endif
class PostEffect;
class ReflectionProbe;
///
/// A simple container for a ReflectionProbe's ProbeInfo and index for it's associated
/// cubemaps in the cubemap array pair
///
struct ProbeRenderInst
{
ReflectionProbe::ProbeInfo* mProbeInfo;
U32 mCubemapIndex;
public:
ProbeRenderInst();
~ProbeRenderInst();
// Copies data passed in from light
void set(const ProbeRenderInst *probeInfo);
};
///
/// A container for all the shader consts needed for rendering probes in forward mode
///
struct ProbeShaderConstants
{
bool mInit;
GFXShaderRef mShader;
//Reflection Probes
GFXShaderConstHandle *mProbePositionArraySC;
GFXShaderConstHandle *mProbeRefPosArraySC;
GFXShaderConstHandle *mRefScaleArraySC;
GFXShaderConstHandle *mWorldToObjArraySC;
GFXShaderConstHandle *mProbeConfigDataArraySC;
GFXShaderConstHandle *mProbeSpecularCubemapArraySC;
GFXShaderConstHandle *mProbeIrradianceCubemapArraySC;
GFXShaderConstHandle *mProbeCountSC;
GFXShaderConstHandle *mBRDFTextureMap;
GFXShaderConstHandle* mWetnessTextureMap;
GFXShaderConstHandle *mSkylightCubemapIdxSC;
GFXShaderConstHandle* mSkylightDampSC;
GFXShaderConstHandle* mMaxProbeDrawDistanceSC;
ProbeShaderConstants();
~ProbeShaderConstants();
void init(GFXShader* buffer);
bool isValid();
void _onShaderReload();
};
typedef Map ProbeConstantMap;
///
/// A container for processed and packed probe data. This is made when we get the frame's
/// best probes, and is passed to the shader for actual rendering.
///
struct ProbeDataSet
{
Vector probePositionArray;
Vector refScaleArray;
Vector probeRefPositionArray;
Vector probeConfigArray;
Vector probeWorldToObjArray;
S32 skyLightIdx;
bool skyLightDamp;
U32 effectiveProbeCount;
U32 maxProbeCount;
ProbeDataSet()
{
probePositionArray.setSize(0);
refScaleArray.setSize(0);
probeRefPositionArray.setSize(0);
probeConfigArray.setSize(0);
probeWorldToObjArray.setSize(0);
skyLightIdx = -1;
effectiveProbeCount = 0;
maxProbeCount = 0;
skyLightDamp = true;
}
ProbeDataSet(U32 _maxProbeCount)
{
maxProbeCount = _maxProbeCount;
probePositionArray.setSize(maxProbeCount);
refScaleArray.setSize(maxProbeCount);
probeRefPositionArray.setSize(maxProbeCount);
probeConfigArray.setSize(maxProbeCount);
probeWorldToObjArray.setSize(maxProbeCount);
effectiveProbeCount = 0;
}
};
//**************************************************************************
// RenderObjectMgr
//**************************************************************************
class RenderProbeMgr : public RenderBinManager
{
typedef RenderBinManager Parent;
public:
//maximum number of allowed probes
static const U32 PROBE_MAX_COUNT = 250;
//maximum number of rendered probes per frame adjust as needed
static const U32 PROBE_MAX_FRAME = 8;
//number of slots to allocate at once in the cubemap array
static const U32 PROBE_ARRAY_SLOT_BUFFER_SIZE = 10;
//These dictate the default resolution size for the probe arrays
static const GFXFormat PROBE_FORMAT = GFXFormatR16G16B16A16F;// GFXFormatR8G8B8A8;// when hdr fixed GFXFormatR16G16B16A16F; look into bc6h compression
static const U32 INVALID_CUBE_SLOT = U32_MAX;
static F32 smMaxProbeDrawDistance;
static S32 smMaxProbesPerFrame;
static S32 smProbeBakeResolution;
SceneRenderState *mState;
private:
///
/// List of registered probes. These are not necessarily rendered in a given frame
/// but the Probe Manager is aware of them and they have cubemap array slots allocated
///
Vector mRegisteredProbes;
///
/// List of active probes. These are ones that are not only registered, but submitted by the probe itself as
/// ready to be rendered. Likely to be rendered in the current frame, settings-dependent.
///
Vector mActiveProbes;
///
/// The PostEffect used to actually rendered the probes into the frame when in deferred mode
///
SimObjectPtr mProbeArrayEffect;
///
/// Do we have a active skylight probe
///
bool mHasSkylight;
///
/// If we have a skylight, what's the array pair index for it?
///
S32 mSkylightCubemapIdx;
bool mSkylightDamp;
///
/// The 'effective' probe count. This tracks the number of probes that are actually going to be rendered
///
U32 mEffectiveProbeCount;
//
//Array rendering
///
/// The number of mips the cubemap array has. Mips are used in the PBR calcs for handling roughness
///
S32 mMipCount;
///
/// The number of cubemaps registered in our array pair
///
U32 mCubeMapCount;
///
/// The number of allocated slots for the array pair. Rather than adding slots one at a time to the arrays
/// We allocate in chunks so we don't have to resize/rebuild the arrays as often
///
U32 mCubeSlotCount;
///
/// List indicating if a given allocated slot is actually in use.
/// Due to the editor these may be mixed around as probes are added and deleted
///
///
bool mCubeMapSlots[PROBE_MAX_COUNT];
///
/// The prefilter cubemap array
///
GFXCubemapArrayHandle mPrefilterArray;
///
/// The irradiance cubemap array
///
GFXCubemapArrayHandle mIrradianceArray;
//Utilized in forward rendering
///
/// This is used to look up already-made ProbeShaderConsts for a given shader
/// This allows us to avoid having to rebuild the consts each frame if it's a shader
/// we've already handled before.
///
ProbeConstantMap mConstantLookup;
///
/// The last shader we rendered(in forward mode). With this, we can shortcut the constant
/// lookup if the shader being processed and the last one are the same.
///
GFXShaderRef mLastShader;
///
/// THe previous shader constants. When used in conjunction with the mLastShader, we can skip
/// having to do a lookup to find an existing ProbeShaderConstants, saving overhead on batched
/// rendering
///
ProbeShaderConstants* mLastConstants;
///
/// The BRDF texture used in PBR math calculations
///
GFXTexHandle mBRDFTexture;
GFXTexHandle mWetnessTexture;
///
/// Processed best probe selection list of the current frame when rendering in deferred mode.
///
ProbeDataSet mProbeData;
///
/// Allows us the full HDR range on the in-memory cubemap captures
///
bool mUseHDRCaptures;
///
/// holds the normal render state for light fade so we can capture them before and restore them after baking
///
S32 mRenderMaximumNumOfLights;
bool mRenderUseLightFade;
protected:
/// The current active light manager.
static RenderProbeMgr* smProbeManager;
//=============================================================================
// Internal Management/Utility Functions
//=============================================================================
///
/// Simple utility function that finds the next free cubemap slot for the cubemap array
///
/// U32 index of next available slot
U32 _findNextEmptyCubeSlot()
{
for (U32 i = 0; i < PROBE_MAX_COUNT; i++)
{
if (!mCubeMapSlots[i])
return i;
}
return INVALID_CUBE_SLOT;
}
///
/// Utility function to quickly find a ProbeRenderInst in association to a
/// ReflectionProbe's ProbeInfo
///
///
/// Associated ProbeRederInst to param's probeInfo. Null if no matches found
ProbeRenderInst* findProbeInst(ReflectionProbe::ProbeInfo* probeInfo)
{
for (U32 i = 0; i < mRegisteredProbes.size(); i++)
{
auto asd = mRegisteredProbes[i];
if (mRegisteredProbes[i].mProbeInfo == probeInfo)
{
return &mRegisteredProbes[i];
}
}
return nullptr;
}
public:
RenderProbeMgr();
RenderProbeMgr(RenderInstType riType, F32 renderOrder, F32 processAddOrder);
virtual ~RenderProbeMgr();
virtual bool onAdd();
virtual void onRemove();
// ConsoleObject
static void initPersistFields();
static void consoleInit();
virtual void addElement(RenderInst* inst) {};
DECLARE_CONOBJECT(RenderProbeMgr);
///
/// Static flag used to indicate if probes should be rendered at all. Used for debugging
///
static bool smRenderReflectionProbes;
//=============================================================================
// Utility functions for processing and setting up the probes for rendering
//=============================================================================
///
/// Sorts probes based on their score values. These scores are calculated by the probes themselves based on size, distance from camera, etc
///
static S32 QSORT_CALLBACK _probeScoreCmp(const ProbeRenderInst* a, const ProbeRenderInst* b);
///
/// Builds a dataset of the best probes to be rendered this frame.
///
///
///
void getBestProbes(const Point3F& objPosition, ProbeDataSet* probeDataSet);
///
/// This function adds a ReflectionProbe to the registered list and also allocates
/// a slot in the cubemap array pair for its use
///
/// The probe info to be registered to the bin
void registerProbe(ReflectionProbe::ProbeInfo* probeInfo);
///
/// This function removes the ReflectionProbe from the registered list, and marks it's cubemap
/// array slots as unused, allowing them to be freed.
///
/// The probe info to be un-registered to the bin
void unregisterProbe(ReflectionProbe::ProbeInfo* probeInfo);
///
/// This function is for registering a ReflectionProbe's probe info
/// as being rendered in the current frame. This is distinct from
/// registered probes in that registered probes are any 'real' probe
/// in the scene, but they may not necessarily render
/// Active(submmitted) probes are intended to actual be rendered this frame
///
/// The ProbeInfo being submitted to be rendered
void submitProbe(ReflectionProbe::ProbeInfo* probe);
///
/// Gets the PostEffect used by the bin for rendering the probe array in deferred
///
/// the PostEffect object
PostEffect* getProbeArrayEffect();
U32 getProbeTexSize();
///
/// Finds the associated cubemap array slot for the incoming ProbeInfo and updates the array's texture(s) from it
///
///
void updateProbeTexture(ReflectionProbe::ProbeInfo* probeInfo);
///
/// Forces an update for all registered probes' cubemaps
///
void reloadTextures();
///
/// Takes a reflection probe and runs the cubemap bake process on it, outputting the resulting files to disk
///
void bakeProbe(ReflectionProbe* probe);
void preBake();
void postBake();
///
/// Runs the cubemap bake on all probes in the current scene
///
void bakeProbes();
///
/// Returns the active Probe Manager.
///
static inline RenderProbeMgr* getProbeManager();
//=============================================================================
// Forward Rendering functions
//=============================================================================
///
/// This function returns or builds a ProbeShaderConsts containing needed data for
/// rendering probes in forward mode
///
/// The GFXShaderConstBuffer used to build or fetch the Probe Consts
ProbeShaderConstants* getProbeShaderConstants(GFXShaderConstBuffer* buffer);
///
/// Sets up the probe data required for doing a render in forward mode.
///
virtual void setProbeInfo(ProcessedMaterial* pmat,
const Material* mat,
const SceneData& sgData,
const SceneRenderState* state,
U32 pass,
GFXShaderConstBuffer* shaderConsts);
///
/// Invoked as part of the setup in preperation to render an object in forward mode. Used to ensure the probes are
/// sorted ahead of render.
///
///
void setupSGData(SceneData& data, const SceneRenderState* state, LightInfo* light);
///
/// Sets up and binds all the shader const data required for rendering probes/IBL for a forward-rendered material.
///
///
void _update4ProbeConsts(const SceneData& sgData,
MatrixSet& matSet,
ProbeShaderConstants* probeShaderConsts,
GFXShaderConstBuffer* shaderConsts);
//=============================================================================
// Deferred Rendering Functions
//=============================================================================
///
/// Ensures the probes are properly sorted before we render them in deferred mode
///
void _setupPerFrameParameters(const SceneRenderState *state);
///
/// Renders the sorted probes list via a PostEffect to draw them into the buffer data in deferred mode.
///
virtual void render(SceneRenderState * state);
virtual void clear() { mActiveProbes.clear(); Parent::clear(); }
};
RenderProbeMgr* RenderProbeMgr::getProbeManager()
{
if (smProbeManager == nullptr)
{
RenderProbeMgr* probeManager = new RenderProbeMgr();
smProbeManager = probeManager;
}
return smProbeManager;
}
#define PROBEMGR RenderProbeMgr::getProbeManager()
#endif // RENDER_PROBE_MGR_H