diff --git a/Engine/source/T3D/lighting/boxEnvironmentProbe.cpp b/Engine/source/T3D/lighting/boxEnvironmentProbe.cpp index a08691d1c..e532acd3c 100644 --- a/Engine/source/T3D/lighting/boxEnvironmentProbe.cpp +++ b/Engine/source/T3D/lighting/boxEnvironmentProbe.cpp @@ -77,7 +77,7 @@ ConsoleDocClass(BoxEnvironmentProbe, BoxEnvironmentProbe::BoxEnvironmentProbe() : ReflectionProbe() { mCaptureMask = REFLECTION_PROBE_CAPTURE_TYPEMASK; - mProbeShapeType = ProbeRenderInst::Box; + mProbeShapeType = ProbeInfo::Box; mAtten = 0.0; } @@ -158,7 +158,7 @@ void BoxEnvironmentProbe::unpackUpdate(NetConnection *conn, BitStream *stream) void BoxEnvironmentProbe::updateProbeParams() { - mProbeShapeType = ProbeRenderInst::Box; + mProbeShapeType = ProbeInfo::Box; mProbeInfo.mAtten = mAtten; Parent::updateProbeParams(); diff --git a/Engine/source/T3D/lighting/reflectionProbe.cpp b/Engine/source/T3D/lighting/reflectionProbe.cpp index 9361b05f1..1715ac758 100644 --- a/Engine/source/T3D/lighting/reflectionProbe.cpp +++ b/Engine/source/T3D/lighting/reflectionProbe.cpp @@ -73,8 +73,8 @@ ConsoleDocClass(ReflectionProbe, ImplementEnumType(ReflectProbeType, "Type of mesh data available in a shape.\n" "@ingroup gameObjects") -{ ProbeRenderInst::Sphere, "Sphere", "Sphere shaped" }, -{ ProbeRenderInst::Box, "Box", "Box shape" } +{ ReflectionProbe::ProbeInfo::Sphere, "Sphere", "Sphere shaped" }, +{ ReflectionProbe::ProbeInfo::Box, "Box", "Box shape" } EndImplementEnumType; ImplementEnumType(ReflectionModeEnum, @@ -97,7 +97,7 @@ ReflectionProbe::ReflectionProbe() mTypeMask = LightObjectType | MarkerObjectType; - mProbeShapeType = ProbeRenderInst::Box; + mProbeShapeType = ProbeInfo::Box; mReflectionModeType = BakedCubemap; @@ -121,8 +121,6 @@ ReflectionProbe::ReflectionProbe() mRefreshRateMS = 200; mDynamicLastBakeMS = 0; - mMaxDrawDistance = 75; - mResourcesCreated = false; mPrefilterSize = 64; mPrefilterMipLevels = mLog2(F32(mPrefilterSize)); @@ -239,7 +237,7 @@ bool ReflectionProbe::_setRadius(void *object, const char *index, const char *da { ReflectionProbe* probe = reinterpret_cast(object); - if (probe->mProbeShapeType != ProbeRenderInst::Sphere) + if (probe->mProbeShapeType != ProbeInfo::Sphere) return false; probe->mObjScale = Point3F(probe->mRadius, probe->mRadius, probe->mRadius); @@ -291,7 +289,7 @@ bool ReflectionProbe::onAdd() if (!mPersistentId) mPersistentId = getOrCreatePersistentId(); - mProbeUniqueID = String::ToString(mPersistentId->getUUID().getHash()); + mProbeUniqueID = mPersistentId->getUUID().toString(); } // Refresh this object's material (if any) @@ -312,7 +310,7 @@ void ReflectionProbe::onRemove() { if (isClientObject()) { - PROBEMGR->unregisterProbe(mProbeInfo.mProbeIdx); + PROBEMGR->unregisterProbe(&mProbeInfo); } // Remove this object from the scene @@ -461,10 +459,10 @@ void ReflectionProbe::unpackUpdate(NetConnection *conn, BitStream *stream) if (stream->readFlag()) // StaticDataMask { - U32 shapeType = ProbeRenderInst::Sphere; + U32 shapeType = ProbeInfo::Sphere; stream->read(&shapeType); - mProbeShapeType = (ProbeRenderInst::ProbeShapeType)shapeType; + mProbeShapeType = (ProbeInfo::ProbeShapeType)shapeType; stream->read(&mRadius); @@ -497,6 +495,8 @@ void ReflectionProbe::unpackUpdate(NetConnection *conn, BitStream *stream) //----------------------------------------------------------------------------- void ReflectionProbe::updateProbeParams() { + mProbeInfo.mObject = this; + if (!mResourcesCreated) { if (!createClientResources()) @@ -507,12 +507,12 @@ void ReflectionProbe::updateProbeParams() mProbeInfo.mProbeShapeType = mProbeShapeType; - if (mProbeShapeType == ProbeRenderInst::Sphere) + if (mProbeShapeType == ProbeInfo::Sphere) mObjScale.set(mRadius, mRadius, mRadius); Box3F bounds; - if (mProbeShapeType == ProbeRenderInst::Skylight) + if (mProbeShapeType == ProbeInfo::Skylight) { mProbeInfo.mPosition = Point3F::Zero; mProbeInfo.mTransform = MatrixF::Identity; @@ -564,8 +564,6 @@ void ReflectionProbe::updateProbeParams() else processDynamicCubemap(); } - - PROBEMGR->updateProbes(); } void ReflectionProbe::processDynamicCubemap() @@ -575,7 +573,7 @@ void ReflectionProbe::processDynamicCubemap() void ReflectionProbe::processBakedCubemap() { - mProbeInfo.mIsEnabled = false; + //mProbeInfo.mIsEnabled = false; if ((mReflectionModeType != BakedCubemap) || mProbeUniqueID.isEmpty()) return; @@ -611,7 +609,7 @@ void ReflectionProbe::processBakedCubemap() if (mEnabled && mProbeInfo.mPrefilterCubemap->isInitialized() && mProbeInfo.mIrradianceCubemap->isInitialized()) { - mProbeInfo.mIsEnabled = true; + //mProbeInfo.mIsEnabled = true; mCubemapDirty = false; @@ -622,6 +620,11 @@ void ReflectionProbe::processBakedCubemap() mProbeInfo.mPrefilterCubemap.free(); mProbeInfo.mIrradianceCubemap.free(); } + else + { + //if we failed, disable + mProbeInfo.mIsEnabled = false; + } } void ReflectionProbe::processStaticCubemap() @@ -811,16 +814,16 @@ void ReflectionProbe::createEditorResources() void ReflectionProbe::prepRenderImage(SceneRenderState *state) { - if (!mEnabled || !RenderProbeMgr::smRenderReflectionProbes) + if (!mEnabled || (!RenderProbeMgr::smRenderReflectionProbes && Con::getVariable("$Probes::Capturing", "0") == "0")) return; Point3F distVec = getRenderPosition() - state->getCameraPosition(); F32 dist = distVec.len(); //Culling distance. Can be adjusted for performance options considerations via the scalar - if (dist > mMaxDrawDistance * Con::getFloatVariable("$pref::GI::ProbeDrawDistScale", 1.0)) + if (dist > RenderProbeMgr::smMaxProbeDrawDistance * Con::getFloatVariable("$pref::GI::ProbeDrawDistScale", 1.0)) { - mProbeInfo.mScore = mMaxDrawDistance; + mProbeInfo.mScore = RenderProbeMgr::smMaxProbeDrawDistance; return; } @@ -842,7 +845,7 @@ void ReflectionProbe::prepRenderImage(SceneRenderState *state) //mProbeInfo.mScore *= mMax(mAbs(mDot(vect, state->getCameraTransform().getForwardVector())),0.001f); - PROBEMGR->submitProbe(mProbeInfo); + PROBEMGR->submitProbe(&mProbeInfo); #ifdef TORQUE_TOOLS if (ReflectionProbe::smRenderPreviewProbes && gEditingMission && mPrefilterMap != nullptr) @@ -938,7 +941,7 @@ void ReflectionProbe::_onRenderViz(ObjectRenderInst *ri, ColorI color = ColorI(255, 0, 255, 63); const MatrixF worldToObjectXfm = mObjToWorld; - if (mProbeShapeType == ProbeRenderInst::Sphere) + if (mProbeShapeType == ProbeInfo::Sphere) { draw->drawSphere(desc, mRadius, getPosition(), color); } diff --git a/Engine/source/T3D/lighting/reflectionProbe.h b/Engine/source/T3D/lighting/reflectionProbe.h index 017cd21df..af6947338 100644 --- a/Engine/source/T3D/lighting/reflectionProbe.h +++ b/Engine/source/T3D/lighting/reflectionProbe.h @@ -41,10 +41,6 @@ #include "renderInstance/renderPassManager.h" #endif -#ifndef RENDER_PROBE_MGR_H -#include "renderInstance/renderProbeMgr.h" -#endif - class BaseMatInstance; //----------------------------------------------------------------------------- @@ -74,6 +70,67 @@ public: DynamicCubemap = 5, }; + /// + /// This contains all the important data the Probe uses for rendering. + /// + struct ProbeInfo + { + bool mIsEnabled; + + MatrixF mTransform; + + ReflectionProbe* mObject; + + F32 mRadius; + + bool mDirty; + + Box3F mBounds; + Point3F mExtents; + Point3F mPosition; + Point3F mProbeRefOffset; + Point3F mProbeRefScale; + F32 mAtten; + + F32 mScore; + + GFXCubemapHandle mPrefilterCubemap; + GFXCubemapHandle mIrradianceCubemap; + + /// The priority of this light used for + /// light and shadow scoring. + F32 mPriority; + + enum ProbeShapeType + { + Box = 0, + Sphere = 1, + Skylight = 2 + }; + + ProbeShapeType mProbeShapeType; + + public: + + ProbeInfo() : mScore(0) {} + ~ProbeInfo() {} + + // Copies data passed in from light + void set(const ProbeInfo* probeInfo); + + // Accessors + const MatrixF& getTransform() const { return mTransform; } + void setTransform(const MatrixF& xfm) { mTransform = xfm; } + + Point3F getPosition() const { return mPosition; } + void setPosition(const Point3F& pos) { mPosition = pos; } + + void setPriority(F32 priority) { mPriority = priority; } + F32 getPriority() const { return mPriority; } + + void clear(); + }; + protected: // Networking masks @@ -124,7 +181,7 @@ protected: /// /// The shape of the probe /// - ProbeRenderInst::ProbeShapeType mProbeShapeType; + ProbeInfo::ProbeShapeType mProbeShapeType; /// /// This is effectively a packed cache of the probe data actually utilized for rendering. @@ -132,7 +189,7 @@ protected: /// When the manager goes to render it has the compacted data to read over more efficiently for setting up what probes should /// Actually render in that frame /// - ProbeRenderInst mProbeInfo; + ProbeInfo mProbeInfo; /// /// Used to dictate what sort of cubemap the probes use when using IBL @@ -166,14 +223,13 @@ protected: CubemapData *mStaticCubemap; GFXCubemapHandle mDynamicCubemap; - String cubeDescName; - U32 cubeDescId; - ReflectorDesc *reflectorDesc; + //String cubeDescName; + //U32 cubeDescId; + //ReflectorDesc *reflectorDesc; //Utilized in dynamic reflections //CubeReflector mCubeReflector; - ///Prevents us from saving out the cubemaps(for now) but allows us the full HDR range on the in-memory cubemap captures bool mUseHDRCaptures; //irridiance resources @@ -196,7 +252,6 @@ protected: U32 mDynamicLastBakeMS; U32 mRefreshRateMS; - F32 mMaxDrawDistance; bool mResourcesCreated; U32 mCaptureMask; @@ -313,7 +368,7 @@ public: void bake(); }; -typedef ProbeRenderInst::ProbeShapeType ReflectProbeType; +typedef ReflectionProbe::ProbeInfo::ProbeShapeType ReflectProbeType; DefineEnumType(ReflectProbeType); typedef ReflectionProbe::ReflectionModeType ReflectionModeEnum; diff --git a/Engine/source/T3D/lighting/skylight.cpp b/Engine/source/T3D/lighting/skylight.cpp index 36036100b..09d813050 100644 --- a/Engine/source/T3D/lighting/skylight.cpp +++ b/Engine/source/T3D/lighting/skylight.cpp @@ -148,7 +148,7 @@ void Skylight::unpackUpdate(NetConnection *conn, BitStream *stream) void Skylight::updateProbeParams() { - mProbeShapeType = ProbeRenderInst::Skylight; + mProbeShapeType = ProbeInfo::Skylight; Parent::updateProbeParams(); } @@ -167,7 +167,7 @@ void Skylight::prepRenderImage(SceneRenderState *state) // Get a handy pointer to our RenderPassmanager //RenderPassManager *renderPass = state->getRenderPass(); - PROBEMGR->submitProbe(mProbeInfo); + PROBEMGR->submitProbe(&mProbeInfo); #ifdef TORQUE_TOOLS if (Skylight::smRenderPreviewProbes && gEditingMission && mEditorShapeInst && mPrefilterMap != nullptr) diff --git a/Engine/source/T3D/lighting/sphereEnvironmentProbe.cpp b/Engine/source/T3D/lighting/sphereEnvironmentProbe.cpp index 54e97b19f..b3e0865a7 100644 --- a/Engine/source/T3D/lighting/sphereEnvironmentProbe.cpp +++ b/Engine/source/T3D/lighting/sphereEnvironmentProbe.cpp @@ -77,7 +77,7 @@ ConsoleDocClass(SphereEnvironmentProbe, SphereEnvironmentProbe::SphereEnvironmentProbe() : ReflectionProbe() { mCaptureMask = REFLECTION_PROBE_CAPTURE_TYPEMASK; - mProbeShapeType = ProbeRenderInst::Sphere; + mProbeShapeType = ProbeInfo::Sphere; } SphereEnvironmentProbe::~SphereEnvironmentProbe() @@ -144,83 +144,10 @@ void SphereEnvironmentProbe::unpackUpdate(NetConnection *conn, BitStream *stream void SphereEnvironmentProbe::updateProbeParams() { - mProbeShapeType = ProbeRenderInst::Sphere; + mProbeShapeType = ProbeInfo::Sphere; Parent::updateProbeParams(); } -void SphereEnvironmentProbe::prepRenderImage(SceneRenderState *state) -{ - if (!mEnabled || !ReflectionProbe::smRenderPreviewProbes) - return; - -#ifdef TORQUE_TOOLS - if (ReflectionProbe::smRenderPreviewProbes && gEditingMission && mEditorShapeInst && mPrefilterMap != nullptr) - { - GFXTransformSaver saver; - - // Calculate the distance of this object from the camera - Point3F cameraOffset; - getRenderTransform().getColumn(3, &cameraOffset); - cameraOffset -= state->getDiffuseCameraPosition(); - F32 dist = cameraOffset.len(); - if (dist < 0.01f) - dist = 0.01f; - - // Set up the LOD for the shape - F32 invScale = (1.0f / getMax(getMax(mObjScale.x, mObjScale.y), mObjScale.z)); - - mEditorShapeInst->setDetailFromDistance(state, dist * invScale); - - // Make sure we have a valid level of detail - if (mEditorShapeInst->getCurrentDetail() < 0) - return; - - BaseMatInstance* probePrevMat = mEditorShapeInst->getMaterialList()->getMaterialInst(0); - - setPreviewMatParameters(state, probePrevMat); - - // GFXTransformSaver is a handy helper class that restores - // the current GFX matrices to their original values when - // it goes out of scope at the end of the function - - // Set up our TS render state - TSRenderState rdata; - rdata.setSceneState(state); - rdata.setFadeOverride(1.0f); - - // We might have some forward lit materials - // so pass down a query to gather lights. - LightQuery query; - query.init(getWorldSphere()); - rdata.setLightQuery(&query); - - // Set the world matrix to the objects render transform - MatrixF mat = getRenderTransform(); - mat.scale(Point3F(1, 1, 1)); - GFX->setWorldMatrix(mat); - - // Animate the the shape - mEditorShapeInst->animate(); - - // Allow the shape to submit the RenderInst(s) for itself - mEditorShapeInst->render(rdata); - - saver.restore(); - } - - // If the light is selected or light visualization - // is enabled then register the callback. - const bool isSelectedInEditor = (gEditingMission && isSelected()); - if (isSelectedInEditor) - { - ObjectRenderInst *ri = state->getRenderPass()->allocInst(); - ri->renderDelegate.bind(this, &ReflectionProbe::_onRenderViz); - ri->type = RenderPassManager::RIT_Editor; - state->getRenderPass()->addInst(ri); - } -#endif -} - void SphereEnvironmentProbe::setPreviewMatParameters(SceneRenderState* renderState, BaseMatInstance* mat) { Parent::setPreviewMatParameters(renderState, mat); diff --git a/Engine/source/T3D/lighting/sphereEnvironmentProbe.h b/Engine/source/T3D/lighting/sphereEnvironmentProbe.h index dc3c9a1a6..3df0b98b5 100644 --- a/Engine/source/T3D/lighting/sphereEnvironmentProbe.h +++ b/Engine/source/T3D/lighting/sphereEnvironmentProbe.h @@ -98,10 +98,6 @@ public: // use the same Materials. //-------------------------------------------------------------------------- virtual void updateProbeParams(); - - // This is the function that allows this object to submit itself for rendering - void prepRenderImage(SceneRenderState *state); - void setPreviewMatParameters(SceneRenderState* renderState, BaseMatInstance* mat); }; diff --git a/Engine/source/environment/scatterSky.cpp b/Engine/source/environment/scatterSky.cpp index 36ab28ecf..5de3bdd94 100644 --- a/Engine/source/environment/scatterSky.cpp +++ b/Engine/source/environment/scatterSky.cpp @@ -970,14 +970,6 @@ void ScatterSky::_render( ObjectRenderInst *ri, SceneRenderState *state, BaseMat xform *= GFX->getViewMatrix(); xform *= GFX->getWorldMatrix(); - if(state->isReflectPass()) - { - static MatrixF rotMat(EulerF(0.0, 0.0, M_PI_F)); - xform.mul(rotMat); - rotMat.set(EulerF(M_PI_F, 0.0, 0.0)); - xform.mul(rotMat); - } - mShaderConsts->setSafe( mModelViewProjSC, xform ); mShaderConsts->setSafe( mMiscSC, miscParams ); mShaderConsts->setSafe( mSphereRadiiSC, sphereRadii ); diff --git a/Engine/source/renderInstance/renderProbeMgr.cpp b/Engine/source/renderInstance/renderProbeMgr.cpp index bfbf65815..268bba5e5 100644 --- a/Engine/source/renderInstance/renderProbeMgr.cpp +++ b/Engine/source/renderInstance/renderProbeMgr.cpp @@ -20,13 +20,8 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- #include "renderProbeMgr.h" -#include "console/consoleTypes.h" -#include "scene/sceneObject.h" -#include "materials/materialManager.h" -#include "scene/sceneRenderState.h" #include "math/util/sphereMesh.h" #include "math/util/matrixSet.h" -#include "materials/processedMaterial.h" #include "renderInstance/renderDeferredMgr.h" #include "math/mPolyhedron.impl.h" #include "gfx/gfxTransformSaver.h" @@ -34,90 +29,60 @@ #include "gfx/gfxDebugEvent.h" #include "shaderGen/shaderGenVars.h" #include "materials/shaderData.h" - -#include "gfx/gfxTextureManager.h" #include "scene/reflectionManager.h" #include "postFx/postEffect.h" #include "T3D/lighting/reflectionProbe.h" #include "T3D/lighting/IBLUtilities.h" +#include "T3D/Scene.h" //For our cameraQuery setup #include "T3D/gameTSCtrl.h" -#include "T3D/Scene.h" #define TORQUE_GFX_VISUAL_DEBUG //renderdoc debugging IMPLEMENT_CONOBJECT(RenderProbeMgr); ConsoleDocClass( RenderProbeMgr, - "@brief A render bin which uses object callbacks for rendering.\n\n" - "This render bin gathers object render instances and calls its delegate " - "method to perform rendering. It is used infrequently for specialized " - "scene objects which perform custom rendering.\n\n" + "@brief This render bin handles the rendering of reflection probes to provide IBL\n" + "lighting for PBR\n\n" + "Probes when added to the scene, are registered to the Manager, and then during the steps\n" + "leading up to the frame being rendered, the probes submit to the Manager that they are ready to be rendered\n" + "resulting in them being added to the active list.\n" + "When the manager is invoked to render, it processes the active probe list and finds the best probes based on\n" + "settings like max probes per frame, probe score, etc to get the final list of probes to be submitted to the shader.\n\n" "@ingroup RenderBin\n" ); RenderProbeMgr *RenderProbeMgr::smProbeManager = NULL; +// This variable is a global toggle on if reflection probes should be rendered or not bool RenderProbeMgr::smRenderReflectionProbes = true; + +// This variable defines the maximum draw distance of a probe. F32 RenderProbeMgr::smMaxProbeDrawDistance = 100; + +// This variable defines the maximum number of probes that can be rendered in a single frame in deferred S32 RenderProbeMgr::smMaxProbesPerFrame = 8; -S32 QSORT_CALLBACK AscendingReflectProbeInfluence(const void* a, const void* b) -{ - // Debug Profiling. - PROFILE_SCOPE(AdvancedLightBinManager_AscendingReflectProbeInfluence); - - // Fetch asset definitions. - const ProbeRenderInst* pReflectProbeA = (*(ProbeRenderInst**)a); - const ProbeRenderInst* pReflectProbeB = (*(ProbeRenderInst**)b); - //sort by score - return pReflectProbeA->mScore - pReflectProbeB->mScore; -} +S32 RenderProbeMgr::smProbeBakeResolution = 64; // // ProbeRenderInst::ProbeRenderInst() : - mIsEnabled(true), - mTransform(true), - mDirty(false), - mPriority(1.0f), - mScore(0.0f), - mPrefilterCubemap(NULL), - mIrradianceCubemap(NULL), - mRadius(1.0f), - mProbeRefOffset(0, 0, 0), - mProbeRefScale(1,1,1), - mAtten(0.0), mCubemapIndex(0), - mProbeIdx(0), - mProbeShapeType(Box) + mProbeInfo(nullptr) { } ProbeRenderInst::~ProbeRenderInst() { - if (mPrefilterCubemap && mPrefilterCubemap.isValid()) - { - mPrefilterCubemap.free(); - } - if (mIrradianceCubemap && mIrradianceCubemap.isValid()) - { - mIrradianceCubemap.free(); - } } -void ProbeRenderInst::set(const ProbeRenderInst *probeInfo) +void ProbeRenderInst::set(const ProbeRenderInst *probe) { - mTransform = probeInfo->mTransform; - mPrefilterCubemap = probeInfo->mPrefilterCubemap; - mIrradianceCubemap = probeInfo->mIrradianceCubemap; - mRadius = probeInfo->mRadius; - mProbeShapeType = probeInfo->mProbeShapeType; - mBounds = probeInfo->mBounds; - mScore = probeInfo->mScore; - mAtten = probeInfo->mAtten; + mCubemapIndex = probe->mCubemapIndex; + mProbeInfo = probe->mProbeInfo; } // @@ -125,16 +90,17 @@ void ProbeRenderInst::set(const ProbeRenderInst *probeInfo) ProbeShaderConstants::ProbeShaderConstants() : mInit(false), mShader(NULL), - mProbePositionSC(NULL), - mProbeRefPosSC(NULL), - mRefScaleSC(NULL), - mProbeConfigDataSC(NULL), - mProbeSpecularCubemapSC(NULL), - mProbeIrradianceCubemapSC(NULL), + mProbePositionArraySC(NULL), + mProbeRefPosArraySC(NULL), + mRefScaleArraySC(NULL), + mProbeConfigDataArraySC(NULL), + mProbeSpecularCubemapArraySC(NULL), + mProbeIrradianceCubemapArraySC(NULL), mProbeCountSC(NULL), mBRDFTextureMap(NULL), mSkylightCubemapIdxSC(NULL), - mWorldToObjArraySC(NULL) + mWorldToObjArraySC(NULL), + mMaxProbeDrawDistanceSC(NULL) { } @@ -159,29 +125,31 @@ void ProbeShaderConstants::init(GFXShader* shader) } //Reflection Probes - mProbePositionSC = shader->getShaderConstHandle(ShaderGenVars::probePosition); - mProbeRefPosSC = shader->getShaderConstHandle(ShaderGenVars::probeRefPos); - mRefScaleSC = shader->getShaderConstHandle(ShaderGenVars::refScale); + mProbePositionArraySC = shader->getShaderConstHandle(ShaderGenVars::probePositionArray); + mProbeRefPosArraySC = shader->getShaderConstHandle(ShaderGenVars::probeRefPosArray); + mRefScaleArraySC = shader->getShaderConstHandle(ShaderGenVars::refScaleArray); mWorldToObjArraySC = shader->getShaderConstHandle(ShaderGenVars::worldToObjArray); - mProbeConfigDataSC = shader->getShaderConstHandle(ShaderGenVars::probeConfigData); - mProbeSpecularCubemapSC = shader->getShaderConstHandle(ShaderGenVars::specularCubemapAR); - mProbeIrradianceCubemapSC = shader->getShaderConstHandle(ShaderGenVars::irradianceCubemapAR); + mProbeConfigDataArraySC = shader->getShaderConstHandle(ShaderGenVars::probeConfigDataArray); + mProbeSpecularCubemapArraySC = shader->getShaderConstHandle(ShaderGenVars::specularCubemapAR); + mProbeIrradianceCubemapArraySC = shader->getShaderConstHandle(ShaderGenVars::irradianceCubemapAR); mProbeCountSC = shader->getShaderConstHandle(ShaderGenVars::probeCount); mBRDFTextureMap = shader->getShaderConstHandle(ShaderGenVars::BRDFTextureMap); mSkylightCubemapIdxSC = shader->getShaderConstHandle(ShaderGenVars::skylightCubemapIdx); + mMaxProbeDrawDistanceSC = shader->getShaderConstHandle(ShaderGenVars::maxProbeDrawDistance); + mInit = true; } bool ProbeShaderConstants::isValid() { - if (mProbePositionSC->isValid() || - mProbeConfigDataSC->isValid() || - mRefScaleSC->isValid() || - mProbeSpecularCubemapSC->isValid() || - mProbeIrradianceCubemapSC->isValid()) + if (mProbePositionArraySC->isValid() || + mProbeConfigDataArraySC->isValid() || + mRefScaleArraySC->isValid() || + mProbeSpecularCubemapArraySC->isValid() || + mProbeIrradianceCubemapArraySC->isValid()) return true; return false; @@ -199,11 +167,9 @@ RenderProbeMgr::RenderProbeMgr() : RenderBinManager(RenderPassManager::RIT_Probes, 1.0f, 1.0f), mLastShader(nullptr), mLastConstants(nullptr), - mProbesDirty(false), mHasSkylight(false), mSkylightCubemapIdx(-1), mCubeMapCount(0), - mDefaultSkyLight(nullptr), mUseHDRCaptures(true) { mEffectiveProbeCount = 0; @@ -220,9 +186,6 @@ RenderProbeMgr::RenderProbeMgr() { mCubeMapSlots[i] = false; } - - mPrefilterSize = 64; - mPrefilterMipLevels = mLog2(F32(mPrefilterSize)) + 1; } RenderProbeMgr::RenderProbeMgr(RenderInstType riType, F32 renderOrder, F32 processAddOrder) @@ -231,17 +194,12 @@ RenderProbeMgr::RenderProbeMgr(RenderInstType riType, F32 renderOrder, F32 proce mCubeMapCount = 0; dMemset(mCubeMapSlots, false, sizeof(mCubeMapSlots)); mCubeSlotCount = PROBE_ARRAY_SLOT_BUFFER_SIZE; - mDefaultSkyLight = nullptr; mEffectiveProbeCount = 0; mHasSkylight = false; mSkylightCubemapIdx = -1; mLastConstants = nullptr; mMipCount = 0; - mProbesDirty = false; mUseHDRCaptures = true; - - mPrefilterSize = 64; - mPrefilterMipLevels = mLog2(F32(mPrefilterSize)) + 1; } RenderProbeMgr::~RenderProbeMgr() @@ -266,29 +224,10 @@ bool RenderProbeMgr::onAdd() mPrefilterArray = GFXCubemapArrayHandle(GFX->createCubemapArray()); //pre-allocate a few slots - mIrradianceArray->init(PROBE_ARRAY_SLOT_BUFFER_SIZE, PROBE_IRRAD_SIZE, PROBE_FORMAT); - mPrefilterArray->init(PROBE_ARRAY_SLOT_BUFFER_SIZE, PROBE_PREFILTER_SIZE, PROBE_FORMAT); + mIrradianceArray->init(PROBE_ARRAY_SLOT_BUFFER_SIZE, RenderProbeMgr::smProbeBakeResolution, PROBE_FORMAT); + mPrefilterArray->init(PROBE_ARRAY_SLOT_BUFFER_SIZE, RenderProbeMgr::smProbeBakeResolution, PROBE_FORMAT); mCubeSlotCount = PROBE_ARRAY_SLOT_BUFFER_SIZE; - //create our own default default skylight - mDefaultSkyLight = new ProbeRenderInst; - mDefaultSkyLight->mProbeShapeType = ProbeRenderInst::Skylight; - mDefaultSkyLight->mIsEnabled = false; - - String defaultIrradMapPath = GFXTextureManager::getDefaultIrradianceCubemapPath(); - if (!mDefaultSkyLight->mIrradianceCubemap.set(defaultIrradMapPath)) - { - Con::errorf("RenderProbeMgr::onAdd: Failed to load default irradiance cubemap"); - return false; - } - - String defaultPrefilterPath = GFXTextureManager::getDefaultPrefilterCubemapPath(); - if (!mDefaultSkyLight->mPrefilterCubemap.set(defaultPrefilterPath)) - { - Con::errorf("RenderProbeMgr::onAdd: Failed to load default prefilter cubemap"); - return false; - } - String brdfTexturePath = GFXTextureManager::getBRDFTexturePath(); if (!mBRDFTexture.set(brdfTexturePath, &GFXTexturePersistentProfile, "BRDFTexture")) { @@ -316,22 +255,103 @@ void RenderProbeMgr::consoleInit() // Vars for debug rendering while the RoadEditor is open, only used if smEditorOpen is true. Con::addVariable("$pref::maxProbeDrawDistance", TypeF32, &RenderProbeMgr::smMaxProbeDrawDistance, "Max distance for reflection probes to render.\n"); Con::addVariable("$pref::MaxProbesPerFrame", TypeS32, &RenderProbeMgr::smMaxProbesPerFrame, "Max number of Environment Probes that can be rendered per-frame.\n"); + Con::addVariable("$pref::ReflectionProbes::BakeResolution", TypeS32, &RenderProbeMgr::smProbeBakeResolution, ""); + } -void RenderProbeMgr::registerProbe(ProbeRenderInst* newProbe) +//============================================================================= +// Utility functions for processing and setting up the probes for rendering +//============================================================================= +S32 QSORT_CALLBACK RenderProbeMgr::_probeScoreCmp(const ProbeRenderInst* a, const ProbeRenderInst* b) +{ + F32 diff = a->mProbeInfo->mScore - b->mProbeInfo->mScore; + return diff > 0 ? 1 : diff < 0 ? -1 : 0; +} +void RenderProbeMgr::getBestProbes(const Point3F& objPosition, ProbeDataSet* probeDataSet) +{ + PROFILE_SCOPE(ProbeManager_getBestProbes); + + //Array rendering + U32 probeCount = mActiveProbes.size(); + + Vector bestPickProbes; + bestPickProbes.setSize(probeDataSet->maxProbeCount); + bestPickProbes.fill(-1); + + mHasSkylight = false; + probeDataSet->skyLightIdx = -1; + + probeDataSet->effectiveProbeCount = 0; + for (U32 i = 0; i < probeCount; i++) + { + //Check if we've already got a skylight. If we do and we've otherwise filled to our max amounto of probes alloewed, then bail + if (mHasSkylight && probeDataSet->effectiveProbeCount >= probeDataSet->maxProbeCount) + break; + + const ProbeRenderInst& curEntry = mActiveProbes[i]; + + //Obviously, if the probe is marked as not enabled, we skip + if (!curEntry.mProbeInfo->mIsEnabled) + continue; + + if (curEntry.mProbeInfo->mProbeShapeType != ReflectionProbe::ProbeInfo::Skylight) + { + if (probeDataSet->effectiveProbeCount < probeDataSet->maxProbeCount) + { + bestPickProbes[probeDataSet->effectiveProbeCount] = i; + probeDataSet->effectiveProbeCount++; + } + } + else + { + probeDataSet->skyLightIdx = curEntry.mCubemapIndex; + mHasSkylight = true; + } + } + + //If we, for whatever reason, have nothing, bail now + if (mHasSkylight == false && probeDataSet->effectiveProbeCount == 0) + return; + + //Grab our best probe picks + for (U32 i = 0; i < bestPickProbes.size(); i++) + { + if (bestPickProbes[i] == -1) + continue; + + const ProbeRenderInst& curEntry = mActiveProbes[bestPickProbes[i]]; + probeDataSet->probeConfigArray[i] = Point4F(curEntry.mProbeInfo->mProbeShapeType, + curEntry.mProbeInfo->mRadius, + curEntry.mProbeInfo->mAtten, + curEntry.mCubemapIndex); + + MatrixF p2A = curEntry.mProbeInfo->mTransform; + probeDataSet->probeWorldToObjArray[i] = p2A; + p2A.inverse(); + probeDataSet->refScaleArray[i] = curEntry.mProbeInfo->mProbeRefScale / p2A.getScale(); + + Point3F probePos = curEntry.mProbeInfo->mObject->getPosition(); + Point3F refPos = probePos + curEntry.mProbeInfo->mProbeRefOffset * probeDataSet->refScaleArray[i].asPoint3F(); + + probeDataSet->probePositionArray[i] = Point4F(probePos.x, probePos.y, probePos.z, 0); + probeDataSet->probeRefPositionArray[i] = Point4F(refPos.x, refPos.y, refPos.z, 0); + + } +} + +void RenderProbeMgr::registerProbe(ReflectionProbe::ProbeInfo* newProbe) { //Can't have over the probe limit if (mRegisteredProbes.size() + 1 >= PROBE_MAX_COUNT) return; - mRegisteredProbes.push_back(newProbe); - - newProbe->mProbeIdx = mRegisteredProbes.size() - 1; + ProbeRenderInst newProbeRenderInst; + newProbeRenderInst.mProbeInfo = newProbe; const U32 cubeIndex = _findNextEmptyCubeSlot(); if (cubeIndex == INVALID_CUBE_SLOT) { - Con::warnf("RenderProbeMgr::addProbe: Invalid cubemap slot."); + Con::warnf("RenderProbeMgr::registerProbe() - Invalid cubemap slot."); return; } @@ -342,8 +362,8 @@ void RenderProbeMgr::registerProbe(ProbeRenderInst* newProbe) GFXCubemapArrayHandle irr = GFXCubemapArrayHandle(GFX->createCubemapArray()); GFXCubemapArrayHandle prefilter = GFXCubemapArrayHandle(GFX->createCubemapArray()); - irr->init(mCubeSlotCount + PROBE_ARRAY_SLOT_BUFFER_SIZE, PROBE_IRRAD_SIZE, PROBE_FORMAT); - prefilter->init(mCubeSlotCount + PROBE_ARRAY_SLOT_BUFFER_SIZE, PROBE_PREFILTER_SIZE, PROBE_FORMAT); + irr->init(mCubeSlotCount + PROBE_ARRAY_SLOT_BUFFER_SIZE, RenderProbeMgr::smProbeBakeResolution, PROBE_FORMAT); + prefilter->init(mCubeSlotCount + PROBE_ARRAY_SLOT_BUFFER_SIZE, RenderProbeMgr::smProbeBakeResolution, PROBE_FORMAT); mIrradianceArray->copyTo(irr); mPrefilterArray->copyTo(prefilter); @@ -355,50 +375,40 @@ void RenderProbeMgr::registerProbe(ProbeRenderInst* newProbe) mCubeSlotCount += PROBE_ARRAY_SLOT_BUFFER_SIZE; } - newProbe->mCubemapIndex = cubeIndex; + newProbeRenderInst.mCubemapIndex = cubeIndex; //mark cubemap slot as taken mCubeMapSlots[cubeIndex] = true; mCubeMapCount++; -#ifdef TORQUE_DEBUG - Con::warnf("RenderProbeMgr::registerProbe: Registered probe %u to cubeIndex %u", newProbe->mProbeIdx, cubeIndex); -#endif + mRegisteredProbes.push_back(newProbeRenderInst); - mProbesDirty = true; +#ifdef TORQUE_DEBUG + Con::warnf("RenderProbeMgr::registerProbe() - Registered probe %u to cubeIndex %u", newProbe->mObject->getId(), cubeIndex); +#endif } -void RenderProbeMgr::unregisterProbe(U32 probeIdx) +void RenderProbeMgr::unregisterProbe(ReflectionProbe::ProbeInfo* probeInfo) { - //Mostly for consolidation, but also lets us sanity check or prep any other data we need for rendering this in one place at time of flagging for render - if (probeIdx >= mRegisteredProbes.size()) + ProbeRenderInst* probe = findProbeInst(probeInfo); + if (probe == nullptr) return; - if (mRegisteredProbes[probeIdx]->mCubemapIndex == INVALID_CUBE_SLOT) + if (probe->mCubemapIndex == INVALID_CUBE_SLOT) return; //mark cubemap slot as available now - mCubeMapSlots[mRegisteredProbes[probeIdx]->mCubemapIndex] = false; + mCubeMapSlots[probe->mCubemapIndex] = false; mCubeMapCount--; - mRegisteredProbes.erase(probeIdx); - - //recalculate all the probe's indicies just to be sure - for (U32 i = 0; i < mRegisteredProbes.size(); i++) - { - mRegisteredProbes[i]->mProbeIdx = i; - } - - //rebuild our probe data - mProbesDirty = true; + mRegisteredProbes.erase(probe); } -void RenderProbeMgr::submitProbe(const ProbeRenderInst& newProbe) +void RenderProbeMgr::submitProbe(ReflectionProbe::ProbeInfo* probe) { - mActiveProbes.push_back(newProbe); + ProbeRenderInst* probeInst = findProbeInst(probe); + mActiveProbes.push_back(*probeInst); } -// -// PostEffect* RenderProbeMgr::getProbeArrayEffect() { if (!mProbeArrayEffect) @@ -407,40 +417,46 @@ PostEffect* RenderProbeMgr::getProbeArrayEffect() if (!mProbeArrayEffect) return nullptr; + + mProbeArrayEffect->setShaderConst("$numProbes", (S32)0); + mProbeArrayEffect->setShaderConst("$skylightCubemapIdx", (S32)-1); + + mProbeArrayEffect->setShaderConst("$cubeMips", (float)0); + mProbeArrayEffect->setShaderConst("$maxProbeDrawDistance", smMaxProbeDrawDistance); + } return mProbeArrayEffect; } -//remove -//Con::setIntVariable("lightMetrics::activeReflectionProbes", mReflectProbeBin.size()); -//Con::setIntVariable("lightMetrics::culledReflectProbes", 0/*mNumLightsCulled*/); -// - -void RenderProbeMgr::updateProbes() +void RenderProbeMgr::updateProbeTexture(ReflectionProbe::ProbeInfo* probeInfo) { - mProbesDirty = true; -} + //If we don't have a registered probe, there's no point in updating the cubemap array for it + ProbeRenderInst* probe = findProbeInst(probeInfo); + if (probe == nullptr) + return; -void RenderProbeMgr::updateProbeTexture(ProbeRenderInst* probeInfo) -{ - if (probeInfo->mIrradianceCubemap.isNull() || !probeInfo->mIrradianceCubemap->isInitialized()) + //Some basic sanity checking that we have valid cubemaps to work with + if (probeInfo->mIrradianceCubemap.isNull() || !probeInfo->mIrradianceCubemap->isInitialized() || + probeInfo->mIrradianceCubemap->getSize() != RenderProbeMgr::smProbeBakeResolution) { Con::errorf("RenderProbeMgr::updateProbeTexture() - tried to update a probe's texture with an invalid or uninitialized irradiance map!"); return; } - if (probeInfo->mPrefilterCubemap.isNull() || !probeInfo->mPrefilterCubemap->isInitialized()) + if (probeInfo->mPrefilterCubemap.isNull() || !probeInfo->mPrefilterCubemap->isInitialized() || + probeInfo->mPrefilterCubemap->getSize() != RenderProbeMgr::smProbeBakeResolution) { Con::errorf("RenderProbeMgr::updateProbeTexture() - tried to update a probe's texture with an invalid or uninitialized specular map!"); return; } - const U32 cubeIndex = probeInfo->mCubemapIndex; + //Run the update on the array pair with the probe's cubemaps and index + const U32 cubeIndex = probe->mCubemapIndex; mIrradianceArray->updateTexture(probeInfo->mIrradianceCubemap, cubeIndex); mPrefilterArray->updateTexture(probeInfo->mPrefilterCubemap, cubeIndex); #ifdef TORQUE_DEBUG - Con::warnf("UpdatedProbeTexture - probeIdx: %u on cubeIndex %u, Irrad validity: %d, Prefilter validity: %d", probeInfo->mProbeIdx, cubeIndex, + Con::warnf("UpdatedProbeTexture - probe id: %u on cubeIndex %u, Irrad validity: %d, Prefilter validity: %d", probeInfo->mObject->getId(), cubeIndex, probeInfo->mIrradianceCubemap->isInitialized(), probeInfo->mPrefilterCubemap->isInitialized()); #endif } @@ -450,21 +466,165 @@ void RenderProbeMgr::reloadTextures() U32 probeCount = mRegisteredProbes.size(); for (U32 i = 0; i < probeCount; i++) { - updateProbeTexture(mRegisteredProbes[i]); + updateProbeTexture(mRegisteredProbes[i].mProbeInfo); + } +} + +void RenderProbeMgr::bakeProbe(ReflectionProbe* probe) +{ + GFXDEBUGEVENT_SCOPE(RenderProbeMgr_Bake, ColorI::WHITE); + + Con::warnf("RenderProbeMgr::bakeProbe() - Beginning bake!"); + U32 startMSTime = Platform::getRealMilliseconds(); + + String path = Con::getVariable("$pref::ReflectionProbes::CurrentLevelPath", "levels/"); + U32 resolution = Con::getIntVariable("$pref::ReflectionProbes::BakeResolution", 64); + U32 prefilterMipLevels = mLog2(F32(resolution)) + 1; + bool renderWithProbes = Con::getIntVariable("$pref::ReflectionProbes::RenderWithProbes", false); + + ReflectionProbe* clientProbe = nullptr; + + if (probe->isServerObject()) + clientProbe = static_cast(probe->getClientObject()); + else + return; + + if (clientProbe == nullptr) + return; + + String probePrefilterPath = clientProbe->getPrefilterMapPath(); + String probeIrradPath = clientProbe->getIrradianceMapPath(); + + if (clientProbe->mReflectionModeType != ReflectionProbe::DynamicCubemap) + { + //Prep our bake path + if (probePrefilterPath.isEmpty() || probeIrradPath.isEmpty()) + { + Con::errorf("RenderProbeMgr::bake() - Unable to bake our captures because probe doesn't have a path set"); + return; + } } - mProbesDirty = true; + // Save the current transforms so we can restore + // it for child control rendering below. + GFXTransformSaver saver; + + bool probeRenderState = RenderProbeMgr::smRenderReflectionProbes; + + F32 farPlane = 1000.0f; + + ReflectorDesc reflDesc; + reflDesc.texSize = resolution; + reflDesc.farDist = farPlane; + reflDesc.detailAdjust = 1; + reflDesc.objectTypeMask = probe->mProbeShapeType == ReflectionProbe::ProbeInfo::Skylight ? SKYLIGHT_CAPTURE_TYPEMASK : REFLECTION_PROBE_CAPTURE_TYPEMASK; + + CubeReflector cubeRefl; + cubeRefl.registerReflector(probe, &reflDesc); + + ReflectParams reflParams; + + //need to get the query somehow. Likely do some sort of get function to fetch from the guiTSControl that's active + CameraQuery query; //need to get the last cameraQuery + query.fov = 90; //90 degree slices for each of the 6 sides + query.nearPlane = 0.1f; + query.farPlane = farPlane; + query.headMatrix = MatrixF(); + query.cameraMatrix = clientProbe->getTransform(); + + Frustum culler; + culler.set(false, + query.fov, + 1.0f, + query.nearPlane, + query.farPlane, + query.cameraMatrix); + + S32 stereoTarget = GFX->getCurrentStereoTarget(); + + Point2I maxRes(2048, 2048); //basically a boundary so we don't go over this and break stuff + + reflParams.culler = culler; + reflParams.eyeId = stereoTarget; + reflParams.query = &query; + reflParams.startOfUpdateMs = startMSTime; + reflParams.viewportExtent = maxRes; + + if (!renderWithProbes) + RenderProbeMgr::smRenderReflectionProbes = false; + + GFXFormat reflectFormat; + + if (mUseHDRCaptures) + reflectFormat = GFXFormatR16G16B16A16F; + else + reflectFormat = GFXFormatR8G8B8A8; + const GFXFormat oldRefFmt = REFLECTMGR->getReflectFormat(); + REFLECTMGR->setReflectFormat(reflectFormat); + + cubeRefl.updateReflection(reflParams, clientProbe->getTransform().getPosition() + clientProbe->mProbeRefOffset); + + //Now, save out the maps + //create irridiance cubemap + if (cubeRefl.getCubemap()) + { + //Just to ensure we're prepped for the generation + clientProbe->createClientResources(); + + //Prep it with whatever resolution we've dictated for our bake + clientProbe->mIrridianceMap->mCubemap->initDynamic(resolution, reflectFormat); + clientProbe->mPrefilterMap->mCubemap->initDynamic(resolution, reflectFormat); + + GFXTextureTargetRef renderTarget = GFX->allocRenderToTextureTarget(false); + + IBLUtilities::GenerateIrradianceMap(renderTarget, cubeRefl.getCubemap(), clientProbe->mIrridianceMap->mCubemap); + IBLUtilities::GeneratePrefilterMap(renderTarget, cubeRefl.getCubemap(), prefilterMipLevels, clientProbe->mPrefilterMap->mCubemap); + + U32 endMSTime = Platform::getRealMilliseconds(); + F32 diffTime = F32(endMSTime - startMSTime); + Con::warnf("RenderProbeMgr::bake() - Finished Capture! Took %g milliseconds", diffTime); + Con::warnf("RenderProbeMgr::bake() - Beginning save now!"); + + IBLUtilities::SaveCubeMap(clientProbe->getIrradianceMapPath(), clientProbe->mIrridianceMap->mCubemap); + IBLUtilities::SaveCubeMap(clientProbe->getPrefilterMapPath(), clientProbe->mPrefilterMap->mCubemap); + } + else + { + Con::errorf("RenderProbeMgr::bake() - Didn't generate a valid scene capture cubemap, unable to generate prefilter and irradiance maps!"); + } + + if (!renderWithProbes) + RenderProbeMgr::smRenderReflectionProbes = probeRenderState; + + cubeRefl.unregisterReflector(); + + U32 endMSTime = Platform::getRealMilliseconds(); + F32 diffTime = F32(endMSTime - startMSTime); + + probe->setMaskBits(-1); + + Con::warnf("RenderProbeMgr::bake() - Finished bake! Took %g milliseconds", diffTime); + REFLECTMGR->setReflectFormat(oldRefFmt); } -void RenderProbeMgr::_setupPerFrameParameters(const SceneRenderState *state) +void RenderProbeMgr::bakeProbes() { - PROFILE_SCOPE(RenderProbeMgr_SetupPerFrameParameters); + Vector probes; - mProbeData = ProbeDataSet(smMaxProbesPerFrame); + Scene::getRootScene()->findObjectByType(probes); - getBestProbes(state->getCameraPosition(), &mProbeData); + for (U32 i = 0; i < probes.size(); i++) + { + if (probes[i]->isClientObject()) + continue; + + bakeProbe(probes[i]); + } } +//============================================================================= +// Forward Rendering functions +//============================================================================= ProbeShaderConstants* RenderProbeMgr::getProbeShaderConstants(GFXShaderConstBuffer* buffer) { if (!buffer) @@ -510,16 +670,45 @@ ProbeShaderConstants* RenderProbeMgr::getProbeShaderConstants(GFXShaderConstBuff return mLastConstants; } +void RenderProbeMgr::setProbeInfo(ProcessedMaterial *pmat, + const Material *mat, + const SceneData &sgData, + const SceneRenderState *state, + U32 pass, + GFXShaderConstBuffer *shaderConsts) +{ + // Skip this if we're rendering from the deferred bin. + if (sgData.binType == SceneData::DeferredBin) + return; + + PROFILE_SCOPE(ProbeManager_setProbeInfo); + + ProbeShaderConstants *psc = getProbeShaderConstants(shaderConsts); + + // NOTE: If you encounter a crash from this point forward + // while setting a shader constant its probably because the + // mConstantLookup has bad shaders/constants in it. + // + // This is a known crash bug that can occur if materials/shaders + // are reloaded and the light manager is not reset. + // + // We should look to fix this by clearing the table. + MatrixSet matSet = state->getRenderPass()->getMatrixSet(); + + // Update the forward shading light constants. + _update4ProbeConsts(sgData, matSet, psc, shaderConsts); +} + void RenderProbeMgr::setupSGData(SceneData& data, const SceneRenderState* state, LightInfo* light) { //ensure they're sorted for forward rendering mActiveProbes.sort(_probeScoreCmp); } -void RenderProbeMgr::_update4ProbeConsts(const SceneData &sgData, - MatrixSet &matSet, - ProbeShaderConstants *probeShaderConsts, - GFXShaderConstBuffer *shaderConsts) +void RenderProbeMgr::_update4ProbeConsts(const SceneData& sgData, + MatrixSet& matSet, + ProbeShaderConstants* probeShaderConsts, + GFXShaderConstBuffer* shaderConsts) { PROFILE_SCOPE(ProbeManager_Update4ProbeConsts); @@ -548,136 +737,46 @@ void RenderProbeMgr::_update4ProbeConsts(const SceneData &sgData, probeConfigAlignedArray[i] = probeSet.probeConfigArray[i]; } + if (probeSet.effectiveProbeCount != 0) + { shaderConsts->setSafe(probeShaderConsts->mProbeCountSC, (S32)probeSet.effectiveProbeCount); - shaderConsts->setSafe(probeShaderConsts->mProbePositionSC, probePositionAlignedArray); - shaderConsts->setSafe(probeShaderConsts->mProbeRefPosSC, probeRefPositionAlignedArray); + shaderConsts->setSafe(probeShaderConsts->mProbePositionArraySC, probePositionAlignedArray); + shaderConsts->setSafe(probeShaderConsts->mProbeRefPosArraySC, probeRefPositionAlignedArray); - if(probeShaderConsts->isValid()) - shaderConsts->set(probeShaderConsts->mWorldToObjArraySC, probeSet.probeWorldToObjArray.address(), probeSet.effectiveProbeCount, GFXSCT_Float4x4); + if (probeShaderConsts->isValid()) + shaderConsts->set(probeShaderConsts->mWorldToObjArraySC, probeSet.probeWorldToObjArray.address(), probeSet.probeWorldToObjArray.size(), GFXSCT_Float4x4); - shaderConsts->setSafe(probeShaderConsts->mRefScaleSC, refScaleAlignedArray); - shaderConsts->setSafe(probeShaderConsts->mProbeConfigDataSC, probeConfigAlignedArray); + shaderConsts->setSafe(probeShaderConsts->mRefScaleArraySC, refScaleAlignedArray); + shaderConsts->setSafe(probeShaderConsts->mProbeConfigDataArraySC, probeConfigAlignedArray); + } + + if (probeShaderConsts->mBRDFTextureMap->getSamplerRegister() != -1 && mBRDFTexture.isValid()) + GFX->setTexture(probeShaderConsts->mBRDFTextureMap->getSamplerRegister(), mBRDFTexture); shaderConsts->setSafe(probeShaderConsts->mSkylightCubemapIdxSC, (float)probeSet.skyLightIdx); - if(probeShaderConsts->mBRDFTextureMap->getSamplerRegister() != -1 && mBRDFTexture.isValid()) - GFX->setTexture(probeShaderConsts->mBRDFTextureMap->getSamplerRegister(), mBRDFTexture); + if (probeShaderConsts->mProbeSpecularCubemapArraySC->getSamplerRegister() != -1) + GFX->setCubeArrayTexture(probeShaderConsts->mProbeSpecularCubemapArraySC->getSamplerRegister(), mPrefilterArray); + if (probeShaderConsts->mProbeIrradianceCubemapArraySC->getSamplerRegister() != -1) + GFX->setCubeArrayTexture(probeShaderConsts->mProbeIrradianceCubemapArraySC->getSamplerRegister(), mIrradianceArray); - if(probeShaderConsts->mProbeSpecularCubemapSC->getSamplerRegister() != -1) - GFX->setCubeArrayTexture(probeShaderConsts->mProbeSpecularCubemapSC->getSamplerRegister(), mPrefilterArray); - if(probeShaderConsts->mProbeIrradianceCubemapSC->getSamplerRegister() != -1) - GFX->setCubeArrayTexture(probeShaderConsts->mProbeIrradianceCubemapSC->getSamplerRegister(), mIrradianceArray); + shaderConsts->setSafe(probeShaderConsts->mMaxProbeDrawDistanceSC, smMaxProbeDrawDistance); } } -S32 QSORT_CALLBACK RenderProbeMgr::_probeScoreCmp(const ProbeRenderInst* a, const ProbeRenderInst* b) +//============================================================================= +// Deferred Rendering Functions +//============================================================================= +void RenderProbeMgr::_setupPerFrameParameters(const SceneRenderState* state) { - F32 diff = a->getScore() - b->getScore(); - return diff > 0 ? 1 : diff < 0 ? -1 : 0; + PROFILE_SCOPE(RenderProbeMgr_SetupPerFrameParameters); + + mProbeData = ProbeDataSet(smMaxProbesPerFrame); + + getBestProbes(state->getCameraPosition(), &mProbeData); } -void RenderProbeMgr::getBestProbes(const Point3F& objPosition, ProbeDataSet* probeDataSet) -{ - PROFILE_SCOPE(ProbeManager_getBestProbes); - - //Array rendering - U32 probeCount = mActiveProbes.size(); - - Vector bestPickProbes; - bestPickProbes.setSize(probeDataSet->maxProbeCount); - bestPickProbes.fill(-1); - - probeDataSet->effectiveProbeCount = 0; - for (U32 i = 0; i < probeCount; i++) - { - if (probeDataSet->skyLightIdx != -1 && probeDataSet->effectiveProbeCount >= probeDataSet->maxProbeCount) - break; - - const ProbeRenderInst& curEntry = mActiveProbes[i]; - if (!curEntry.mIsEnabled) - continue; - - if (curEntry.mProbeShapeType != ProbeRenderInst::Skylight) - { - if (probeDataSet->effectiveProbeCount < probeDataSet->maxProbeCount) - { - bestPickProbes[probeDataSet->effectiveProbeCount] = i; - probeDataSet->effectiveProbeCount++; - } - } - else - { - probeDataSet->skyLightIdx = curEntry.mCubemapIndex; - } - } - - //Grab our best probe picks - for (U32 i = 0; i < bestPickProbes.size(); i++) - { - if (bestPickProbes[i] == -1) - continue; - - const ProbeRenderInst& curEntry = mActiveProbes[bestPickProbes[i]]; - - MatrixF p2A = curEntry.getTransform(); - p2A.inverse(); - probeDataSet->refScaleArray[i] = curEntry.mProbeRefScale / p2A.getScale(); - - Point3F probePos = curEntry.getPosition(); - Point3F refPos = probePos + curEntry.mProbeRefOffset * probeDataSet->refScaleArray[i].asPoint3F(); - probeDataSet->probeWorldToObjArray[i] = curEntry.getTransform(); - - probeDataSet->probePositionArray[i] = Point4F(probePos.x, probePos.y, probePos.z, 0); - probeDataSet->probeRefPositionArray[i] = Point4F(refPos.x, refPos.y, refPos.z, 0); - - probeDataSet->probeConfigArray[i] = Point4F(curEntry.mProbeShapeType, - curEntry.mRadius, - curEntry.mAtten, - curEntry.mCubemapIndex); - } -} - -void RenderProbeMgr::getProbeTextureData(ProbeTextureArrayData* probeTextureSet) -{ - probeTextureSet->BRDFTexture = mBRDFTexture; - probeTextureSet->prefilterArray = mPrefilterArray; - probeTextureSet->irradianceArray = mIrradianceArray; -} - -void RenderProbeMgr::setProbeInfo(ProcessedMaterial *pmat, - const Material *mat, - const SceneData &sgData, - const SceneRenderState *state, - U32 pass, - GFXShaderConstBuffer *shaderConsts) -{ - - // Skip this if we're rendering from the deferred bin. - if (sgData.binType == SceneData::DeferredBin) - return; - - PROFILE_SCOPE(ProbeManager_setProbeInfo); - - ProbeShaderConstants *psc = getProbeShaderConstants(shaderConsts); - - // NOTE: If you encounter a crash from this point forward - // while setting a shader constant its probably because the - // mConstantLookup has bad shaders/constants in it. - // - // This is a known crash bug that can occur if materials/shaders - // are reloaded and the light manager is not reset. - // - // We should look to fix this by clearing the table. - MatrixSet matSet = state->getRenderPass()->getMatrixSet(); - - // Update the forward shading light constants. - _update4ProbeConsts(sgData, matSet, psc, shaderConsts); -} - -//----------------------------------------------------------------------------- -// render objects -//----------------------------------------------------------------------------- void RenderProbeMgr::render( SceneRenderState *state ) { if (getProbeArrayEffect() == nullptr) @@ -695,7 +794,7 @@ void RenderProbeMgr::render( SceneRenderState *state ) _setupPerFrameParameters(state); // Early out if nothing to draw. - if (!RenderProbeMgr::smRenderReflectionProbes || (!state->isDiffusePass() && !state->isReflectPass()) || (mProbeData.effectiveProbeCount == 0 && mProbeData.skyLightIdx == -1)) + if ((!RenderProbeMgr::smRenderReflectionProbes && Con::getVariable("$Probes::Capturing", "0") == "0") || (!mHasSkylight && mProbeData.effectiveProbeCount == 0)) { getProbeArrayEffect()->setSkip(true); mActiveProbes.clear(); @@ -717,7 +816,7 @@ void RenderProbeMgr::render( SceneRenderState *state ) String useDebugContrib = Con::getVariable("$Probes::showProbeContrib", "0"); mProbeArrayEffect->setShaderMacro("DEBUGVIZ_CONTRIB", useDebugContrib); - if(mProbeData.skyLightIdx != -1 && mProbeData.effectiveProbeCount == 0) + if(mHasSkylight && mProbeData.effectiveProbeCount == 0) mProbeArrayEffect->setShaderMacro("SKYLIGHT_ONLY", "1"); else mProbeArrayEffect->setShaderMacro("SKYLIGHT_ONLY", "0"); @@ -725,6 +824,8 @@ void RenderProbeMgr::render( SceneRenderState *state ) String probePerFrame = Con::getVariable("$pref::MaxProbesPerFrame", "8"); mProbeArrayEffect->setShaderMacro("MAX_PROBES", probePerFrame); + String probeCapturing = Con::getVariable("$Probes::Capturing", "0"); + mProbeArrayEffect->setShaderMacro("CAPTURING", probeCapturing); //ssao mask if (AdvancedLightBinManager::smUseSSAOMask) { @@ -785,166 +886,17 @@ void RenderProbeMgr::render( SceneRenderState *state ) mProbeArrayEffect->setShaderConst("$worldToObjArray", mProbeData.probeWorldToObjArray); mProbeArrayEffect->setShaderConst("$refScaleArray", mProbeData.refScaleArray); mProbeArrayEffect->setShaderConst("$probeConfigData", mProbeData.probeConfigArray); + mProbeArrayEffect->setShaderConst("$maxProbeDrawDistance", smMaxProbeDrawDistance); // Make sure the effect is gonna render. getProbeArrayEffect()->setSkip(false); - - mActiveProbes.clear(); } -void RenderProbeMgr::bakeProbe(ReflectionProbe *probe) -{ - GFXDEBUGEVENT_SCOPE(RenderProbeMgr_Bake, ColorI::WHITE); +//============================================================================= +// Console functions +//============================================================================= - Con::warnf("RenderProbeMgr::bakeProbe() - Beginning bake!"); - U32 startMSTime = Platform::getRealMilliseconds(); - String path = Con::getVariable("$pref::ReflectionProbes::CurrentLevelPath", "levels/"); - U32 resolution = Con::getIntVariable("$pref::ReflectionProbes::BakeResolution", 64); - U32 prefilterMipLevels = mLog2(F32(resolution)) + 1; - bool renderWithProbes = Con::getIntVariable("$pref::ReflectionProbes::RenderWithProbes", false); - - ReflectionProbe* clientProbe = nullptr; - - if (probe->isServerObject()) - clientProbe = static_cast(probe->getClientObject()); - else - return; - - if (clientProbe == nullptr) - return; - - String probePrefilterPath = clientProbe->getPrefilterMapPath(); - String probeIrradPath = clientProbe->getIrradianceMapPath(); - - if (clientProbe->mReflectionModeType != ReflectionProbe::DynamicCubemap) - { - //Prep our bake path - if (probePrefilterPath.isEmpty() || probeIrradPath.isEmpty()) - { - Con::errorf("RenderProbeMgr::bake() - Unable to bake our captures because probe doesn't have a path set"); - return; - } - } - - // Save the current transforms so we can restore - // it for child control rendering below. - GFXTransformSaver saver; - - bool probeRenderState = RenderProbeMgr::smRenderReflectionProbes; - - F32 farPlane = 1000.0f; - - ReflectorDesc reflDesc; - reflDesc.texSize = resolution; - reflDesc.farDist = farPlane; - reflDesc.detailAdjust = 1; - reflDesc.objectTypeMask = probe->mProbeShapeType == ProbeRenderInst::ProbeShapeType::Skylight ? SKYLIGHT_CAPTURE_TYPEMASK : REFLECTION_PROBE_CAPTURE_TYPEMASK; - - CubeReflector cubeRefl; - cubeRefl.registerReflector(probe, &reflDesc); - - ReflectParams reflParams; - - //need to get the query somehow. Likely do some sort of get function to fetch from the guiTSControl that's active - CameraQuery query; //need to get the last cameraQuery - query.fov = 90; //90 degree slices for each of the 6 sides - query.nearPlane = 0.1f; - query.farPlane = farPlane; - query.headMatrix = MatrixF(); - query.cameraMatrix = clientProbe->getTransform(); - - Frustum culler; - culler.set(false, - query.fov, - 1.0f, - query.nearPlane, - query.farPlane, - query.cameraMatrix); - - S32 stereoTarget = GFX->getCurrentStereoTarget(); - - Point2I maxRes(2048, 2048); //basically a boundary so we don't go over this and break stuff - - reflParams.culler = culler; - reflParams.eyeId = stereoTarget; - reflParams.query = &query; - reflParams.startOfUpdateMs = startMSTime; - reflParams.viewportExtent = maxRes; - - if (!renderWithProbes) - RenderProbeMgr::smRenderReflectionProbes = false; - - GFXFormat reflectFormat; - - if (mUseHDRCaptures) - reflectFormat = GFXFormatR16G16B16A16F; - else - reflectFormat = GFXFormatR8G8B8A8; - const GFXFormat oldRefFmt = REFLECTMGR->getReflectFormat(); - REFLECTMGR->setReflectFormat(reflectFormat); - - mProbeArrayEffect->setShaderConst("$CAPTURING", true); - cubeRefl.updateReflection(reflParams, clientProbe->getTransform().getPosition()+clientProbe->mProbeRefOffset); - mProbeArrayEffect->setShaderConst("$CAPTURING", false); - - //Now, save out the maps - //create irridiance cubemap - if (cubeRefl.getCubemap()) - { - //Just to ensure we're prepped for the generation - clientProbe->createClientResources(); - - //Prep it with whatever resolution we've dictated for our bake - clientProbe->mIrridianceMap->mCubemap->initDynamic(resolution, reflectFormat); - clientProbe->mPrefilterMap->mCubemap->initDynamic(resolution, reflectFormat); - - GFXTextureTargetRef renderTarget = GFX->allocRenderToTextureTarget(false); - - IBLUtilities::GenerateIrradianceMap(renderTarget, cubeRefl.getCubemap(), clientProbe->mIrridianceMap->mCubemap); - IBLUtilities::GeneratePrefilterMap(renderTarget, cubeRefl.getCubemap(), prefilterMipLevels, clientProbe->mPrefilterMap->mCubemap); - - U32 endMSTime = Platform::getRealMilliseconds(); - F32 diffTime = F32(endMSTime - startMSTime); - Con::warnf("RenderProbeMgr::bake() - Finished Capture! Took %g milliseconds", diffTime); - Con::warnf("RenderProbeMgr::bake() - Beginning save now!"); - - IBLUtilities::SaveCubeMap(clientProbe->getIrradianceMapPath(), clientProbe->mIrridianceMap->mCubemap); - IBLUtilities::SaveCubeMap(clientProbe->getPrefilterMapPath(), clientProbe->mPrefilterMap->mCubemap); - } - else - { - Con::errorf("RenderProbeMgr::bake() - Didn't generate a valid scene capture cubemap, unable to generate prefilter and irradiance maps!"); - } - - if (!renderWithProbes) - RenderProbeMgr::smRenderReflectionProbes = probeRenderState; - - cubeRefl.unregisterReflector(); - - U32 endMSTime = Platform::getRealMilliseconds(); - F32 diffTime = F32(endMSTime - startMSTime); - - probe->setMaskBits(-1); - - Con::warnf("RenderProbeMgr::bake() - Finished bake! Took %g milliseconds", diffTime); - REFLECTMGR->setReflectFormat(oldRefFmt); -} - -void RenderProbeMgr::bakeProbes() -{ - Vector probes; - - Scene::getRootScene()->findObjectByType(probes); - - for (U32 i = 0; i < probes.size(); i++) - { - if (probes[i]->isClientObject()) - continue; - - bakeProbe(probes[i]); - } -} DefineEngineMethod(RenderProbeMgr, bakeProbe, void, (ReflectionProbe* probe), (nullAsType< ReflectionProbe*>()), "@brief Bakes the cubemaps for a reflection probe\n\n.") @@ -955,5 +907,7 @@ DefineEngineMethod(RenderProbeMgr, bakeProbe, void, (ReflectionProbe* probe), (n DefineEngineMethod(RenderProbeMgr, bakeProbes, void, (),, "@brief Iterates over all reflection probes in the scene and bakes their cubemaps\n\n.") { + Con::setVariable("$Probes::Capturing", "1"); object->bakeProbes(); + Con::setVariable("$Probes::Capturing", "0"); } diff --git a/Engine/source/renderInstance/renderProbeMgr.h b/Engine/source/renderInstance/renderProbeMgr.h index c9dbd69bd..3708f2e1e 100644 --- a/Engine/source/renderInstance/renderProbeMgr.h +++ b/Engine/source/renderInstance/renderProbeMgr.h @@ -39,7 +39,7 @@ #include "gfx/gfxVertexBuffer.h" #endif -#include "core/util/systemInterfaceList.h" +//#include "core/util/systemInterfaceList.h" #ifndef _MATERIALS_PROCESSEDSHADERMATERIAL_H_ #include "materials/processedShaderMaterial.h" @@ -52,52 +52,23 @@ #include "scene/reflector.h" #endif -static U32 MAXPROBECOUNT = 50; +#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 { - bool mIsEnabled; - - MatrixF mTransform; - - F32 mRadius; - - bool mDirty; - - Box3F mBounds; - Point3F mExtents; - Point3F mPosition; - Point3F mProbeRefOffset; - Point3F mProbeRefScale; - F32 mAtten; - - GFXCubemapHandle mPrefilterCubemap; - GFXCubemapHandle mIrradianceCubemap; - - /// The priority of this light used for - /// light and shadow scoring. - F32 mPriority; - - /// A temporary which holds the score used - /// when prioritizing lights for rendering. - F32 mScore; - - enum ProbeShapeType - { - Box = 0, ///< Sphere shaped - Sphere = 1, ///< Box-based shape - Skylight = 2 - }; - - ProbeShapeType mProbeShapeType; + ReflectionProbe::ProbeInfo* mProbeInfo; U32 mCubemapIndex; - U32 mProbeIdx; - public: ProbeRenderInst(); @@ -105,28 +76,11 @@ public: // Copies data passed in from light void set(const ProbeRenderInst *probeInfo); - - // Accessors - const MatrixF& getTransform() const { return mTransform; } - void setTransform(const MatrixF &xfm) { mTransform = xfm; } - - Point3F getPosition() const { return mPosition; } - void setPosition(const Point3F &pos) { mPosition = pos; } - - void setPriority(F32 priority) { mPriority = priority; } - F32 getPriority() const { return mPriority; } - - void setScore(F32 score) { mScore = score; } - F32 getScore() const { return mScore; } - - void clear(); - - inline bool operator ==(const ProbeRenderInst& b) const - { - return mProbeIdx == b.mProbeIdx; - } }; +/// +/// A container for all the shader consts needed for rendering probes in forward mode +/// struct ProbeShaderConstants { bool mInit; @@ -134,19 +88,21 @@ struct ProbeShaderConstants GFXShaderRef mShader; //Reflection Probes - GFXShaderConstHandle *mProbePositionSC; - GFXShaderConstHandle *mProbeRefPosSC; - GFXShaderConstHandle *mRefScaleSC; + GFXShaderConstHandle *mProbePositionArraySC; + GFXShaderConstHandle *mProbeRefPosArraySC; + GFXShaderConstHandle *mRefScaleArraySC; GFXShaderConstHandle *mWorldToObjArraySC; - GFXShaderConstHandle *mProbeConfigDataSC; - GFXShaderConstHandle *mProbeSpecularCubemapSC; - GFXShaderConstHandle *mProbeIrradianceCubemapSC; + GFXShaderConstHandle *mProbeConfigDataArraySC; + GFXShaderConstHandle *mProbeSpecularCubemapArraySC; + GFXShaderConstHandle *mProbeIrradianceCubemapArraySC; GFXShaderConstHandle *mProbeCountSC; GFXShaderConstHandle *mBRDFTextureMap; GFXShaderConstHandle *mSkylightCubemapIdxSC; + GFXShaderConstHandle* mMaxProbeDrawDistanceSC; + ProbeShaderConstants(); ~ProbeShaderConstants(); @@ -159,6 +115,10 @@ struct ProbeShaderConstants 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; @@ -198,18 +158,10 @@ struct ProbeDataSet probeWorldToObjArray.setSize(maxProbeCount); - skyLightIdx = -1; effectiveProbeCount = 0; } }; -struct ProbeTextureArrayData -{ - GFXTexHandle BRDFTexture; - GFXCubemapArrayHandle prefilterArray; - GFXCubemapArrayHandle irradianceArray; -}; - //************************************************************************** // RenderObjectMgr //************************************************************************** @@ -217,11 +169,6 @@ class RenderProbeMgr : public RenderBinManager { typedef RenderBinManager Parent; - Vector mRegisteredProbes; - - bool mProbesDirty; - - Vector mActiveProbes; public: //maximum number of allowed probes static const U32 PROBE_MAX_COUNT = 250; @@ -230,51 +177,161 @@ public: //number of slots to allocate at once in the cubemap array static const U32 PROBE_ARRAY_SLOT_BUFFER_SIZE = 10; - static const U32 PROBE_IRRAD_SIZE = 64; - static const U32 PROBE_PREFILTER_SIZE = 64; + //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: - //Array rendering - U32 mEffectiveProbeCount; - S32 mMipCount; + /// + /// 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; - //number of cubemaps + /// + /// 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; - //number of cubemap slots allocated + + /// + /// 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; - //array of cubemap slots, due to the editor these may be mixed around as probes are added and deleted + + /// + /// 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; - // - SimObjectPtr mProbeArrayEffect; - - //Default skylight, used for shape editors, etc - ProbeRenderInst* mDefaultSkyLight; - + /// + /// The BRDF texture used in PBR math calculations + /// GFXTexHandle mBRDFTexture; + /// + /// Processed best probe selection list of the current frame when rendering in deferred mode. + /// ProbeDataSet mProbeData; - ///Prevents us from saving out the cubemaps(for now) but allows us the full HDR range on the in-memory cubemap captures + + /// + /// Allows us the full HDR range on the in-memory cubemap captures + /// bool mUseHDRCaptures; - U32 mPrefilterMipLevels; - U32 mPrefilterSize; +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); @@ -286,75 +343,139 @@ public: static void initPersistFields(); static void consoleInit(); + virtual void addElement(RenderInst* inst) {}; DECLARE_CONOBJECT(RenderProbeMgr); -protected: - /// The current active light manager. - static RenderProbeMgr *smProbeManager; - - /// This helper function sets the shader constansts - /// for the stock 4 light forward lighting code. - void _update4ProbeConsts(const SceneData &sgData, - MatrixSet &matSet, - ProbeShaderConstants *probeShaderConsts, - GFXShaderConstBuffer *shaderConsts); - - void _setupStaticParameters(); - void _setupPerFrameParameters(const SceneRenderState *state); - virtual void addElement(RenderInst* inst) {}; - virtual void render(SceneRenderState * state); - - ProbeShaderConstants* getProbeShaderConstants(GFXShaderConstBuffer* buffer); - - PostEffect* getProbeArrayEffect(); - - - U32 _findNextEmptyCubeSlot() - { - for (U32 i = 0; i < PROBE_MAX_COUNT; i++) - { - if (!mCubeMapSlots[i]) - return i; - } - return INVALID_CUBE_SLOT; - } - -public: - // RenderBinMgr - void updateProbes(); - - /// Returns the active LM. - static inline RenderProbeMgr* getProbeManager(); - - void registerProbe(ProbeRenderInst* newProbe); - void unregisterProbe(U32 probeIdx); - void submitProbe(const ProbeRenderInst& newProbe); - - static S32 QSORT_CALLBACK _probeScoreCmp(const ProbeRenderInst* a, const ProbeRenderInst* b); - - virtual void setProbeInfo(ProcessedMaterial *pmat, - const Material *mat, - const SceneData &sgData, - const SceneRenderState *state, - U32 pass, - GFXShaderConstBuffer *shaderConsts); - - void setupSGData(SceneData& data, const SceneRenderState* state, LightInfo* light); - - void updateProbeTexture(ProbeRenderInst* probeInfo); - - void reloadTextures(); - - /// Debug rendering + /// + /// Static flag used to indicate if probes should be rendered at all. Used for debugging + /// static bool smRenderReflectionProbes; - void bakeProbe(ReflectionProbe *probeInfo); + //============================================================================= + // 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(); + + /// + /// 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); + + /// + /// Runs the cubemap bake on all probes in the current scene + /// void bakeProbes(); - void getProbeTextureData(ProbeTextureArrayData* probeTextureSet); - S32 getSkylightIndex() { return mSkylightCubemapIdx; } - //accumulates the best fit of probes given the object position - void getBestProbes(const Point3F& objPosition, ProbeDataSet* probeDataSet); + /// + /// 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() diff --git a/Engine/source/shaderGen/GLSL/shaderFeatureGLSL.cpp b/Engine/source/shaderGen/GLSL/shaderFeatureGLSL.cpp index 69af7ef5c..94b457c75 100644 --- a/Engine/source/shaderGen/GLSL/shaderFeatureGLSL.cpp +++ b/Engine/source/shaderGen/GLSL/shaderFeatureGLSL.cpp @@ -758,7 +758,7 @@ Var* ShaderFeatureGLSL::getWsView( Var *wsPosition, MultiLine *meta ) eyePos->constSortPos = cspPass; } - meta->addStatement( new GenOp( " @ = normalize( @ - @ );\r\n", + meta->addStatement( new GenOp( " @ = @ - @;\r\n", new DecOp( wsView ), eyePos, wsPosition ) ); } @@ -838,79 +838,66 @@ Var* ShaderFeatureGLSL::addOutDetailTexCoord( Vector &compon Var* ShaderFeatureGLSL::getSurface(Vector& componentList, MultiLine* meta, const MaterialFeatureData& fd) { - ShaderConnector* connectComp = dynamic_cast(componentList[C_CONNECTOR]); - - Var* diffuseColor = (Var*)LangElement::find(getOutputTargetVarName(ShaderFeature::DefaultTarget)); - - Var* ormConfig = (Var*)LangElement::find("ORMConfig"); - if (!ormConfig) - { - Var* metalness = (Var*)LangElement::find("metalness"); - if (!metalness) - { - metalness = new Var("metalness", "float"); - metalness->uniform = true; - metalness->constSortPos = cspPotentialPrimitive; - } - - Var* roughness = (Var*)LangElement::find("roughness"); - if (!roughness) - { - roughness = new Var("roughness", "float"); - roughness->uniform = true; - roughness->constSortPos = cspPotentialPrimitive; - } - - ormConfig = new Var("ORMConfig", "vec4"); - LangElement* colorDecl = new DecOp(ormConfig); - meta->addStatement(new GenOp(" @ = vec4(0.0,1.0,@,@);\r\n", colorDecl, roughness, metalness)); //reconstruct ormConfig, no ao darkening - } - - Var* normal = (Var*)LangElement::find("normal"); - if (!normal) - { - normal = new Var("normal", "vec3"); - meta->addStatement(new GenOp(" @;\r\n\n", new DecOp(normal))); - - Var* wsNormal = (Var*)LangElement::find("wsNormal"); - if (!fd.features[MFT_NormalMap]) - { - if (!wsNormal) - wsNormal = getInWorldNormal(componentList); - meta->addStatement(new GenOp(" @ = normalize( @ );\r\n\n", normal, wsNormal)); - } - else - { - meta->addStatement(new GenOp(" @ = normalize( @ );\r\n", normal, wsNormal)); - } - } - - Var* wsEyePos = (Var*)LangElement::find("eyePosWorld"); - - if (!wsEyePos) - { - wsEyePos = new Var("eyePosWorld", "vec3"); - wsEyePos->uniform = true; - wsEyePos->constSortPos = cspPass; - } - - Var* wsPosition = getInWsPosition(componentList); - Var* wsView = getWsView(wsPosition, meta); - - Var* surface = (Var*)LangElement::find("surface"); + Var *surface = (Var *)LangElement::find("surface"); if (!surface) { + Var* diffuseColor = (Var*)LangElement::find(getOutputTargetVarName(ShaderFeature::DefaultTarget)); + + Var* ormConfig = (Var*)LangElement::find("ORMConfig"); + if (!ormConfig) + { + Var* metalness = (Var*)LangElement::find("metalness"); + if (!metalness) + { + metalness = new Var("metalness", "float"); + metalness->uniform = true; + metalness->constSortPos = cspPotentialPrimitive; + } + + Var* roughness = (Var*)LangElement::find("roughness"); + if (!roughness) + { + roughness = new Var("roughness", "float"); + roughness->uniform = true; + roughness->constSortPos = cspPotentialPrimitive; + } + + ormConfig = new Var("ORMConfig", "vec4"); + LangElement* colorDecl = new DecOp(ormConfig); + meta->addStatement(new GenOp(" @ = vec4(0.0,1.0,@,@);\r\n", colorDecl, roughness, metalness)); //reconstruct ormConfig, no ao darkening + } + + Var* normal = (Var*)LangElement::find("normal"); + if (!normal) + { + normal = new Var("normal", "vec3"); + meta->addStatement(new GenOp(" @;\r\n\n", new DecOp(normal))); + + Var *wsNormal = (Var *)LangElement::find("wsNormal"); + if (!wsNormal) + wsNormal = getInWorldNormal(componentList); + + meta->addStatement(new GenOp(" @ = normalize( @ );\r\n", normal, wsNormal)); + } + + Var* wsEyePos = (Var*)LangElement::find("eyePosWorld"); + + if (!wsEyePos) + { + wsEyePos = new Var("eyePosWorld", "vec3"); + wsEyePos->uniform = true; + wsEyePos->constSortPos = cspPass; + } + + Var* wsPosition = getInWsPosition(componentList); + Var* wsView = getWsView(wsPosition, meta); + surface = new Var("surface", "Surface"); - meta->addStatement(new GenOp(" @ = createForwardSurface(@,@,@,@,@,@);\r\n\n", new DecOp(surface), diffuseColor, normal, ormConfig, + meta->addStatement(new GenOp(" @ = createForwardSurface(@,normalize(@),@,@,@,@);\r\n\n", new DecOp(surface), diffuseColor, normal, ormConfig, wsPosition, wsEyePos, wsView)); } - /*Var* surface = (Var*)LangElement::find("surface"); - if (!surface) - { - surface = new Var("surface", "float"); - }*/ return surface; } //**************************************************************************** @@ -3003,12 +2990,12 @@ void ReflectionProbeFeatGLSL::processPix(Vector& componentList inRefPosArray->uniform = true; inRefPosArray->constSortPos = cspPotentialPrimitive; - Var * refScaleArray = new Var("inRefScale", "vec4"); + Var * refScaleArray = new Var("inRefScaleArray", "vec4"); refScaleArray->arraySize = MAX_FORWARD_PROBES; refScaleArray->uniform = true; refScaleArray->constSortPos = cspPotentialPrimitive; - Var * probeConfigData = new Var("inProbeConfigData", "vec4"); + Var * probeConfigData = new Var("inProbeConfigDataArray", "vec4"); probeConfigData->arraySize = MAX_FORWARD_PROBES; probeConfigData->uniform = true; probeConfigData->constSortPos = cspPotentialPrimitive; @@ -3026,12 +3013,12 @@ void ReflectionProbeFeatGLSL::processPix(Vector& componentList BRDFTexture->sampler = true; BRDFTexture->constNum = Var::getTexUnitNum(); // used as texture unit num here - Var * specularCubemapAR = new Var("inSpecularCubemapAR", "samplerCubeArray"); + Var * specularCubemapAR = new Var("SpecularCubemapAR", "samplerCubeArray"); specularCubemapAR->uniform = true; specularCubemapAR->sampler = true; specularCubemapAR->constNum = Var::getTexUnitNum(); - Var * irradianceCubemapAR = new Var("inIrradianceCubemapAR", "samplerCubeArray"); + Var * irradianceCubemapAR = new Var("IrradianceCubemapAR", "samplerCubeArray"); irradianceCubemapAR->uniform = true; irradianceCubemapAR->sampler = true; irradianceCubemapAR->constNum = Var::getTexUnitNum(); @@ -3044,14 +3031,24 @@ void ReflectionProbeFeatGLSL::processPix(Vector& componentList return; } + Var* eyePos = (Var*)LangElement::find("eyePosWorld"); + if (!eyePos) + { + eyePos = new Var; + eyePos->setType("vec3"); + eyePos->setName("eyePosWorld"); + eyePos->uniform = true; + eyePos->constSortPos = cspPotentialPrimitive; + } + Var *curColor = (Var*)LangElement::find(getOutputTargetVarName(ShaderFeature::DefaultTarget)); //Reflection vec - String computeForwardProbes = String(" @.rgb = computeForwardProbes(@,@,@,@,@,@,@,@,\r\n\t\t"); + String computeForwardProbes = String(" @.rgb = computeForwardProbes(@,@,@,@,@,@,@,@,@,\r\n\t\t"); computeForwardProbes += String("@,@,\r\n\t\t"); computeForwardProbes += String("@,@).rgb; \r\n"); - meta->addStatement(new GenOp(computeForwardProbes.c_str(), curColor, surface, cubeMips, numProbes, worldToObjArray, probeConfigData, inProbePosArray, refScaleArray, inRefPosArray, + meta->addStatement(new GenOp(computeForwardProbes.c_str(), curColor, surface, cubeMips, numProbes, worldToObjArray, probeConfigData, inProbePosArray, refScaleArray, inRefPosArray, eyePos, skylightCubemapIdx, BRDFTexture, irradianceCubemapAR, specularCubemapAR)); @@ -3078,9 +3075,9 @@ void ReflectionProbeFeatGLSL::setTexData(Material::StageData& stageDat, passData.mSamplerNames[texIndex] = "BRDFTexture"; passData.mTexType[texIndex++] = Material::Standard; // assuming here that it is a scenegraph cubemap - passData.mSamplerNames[texIndex] = "inSpecularCubemapAR"; + passData.mSamplerNames[texIndex] = "SpecularCubemapAR"; passData.mTexType[texIndex++] = Material::SGCube; - passData.mSamplerNames[texIndex] = "inIrradianceCubemapAR"; + passData.mSamplerNames[texIndex] = "IrradianceCubemapAR"; passData.mTexType[texIndex++] = Material::SGCube; } } diff --git a/Engine/source/shaderGen/HLSL/shaderFeatureHLSL.cpp b/Engine/source/shaderGen/HLSL/shaderFeatureHLSL.cpp index c53e939e0..a294f5f85 100644 --- a/Engine/source/shaderGen/HLSL/shaderFeatureHLSL.cpp +++ b/Engine/source/shaderGen/HLSL/shaderFeatureHLSL.cpp @@ -764,7 +764,7 @@ Var* ShaderFeatureHLSL::getWsView( Var *wsPosition, MultiLine *meta ) eyePos->constSortPos = cspPass; } - meta->addStatement( new GenOp( " @ = normalize( @ - @ );\r\n", + meta->addStatement( new GenOp( " @ = @ - @;\r\n", new DecOp( wsView ), eyePos, wsPosition ) ); } @@ -844,14 +844,16 @@ Var* ShaderFeatureHLSL::addOutDetailTexCoord( Vector &compon Var* ShaderFeatureHLSL::getSurface(Vector& componentList, MultiLine* meta, const MaterialFeatureData& fd) { - ShaderConnector* connectComp = dynamic_cast(componentList[C_CONNECTOR]); + Var *surface = (Var *)LangElement::find("surface"); - Var* diffuseColor = (Var*)LangElement::find(getOutputTargetVarName(ShaderFeature::DefaultTarget)); + if (!surface) + { + Var *diffuseColor = (Var *)LangElement::find(getOutputTargetVarName(ShaderFeature::DefaultTarget)); - Var* ormConfig = (Var*)LangElement::find("ORMConfig"); + Var *ormConfig = (Var *)LangElement::find("ORMConfig"); if (!ormConfig) { - Var* metalness = (Var*)LangElement::find("metalness"); + Var *metalness = (Var *)LangElement::find("metalness"); if (!metalness) { metalness = new Var("metalness", "float"); @@ -859,7 +861,7 @@ Var* ShaderFeatureHLSL::getSurface(Vector& componentList, Mult metalness->constSortPos = cspPotentialPrimitive; } - Var* roughness = (Var*)LangElement::find("roughness"); + Var *roughness = (Var *)LangElement::find("roughness"); if (!roughness) { roughness = new Var("roughness", "float"); @@ -868,30 +870,24 @@ Var* ShaderFeatureHLSL::getSurface(Vector& componentList, Mult } ormConfig = new Var("ORMConfig", "float4"); - LangElement* colorDecl = new DecOp(ormConfig); + LangElement *colorDecl = new DecOp(ormConfig); meta->addStatement(new GenOp(" @ = float4(0.0,1.0,@,@);\r\n", colorDecl, roughness, metalness)); //reconstruct matinfo, no ao darkening } - Var* normal = (Var*)LangElement::find("normal"); + Var *normal = (Var *)LangElement::find("normal"); if (!normal) { normal = new Var("normal", "float3"); meta->addStatement(new GenOp(" @;\r\n\n", new DecOp(normal))); - Var* wsNormal = (Var*)LangElement::find("wsNormal"); - if (!fd.features[MFT_NormalMap]) - { + Var *wsNormal = (Var *)LangElement::find("wsNormal"); if (!wsNormal) wsNormal = getInWorldNormal(componentList); - meta->addStatement(new GenOp(" @ = normalize( @ );\r\n\n", normal, wsNormal)); - } - else - { + meta->addStatement(new GenOp(" @ = normalize( @ );\r\n", normal, wsNormal)); } - } - Var* wsEyePos = (Var*)LangElement::find("eyePosWorld"); + Var *wsEyePos = (Var *)LangElement::find("eyePosWorld"); if (!wsEyePos) { @@ -900,15 +896,11 @@ Var* ShaderFeatureHLSL::getSurface(Vector& componentList, Mult wsEyePos->constSortPos = cspPass; } - Var* wsPosition = getInWsPosition(componentList); - Var* wsView = getWsView(wsPosition, meta); + Var *wsPosition = getInWsPosition(componentList); + Var *wsView = getWsView(wsPosition, meta); - Var* surface = (Var*)LangElement::find("surface"); - - if (!surface) - { surface = new Var("surface", "Surface"); - meta->addStatement(new GenOp(" @ = createForwardSurface(@,@,@,@,@,@);\r\n\n", new DecOp(surface), diffuseColor, normal, ormConfig, + meta->addStatement(new GenOp(" @ = createForwardSurface(@,normalize(@),@,@,@,@);\r\n\n", new DecOp(surface), diffuseColor, normal, ormConfig, wsPosition, wsEyePos, wsView)); } @@ -3076,12 +3068,12 @@ void ReflectionProbeFeatHLSL::processPix(Vector &componentList inRefPosArray->uniform = true; inRefPosArray->constSortPos = cspPotentialPrimitive; - Var * refScaleArray = new Var("inRefScale", "float4"); + Var * refScaleArray = new Var("inRefScaleArray", "float4"); refScaleArray->arraySize = MAX_FORWARD_PROBES; refScaleArray->uniform = true; refScaleArray->constSortPos = cspPotentialPrimitive; - Var *probeConfigData = new Var("inProbeConfigData", "float4"); + Var *probeConfigData = new Var("inProbeConfigDataArray", "float4"); probeConfigData->arraySize = MAX_FORWARD_PROBES; probeConfigData->uniform = true; probeConfigData->constSortPos = cspPotentialPrimitive; @@ -3101,22 +3093,22 @@ void ReflectionProbeFeatHLSL::processPix(Vector &componentList BRDFTextureTex->texture = true; BRDFTextureTex->constNum = BRDFTexture->constNum; - Var *specularCubemapAR = new Var("inSpecularCubemapAR", "SamplerState"); + Var *specularCubemapAR = new Var("SpecularCubemapAR", "SamplerState"); specularCubemapAR->uniform = true; specularCubemapAR->sampler = true; specularCubemapAR->constNum = Var::getTexUnitNum(); // used as texture unit num here - Var *specularCubemapARTex = new Var("texture_inSpecularCubemapAR", "TextureCubeArray"); + Var *specularCubemapARTex = new Var("texture_SpecularCubemapAR", "TextureCubeArray"); specularCubemapARTex->uniform = true; specularCubemapARTex->texture = true; specularCubemapARTex->constNum = specularCubemapAR->constNum; - Var *irradianceCubemapAR = new Var("inIrradianceCubemapAR", "SamplerState"); + Var *irradianceCubemapAR = new Var("IrradianceCubemapAR", "SamplerState"); irradianceCubemapAR->uniform = true; irradianceCubemapAR->sampler = true; irradianceCubemapAR->constNum = Var::getTexUnitNum(); // used as texture unit num here - Var *irradianceCubemapARTex = new Var("texture_inIrradianceCubemapAR", "TextureCubeArray"); + Var *irradianceCubemapARTex = new Var("texture_IrradianceCubemapAR", "TextureCubeArray"); irradianceCubemapARTex->uniform = true; irradianceCubemapARTex->texture = true; irradianceCubemapARTex->constNum = irradianceCubemapAR->constNum; @@ -3138,11 +3130,21 @@ void ReflectionProbeFeatHLSL::processPix(Vector &componentList ibl = new Var("ibl", "float3"); } - String computeForwardProbes = String(" @ = computeForwardProbes(@,@,@,@,@,@,@,@,\r\n\t\t"); + Var* eyePos = (Var*)LangElement::find("eyePosWorld"); + if (!eyePos) + { + eyePos = new Var; + eyePos->setType("float3"); + eyePos->setName("eyePosWorld"); + eyePos->uniform = true; + eyePos->constSortPos = cspPass; + } + + String computeForwardProbes = String(" @ = computeForwardProbes(@,@,@,@,@,@,@,@,@,\r\n\t\t"); computeForwardProbes += String("@,TORQUE_SAMPLER2D_MAKEARG(@),\r\n\t\t"); computeForwardProbes += String("TORQUE_SAMPLERCUBEARRAY_MAKEARG(@),TORQUE_SAMPLERCUBEARRAY_MAKEARG(@)).rgb; \r\n"); - meta->addStatement(new GenOp(computeForwardProbes.c_str(), new DecOp(ibl), surface, cubeMips, numProbes, worldToObjArray, probeConfigData, inProbePosArray, refScaleArray, inRefPosArray, + meta->addStatement(new GenOp(computeForwardProbes.c_str(), new DecOp(ibl), surface, cubeMips, numProbes, worldToObjArray, probeConfigData, inProbePosArray, refScaleArray, inRefPosArray, eyePos, skylightCubemapIdx, BRDFTexture, irradianceCubemapAR, specularCubemapAR)); @@ -3171,9 +3173,9 @@ void ReflectionProbeFeatHLSL::setTexData(Material::StageData &stageDat, passData.mSamplerNames[texIndex] = "BRDFTexture"; passData.mTexType[texIndex++] = Material::Standard; // assuming here that it is a scenegraph cubemap - passData.mSamplerNames[texIndex] = "inSpecularCubemapAR"; + passData.mSamplerNames[texIndex] = "SpecularCubemapAR"; passData.mTexType[texIndex++] = Material::SGCube; - passData.mSamplerNames[texIndex] = "inIrradianceCubemapAR"; + passData.mSamplerNames[texIndex] = "IrradianceCubemapAR"; passData.mTexType[texIndex++] = Material::SGCube; } } diff --git a/Engine/source/shaderGen/shaderGenVars.cpp b/Engine/source/shaderGen/shaderGenVars.cpp index 839a4c36b..e7e7296c1 100644 --- a/Engine/source/shaderGen/shaderGenVars.cpp +++ b/Engine/source/shaderGen/shaderGenVars.cpp @@ -80,17 +80,19 @@ const String ShaderGenVars::glowMul("$glowMul"); //Reflection Probes - Forward lit. not to be confused with the deferred handwritten vars //change to parity once we've got the same arrays used for both routes -const String ShaderGenVars::probePosition("$inProbePosArray"); -const String ShaderGenVars::probeRefPos("$inRefPosArray"); -const String ShaderGenVars::refScale("$inRefScale"); +const String ShaderGenVars::probePositionArray("$inProbePosArray"); +const String ShaderGenVars::probeRefPosArray("$inRefPosArray"); +const String ShaderGenVars::refScaleArray("$inRefScaleArray"); const String ShaderGenVars::worldToObjArray("$inWorldToObjArray"); -const String ShaderGenVars::probeConfigData("$inProbeConfigData"); -const String ShaderGenVars::specularCubemapAR("$inSpecularCubemapAR"); -const String ShaderGenVars::irradianceCubemapAR("$inIrradianceCubemapAR"); +const String ShaderGenVars::probeConfigDataArray("$inProbeConfigDataArray"); +const String ShaderGenVars::specularCubemapAR("$SpecularCubemapAR"); +const String ShaderGenVars::irradianceCubemapAR("$IrradianceCubemapAR"); const String ShaderGenVars::probeCount("$inNumProbes"); const String ShaderGenVars::BRDFTextureMap("$BRDFTexture"); +const String ShaderGenVars::maxProbeDrawDistance("$maxProbeDrawDistance"); + //Skylight const String ShaderGenVars::skylightCubemapIdx("$inSkylightCubemapIdx"); diff --git a/Engine/source/shaderGen/shaderGenVars.h b/Engine/source/shaderGen/shaderGenVars.h index 6c32d4522..c32d97c94 100644 --- a/Engine/source/shaderGen/shaderGenVars.h +++ b/Engine/source/shaderGen/shaderGenVars.h @@ -91,17 +91,19 @@ struct ShaderGenVars const static String glowMul; //Reflection Probes - const static String probePosition; - const static String probeRefPos; - const static String refScale; + const static String probePositionArray; + const static String probeRefPosArray; + const static String refScaleArray; const static String worldToObjArray; - const static String probeConfigData; + const static String probeConfigDataArray; const static String specularCubemapAR; const static String irradianceCubemapAR; const static String probeCount; const static String BRDFTextureMap; + const static String maxProbeDrawDistance; + //Skylight const static String skylightCubemapIdx; diff --git a/Templates/BaseGame/game/core/postFX/scripts/ReflectionProbes/reflectionProbeArrayPostFX.tscript b/Templates/BaseGame/game/core/postFX/scripts/ReflectionProbes/reflectionProbeArrayPostFX.tscript index c5811c34b..879ec5774 100644 --- a/Templates/BaseGame/game/core/postFX/scripts/ReflectionProbes/reflectionProbeArrayPostFX.tscript +++ b/Templates/BaseGame/game/core/postFX/scripts/ReflectionProbes/reflectionProbeArrayPostFX.tscript @@ -15,4 +15,6 @@ singleton PostEffect( reflectionProbeArrayPostFX ) texture[0] = "#deferred"; texture[1] = "#color"; texture[2] = "#matinfo"; + + allowReflectPass = true; }; diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/lighting.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/lighting.glsl index 55d9866ce..57ee38190 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/gl/lighting.glsl +++ b/Templates/BaseGame/game/core/rendering/shaders/gl/lighting.glsl @@ -23,6 +23,8 @@ #include "./torque.glsl" #include "./brdf.glsl" +uniform float maxProbeDrawDistance; + #ifndef TORQUE_SHADERGEN #line 27 // These are the uniforms used by most lighting shaders. @@ -330,7 +332,7 @@ float defineSphereSpaceInfluence(vec3 wsPosition, vec3 wsProbePosition, float ra { vec3 L = wsProbePosition.xyz - wsPosition; float contribution = 1.0 - length(L) / radius; - return contribution; + return saturate(contribution); } float getDistBoxToPoint(vec3 pt, vec3 extents) @@ -342,10 +344,9 @@ float getDistBoxToPoint(vec3 pt, vec3 extents) float defineBoxSpaceInfluence(vec3 wsPosition, mat4 worldToObj, float attenuation) { vec3 surfPosLS = tMul(worldToObj, vec4(wsPosition, 1.0)).xyz; - float atten = 1.0 - attenuation; float baseVal = 0.25; float dist = getDistBoxToPoint(surfPosLS, vec3(baseVal, baseVal, baseVal)); - return saturate(smoothstep(baseVal + 0.0001, atten*baseVal, dist)); + return saturate(smoothstep(baseVal, (baseVal-attenuation/2), dist)); } // Box Projected IBL Lighting @@ -367,9 +368,9 @@ vec3 boxProject(vec3 wsPosition, vec3 wsReflectVec, mat4 worldToObj, vec3 refSca } vec4 computeForwardProbes(Surface surface, - float cubeMips, int numProbes, mat4x4 worldToObjArray[MAX_FORWARD_PROBES], vec4 probeConfigData[MAX_FORWARD_PROBES], - vec4 inProbePosArray[MAX_FORWARD_PROBES], vec4 refScaleArray[MAX_FORWARD_PROBES], vec4 inRefPosArray[MAX_FORWARD_PROBES], - float skylightCubemapIdx, sampler2D BRDFTexture, + float cubeMips, int numProbes, mat4x4 inWorldToObjArray[MAX_FORWARD_PROBES], vec4 inProbeConfigData[MAX_FORWARD_PROBES], + vec4 inProbePosArray[MAX_FORWARD_PROBES], vec4 inRefScaleArray[MAX_FORWARD_PROBES], vec4 inRefPosArray[MAX_FORWARD_PROBES], + vec3 wsEyePos, float skylightCubemapIdx, sampler2D BRDFTexture, samplerCubeArray irradianceCubemapAR, samplerCubeArray specularCubemapAR) { int i = 0; @@ -384,47 +385,37 @@ vec4 computeForwardProbes(Surface surface, for (i = 0; i < numProbes; ++i) { contribution[i] = 0; - - if (probeConfigData[i].r == 0) //box + float atten = 1.0-(length(wsEyePos-inProbePosArray[i].xyz)/maxProbeDrawDistance); + if (inProbeConfigData[i].r == 0) //box { - contribution[i] = defineBoxSpaceInfluence(surface.P, worldToObjArray[i], probeConfigData[i].b); - if (contribution[i] > 0.0) - probehits++; + contribution[i] = defineBoxSpaceInfluence(surface.P, inWorldToObjArray[i], inProbeConfigData[i].b)*atten; } - else if (probeConfigData[i].r == 1) //sphere + else if (inProbeConfigData[i].r == 1) //sphere { - contribution[i] = defineSphereSpaceInfluence(surface.P, inProbePosArray[i].xyz, probeConfigData[i].g); - if (contribution[i] > 0.0) - probehits++; + contribution[i] = defineSphereSpaceInfluence(surface.P, inProbePosArray[i].xyz, inProbeConfigData[i].g)*atten; } - contribution[i] = max(contribution[i], 0); + if (contribution[i]>0.0) + probehits++; + else + contribution[i] = 0.0; blendSum += contribution[i]; - invBlendSum += (1.0f - contribution[i]); } - if (probehits > 1.0) + if (probehits > 1.0)//if we overlap { + invBlendSum = (probehits - blendSum)/(probehits-1); //grab the remainder for (i = 0; i < numProbes; i++) { - blendFactor[i] = ((contribution[i] / blendSum)) / probehits; - blendFactor[i] *= ((contribution[i]) / invBlendSum); - blendFactor[i] = saturate(blendFactor[i]); - blendFacSum += blendFactor[i]; + blendFactor[i] = contribution[i]/blendSum; //what % total is this instance + blendFactor[i] *= blendFactor[i] / invBlendSum; //what should we add to sum to 1 + blendFacSum += blendFactor[i]; //running tally of results } - // Normalize blendVal - if (blendFacSum == 0.0f) // Possible with custom weight - { - blendFacSum = 1.0f; - } - - float invBlendSumWeighted = 1.0f / blendFacSum; for (i = 0; i < numProbes; ++i) { - blendFactor[i] *= invBlendSumWeighted; - contribution[i] *= blendFactor[i]; + contribution[i] *= blendFactor[i]/blendFacSum; //normalize } } @@ -471,8 +462,8 @@ vec4 computeForwardProbes(Surface surface, float contrib = contribution[i]; if (contrib > 0.0f) { - float cubemapIdx = int(probeConfigData[i].a); - vec3 dir = boxProject(surface.P, surface.R, worldToObjArray[i], refScaleArray[i].xyz, inRefPosArray[i].xyz); + float cubemapIdx = int(inProbeConfigData[i].a); + vec3 dir = boxProject(surface.P, surface.R, inWorldToObjArray[i], inRefScaleArray[i].xyz, inRefPosArray[i].xyz); irradiance += textureLod(irradianceCubemapAR, vec4(dir, cubemapIdx), 0).xyz * contrib; specular += textureLod(specularCubemapAR, vec4(dir, cubemapIdx), lod).xyz * contrib; @@ -491,8 +482,8 @@ vec4 computeForwardProbes(Surface surface, vec3 kD = 1.0f - F; kD *= 1.0f - surface.metalness; - float dfgNdotV = max( surface.NdotV , 0.0009765625f ); //0.5f/512.0f (512 is size of dfg/brdf lookup tex) - vec2 envBRDF = textureLod(BRDFTexture, vec2(dfgNdotV, surface.roughness),0).rg; + //float dfgNdotV = max( surface.NdotV , 0.0009765625f ); //0.5f/512.0f (512 is size of dfg/brdf lookup tex) + vec2 envBRDF = textureLod(BRDFTexture, vec2(surface.NdotV, surface.roughness),0).rg; specular *= F * envBRDF.x + surface.f90 * envBRDF.y; irradiance *= kD * surface.baseColor.rgb; @@ -504,13 +495,16 @@ vec4 computeForwardProbes(Surface surface, float horizonOcclusion = 1.3; float horizon = saturate( 1 + horizonOcclusion * dot(surface.R, surface.N)); horizon *= horizon; - +#if CAPTURING == 1 + return vec4(mix(surface.baseColor.rgb,(irradiance + specular) * horizon,surface.metalness/2),0); +#else return vec4((irradiance + specular) * horizon, 0);//alpha writes disabled +#endif } vec4 debugVizForwardProbes(Surface surface, - float cubeMips, int numProbes, mat4 worldToObjArray[MAX_FORWARD_PROBES], vec4 probeConfigData[MAX_FORWARD_PROBES], - vec4 inProbePosArray[MAX_FORWARD_PROBES], vec4 refScaleArray[MAX_FORWARD_PROBES], vec4 inRefPosArray[MAX_FORWARD_PROBES], + float cubeMips, int numProbes, mat4 inWorldToObjArray[MAX_FORWARD_PROBES], vec4 inProbeConfigData[MAX_FORWARD_PROBES], + vec4 inProbePosArray[MAX_FORWARD_PROBES], vec4 inRefScaleArray[MAX_FORWARD_PROBES], vec4 inRefPosArray[MAX_FORWARD_PROBES], float skylightCubemapIdx, sampler2D BRDFTexture, samplerCubeArray irradianceCubemapAR, samplerCubeArray specularCubemapAR, int showAtten, int showContrib, int showSpec, int showDiff) { @@ -527,15 +521,15 @@ vec4 debugVizForwardProbes(Surface surface, { contribution[i] = 0; - if (probeConfigData[i].r == 0) //box + if (inProbeConfigData[i].r == 0) //box { - contribution[i] = defineBoxSpaceInfluence(surface.P, worldToObjArray[i], probeConfigData[i].b); + contribution[i] = defineBoxSpaceInfluence(surface.P, inWorldToObjArray[i], inProbeConfigData[i].b); if (contribution[i] > 0.0) probehits++; } - else if (probeConfigData[i].r == 1) //sphere + else if (inProbeConfigData[i].r == 1) //sphere { - contribution[i] = defineSphereSpaceInfluence(surface.P, inProbePosArray[i].xyz, probeConfigData[i].g); + contribution[i] = defineSphereSpaceInfluence(surface.P, inProbePosArray[i].xyz, inProbeConfigData[i].g); if (contribution[i] > 0.0) probehits++; } @@ -620,8 +614,8 @@ vec4 debugVizForwardProbes(Surface surface, float contrib = contribution[i]; if (contrib > 0.0f) { - float cubemapIdx = probeConfigData[i].a; - vec3 dir = boxProject(surface.P, surface.R, worldToObjArray[i], refScaleArray[i].xyz, inRefPosArray[i].xyz); + float cubemapIdx = inProbeConfigData[i].a; + vec3 dir = boxProject(surface.P, surface.R, inWorldToObjArray[i], inRefScaleArray[i].xyz, inRefPosArray[i].xyz); irradiance += textureLod(irradianceCubemapAR, vec4(dir, cubemapIdx), 0).xyz * contrib; specular += textureLod(specularCubemapAR, vec4(dir, cubemapIdx), lod).xyz * contrib; diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting.hlsl index c91bd21a1..2a52e6eeb 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/lighting.hlsl +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting.hlsl @@ -24,6 +24,9 @@ #include "./brdf.hlsl" #include "./shaderModelAutoGen.hlsl" +//globals +uniform float3 eyePosWorld; +uniform float maxProbeDrawDistance; #ifndef TORQUE_SHADERGEN // These are the uniforms used by most lighting shaders. @@ -333,7 +336,7 @@ float defineSphereSpaceInfluence(float3 wsPosition, float3 wsProbePosition, floa { float3 L = wsProbePosition.xyz - wsPosition; float contribution = 1.0 - length(L) / radius; - return contribution; + return saturate(contribution); } float getDistBoxToPoint(float3 pt, float3 extents) @@ -345,10 +348,9 @@ float getDistBoxToPoint(float3 pt, float3 extents) float defineBoxSpaceInfluence(float3 wsPosition, float4x4 worldToObj, float attenuation) { float3 surfPosLS = mul(worldToObj, float4(wsPosition, 1.0)).xyz; - float atten = 1.0 - attenuation; float baseVal = 0.25; float dist = getDistBoxToPoint(surfPosLS, float3(baseVal, baseVal, baseVal)); - return saturate(smoothstep(baseVal + 0.0001, atten*baseVal, dist)); + return saturate(smoothstep(baseVal, (baseVal-attenuation/2), dist)); } // Box Projected IBL Lighting @@ -370,9 +372,9 @@ float3 boxProject(float3 wsPosition, float3 wsReflectVec, float4x4 worldToObj, f } float4 computeForwardProbes(Surface surface, - float cubeMips, int numProbes, float4x4 worldToObjArray[MAX_FORWARD_PROBES], float4 probeConfigData[MAX_FORWARD_PROBES], - float4 inProbePosArray[MAX_FORWARD_PROBES], float4 refScaleArray[MAX_FORWARD_PROBES], float4 inRefPosArray[MAX_FORWARD_PROBES], - float skylightCubemapIdx, TORQUE_SAMPLER2D(BRDFTexture), + float cubeMips, int numProbes, float4x4 inWorldToObjArray[MAX_FORWARD_PROBES], float4 inProbeConfigData[MAX_FORWARD_PROBES], + float4 inProbePosArray[MAX_FORWARD_PROBES], float4 inRefScaleArray[MAX_FORWARD_PROBES], float4 inRefPosArray[MAX_FORWARD_PROBES], + float3 wsEyePos, float skylightCubemapIdx, TORQUE_SAMPLER2D(BRDFTexture), TORQUE_SAMPLERCUBEARRAY(irradianceCubemapAR), TORQUE_SAMPLERCUBEARRAY(specularCubemapAR)) { int i = 0; @@ -384,50 +386,41 @@ float4 computeForwardProbes(Surface surface, float probehits = 0; //Set up our struct data float contribution[MAX_FORWARD_PROBES]; + //Process prooooobes for (i = 0; i < numProbes; ++i) { - contribution[i] = 0; - - if (probeConfigData[i].r == 0) //box + contribution[i] = 0.0; + float atten = 1.0-(length(wsEyePos-inProbePosArray[i].xyz)/maxProbeDrawDistance); + if (inProbeConfigData[i].r == 0) //box { - contribution[i] = defineBoxSpaceInfluence(surface.P, worldToObjArray[i], probeConfigData[i].b); - if (contribution[i] > 0.0) - probehits++; + contribution[i] = defineBoxSpaceInfluence(surface.P, inWorldToObjArray[i], inProbeConfigData[i].b)*atten; } - else if (probeConfigData[i].r == 1) //sphere + else if (inProbeConfigData[i].r == 1) //sphere { - contribution[i] = defineSphereSpaceInfluence(surface.P, inProbePosArray[i].xyz, probeConfigData[i].g); - if (contribution[i] > 0.0) - probehits++; + contribution[i] = defineSphereSpaceInfluence(surface.P, inProbePosArray[i].xyz, inProbeConfigData[i].g)*atten; } - contribution[i] = max(contribution[i], 0); + if (contribution[i]>0.0) + probehits++; + else + contribution[i] = 0.0; blendSum += contribution[i]; - invBlendSum += (1.0f - contribution[i]); } - if (probehits > 1.0) + if (probehits > 1.0)//if we overlap { + invBlendSum = (probehits - blendSum)/(probehits-1); //grab the remainder for (i = 0; i < numProbes; i++) { - blendFactor[i] = ((contribution[i] / blendSum)) / probehits; - blendFactor[i] *= ((contribution[i]) / invBlendSum); - blendFactor[i] = saturate(blendFactor[i]); - blendFacSum += blendFactor[i]; + blendFactor[i] = contribution[i]/blendSum; //what % total is this instance + blendFactor[i] *= blendFactor[i] / invBlendSum; //what should we add to sum to 1 + blendFacSum += blendFactor[i]; //running tally of results } - // Normalize blendVal - if (blendFacSum == 0.0f) // Possible with custom weight - { - blendFacSum = 1.0f; - } - - float invBlendSumWeighted = 1.0f / blendFacSum; for (i = 0; i < numProbes; ++i) { - blendFactor[i] *= invBlendSumWeighted; - contribution[i] *= blendFactor[i]; + contribution[i] *= blendFactor[i]/blendFacSum; //normalize } } @@ -474,8 +467,8 @@ float4 computeForwardProbes(Surface surface, float contrib = contribution[i]; if (contrib > 0.0f) { - int cubemapIdx = probeConfigData[i].a; - float3 dir = boxProject(surface.P, surface.R, worldToObjArray[i], refScaleArray[i].xyz, inRefPosArray[i].xyz); + int cubemapIdx = inProbeConfigData[i].a; + float3 dir = boxProject(surface.P, surface.R, inWorldToObjArray[i], inRefScaleArray[i].xyz, inRefPosArray[i].xyz); irradiance += TORQUE_TEXCUBEARRAYLOD(irradianceCubemapAR, dir, cubemapIdx, 0).xyz * contrib; specular += TORQUE_TEXCUBEARRAYLOD(specularCubemapAR, dir, cubemapIdx, lod).xyz * contrib; @@ -494,8 +487,8 @@ float4 computeForwardProbes(Surface surface, float3 kD = 1.0f - F; kD *= 1.0f - surface.metalness; - float dfgNdotV = max( surface.NdotV , 0.0009765625f ); //0.5f/512.0f (512 is size of dfg/brdf lookup tex) - float2 envBRDF = TORQUE_TEX2DLOD(BRDFTexture, float4(dfgNdotV, surface.roughness,0,0)).rg; + //float dfgNdotV = max( surface.NdotV , 0.0009765625f ); //0.5f/512.0f (512 is size of dfg/brdf lookup tex) + float2 envBRDF = TORQUE_TEX2DLOD(BRDFTexture, float4(surface.NdotV, surface.roughness,0,0)).rg; specular *= F * envBRDF.x + surface.f90 * envBRDF.y; irradiance *= kD * surface.baseColor.rgb; @@ -507,13 +500,16 @@ float4 computeForwardProbes(Surface surface, float horizonOcclusion = 1.3; float horizon = saturate( 1 + horizonOcclusion * dot(surface.R, surface.N)); horizon *= horizon; - +#if CAPTURING == 1 + return float4(lerp(surface.baseColor.rgb,(irradiance + specular) * horizon,surface.metalness/2),0); +#else return float4((irradiance + specular) * horizon, 0);//alpha writes disabled +#endif } float4 debugVizForwardProbes(Surface surface, - float cubeMips, int numProbes, float4x4 worldToObjArray[MAX_FORWARD_PROBES], float4 probeConfigData[MAX_FORWARD_PROBES], - float4 inProbePosArray[MAX_FORWARD_PROBES], float4 refScaleArray[MAX_FORWARD_PROBES], float4 inRefPosArray[MAX_FORWARD_PROBES], + float cubeMips, int numProbes, float4x4 inWorldToObjArray[MAX_FORWARD_PROBES], float4 inProbeConfigData[MAX_FORWARD_PROBES], + float4 inProbePosArray[MAX_FORWARD_PROBES], float4 inRefScaleArray[MAX_FORWARD_PROBES], float4 inRefPosArray[MAX_FORWARD_PROBES], float skylightCubemapIdx, TORQUE_SAMPLER2D(BRDFTexture), TORQUE_SAMPLERCUBEARRAY(irradianceCubemapAR), TORQUE_SAMPLERCUBEARRAY(specularCubemapAR), int showAtten, int showContrib, int showSpec, int showDiff) { @@ -530,15 +526,15 @@ float4 debugVizForwardProbes(Surface surface, { contribution[i] = 0; - if (probeConfigData[i].r == 0) //box + if (inProbeConfigData[i].r == 0) //box { - contribution[i] = defineBoxSpaceInfluence(surface.P, worldToObjArray[i], probeConfigData[i].b); + contribution[i] = defineBoxSpaceInfluence(surface.P, inWorldToObjArray[i], inProbeConfigData[i].b); if (contribution[i] > 0.0) probehits++; } - else if (probeConfigData[i].r == 1) //sphere + else if (inProbeConfigData[i].r == 1) //sphere { - contribution[i] = defineSphereSpaceInfluence(surface.P, inProbePosArray[i].xyz, probeConfigData[i].g); + contribution[i] = defineSphereSpaceInfluence(surface.P, inProbePosArray[i].xyz, inProbeConfigData[i].g); if (contribution[i] > 0.0) probehits++; } @@ -623,8 +619,8 @@ float4 debugVizForwardProbes(Surface surface, float contrib = contribution[i]; if (contrib > 0.0f) { - int cubemapIdx = probeConfigData[i].a; - float3 dir = boxProject(surface.P, surface.R, worldToObjArray[i], refScaleArray[i].xyz, inRefPosArray[i].xyz); + int cubemapIdx = inProbeConfigData[i].a; + float3 dir = boxProject(surface.P, surface.R, inWorldToObjArray[i], inRefScaleArray[i].xyz, inRefPosArray[i].xyz); irradiance += TORQUE_TEXCUBEARRAYLOD(irradianceCubemapAR, dir, cubemapIdx, 0).xyz * contrib; specular += TORQUE_TEXCUBEARRAYLOD(specularCubemapAR, dir, cubemapIdx, lod).xyz * contrib; diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/pointLightP.glsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/pointLightP.glsl index 429208a29..310a84a0a 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/pointLightP.glsl +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/pointLightP.glsl @@ -196,6 +196,38 @@ void main() lightCol *= max(cookie.r, max(cookie.g, cookie.b)); #endif + #ifdef DIFFUSE_LIGHT_VIZ + float attenuation = getDistanceAtt(surfaceToLight.Lu, radius); + vec3 factor = lightColor * max(surfaceToLight.NdotL, 0) * shadow * lightIntensity * attenuation; + + vec3 diffuse = BRDF_GetDebugDiffuse(surface,surfaceToLight) * factor; + vec3 final = max(0.0f, diffuse); + OUT_col = vec4(final, 0); + return + #endif + + #ifdef SPECULAR_LIGHT_VIZ + float attenuation = getDistanceAtt(surfaceToLight.Lu, radius); + vec3 factor = lightColor * max(surfaceToLight.NdotL, 0) * shadow * lightIntensity * attenuation; + + vec3 diffuse = BRDF_GetDebugSpecular(surface,surfaceToLight) * factor; + vec3 final = max(0.0f, diffuse); + OUT_col = vec4(final, 0); + return + #endif + + #ifdef DETAIL_LIGHTING_VIZ + float attenuation = getDistanceAtt(surfaceToLight.Lu, radius); + vec3 factor = lightColor * max(surfaceToLight.NdotL, 0) * shadow * lightIntensity * attenuation; + + vec3 diffuse = BRDF_GetDiffuse(surface,surfaceToLight) * factor; + vec3 spec = BRDF_GetSpecular(surface,surfaceToLight) * factor; + + vec3 final = max(vec3(0.0f), diffuse + spec * surface.F); + OUT_col = vec4(final, 0); + return + #endif + //get punctual light contribution lighting = getPunctualLight(surface, surfaceToLight, lightCol, lightBrightness, lightInvSqrRange, shadowed); } diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/reflectionProbeArrayP.glsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/reflectionProbeArrayP.glsl index 8efe15c05..e7fa0e2f8 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/reflectionProbeArrayP.glsl +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/reflectionProbeArrayP.glsl @@ -84,78 +84,57 @@ void main() { contribution[i] = 0; + float atten =1.0-(length(eyePosWorld-probePosArray[i].xyz)/maxProbeDrawDistance); if (probeConfigData[i].r == 0) //box { - contribution[i] = defineBoxSpaceInfluence(surface.P, worldToObjArray[i], probeConfigData[i].b); - if (contribution[i]>0.0) - probehits++; + contribution[i] = defineBoxSpaceInfluence(surface.P, worldToObjArray[i], probeConfigData[i].b)*atten; } else if (probeConfigData[i].r == 1) //sphere { - contribution[i] = defineSphereSpaceInfluence(surface.P, probePosArray[i].xyz, probeConfigData[i].g); + contribution[i] = defineSphereSpaceInfluence(surface.P, probePosArray[i].xyz, probeConfigData[i].g)*atten; + } + if (contribution[i]>0.0) probehits++; - } - - contribution[i] = max(contribution[i],0); + else + contribution[i] = 0; blendSum += contribution[i]; - invBlendSum += (1.0f - contribution[i]); } - // Weight0 = normalized NDF, inverted to have 1 at center, 0 at boundary. - // And as we invert, we need to divide by Num-1 to stay normalized (else sum is > 1). - // respect constraint B. - // Weight1 = normalized inverted NDF, so we have 1 at center, 0 at boundary - // and respect constraint A. - if (probehits > 1.0) + if (probehits > 1.0)//if we overlap { + invBlendSum = (probehits - blendSum)/(probehits-1); //grab the remainder for (i = 0; i < numProbes; i++) { - blendFactor[i] = ((contribution[i] / blendSum)) / probehits; - blendFactor[i] *= ((contribution[i]) / invBlendSum); - blendFactor[i] = saturate(blendFactor[i]); - blendFacSum += blendFactor[i]; + blendFactor[i] = contribution[i]/blendSum; //what % total is this instance + blendFactor[i] *= blendFactor[i] / invBlendSum; //what should we add to sum to 1 + blendFacSum += blendFactor[i]; //running tally of results } - // Normalize blendVal - if (blendFacSum == 0.0f) // Possible with custom weight - { - blendFacSum = 1.0f; - } - - float invBlendSumWeighted = 1.0f / blendFacSum; for (i = 0; i < numProbes; ++i) { - blendFactor[i] *= invBlendSumWeighted; - contribution[i] *= blendFactor[i]; + contribution[i] *= blendFactor[i]/blendFacSum; //normalize } } #if DEBUGVIZ_ATTENUATION == 1 - float contribAlpha = 1; + float contribAlpha = 0; for (i = 0; i < numProbes; ++i) { - contribAlpha -= contribution[i]; + contribAlpha += contribution[i]; } - OUT_col = vec4(1 - contribAlpha, 1 - contribAlpha, 1 - contribAlpha, 1); + OUT_col = vec4(contribAlpha,contribAlpha,contribAlpha, 1); return; #endif #if DEBUGVIZ_CONTRIB == 1 vec3 finalContribColor = vec3(0, 0, 0); - float contribAlpha = 1; for (i = 0; i < numProbes; ++i) { - finalContribColor += contribution[i] *probeContribColors[i].rgb; - contribAlpha -= contribution[i]; + finalContribColor += contribution[i] * vec3(fmod(i+1,2),fmod(i+1,3),fmod(i+1,4)); } - - //Skylight coloration for anything not covered by probes above - if(skylightCubemapIdx != -1) - finalContribColor += vec3(0, 1, 0) * contribAlpha; - OUT_col = vec4(finalContribColor, 1); return; #endif @@ -188,7 +167,7 @@ void main() } #endif - if (skylightCubemapIdx != -1 && alpha > 0.001) + if (skylightCubemapIdx != -1 && alpha >= 0.001) { irradiance = lerp(irradiance,textureLod(irradianceCubemapAR, vec4(surface.R, skylightCubemapIdx), 0).xyz,alpha); specular = lerp(specular,textureLod(specularCubemapAR, vec4(surface.R, skylightCubemapIdx), lod).xyz,alpha); @@ -220,6 +199,9 @@ void main() float horizonOcclusion = 1.3; float horizon = saturate( 1 + horizonOcclusion * dot(surface.R, surface.N)); horizon *= horizon; - - OUT_col = vec4(irradiance + specular, 0);//alpha writes disabled +#if CAPTURING == 1 + OUT_col = vec4(mix(surface.baseColor.rgb,(irradiance + specular) * horizon,surface.metalness/2),0); +#else + OUT_col = vec4((irradiance + specular) * horizon, 0);//alpha writes disabled +#endif } diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/spotLightP.glsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/spotLightP.glsl index d73aaf25a..6c80cc1eb 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/spotLightP.glsl +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/spotLightP.glsl @@ -122,6 +122,41 @@ void main() lightCol *= max(cookie.r, max(cookie.g, cookie.b)); #endif + #ifdef DIFFUSE_LIGHT_VIZ + float attenuation = getDistanceAtt(surfaceToLight.Lu, radius); + vec3 factor = lightColor * max(surfaceToLight.NdotL, 0) * shadow * lightIntensity * attenuation; + + vec3 diffuse = BRDF_GetDebugDiffuse(surface,surfaceToLight) * factor; + vec3 final = max(0.0f, diffuse) * getSpotAngleAtt(-surfaceToLight.L, lightDirection, lightSpotParams ); + + OUT_col = vec4(final, 0); + return; + #endif + + #ifdef SPECULAR_LIGHT_VIZ + float attenuation = getDistanceAtt(surfaceToLight.Lu, radius); + float3 factor = lightColor * max(surfaceToLight.NdotL, 0) * shadow * lightIntensity * attenuation; + + vec3 diffuse = BRDF_GetDebugSpecular(surface,surfaceToLight) * factor; + vec3 final = max(0.0f, diffuse) * getSpotAngleAtt(-surfaceToLight.L, lightDirection, lightSpotParams ); + + OUT_col = vec4(final, 0); + return; + #endif + + #ifdef DETAIL_LIGHTING_VIZ + float attenuation = getDistanceAtt(surfaceToLight.Lu, radius); + vec3 factor = lightColor * max(surfaceToLight.NdotL, 0) * shadow * lightIntensity * attenuation; + + vec3 diffuse = BRDF_GetDiffuse(surface,surfaceToLight) * factor; + vec3 spec = BRDF_GetSpecular(surface,surfaceToLight) * factor; + + vec3 final = max(vec3(0.0f), diffuse + spec * surface.F) * getSpotAngleAtt(-surfaceToLight.L, lightDirection, lightSpotParams ); + + OUT_col = vec4(final, 0); + return; + #endif + //get Punctual light contribution lighting = getPunctualLight(surface, surfaceToLight, lightCol, lightBrightness, lightInvSqrRange, shadowed); //get spot angle attenuation diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/vectorLightP.glsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/vectorLightP.glsl index 6ee55321c..0bfa6e0f0 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/vectorLightP.glsl +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/vectorLightP.glsl @@ -216,7 +216,7 @@ void main() lightingColor = shadowed_colors.rgb; #endif - shadow = lerp( shadow, 1.0, saturate( fadeOutAmt ) ); + shadow = mix( shadow, 1.0, saturate( fadeOutAmt ) ); #ifdef PSSM_DEBUG_RENDER if ( fadeOutAmt > 1.0 ) @@ -225,6 +225,37 @@ void main() #endif //NO_SHADOW + #ifdef DIFFUSE_LIGHT_VIZ + vec3 factor = lightingColor.rgb * max(surfaceToLight.NdotL, 0) * shadow * lightBrightness; + vec3 diffuse = BRDF_GetDebugDiffuse(surface,surfaceToLight) * factor; + + vec3 final = max(0.0f, diffuse); + + OUT_col = vec4(final, 0); + return; + #endif + + #ifdef SPECULAR_LIGHT_VIZ + vec3 factor = lightingColor.rgb * max(surfaceToLight.NdotL, 0) * shadow * lightBrightness; + vec3 spec = BRDF_GetDebugSpecular(surface, surfaceToLight) * factor; + + vec3 final = max(0.0f, factor); + + OUT_col = vec4(final, 0); + return; + #endif + + #ifdef DETAIL_LIGHTING_VIZ + vec3 factor = lightingColor.rgb * max(surfaceToLight.NdotL, 0) * shadow * lightBrightness; + vec3 diffuse = BRDF_GetDebugDiffuse(surface,surfaceToLight) * factor; + vec3 spec = BRDF_GetDebugSpecular(surface,surfaceToLight) * factor; + + vec3 final = max(0.0f, diffuse + spec); + + OUT_col = vec4(final, 0); + return; + #endif + //get directional light contribution vec3 lighting = getDirectionalLight(surface, surfaceToLight, lightingColor.rgb, lightBrightness, shadow); diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/pointLightP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/pointLightP.hlsl index faa7a01ae..05a29d66d 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/pointLightP.hlsl +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/pointLightP.hlsl @@ -134,7 +134,6 @@ uniform float shadowSoftness; uniform float4x4 worldToCamera; uniform float3x3 worldToLightProj; -uniform float3 eyePosWorld; uniform float4x4 cameraToWorld; float4 main( ConvexConnectP IN ) : SV_TARGET @@ -218,12 +217,12 @@ float4 main( ConvexConnectP IN ) : SV_TARGET #ifdef DETAIL_LIGHTING_VIZ float attenuation = getDistanceAtt(surfaceToLight.Lu, radius); - vec3 factor = lightColor * max(surfaceToLight.NdotL, 0) * shadow * lightIntensity * attenuation; + float3 factor = lightColor * max(surfaceToLight.NdotL, 0) * shadow * lightIntensity * attenuation; - vec3 diffuse = BRDF_GetDiffuse(surface,surfaceToLight) * factor; - vec3 spec = BRDF_GetSpecular(surface,surfaceToLight) * factor; + float3 diffuse = BRDF_GetDiffuse(surface,surfaceToLight) * factor; + float3 spec = BRDF_GetSpecular(surface,surfaceToLight) * factor; - vec3 final = max(vec3(0.0f), diffuse + spec * surface.F); + float3 final = max(float3(0.0f), diffuse + spec * surface.F); return final; #endif diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/reflectionProbeArrayP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/reflectionProbeArrayP.hlsl index cff06decf..83f435de8 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/reflectionProbeArrayP.hlsl +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/reflectionProbeArrayP.hlsl @@ -12,7 +12,6 @@ TORQUE_UNIFORM_SAMPLER2D(BRDFTexture, 3); uniform float4 rtParams0; uniform float4 vsFarPlane; uniform float4x4 cameraToWorld; -uniform float3 eyePosWorld; //cubemap arrays require all the same size. so shared mips# value uniform float cubeMips; @@ -76,79 +75,58 @@ float4 main(PFXVertToPix IN) : SV_TARGET //Process prooooobes for (i = 0; i < numProbes; ++i) { - contribution[i] = 0; + contribution[i] = 0.0; + float atten =1.0-(length(eyePosWorld-probePosArray[i].xyz)/maxProbeDrawDistance); if (probeConfigData[i].r == 0) //box { - contribution[i] = defineBoxSpaceInfluence(surface.P, worldToObjArray[i], probeConfigData[i].b); - if (contribution[i]>0.0) - probehits++; + contribution[i] = defineBoxSpaceInfluence(surface.P, worldToObjArray[i], probeConfigData[i].b)*atten; } else if (probeConfigData[i].r == 1) //sphere { - contribution[i] = defineSphereSpaceInfluence(surface.P, probePosArray[i].xyz, probeConfigData[i].g); + contribution[i] = defineSphereSpaceInfluence(surface.P, probePosArray[i].xyz, probeConfigData[i].g)*atten; + } + if (contribution[i]>0.0) probehits++; - } - - contribution[i] = max(contribution[i],0); + else + contribution[i] = 0.0; blendSum += contribution[i]; - invBlendSum += (1.0f - contribution[i]); } - // Weight0 = normalized NDF, inverted to have 1 at center, 0 at boundary. - // And as we invert, we need to divide by Num-1 to stay normalized (else sum is > 1). - // respect constraint B. - // Weight1 = normalized inverted NDF, so we have 1 at center, 0 at boundary - // and respect constraint A. - if (probehits > 1.0) + if (probehits > 1.0)//if we overlap { + invBlendSum = (probehits - blendSum)/(probehits-1); //grab the remainder for (i = 0; i < numProbes; i++) { - blendFactor[i] = ((contribution[i] / blendSum)) / probehits; - blendFactor[i] *= ((contribution[i]) / invBlendSum); - blendFactor[i] = saturate(blendFactor[i]); - blendFacSum += blendFactor[i]; + blendFactor[i] = contribution[i]/blendSum; //what % total is this instance + blendFactor[i] *= blendFactor[i] / invBlendSum; //what should we add to sum to 1 + blendFacSum += blendFactor[i]; //running tally of results } - // Normalize blendVal - if (blendFacSum == 0.0f) // Possible with custom weight - { - blendFacSum = 1.0f; - } - - float invBlendSumWeighted = 1.0f / blendFacSum; for (i = 0; i < numProbes; ++i) { - blendFactor[i] *= invBlendSumWeighted; - contribution[i] *= blendFactor[i]; + contribution[i] *= blendFactor[i]/blendFacSum; //normalize } } #if DEBUGVIZ_ATTENUATION == 1 - float contribAlpha = 1; + float contribAlpha = 0; for (i = 0; i < numProbes; ++i) { - contribAlpha -= contribution[i]; + contribAlpha += contribution[i]; } - return float4(1 - contribAlpha, 1 - contribAlpha, 1 - contribAlpha, 1); + return float4(contribAlpha,contribAlpha,contribAlpha, 1); #endif #if DEBUGVIZ_CONTRIB == 1 float3 finalContribColor = float3(0, 0, 0); - float contribAlpha = 1; for (i = 0; i < numProbes; ++i) { - finalContribColor += contribution[i] *probeContribColors[i].rgb; - contribAlpha -= contribution[i]; + finalContribColor += contribution[i] * float3(fmod(i+1,2),fmod(i+1,3),fmod(i+1,4)); } - - //Skylight coloration for anything not covered by probes above - if(skylightCubemapIdx != -1) - finalContribColor += float3(0, 1, 0) * contribAlpha; - return float4(finalContribColor, 1); #endif } @@ -209,6 +187,9 @@ float4 main(PFXVertToPix IN) : SV_TARGET float horizonOcclusion = 1.3; float horizon = saturate( 1 + horizonOcclusion * dot(surface.R, surface.N)); horizon *= horizon; - +#if CAPTURING == 1 + return float4(lerp(surface.baseColor.rgb,(irradiance + specular) * horizon,surface.metalness/2),0); +#else return float4((irradiance + specular) * horizon, 0);//alpha writes disabled +#endif } diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/spotLightP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/spotLightP.hlsl index 02e11570a..fb3d4aae0 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/spotLightP.hlsl +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/spotLightP.hlsl @@ -67,7 +67,6 @@ uniform float4x4 worldToLightProj; uniform float4 lightParams; uniform float shadowSoftness; -uniform float3 eyePosWorld; uniform float4x4 cameraToWorld; uniform float4x4 worldToCamera; @@ -147,12 +146,12 @@ float4 main( ConvexConnectP IN ) : SV_TARGET #ifdef DETAIL_LIGHTING_VIZ float attenuation = getDistanceAtt(surfaceToLight.Lu, radius); - vec3 factor = lightColor * max(surfaceToLight.NdotL, 0) * shadow * lightIntensity * attenuation; + float3 factor = lightColor * max(surfaceToLight.NdotL, 0) * shadow * lightIntensity * attenuation; - vec3 diffuse = BRDF_GetDiffuse(surface,surfaceToLight) * factor; - vec3 spec = BRDF_GetSpecular(surface,surfaceToLight) * factor; + float3 diffuse = BRDF_GetDiffuse(surface,surfaceToLight) * factor; + float3 spec = BRDF_GetSpecular(surface,surfaceToLight) * factor; - vec3 final = max(vec3(0.0f), diffuse + spec * surface.F) * getSpotAngleAtt(-surfaceToLight.L, lightDirection, lightSpotParams ); + vec3 final = max(float3(0.0f), diffuse + spec * surface.F) * getSpotAngleAtt(-surfaceToLight.L, lightDirection, lightSpotParams ); return final; #endif diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/vectorLightP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/vectorLightP.hlsl index e3b9206d4..d99544dca 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/vectorLightP.hlsl +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/vectorLightP.hlsl @@ -42,7 +42,6 @@ uniform float4 lightColor; uniform float4 lightAmbient; uniform float shadowSoftness; -uniform float3 eyePosWorld; uniform float4 atlasXOffset; uniform float4 atlasYOffset;