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