From 399088d09efe3ae8435da0084d55ca1a8b69c1f6 Mon Sep 17 00:00:00 2001 From: Areloch Date: Sun, 24 Mar 2019 18:18:44 -0500 Subject: [PATCH 1/2] WIP of timmy's changes merged in. Not properly initializing the probes/array slots just yet. --- .../source/T3D/lighting/reflectionProbe.cpp | 9 +- Engine/source/gfx/D3D11/gfxD3D11Cubemap.cpp | 113 +++++++- Engine/source/gfx/D3D11/gfxD3D11Cubemap.h | 7 +- Engine/source/gfx/Null/gfxNullDevice.cpp | 6 +- Engine/source/gfx/bitmap/imageUtils.cpp | 5 + Engine/source/gfx/bitmap/imageUtils.h | 5 + Engine/source/gfx/gfxCubemap.h | 25 +- .../source/renderInstance/renderProbeMgr.cpp | 170 ++++++++++-- Engine/source/renderInstance/renderProbeMgr.h | 48 +++- .../advanced/reflectionProbeArrayP.hlsl | 256 ++++++++++-------- 10 files changed, 485 insertions(+), 159 deletions(-) diff --git a/Engine/source/T3D/lighting/reflectionProbe.cpp b/Engine/source/T3D/lighting/reflectionProbe.cpp index 031381ee4..c4e79e34a 100644 --- a/Engine/source/T3D/lighting/reflectionProbe.cpp +++ b/Engine/source/T3D/lighting/reflectionProbe.cpp @@ -631,7 +631,7 @@ void ReflectionProbe::processStaticCubemap() IBLUtilities::SaveCubeMap(getPrefilterMapPath(), mPrefilterMap->mCubemap); } - mProbeInfo->mCubemap = mPrefilterMap->mCubemap; + mProbeInfo->mPrefilterCubemap = mPrefilterMap->mCubemap; mProbeInfo->mIrradianceCubemap = mIrridianceMap->mCubemap; } @@ -647,7 +647,7 @@ void ReflectionProbe::updateMaterial() { if (mPrefilterMap != nullptr && mPrefilterMap->mCubemap.isValid()) { - mProbeInfo->mCubemap = mPrefilterMap->mCubemap; + mProbeInfo->mPrefilterCubemap = mPrefilterMap->mCubemap; } else { @@ -667,7 +667,7 @@ void ReflectionProbe::updateMaterial() { if (mReflectionModeType == DynamicCubemap && !mDynamicCubemap.isNull()) { - mProbeInfo->mCubemap = mDynamicCubemap; + mProbeInfo->mPrefilterCubemap = mDynamicCubemap; mProbeInfo->mCubeReflector.registerReflector(this, reflectorDesc); //need to decide how we wanna do the reflectorDesc. static name or a field } @@ -684,6 +684,9 @@ void ReflectionProbe::updateMaterial() mProbeInfo->mIsEnabled = false; PROBEMGR->updateProbes(); + + if (mProbeInfo->mPrefilterCubemap->isInitialized() && mProbeInfo->mIrradianceCubemap->isInitialized()) + PROBEMGR->updateProbeTexture(mProbeInfo); } bool ReflectionProbe::createClientResources() diff --git a/Engine/source/gfx/D3D11/gfxD3D11Cubemap.cpp b/Engine/source/gfx/D3D11/gfxD3D11Cubemap.cpp index 565fa8173..cd5f528e5 100644 --- a/Engine/source/gfx/D3D11/gfxD3D11Cubemap.cpp +++ b/Engine/source/gfx/D3D11/gfxD3D11Cubemap.cpp @@ -141,7 +141,7 @@ void GFXD3D11Cubemap::initStatic(GFXTexHandle *faces) mSRView->GetDesc(&viewDesc); mMipMapLevels = viewDesc.TextureCube.MipLevels; } - mInitialized = true; + } void GFXD3D11Cubemap::initStatic(DDSFile *dds) @@ -208,7 +208,6 @@ void GFXD3D11Cubemap::initStatic(DDSFile *dds) { AssertFatal(false, "GFXD3D11Cubemap::initStatic(DDSFile *dds) - CreateTexture2D call failure"); } - mInitialized = true; } void GFXD3D11Cubemap::initDynamic(U32 texSize, GFXFormat faceFormat, U32 mipLevels) @@ -331,7 +330,7 @@ void GFXD3D11Cubemap::initDynamic(U32 texSize, GFXFormat faceFormat, U32 mipLeve } SAFE_RELEASE(depthTex); - mInitialized = true; + } //----------------------------------------------------------------------------- @@ -392,10 +391,11 @@ GFXD3D11CubemapArray::~GFXD3D11CubemapArray() SAFE_RELEASE(mTexture); } -void GFXD3D11CubemapArray::initStatic(GFXCubemapHandle *cubemaps, const U32 cubemapCount) +//TODO: really need a common private 'init' function to avoid code double up with these init* functions +void GFXD3D11CubemapArray::init(GFXCubemapHandle *cubemaps, const U32 cubemapCount) { - AssertFatal(cubemaps, "GFXD3D11CubemapArray - Got null GFXCubemapHandle!"); - AssertFatal(*cubemaps, "GFXD3D11CubemapArray - Got empty cubemap!"); + AssertFatal(cubemaps, "GFXD3D11CubemapArray::initStatic - Got null GFXCubemapHandle!"); + AssertFatal(*cubemaps, "GFXD3D11CubemapArray::initStatic - Got empty cubemap!"); //all cubemaps must be the same size,format and number of mipmaps. Grab the details from the first cubemap mSize = cubemaps[0]->getSize(); @@ -424,7 +424,7 @@ void GFXD3D11CubemapArray::initStatic(GFXCubemapHandle *cubemaps, const U32 cube HRESULT hr = D3D11DEVICE->CreateTexture2D(&desc, NULL, &mTexture); if (FAILED(hr)) - AssertFatal(false, "GFXD3D11CubemapArray:initStatic(GFXCubemap *cubemaps,const U32 cubemapCount) - CreateTexture2D failure"); + AssertFatal(false, "GFXD3D11CubemapArray::initStatic - CreateTexture2D failure"); for (U32 i = 0; i < cubemapCount; i++) { @@ -434,7 +434,7 @@ void GFXD3D11CubemapArray::initStatic(GFXCubemapHandle *cubemaps, const U32 cube { Con::printf("Trying to add an invalid Cubemap to a CubemapArray"); //destroy array here first - AssertFatal(false, "GFXD3D11CubemapArray:initStatic(GFXCubemap *cubemaps,const U32 cubemapCount) - invalid cubemap"); + AssertFatal(false, "GFXD3D11CubemapArray::initStatic - invalid cubemap"); } for (U32 face = 0; face < CubeFaces; face++) @@ -460,7 +460,102 @@ void GFXD3D11CubemapArray::initStatic(GFXCubemapHandle *cubemaps, const U32 cube hr = D3D11DEVICE->CreateShaderResourceView(mTexture, &SMViewDesc, &mSRView); if (FAILED(hr)) - AssertFatal(false, "GFXD3D11CubemapArray:initStatic(GFXCubemap *cubemaps,const U32 cubemapCount) - shader resource view creation failure"); + AssertFatal(false, "GFXD3D11CubemapArray::initStatic - shader resource view creation failure"); + +} + +//Just allocate the cubemap array but we don't upload any data +void GFXD3D11CubemapArray::init(const U32 cubemapCount, const U32 cubemapFaceSize, const GFXFormat format) +{ + mSize = cubemapFaceSize; + mMipMapLevels = ImageUtil::getMaxMipCount(cubemapFaceSize, cubemapFaceSize); + mNumCubemaps = cubemapCount; + mFormat = format; + + //create texture object + UINT bindFlags = D3D11_BIND_SHADER_RESOURCE; + UINT miscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE; + + D3D11_TEXTURE2D_DESC desc; + ZeroMemory(&desc, sizeof(D3D11_TEXTURE2D_DESC)); + desc.Width = mSize; + desc.Height = mSize; + desc.MipLevels = mMipMapLevels; + desc.ArraySize = CubeFaces * cubemapCount; + desc.Format = GFXD3D11TextureFormat[mFormat]; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = bindFlags; + desc.MiscFlags = miscFlags; + desc.CPUAccessFlags = 0; + + HRESULT hr = D3D11DEVICE->CreateTexture2D(&desc, NULL, &mTexture); + + if (FAILED(hr)) + AssertFatal(false, "GFXD3D11CubemapArray::initStatic - CreateTexture2D failure"); + + //create shader resource view + D3D11_SHADER_RESOURCE_VIEW_DESC SMViewDesc; + SMViewDesc.Format = GFXD3D11TextureFormat[mFormat]; + SMViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBEARRAY; + SMViewDesc.TextureCubeArray.MipLevels = mMipMapLevels; + SMViewDesc.TextureCubeArray.MostDetailedMip = 0; + SMViewDesc.TextureCubeArray.NumCubes = mNumCubemaps; + SMViewDesc.TextureCubeArray.First2DArrayFace = 0; + + hr = D3D11DEVICE->CreateShaderResourceView(mTexture, &SMViewDesc, &mSRView); + if (FAILED(hr)) + AssertFatal(false, "GFXD3D11CubemapArray::initStatic - shader resource view creation failure"); + +} + +void GFXD3D11CubemapArray::updateTexture(const GFXCubemapHandle &cubemap, const U32 slot) +{ + AssertFatal(slot <= mNumCubemaps, "GFXD3D11CubemapArray::updateTexture - trying to update a cubemap texture that is out of bounds!"); + + GFXD3D11Cubemap *pCubeObj = static_cast((GFXCubemap*)cubemap); + ID3D11Resource *pDstRes = pCubeObj->get2DTex(); + for (U32 face = 0; face < CubeFaces; face++) + { + const U32 arraySlice = face + CubeFaces * slot; + for (U32 currentMip = 0; currentMip < mMipMapLevels; currentMip++) + { + const U32 srcSubResource = D3D11CalcSubresource(currentMip, face, mMipMapLevels); + const U32 dstSubResource = D3D11CalcSubresource(currentMip, arraySlice, mMipMapLevels); + D3D11DEVICECONTEXT->CopySubresourceRegion(mTexture, dstSubResource, 0, 0, 0, pDstRes, srcSubResource, NULL); + } + } +} + +void GFXD3D11CubemapArray::copyTo(GFXCubemapArray *pDstCubemap) +{ + AssertFatal(pDstCubemap, "GFXD3D11CubemapArray::copyTo - Got null GFXCubemapArray"); + + const U32 dstCount = pDstCubemap->getNumCubemaps(); + const GFXFormat dstFmt = pDstCubemap->getFormat(); + const U32 dstSize = pDstCubemap->getSize(); + const U32 dstMips = pDstCubemap->getMipMapLevels(); + + AssertFatal(dstCount > mNumCubemaps, "GFXD3D11CubemapArray::copyTo - Destination too small"); + AssertFatal(dstFmt == mFormat, "GFXD3D11CubemapArray::copyTo - Destination format doesn't match"); + AssertFatal(dstSize == mSize, "GFXD3D11CubemapArray::copyTo - Destination size doesn't match"); + AssertFatal(dstMips == mMipMapLevels, "GFXD3D11CubemapArray::copyTo - Destination mip levels doesn't match"); + + GFXD3D11CubemapArray *pDstCube = static_cast(pDstCubemap); + ID3D11Resource *pDstRes = pDstCube->get2DTex(); + for (U32 cubeMap = 0; cubeMap < mNumCubemaps; cubeMap++) + { + for (U32 face = 0; face < CubeFaces; face++) + { + const U32 arraySlice = face + CubeFaces * cubeMap; + for (U32 currentMip = 0; currentMip < mMipMapLevels; currentMip++) + { + const U32 subResource = D3D11CalcSubresource(currentMip, arraySlice, mMipMapLevels); + D3D11DEVICECONTEXT->CopySubresourceRegion(pDstRes, subResource, 0, 0, 0, mTexture, subResource, NULL); + } + } + } } diff --git a/Engine/source/gfx/D3D11/gfxD3D11Cubemap.h b/Engine/source/gfx/D3D11/gfxD3D11Cubemap.h index 6f2524622..02cc91627 100644 --- a/Engine/source/gfx/D3D11/gfxD3D11Cubemap.h +++ b/Engine/source/gfx/D3D11/gfxD3D11Cubemap.h @@ -48,6 +48,8 @@ public: virtual void zombify(); virtual void resurrect(); + virtual bool isInitialized() { return mTexture ? true : false; } + // Get functions ID3D11ShaderResourceView* getSRView(); ID3D11RenderTargetView* getRTView(U32 faceIdx, U32 mipIndex=0); @@ -81,7 +83,10 @@ class GFXD3D11CubemapArray : public GFXCubemapArray public: GFXD3D11CubemapArray(); virtual ~GFXD3D11CubemapArray(); - virtual void initStatic(GFXCubemapHandle *cubemaps, const U32 cubemapCount); + virtual void init(GFXCubemapHandle *cubemaps, const U32 cubemapCount); + virtual void init(const U32 cubemapCount, const U32 cubemapFaceSize, const GFXFormat format); + virtual void updateTexture(const GFXCubemapHandle &cubemap, const U32 slot); + virtual void copyTo(GFXCubemapArray *pDstCubemap); virtual void setToTexUnit(U32 tuNum); ID3D11ShaderResourceView* getSRView() { return mSRView; } diff --git a/Engine/source/gfx/Null/gfxNullDevice.cpp b/Engine/source/gfx/Null/gfxNullDevice.cpp index fbf854d2b..83933733c 100644 --- a/Engine/source/gfx/Null/gfxNullDevice.cpp +++ b/Engine/source/gfx/Null/gfxNullDevice.cpp @@ -169,8 +169,10 @@ private: virtual void setToTexUnit(U32 tuNum) { }; public: - virtual void initStatic(GFXCubemapHandle *cubemaps, const U32 cubemapCount) { }; - + virtual void init(GFXCubemapHandle *cubemaps, const U32 cubemapCount) { }; + virtual void init(const U32 cubemapCount, const U32 cubemapFaceSize, const GFXFormat format) { }; + virtual void updateTexture(const GFXCubemapHandle &cubemap, const U32 slot) { }; + virtual void copyTo(GFXCubemapArray *pDstCubemap) { } virtual ~GFXNullCubemapArray() {}; virtual void zombify() {} virtual void resurrect() {} diff --git a/Engine/source/gfx/bitmap/imageUtils.cpp b/Engine/source/gfx/bitmap/imageUtils.cpp index 0d550f704..2d9e7ab8d 100644 --- a/Engine/source/gfx/bitmap/imageUtils.cpp +++ b/Engine/source/gfx/bitmap/imageUtils.cpp @@ -301,4 +301,9 @@ namespace ImageUtil return format; }; } + + U32 getMaxMipCount(const U32 width, const U32 height) + { + return mFloor(mLog2(mMax(width, height))) + 1; + } } \ No newline at end of file diff --git a/Engine/source/gfx/bitmap/imageUtils.h b/Engine/source/gfx/bitmap/imageUtils.h index 2cbb278e6..62784aa85 100644 --- a/Engine/source/gfx/bitmap/imageUtils.h +++ b/Engine/source/gfx/bitmap/imageUtils.h @@ -29,6 +29,9 @@ #ifndef _GFXENUMS_H_ #include "gfx/gfxEnums.h" #endif +#ifndef _MMATHFN_H_ +#include "math/mMathFn.h" +#endif struct DDSFile; @@ -57,6 +60,8 @@ namespace ImageUtil //convert to sRGB format GFXFormat toSRGBFormat(const GFXFormat format); + + U32 getMaxMipCount(const U32 width, const U32 height); }; #endif \ No newline at end of file diff --git a/Engine/source/gfx/gfxCubemap.h b/Engine/source/gfx/gfxCubemap.h index f8ad9e31d..798251d12 100644 --- a/Engine/source/gfx/gfxCubemap.h +++ b/Engine/source/gfx/gfxCubemap.h @@ -49,6 +49,7 @@ protected: U32 mMipMapLevels; + bool mInitialized; public: @@ -62,6 +63,7 @@ public: virtual void initDynamic( U32 texSize, GFXFormat faceFormat = GFXFormatR8G8B8A8, U32 mipLevels = 0 ) = 0; void initNormalize(U32 size); + GFXCubemap(); virtual ~GFXCubemap(); @@ -71,6 +73,9 @@ public: /// Returns the face texture format. virtual GFXFormat getFormat() const = 0; + /// Returns if this cubemap has been initialized + virtual bool isInitialized() { return false; } + /// Returns the cubemap file path set at creation. const String& getPath() const { return mPath; } @@ -83,7 +88,6 @@ public: /// Get Z up face index of the cubemap. DDS files will be stored Y up static U32 zUpFaceIndex(const U32 index); - bool isInitialised() { return mInitialized; } }; @@ -102,32 +106,43 @@ public: void free() { StrongObjectRef::set( NULL ); } }; -/// Cubemap array +/// Cubemap array - data lives on the GPU only with this class, but the data is not immutable so it can be updated class GFXCubemapArray : public StrongRefBase, public GFXResource { friend class GFXDevice; friend class GFXTextureManager; protected: - // should only be called by GFXDevice + /// should only be called by GFXDevice virtual void setToTexUnit( U32 tuNum ) = 0; /// number of cubemaps in the array U32 mNumCubemaps; + /// cubemap face size U32 mSize; + /// number of mip levels U32 mMipMapLevels; + /// format GFXFormat mFormat; public: virtual ~GFXCubemapArray() {}; - - virtual void initStatic(GFXCubemapHandle *cubemaps, const U32 cubemapCount) = 0; + /// Initialize from an array of cubemaps + virtual void init(GFXCubemapHandle *cubemaps, const U32 cubemapCount) = 0; + /// Initialize cubemapCount number of blank cubemaps in the array + virtual void init(const U32 cubemapCount, const U32 cubemapFaceSize, const GFXFormat format) = 0; + /// Update cubemap in the array + virtual void updateTexture(const GFXCubemapHandle &cubemap, const U32 slot) = 0; + /// Copy this cubemap to another - destination must be same format, same face size & at-least the same size(or larger) + virtual void copyTo(GFXCubemapArray *pDstCubemap) = 0; /// Return number of textures in the array const U32 getNumCubemaps() const { return mNumCubemaps; } /// Get the number of mip maps const U32 getMipMapLevels() const { return mMipMapLevels; } /// Returns the size of the faces. const U32 getSize() const { return mSize; } + /// Returns the format + const GFXFormat getFormat() const { return mFormat; } virtual const String describeSelf() const; }; diff --git a/Engine/source/renderInstance/renderProbeMgr.cpp b/Engine/source/renderInstance/renderProbeMgr.cpp index 12e15b08d..4266255b3 100644 --- a/Engine/source/renderInstance/renderProbeMgr.cpp +++ b/Engine/source/renderInstance/renderProbeMgr.cpp @@ -78,20 +78,21 @@ ProbeRenderInst::ProbeRenderInst() : SystemInterface(), mDirty(false), mPriority(1.0f), mScore(0.0f), - mCubemap(NULL), + mPrefilterCubemap(NULL), mIrradianceCubemap(NULL), mRadius(1.0f), mProbeRefOffset(0, 0, 0), mProbeRefScale(1,1,1), - mAtten(0.0) + mAtten(0.0), + mCubemapIndex(0) { } ProbeRenderInst::~ProbeRenderInst() { - if (mCubemap && mCubemap.isValid()) + if (mPrefilterCubemap && mPrefilterCubemap.isValid()) { - mCubemap.free(); + mPrefilterCubemap.free(); } if (mIrradianceCubemap && mIrradianceCubemap.isValid()) { @@ -102,7 +103,7 @@ ProbeRenderInst::~ProbeRenderInst() void ProbeRenderInst::set(const ProbeRenderInst *probeInfo) { mTransform = probeInfo->mTransform; - mCubemap = probeInfo->mCubemap; + mPrefilterCubemap = probeInfo->mPrefilterCubemap; mIrradianceCubemap = probeInfo->mIrradianceCubemap; mRadius = probeInfo->mRadius; mProbeShapeType = probeInfo->mProbeShapeType; @@ -183,6 +184,13 @@ RenderProbeMgr::RenderProbeMgr() mProbeArrayEffect = nullptr; smProbeManager = this; + + mCubeMapCount = 0; + + for (U32 i = 0; i < PROBE_MAX_COUNT; i++) + { + mCubeMapSlots[i] = false; + } } RenderProbeMgr::RenderProbeMgr(RenderInstType riType, F32 renderOrder, F32 processAddOrder) @@ -203,6 +211,37 @@ RenderProbeMgr::~RenderProbeMgr() mConstantLookup.clear(); } +bool RenderProbeMgr::onAdd() +{ + if (!Parent::onAdd()) + return false; + + mIrradianceArray = GFXCubemapArrayHandle(GFX->createCubemapArray()); + 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); + mCubeSlotCount = PROBE_ARRAY_SLOT_BUFFER_SIZE; + + //create our own default default skylight + mDefaultSkyLight = new ProbeRenderInst; + mDefaultSkyLight->mProbeShapeType = ProbeRenderInst::Skylight; + if (!mDefaultSkyLight->mIrradianceCubemap.set("core/art/pbr/default_irradiance.dds")) + { + Con::errorf("RenderProbeMgr::onAdd: Failed to load default irradiance cubemap"); + return false; + } + + if (!mDefaultSkyLight->mPrefilterCubemap.set("core/art/pbr/default_prefilter.dds")) + { + Con::errorf("RenderProbeMgr::onAdd: Failed to load default prefilter cubemap"); + return false; + } + + return true; +} + void RenderProbeMgr::onRemove() { Parent::onRemove(); @@ -246,6 +285,38 @@ void RenderProbeMgr::registerProbe(U32 probeIdx) mRegisteredProbes.push_back_unique(probeIdx); + const U32 cubeIndex = _findNextEmptyCubeSlot(); + if (cubeIndex == INVALID_CUBE_SLOT) + { + Con::warnf("RenderProbeMgr::addProbe: Invalid cubemap slot."); + return; + } + + //check if we need to resize the cubemap array + if (cubeIndex >= mCubeSlotCount) + { + //alloc temp array handles + 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); + + mIrradianceArray->copyTo(irr); + mPrefilterArray->copyTo(prefilter); + + //assign the temp handles to the new ones, this will destroy the old ones as well + mIrradianceArray = irr; + mPrefilterArray = prefilter; + + mCubeSlotCount += PROBE_ARRAY_SLOT_BUFFER_SIZE; + } + + ProbeRenderInst::all[probeIdx]->mCubemapIndex = cubeIndex; + //mark cubemap slot as taken + mCubeMapSlots[cubeIndex] = true; + mCubeMapCount++; + //rebuild our probe data _setupStaticParameters(); } @@ -258,6 +329,13 @@ void RenderProbeMgr::unregisterProbe(U32 probeIdx) mRegisteredProbes.remove(probeIdx); + if (ProbeRenderInst::all[probeIdx]->mCubemapIndex == INVALID_CUBE_SLOT) + return; + + //mark cubemap slot as available now + mCubeMapSlots[ProbeRenderInst::all[probeIdx]->mCubemapIndex] = false; + mCubeMapCount--; + //rebuild our probe data _setupStaticParameters(); } @@ -314,6 +392,16 @@ void RenderProbeMgr::_setupStaticParameters() cubeMaps.clear(); irradMaps.clear(); + if (probeCount != 0 && ProbeRenderInst::all[0]->mPrefilterCubemap != nullptr) + { + //Get our mipCount + mMipCount = ProbeRenderInst::all[0]->mPrefilterCubemap.getPointer()->getMipMapLevels(); + } + else + { + mMipCount = 1; + } + for (U32 i = 0; i < probeCount; i++) { if (mEffectiveProbeCount >= MAXPROBECOUNT) @@ -323,19 +411,23 @@ void RenderProbeMgr::_setupStaticParameters() if (!curEntry.mIsEnabled) continue; - if (curEntry.mCubemap.isNull() || curEntry.mIrradianceCubemap.isNull()) + if (curEntry.mIsSkylight) + { + skylightPos = curEntry.getPosition(); + skylightPrefilterMap = curEntry.mPrefilterCubemap; + skylightIrradMap = curEntry.mIrradianceCubemap; + hasSkylight = true; continue; + } - if (!curEntry.mCubemap->isInitialised()) - continue; - - if (!curEntry.mIrradianceCubemap->isInitialised()) - continue; - - //if (curEntry.mIsSkylight) + //if (curEntry.mCubemap.isNull() || curEntry.mIrradianceCubemap.isNull()) // continue; - mMipCount = curEntry.mCubemap.getPointer()->getMipMapLevels(); + //if (!curEntry.mCubemap->isInitialized()) + // continue; + + //if (!curEntry.mIrradianceCubemap->isInitialized()) + // continue; //Setup Point3F probePos = curEntry.getPosition(); @@ -354,22 +446,40 @@ void RenderProbeMgr::_setupStaticParameters() curEntry.mAtten, 1); - cubeMaps.push_back(curEntry.mCubemap); - irradMaps.push_back(curEntry.mIrradianceCubemap); + //cubeMaps.push_back(curEntry.mCubemap); + //irradMaps.push_back(curEntry.mIrradianceCubemap); mEffectiveProbeCount++; } if (mEffectiveProbeCount != 0) { - mCubemapArray = GFXCubemapArrayHandle(GFX->createCubemapArray()); - mIrradArray = GFXCubemapArrayHandle(GFX->createCubemapArray()); + //mPrefilterArray = GFXCubemapArrayHandle(GFX->createCubemapArray()); + //mIrradianceArray = GFXCubemapArrayHandle(GFX->createCubemapArray()); - mCubemapArray->initStatic(cubeMaps.address(), cubeMaps.size()); - mIrradArray->initStatic(irradMaps.address(), irradMaps.size()); + //mPrefilterArray->initStatic(cubeMaps.address(), cubeMaps.size()); + //mIrradianceArray->initStatic(irradMaps.address(), irradMaps.size()); } } +void RenderProbeMgr::updateProbeTexture(ProbeRenderInst* probe) +{ + S32 probeIdx = ProbeRenderInst::all.find_next(probe); + + if (probeIdx != -1) //i mean, the opposite shouldn't even be possible + updateProbeTexture(probeIdx); +} + +void RenderProbeMgr::updateProbeTexture(U32 probeIdx) +{ + if (probeIdx >= ProbeRenderInst::all.size()) + return; + + const U32 cubeIndex = ProbeRenderInst::all[probeIdx]->mCubemapIndex; + mIrradianceArray->updateTexture(ProbeRenderInst::all[probeIdx]->mIrradianceCubemap, cubeIndex); + mPrefilterArray->updateTexture(ProbeRenderInst::all[probeIdx]->mPrefilterCubemap, cubeIndex); +} + void RenderProbeMgr::_setupPerFrameParameters(const SceneRenderState *state) { PROFILE_SCOPE(RenderProbeMgr_SetupPerFrameParameters); @@ -607,11 +717,11 @@ void RenderProbeMgr::render( SceneRenderState *state ) //updateProbes(); // Early out if nothing to draw. - if (!ProbeRenderInst::all.size() || !RenderProbeMgr::smRenderReflectionProbes || mEffectiveProbeCount == 0 - || !state->isDiffusePass() || cubeMaps.empty() || irradMaps.empty()) + if (!ProbeRenderInst::all.size() || !RenderProbeMgr::smRenderReflectionProbes || !state->isDiffusePass() || (mEffectiveProbeCount == 0 + || mCubeMapCount != 0 && !hasSkylight)) { - getProbeArrayEffect()->setSkip(true); - return; + getProbeArrayEffect()->setSkip(true); + return; } GFXTransformSaver saver; @@ -625,10 +735,18 @@ void RenderProbeMgr::render( SceneRenderState *state ) //Array rendering //U32 probeCount = ProbeRenderInst::all.size(); + mProbeArrayEffect->setShaderConst("$hasSkylight", (float)hasSkylight); + if (hasSkylight) + { + mProbeArrayEffect->setCubemapTexture(6, skylightPrefilterMap); + mProbeArrayEffect->setCubemapTexture(7, skylightIrradMap); + + } + if (mEffectiveProbeCount != 0) { - mProbeArrayEffect->setCubemapArrayTexture(4, mCubemapArray); - mProbeArrayEffect->setCubemapArrayTexture(5, mIrradArray); + mProbeArrayEffect->setCubemapArrayTexture(4, mPrefilterArray); + mProbeArrayEffect->setCubemapArrayTexture(5, mIrradianceArray); String useDebugAtten = Con::getVariable("$Probes::showAttenuation", "0"); mProbeArrayEffect->setShaderMacro("DEBUGVIZ_ATTENUATION", useDebugAtten); diff --git a/Engine/source/renderInstance/renderProbeMgr.h b/Engine/source/renderInstance/renderProbeMgr.h index a482f37be..2d796d4e4 100644 --- a/Engine/source/renderInstance/renderProbeMgr.h +++ b/Engine/source/renderInstance/renderProbeMgr.h @@ -72,7 +72,7 @@ struct ProbeRenderInst : public SystemInterface Point3F mProbeRefScale; F32 mAtten; - GFXCubemapHandle mCubemap; + GFXCubemapHandle mPrefilterCubemap; GFXCubemapHandle mIrradianceCubemap; //Utilized in dynamic reflections @@ -97,6 +97,8 @@ struct ProbeRenderInst : public SystemInterface ProbeShapeType mProbeShapeType; + U32 mCubemapIndex; + public: ProbeRenderInst(); @@ -161,6 +163,18 @@ class RenderProbeMgr : public RenderBinManager Vector mRegisteredProbes; + //maximum number of allowed probes + static const U32 PROBE_MAX_COUNT = 250; + //maximum number of rendered probes per frame adjust as needed + static const U32 PROBE_MAX_FRAME = 8; + //number of slots to allocate at once in the cubemap array + static const U32 PROBE_ARRAY_SLOT_BUFFER_SIZE = 10; + + static const U32 PROBE_IRRAD_SIZE = 32; + static const U32 PROBE_PREFILTER_SIZE = 128; + static const GFXFormat PROBE_FORMAT = GFXFormatR8G8B8A8;// when hdr fixed GFXFormatR16G16B16A16F; look into bc6h compression + static const U32 INVALID_CUBE_SLOT = U32_MAX; + //Array rendering U32 mEffectiveProbeCount; S32 mMipCount; @@ -173,6 +187,11 @@ class RenderProbeMgr : public RenderBinManager Vector cubeMaps; Vector irradMaps; + bool hasSkylight; + GFXCubemapHandle skylightIrradMap; + GFXCubemapHandle skylightPrefilterMap; + Point4F skylightPos; + AlignedArray mProbePositions; AlignedArray mProbeBBMin; AlignedArray mProbeBBMax; @@ -180,8 +199,15 @@ class RenderProbeMgr : public RenderBinManager AlignedArray mProbeRadius; AlignedArray mProbeAttenuation; - GFXCubemapArrayHandle mCubemapArray; - GFXCubemapArrayHandle mIrradArray; + //number of cubemaps + U32 mCubeMapCount; + //number of cubemap slots allocated + U32 mCubeSlotCount; + //array of cubemap slots, due to the editor these may be mixed around as probes are added and deleted + bool mCubeMapSlots[PROBE_MAX_COUNT]; + + GFXCubemapArrayHandle mPrefilterArray; + GFXCubemapArrayHandle mIrradianceArray; //Utilized in forward rendering ProbeConstantMap mConstantLookup; @@ -191,10 +217,14 @@ class RenderProbeMgr : public RenderBinManager // SimObjectPtr mProbeArrayEffect; + //Default skylight, used for shape editors, etc + ProbeRenderInst* mDefaultSkyLight; + public: RenderProbeMgr(); RenderProbeMgr(RenderInstType riType, F32 renderOrder, F32 processAddOrder); virtual ~RenderProbeMgr(); + virtual bool onAdd(); virtual void onRemove(); // ConsoleObject @@ -219,6 +249,7 @@ protected: GFXShaderConstBuffer *shaderConsts); void _setupStaticParameters(); + void updateProbeTexture(U32 probeIdx); void _setupPerFrameParameters(const SceneRenderState *state); virtual void addElement(RenderInst *inst); virtual void render(SceneRenderState * state); @@ -230,6 +261,7 @@ protected: public: // RenderBinMgr void updateProbes(); + void updateProbeTexture(ProbeRenderInst* probe); /// Returns the active LM. static inline RenderProbeMgr* getProbeManager(); @@ -249,6 +281,16 @@ public: void bakeProbe(ReflectionProbe *probeInfo); void bakeProbes(); + + U32 _findNextEmptyCubeSlot() + { + for (U32 i = 0; i < PROBE_MAX_COUNT; i++) + { + if (!mCubeMapSlots[i]) + return i; + } + return INVALID_CUBE_SLOT; + } }; RenderProbeMgr* RenderProbeMgr::getProbeManager() diff --git a/Templates/Full/game/shaders/common/lighting/advanced/reflectionProbeArrayP.hlsl b/Templates/Full/game/shaders/common/lighting/advanced/reflectionProbeArrayP.hlsl index 600544501..9cee66918 100644 --- a/Templates/Full/game/shaders/common/lighting/advanced/reflectionProbeArrayP.hlsl +++ b/Templates/Full/game/shaders/common/lighting/advanced/reflectionProbeArrayP.hlsl @@ -29,9 +29,13 @@ uniform float4 bbMaxArray[MAX_PROBES]; uniform float4 probeConfigData[MAX_PROBES]; //r,g,b/mode,radius,atten #if DEBUGVIZ_CONTRIB -uniform float4 probeContribColors[MAX_PROBES]; +uniform float4 probeContribColors[MAX_PROBES]; #endif +TORQUE_UNIFORM_SAMPLERCUBE(skylightPrefilterMap, 6); +TORQUE_UNIFORM_SAMPLERCUBE(skylightIrradMap, 7); +uniform float hasSkylight; + //Probe IBL stuff struct ProbeData { @@ -64,17 +68,18 @@ float defineSphereSpaceInfluence(Surface surface, ProbeData probe, float3 wsEyeR float getDistBoxToPoint(float3 pt, float3 extents) { - float3 d = max(max(-extents - pt, 0), pt - extents); - return max(max(d.x,d.y),d.z); + float3 d = max(max(-extents - pt, 0), pt - extents); + return max(max(d.x, d.y), d.z); } float defineBoxSpaceInfluence(Surface surface, ProbeData probe, float3 wsEyeRay) { float3 surfPosLS = mul(probe.worldToLocal, float4(surface.P, 1.0)).xyz; - float atten = probe.attenuation; + float probeattenuationvalue = 0.5; // feed meh + float atten = 1.0 - probeattenuationvalue; float baseVal = 0.25; - float dist = getDistBoxToPoint(surfPosLS,float3(baseVal,baseVal,baseVal)); - return saturate(smoothstep(baseVal+0.0001,atten*baseVal,dist)); + float dist = getDistBoxToPoint(surfPosLS, float3(baseVal, baseVal, baseVal)); + return saturate(smoothstep(baseVal + 0.0001, atten*baseVal, dist)); } // Box Projected IBL Lighting @@ -82,12 +87,12 @@ float defineBoxSpaceInfluence(Surface surface, ProbeData probe, float3 wsEyeRay) // and https://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/ float3 boxProject(Surface surface, ProbeData probe) { - float3 RayLS = mul(probe.worldToLocal, float4(surface.R,0.0)).xyz; - float3 PositionLS = mul( probe.worldToLocal, float4(surface.P,1.0)).xyz; - - float3 unit = probe.boxMax-probe.boxMin; - float3 plane1vec = (unit/2 - PositionLS) / RayLS; - float3 plane2vec = (-unit/2 - PositionLS) / RayLS; + float3 RayLS = mul(probe.worldToLocal, float4(surface.R, 0.0)).xyz; + float3 PositionLS = mul(probe.worldToLocal, float4(surface.P, 1.0)).xyz; + + float3 unit = probe.boxMax - probe.boxMin; + float3 plane1vec = (unit / 2 - PositionLS) / RayLS; + float3 plane2vec = (-unit / 2 - PositionLS) / RayLS; float3 furthestPlane = max(plane1vec, plane2vec); float dist = min(min(furthestPlane.x, furthestPlane.y), furthestPlane.z); float3 posonbox = surface.P + surface.R * dist; @@ -99,8 +104,7 @@ float3 iblBoxDiffuse(Surface surface, ProbeData probe) { float3 dir = boxProject(surface, probe); - float lod = surface.roughness*cubeMips; - float3 color = TORQUE_TEXCUBEARRAYLOD(irradianceCubemapAR, dir, probe.probeIdx, lod).xyz; + float3 color = TORQUE_TEXCUBEARRAYLOD(irradianceCubemapAR, dir, probe.probeIdx, 0).xyz; if (probe.contribution>0) return color*probe.contribution; else @@ -154,129 +158,163 @@ float3 iblSkylightSpecular(Surface surface, ProbeData probe) return color; } -float4 main( PFXVertToPix IN ) : SV_TARGET +float4 main(PFXVertToPix IN) : SV_TARGET { //unpack normal and linear depth float4 normDepth = TORQUE_DEFERRED_UNCONDITION(deferredBuffer, IN.uv0.xy); //create surface - Surface surface = createSurface( normDepth, TORQUE_SAMPLER2D_MAKEARG(colorBuffer),TORQUE_SAMPLER2D_MAKEARG(matInfoBuffer), - IN.uv0.xy, eyePosWorld, IN.wsEyeRay, cameraToWorld); + Surface surface = createSurface(normDepth, TORQUE_SAMPLER2D_MAKEARG(colorBuffer),TORQUE_SAMPLER2D_MAKEARG(matInfoBuffer), + IN.uv0.xy, eyePosWorld, IN.wsEyeRay, cameraToWorld); //early out if emissive if (getFlag(surface.matFlag, 0)) - { + { discard; - } + } + + float alpha = 1; int i = 0; float blendFactor[MAX_PROBES]; float blendSum = 0; float blendFacSum = 0; float invBlendSum = 0; - int skyID = 0; float probehits = 0; //Set up our struct data ProbeData probes[MAX_PROBES]; - //Process prooooobes - for (i = 0; i < numProbes; ++i) + if (alpha > 0) { - probes[i].wsPosition = inProbePosArray[i].xyz; - probes[i].radius = probeConfigData[i].g; - probes[i].boxMin = bbMinArray[i].xyz; - probes[i].boxMax = bbMaxArray[i].xyz; - probes[i].refPosition = inRefPosArray[i].xyz; - probes[i].attenuation = probeConfigData[i].b; - probes[i].worldToLocal = worldToObjArray[i]; - probes[i].probeIdx = i; - probes[i].type = probeConfigData[i].r; - probes[i].contribution = 0; - - if (probes[i].type == 0) //box - { - probes[i].contribution = defineBoxSpaceInfluence(surface, probes[i], IN.wsEyeRay); - probehits++; - } - else if (probes[i].type == 1) //sphere - { - probes[i].contribution = defineSphereSpaceInfluence(surface, probes[i], IN.wsEyeRay); - probehits++; - } - else //skylight - { - // - //probes[i].contribution = defineSkylightInfluence(surface, probes[i], IN.wsEyeRay); - skyID = i; - } - - if (probes[i].contribution>1 || probes[i].contribution<0) - probes[i].contribution = 0; - - blendSum += probes[i].contribution; - invBlendSum += (1.0f - probes[i].contribution); - } - - // 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. - for (i = 0; i < numProbes; i++) - { - if (probehits>1.0) - { - blendFactor[i] = ((probes[i].contribution / blendSum)) / (probehits - 1); - blendFactor[i] *= ((probes[i].contribution) / invBlendSum); - blendFacSum += blendFactor[i]; - } - else - { - blendFactor[i] = probes[i].contribution; - blendFacSum = probes[i].contribution; - } - } - - // Normalize blendVal -#if DEBUGVIZ_ATTENUATION == 0 //this can likely be removed when we fix the above normalization behavior - if (blendFacSum == 0.0f) // Possible with custom weight - { - blendFacSum = 1.0f; - } -#endif - //use probehits for sharp cuts when singular, - //blendSum when wanting blend on all edging - if (blendSum>1.0) - { - float invBlendSumWeighted = 1.0f / blendFacSum; + //Process prooooobes for (i = 0; i < numProbes; ++i) { - blendFactor[i] *= invBlendSumWeighted; - probes[i].contribution = blendFactor[i]; + probes[i].wsPosition = inProbePosArray[i].xyz; + probes[i].radius = probeConfigData[i].g; + probes[i].boxMin = bbMinArray[i].xyz; + probes[i].boxMax = bbMaxArray[i].xyz; + probes[i].refPosition = inRefPosArray[i].xyz; + probes[i].attenuation = probeConfigData[i].b; + probes[i].worldToLocal = worldToObjArray[i]; + probes[i].probeIdx = i; + probes[i].type = probeConfigData[i].r; + probes[i].contribution = 0; + + if (probes[i].type == 0) //box + { + probes[i].contribution = defineBoxSpaceInfluence(surface, probes[i], IN.wsEyeRay); + probehits++; + } + else if (probes[i].type == 1) //sphere + { + probes[i].contribution = defineSphereSpaceInfluence(surface, probes[i], IN.wsEyeRay); + probehits++; + } + + if (probes[i].contribution>1 || probes[i].contribution<0) + probes[i].contribution = 0; + + blendSum += probes[i].contribution; + invBlendSum += (1.0f - probes[i].contribution); + + alpha -= probes[i].contribution; } - } + + // 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. + for (i = 0; i < numProbes; i++) + { + if (probehits>1.0) + { + blendFactor[i] = ((probes[i].contribution / blendSum)) / (probehits - 1); + blendFactor[i] *= ((probes[i].contribution) / invBlendSum); + blendFacSum += blendFactor[i]; + } + else + { + blendFactor[i] = probes[i].contribution; + blendFacSum = probes[i].contribution; + } + } + + + // Normalize blendVal +#if DEBUGVIZ_ATTENUATION == 0 //this can likely be removed when we fix the above normalization behavior + if (blendFacSum == 0.0f) // Possible with custom weight + { + blendFacSum = 1.0f; + } +#endif + + //use probehits for sharp cuts when singular, + //blendSum when wanting blend on all edging + if (blendSum>1.0) + { + float invBlendSumWeighted = 1.0f / blendFacSum; + for (i = 0; i < numProbes; ++i) + { + blendFactor[i] *= invBlendSumWeighted; + probes[i].contribution = blendFactor[i]; + + alpha -= probes[i].contribution; + } + } + #if DEBUGVIZ_ATTENUATION == 1 - float attenVis = 0; - for (i = 0; i < numProbes; ++i) - { + /*float attenVis = 0; + for (i = 0; i < numProbes; ++i) + { attenVis += probes[i].contribution; - } - return float4(attenVis, attenVis, attenVis, 1); + } + return float4(attenVis, attenVis, attenVis, 1);*/ + return float4(alpha, alpha, alpha, 1); #endif #if DEBUGVIZ_CONTRIB == 1 - float3 finalContribColor = float3(0, 0, 0); - for (i = 0; i < numProbes; ++i) - { - if (probes[i].contribution == 0) - continue; + float3 finalContribColor = float3(0, 0, 0); + for (i = 0; i < numProbes; ++i) + { + if (probes[i].contribution == 0) + continue; - finalContribColor += probes[i].contribution * probeContribColors[i].rgb; + finalContribColor += probes[i].contribution * probeContribColors[i].rgb; + } + + return float4(finalContribColor, 1); +#endif } - return float4(finalContribColor, 1); + if (hasSkylight && alpha == 1) + { + float2 brdf = TORQUE_TEX2DLOD(BRDFTexture, float4(surface.roughness, surface.NdotV, 0.0, 0.0)).xy; + float lod = surface.roughness*cubeMips; +#if DEBUGVIZ_SPECCUBEMAP == 0 && DEBUGVIZ_DIFFCUBEMAP == 0 + float3 specular = TORQUE_TEXCUBELOD(skylightPrefilterMap, float4(surface.R, lod)).xyz * (brdf.x + brdf.y); + float3 irradiance = TORQUE_TEXCUBELOD(skylightIrradMap, float4(surface.R, 0)).xyz; + + float3 F = FresnelSchlickRoughness(surface.NdotV, surface.f0, surface.roughness); + + //energy conservation + float3 kD = 1.0.xxx - F; + kD *= 1.0 - surface.metalness; + + float3 diffuse = kD * irradiance * surface.baseColor.rgb; + float4 finalColor = float4(diffuse + specular * surface.ao, alpha); + return finalColor; +#elif DEBUGVIZ_SPECCUBEMAP == 1 && DEBUGVIZ_DIFFCUBEMAP == 0 + float3 specular = TORQUE_TEXCUBELOD(skylightPrefilterMap, float4(surface.R, lod)).xyz; + float4 finalColor = float4(specular, 1); + return finalColor; +#elif DEBUGVIZ_DIFFCUBEMAP == 1 + float3 irradiance = TORQUE_TEXCUBELOD(skylightIrradMap, float4(surface.R, 0)).xyz; + float4 finalColor = float4(irradiance, 1); + return finalColor; #endif + } #if DEBUGVIZ_SPECCUBEMAP == 0 && DEBUGVIZ_DIFFCUBEMAP == 0 @@ -292,17 +330,15 @@ float4 main( PFXVertToPix IN ) : SV_TARGET { if (probes[i].contribution == 0) continue; - + if (probes[i].type == 2) //skip skylight continue; - + irradiance += iblBoxDiffuse(surface, probes[i]); specular += F*iblBoxSpecular(surface, probes[i]); - contrib +=probes[i].contribution; + contrib += probes[i].contribution; } contrib = saturate(contrib); - irradiance = lerp(iblSkylightDiffuse(surface, probes[skyID]),irradiance,contrib); - specular = lerp(F*iblSkylightSpecular(surface, probes[skyID]),specular,contrib); //final diffuse color float3 diffuse = kD * irradiance * surface.baseColor.rgb; @@ -328,7 +364,7 @@ float4 main( PFXVertToPix IN ) : SV_TARGET return float4(cubeColor, 1); #elif DEBUGVIZ_DIFFCUBEMAP == 1 - + float3 cubeColor = float3(0, 0, 0); for (i = 0; i < numProbes; ++i) { From e241cbc7c98535fd03914ce652f50e479e954151 Mon Sep 17 00:00:00 2001 From: Areloch Date: Mon, 25 Mar 2019 00:06:08 -0500 Subject: [PATCH 2/2] ongoing WIP to sort out init'ing issues as well as correcting values so the probes actually correctly update data into the arrays Additional sanity checks on the updateTexture calls added by timmy --- .../source/T3D/lighting/reflectionProbe.cpp | 145 ++++++++---------- Engine/source/T3D/lighting/reflectionProbe.h | 4 +- Engine/source/gfx/D3D11/gfxD3D11Cubemap.cpp | 18 +-- .../source/renderInstance/renderProbeMgr.cpp | 49 ++++-- Engine/source/renderInstance/renderProbeMgr.h | 6 +- .../advanced/reflectionProbeArrayP.hlsl | 8 +- 6 files changed, 116 insertions(+), 114 deletions(-) diff --git a/Engine/source/T3D/lighting/reflectionProbe.cpp b/Engine/source/T3D/lighting/reflectionProbe.cpp index c4e79e34a..3668102e4 100644 --- a/Engine/source/T3D/lighting/reflectionProbe.cpp +++ b/Engine/source/T3D/lighting/reflectionProbe.cpp @@ -109,7 +109,6 @@ ReflectionProbe::ReflectionProbe() mObjScale = Point3F::One * 10; mProbeRefScale = Point3F::One*10; - mUseCubemap = false; mUseHDRCaptures = true; mStaticCubemap = NULL; @@ -436,7 +435,6 @@ U32 ReflectionProbe::packUpdate(NetConnection *conn, U32 mask, BitStream *stream if (stream->writeFlag(mask & CubemapMask)) { - stream->writeFlag(mUseCubemap); stream->write(mCubemapName); } @@ -497,12 +495,8 @@ void ReflectionProbe::unpackUpdate(NetConnection *conn, BitStream *stream) isMaterialDirty = true; } - updateProbeParams(); - if (stream->readFlag()) // CubemapMask { - mUseCubemap = stream->readFlag(); - String newCubemapName; stream->read(&mCubemapName); @@ -514,29 +508,9 @@ void ReflectionProbe::unpackUpdate(NetConnection *conn, BitStream *stream) isMaterialDirty = true; } - if (isMaterialDirty) + if (mDirty) { - updateMaterial(); - } - - PROBEMGR->updateProbes(); -} - -void ReflectionProbe::createGeometry() -{ - // Clean up our previous shape - if (mEditorShapeInst) - SAFE_DELETE(mEditorShapeInst); - - mEditorShape = NULL; - - String shapeFile = "tools/resources/ReflectProbeSphere.dae"; - - // Attempt to get the resource from the ResourceManager - mEditorShape = ResourceManager::get().load(shapeFile); - if (mEditorShape) - { - mEditorShapeInst = new TSShapeInstance(mEditorShape, isClientObject()); + updateProbeParams(); } } @@ -552,13 +526,11 @@ void ReflectionProbe::updateProbeParams() mProbeInfo->mIsEnabled = false; } - updateMaterial(); + updateCubemaps(); mProbeInfo->mProbeShapeType = mProbeShapeType; MatrixF transform = getTransform(); - - mProbeInfo->mPosition = getPosition(); if (mProbeShapeType == ProbeRenderInst::Sphere) @@ -633,9 +605,12 @@ void ReflectionProbe::processStaticCubemap() mProbeInfo->mPrefilterCubemap = mPrefilterMap->mCubemap; mProbeInfo->mIrradianceCubemap = mIrridianceMap->mCubemap; + + //Update the probe manager with our new texture! + //PROBEMGR->updateProbeTexture(mProbeInfo); } -void ReflectionProbe::updateMaterial() +void ReflectionProbe::updateCubemaps() { createClientResources(); @@ -685,8 +660,8 @@ void ReflectionProbe::updateMaterial() PROBEMGR->updateProbes(); - if (mProbeInfo->mPrefilterCubemap->isInitialized() && mProbeInfo->mIrradianceCubemap->isInitialized()) - PROBEMGR->updateProbeTexture(mProbeInfo); + //if (mProbeInfo->mPrefilterCubemap->isInitialized() && mProbeInfo->mIrradianceCubemap->isInitialized()) + // PROBEMGR->updateProbeTexture(mProbeInfo); } bool ReflectionProbe::createClientResources() @@ -734,8 +709,66 @@ bool ReflectionProbe::createClientResources() return true; } -void ReflectionProbe::generateTextures() +String ReflectionProbe::getPrefilterMapPath() { + if (mProbeUniqueID.isEmpty()) + { + Con::errorf("ReflectionProbe::getPrefilterMapPath() - We don't have a set output path or persistant id, so no valid path can be provided!"); + return ""; + } + + String path = Con::getVariable("$pref::ReflectionProbes::CurrentLevelPath", "levels/"); + + char fileName[256]; + dSprintf(fileName, 256, "%s%s_Prefilter.dds", path.c_str(), mProbeUniqueID.c_str()); + + return fileName; +} + +String ReflectionProbe::getIrradianceMapPath() +{ + if (mProbeUniqueID.isEmpty()) + { + Con::errorf("ReflectionProbe::getIrradianceMapPath() - We don't have a set output path or persistant id, so no valid path can be provided!"); + return ""; + } + + String path = Con::getVariable("$pref::ReflectionProbes::CurrentLevelPath", "levels/"); + + char fileName[256]; + dSprintf(fileName, 256, "%s%s_Irradiance.dds", path.c_str(), mProbeUniqueID.c_str()); + + return fileName; +} + +void ReflectionProbe::bake() +{ + if (mReflectionModeType == DynamicCubemap) + return; + + PROBEMGR->bakeProbe(this); + + setMaskBits(CubemapMask); +} +//----------------------------------------------------------------------------- +//Rendering of editing/debug stuff +//----------------------------------------------------------------------------- +void ReflectionProbe::createGeometry() +{ + // Clean up our previous shape + if (mEditorShapeInst) + SAFE_DELETE(mEditorShapeInst); + + mEditorShape = NULL; + + String shapeFile = "tools/resources/ReflectProbeSphere.dae"; + + // Attempt to get the resource from the ResourceManager + mEditorShape = ResourceManager::get().load(shapeFile); + if (mEditorShape) + { + mEditorShapeInst = new TSShapeInstance(mEditorShape, isClientObject()); + } } void ReflectionProbe::prepRenderImage(SceneRenderState *state) @@ -918,48 +951,6 @@ DefineEngineMethod(ReflectionProbe, postApply, void, (), , object->inspectPostApply(); } -String ReflectionProbe::getPrefilterMapPath() -{ - if (mProbeUniqueID.isEmpty()) - { - Con::errorf("ReflectionProbe::getPrefilterMapPath() - We don't have a set output path or persistant id, so no valid path can be provided!"); - return ""; - } - - String path = Con::getVariable("$pref::ReflectionProbes::CurrentLevelPath", "levels/"); - - char fileName[256]; - dSprintf(fileName, 256, "%s%s_Prefilter.dds", path.c_str(), mProbeUniqueID.c_str()); - - return fileName; -} - -String ReflectionProbe::getIrradianceMapPath() -{ - if (mProbeUniqueID.isEmpty()) - { - Con::errorf("ReflectionProbe::getIrradianceMapPath() - We don't have a set output path or persistant id, so no valid path can be provided!"); - return ""; - } - - String path = Con::getVariable("$pref::ReflectionProbes::CurrentLevelPath", "levels/"); - - char fileName[256]; - dSprintf(fileName, 256, "%s%s_Irradiance.dds", path.c_str(), mProbeUniqueID.c_str()); - - return fileName; -} - -void ReflectionProbe::bake() -{ - if (mReflectionModeType == DynamicCubemap) - return; - - PROBEMGR->bakeProbe(this); - - setMaskBits(CubemapMask); -} - DefineEngineMethod(ReflectionProbe, Bake, void, (), , "@brief returns true if control object is inside the fog\n\n.") { diff --git a/Engine/source/T3D/lighting/reflectionProbe.h b/Engine/source/T3D/lighting/reflectionProbe.h index 544b2ec81..696091771 100644 --- a/Engine/source/T3D/lighting/reflectionProbe.h +++ b/Engine/source/T3D/lighting/reflectionProbe.h @@ -118,7 +118,6 @@ protected: String mCubemapName; CubemapData *mStaticCubemap; GFXCubemapHandle mDynamicCubemap; - bool mUseCubemap; String cubeDescName; U32 cubeDescId; @@ -223,12 +222,11 @@ public: void createGeometry(); // Get the Material instance - void updateMaterial(); + void updateCubemaps(); virtual void updateProbeParams(); bool createClientResources(); - void generateTextures(); void processStaticCubemap(); diff --git a/Engine/source/gfx/D3D11/gfxD3D11Cubemap.cpp b/Engine/source/gfx/D3D11/gfxD3D11Cubemap.cpp index cd5f528e5..1451df186 100644 --- a/Engine/source/gfx/D3D11/gfxD3D11Cubemap.cpp +++ b/Engine/source/gfx/D3D11/gfxD3D11Cubemap.cpp @@ -513,6 +513,9 @@ void GFXD3D11CubemapArray::init(const U32 cubemapCount, const U32 cubemapFaceSiz void GFXD3D11CubemapArray::updateTexture(const GFXCubemapHandle &cubemap, const U32 slot) { AssertFatal(slot <= mNumCubemaps, "GFXD3D11CubemapArray::updateTexture - trying to update a cubemap texture that is out of bounds!"); + AssertFatal(mFormat == cubemap->getFormat(), "GFXD3D11CubemapArray::updateTexture - Destination format doesn't match"); + AssertFatal(mSize == cubemap->getSize(), "GFXD3D11CubemapArray::updateTexture - Destination size doesn't match"); + AssertFatal(mMipMapLevels == cubemap->getMipMapLevels(), "GFXD3D11CubemapArray::updateTexture - Destination mip levels doesn't match"); GFXD3D11Cubemap *pCubeObj = static_cast((GFXCubemap*)cubemap); ID3D11Resource *pDstRes = pCubeObj->get2DTex(); @@ -531,16 +534,10 @@ void GFXD3D11CubemapArray::updateTexture(const GFXCubemapHandle &cubemap, const void GFXD3D11CubemapArray::copyTo(GFXCubemapArray *pDstCubemap) { AssertFatal(pDstCubemap, "GFXD3D11CubemapArray::copyTo - Got null GFXCubemapArray"); - - const U32 dstCount = pDstCubemap->getNumCubemaps(); - const GFXFormat dstFmt = pDstCubemap->getFormat(); - const U32 dstSize = pDstCubemap->getSize(); - const U32 dstMips = pDstCubemap->getMipMapLevels(); - - AssertFatal(dstCount > mNumCubemaps, "GFXD3D11CubemapArray::copyTo - Destination too small"); - AssertFatal(dstFmt == mFormat, "GFXD3D11CubemapArray::copyTo - Destination format doesn't match"); - AssertFatal(dstSize == mSize, "GFXD3D11CubemapArray::copyTo - Destination size doesn't match"); - AssertFatal(dstMips == mMipMapLevels, "GFXD3D11CubemapArray::copyTo - Destination mip levels doesn't match"); + AssertFatal(pDstCubemap->getNumCubemaps() > mNumCubemaps, "GFXD3D11CubemapArray::copyTo - Destination too small"); + AssertFatal(pDstCubemap->getFormat() == mFormat, "GFXD3D11CubemapArray::copyTo - Destination format doesn't match"); + AssertFatal(pDstCubemap->getSize() == mSize, "GFXD3D11CubemapArray::copyTo - Destination size doesn't match"); + AssertFatal(pDstCubemap->getMipMapLevels() == mMipMapLevels, "GFXD3D11CubemapArray::copyTo - Destination mip levels doesn't match"); GFXD3D11CubemapArray *pDstCube = static_cast(pDstCubemap); ID3D11Resource *pDstRes = pDstCube->get2DTex(); @@ -556,7 +553,6 @@ void GFXD3D11CubemapArray::copyTo(GFXCubemapArray *pDstCubemap) } } } - } void GFXD3D11CubemapArray::setToTexUnit(U32 tuNum) diff --git a/Engine/source/renderInstance/renderProbeMgr.cpp b/Engine/source/renderInstance/renderProbeMgr.cpp index 4266255b3..1f7850f50 100644 --- a/Engine/source/renderInstance/renderProbeMgr.cpp +++ b/Engine/source/renderInstance/renderProbeMgr.cpp @@ -391,6 +391,7 @@ void RenderProbeMgr::_setupStaticParameters() cubeMaps.clear(); irradMaps.clear(); + Vector cubemapIdxes; if (probeCount != 0 && ProbeRenderInst::all[0]->mPrefilterCubemap != nullptr) { @@ -420,15 +421,6 @@ void RenderProbeMgr::_setupStaticParameters() continue; } - //if (curEntry.mCubemap.isNull() || curEntry.mIrradianceCubemap.isNull()) - // continue; - - //if (!curEntry.mCubemap->isInitialized()) - // continue; - - //if (!curEntry.mIrradianceCubemap->isInitialized()) - // continue; - //Setup Point3F probePos = curEntry.getPosition(); Point3F refPos = curEntry.getPosition() +curEntry.mProbeRefOffset; @@ -444,21 +436,40 @@ void RenderProbeMgr::_setupStaticParameters() probeConfigData[mEffectiveProbeCount] = Point4F(curEntry.mProbeShapeType, curEntry.mRadius, curEntry.mAtten, - 1); + curEntry.mCubemapIndex); - //cubeMaps.push_back(curEntry.mCubemap); - //irradMaps.push_back(curEntry.mIrradianceCubemap); + cubeMaps.push_back(curEntry.mPrefilterCubemap); + irradMaps.push_back(curEntry.mIrradianceCubemap); + + cubemapIdxes.push_back(i); mEffectiveProbeCount++; } if (mEffectiveProbeCount != 0) { - //mPrefilterArray = GFXCubemapArrayHandle(GFX->createCubemapArray()); - //mIrradianceArray = GFXCubemapArrayHandle(GFX->createCubemapArray()); + bool useOldWay = false; + if (useOldWay) + { + //old static way + mPrefilterArray = GFXCubemapArrayHandle(GFX->createCubemapArray()); + mIrradianceArray = GFXCubemapArrayHandle(GFX->createCubemapArray()); - //mPrefilterArray->initStatic(cubeMaps.address(), cubeMaps.size()); - //mIrradianceArray->initStatic(irradMaps.address(), irradMaps.size()); + mPrefilterArray->init(cubeMaps.address(), cubeMaps.size()); + mIrradianceArray->init(irradMaps.address(), irradMaps.size()); + } + else + { + //faked static way by doing it via update + for (U32 i = 0; i < cubemapIdxes.size(); i++) + { + U32 probeIdx = cubemapIdxes[i]; + + const U32 cubeIndex = ProbeRenderInst::all[probeIdx]->mCubemapIndex; + mIrradianceArray->updateTexture(irradMaps[i], cubeIndex); + mPrefilterArray->updateTexture(cubeMaps[i], cubeIndex); + } + } } } @@ -740,7 +751,6 @@ void RenderProbeMgr::render( SceneRenderState *state ) { mProbeArrayEffect->setCubemapTexture(6, skylightPrefilterMap); mProbeArrayEffect->setCubemapTexture(7, skylightIrradMap); - } if (mEffectiveProbeCount != 0) @@ -909,6 +919,11 @@ void RenderProbeMgr::bakeProbe(ReflectionProbe *probe) 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); } diff --git a/Engine/source/renderInstance/renderProbeMgr.h b/Engine/source/renderInstance/renderProbeMgr.h index 2d796d4e4..264e4d05c 100644 --- a/Engine/source/renderInstance/renderProbeMgr.h +++ b/Engine/source/renderInstance/renderProbeMgr.h @@ -170,9 +170,9 @@ class RenderProbeMgr : public RenderBinManager //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 = 32; - static const U32 PROBE_PREFILTER_SIZE = 128; - static const GFXFormat PROBE_FORMAT = GFXFormatR8G8B8A8;// when hdr fixed GFXFormatR16G16B16A16F; look into bc6h compression + static const U32 PROBE_IRRAD_SIZE = 64; + static const U32 PROBE_PREFILTER_SIZE = 64; + static const GFXFormat PROBE_FORMAT = GFXFormatR16G16B16A16F;// GFXFormatR8G8B8A8;// when hdr fixed GFXFormatR16G16B16A16F; look into bc6h compression static const U32 INVALID_CUBE_SLOT = U32_MAX; //Array rendering diff --git a/Templates/Full/game/shaders/common/lighting/advanced/reflectionProbeArrayP.hlsl b/Templates/Full/game/shaders/common/lighting/advanced/reflectionProbeArrayP.hlsl index 9cee66918..48220f067 100644 --- a/Templates/Full/game/shaders/common/lighting/advanced/reflectionProbeArrayP.hlsl +++ b/Templates/Full/game/shaders/common/lighting/advanced/reflectionProbeArrayP.hlsl @@ -49,7 +49,8 @@ struct ProbeData uint type; //box = 0, sphere = 1 float contribution; float3 refPosition; - float3 pad; + float cubemapIdx; + float2 pad; }; float defineSkylightInfluence(Surface surface, ProbeData probe, float3 wsEyeRay) @@ -104,7 +105,7 @@ float3 iblBoxDiffuse(Surface surface, ProbeData probe) { float3 dir = boxProject(surface, probe); - float3 color = TORQUE_TEXCUBEARRAYLOD(irradianceCubemapAR, dir, probe.probeIdx, 0).xyz; + float3 color = TORQUE_TEXCUBEARRAYLOD(irradianceCubemapAR, dir, probe.cubemapIdx, 0).xyz; if (probe.contribution>0) return color*probe.contribution; else @@ -125,7 +126,7 @@ float3 iblBoxSpecular(Surface surface, ProbeData probe) float lod = 0; #endif - float3 color = TORQUE_TEXCUBEARRAYLOD(cubeMapAR, dir, probe.probeIdx, lod).xyz * (brdf.x + brdf.y); + float3 color = TORQUE_TEXCUBEARRAYLOD(cubeMapAR, dir, probe.cubemapIdx, lod).xyz * (brdf.x + brdf.y); if (probe.contribution>0) return color*probe.contribution; @@ -197,6 +198,7 @@ float4 main(PFXVertToPix IN) : SV_TARGET probes[i].attenuation = probeConfigData[i].b; probes[i].worldToLocal = worldToObjArray[i]; probes[i].probeIdx = i; + probes[i].cubemapIdx = probeConfigData[i].a; probes[i].type = probeConfigData[i].r; probes[i].contribution = 0;