From f31445751f8616f4c69095ee995faa81901581b7 Mon Sep 17 00:00:00 2001 From: Areloch Date: Mon, 17 Sep 2018 01:52:18 -0500 Subject: [PATCH] Updates and fixes to probe and lighting logic. --- Engine/source/T3D/lighting/IBLUtilities.cpp | 107 ++- Engine/source/T3D/lighting/IBLUtilities.h | 5 + .../source/T3D/lighting/reflectionProbe.cpp | 763 ++++++------------ Engine/source/T3D/lighting/reflectionProbe.h | 43 +- Engine/source/T3D/lighting/skylight.cpp | 636 +-------------- Engine/source/T3D/lighting/skylight.h | 102 +-- Engine/source/gfx/bitmap/cubemapSaver.h | 2 +- Engine/source/gfx/gfxEnums.h | 2 +- Engine/source/lighting/probeManager.cpp | 3 +- Engine/source/lighting/probeManager.h | 1 + .../source/renderInstance/renderPassManager.h | 1 + .../source/renderInstance/renderProbeMgr.cpp | 9 +- Engine/source/renderInstance/renderProbeMgr.h | 1 + .../lighting/advanced/deferredShading.cs | 20 +- .../client/lighting/advanced/shaders.cs | 6 +- .../advanced/gl/deferredShadingP.glsl | 27 +- .../lighting/advanced/gl/lightingUtils.glsl | 28 - .../common/lighting/advanced/pointLightP.hlsl | 9 +- .../common/lighting/advanced/prefilterP.hlsl | 8 +- .../lighting/advanced/probeShadingP.hlsl | 14 +- .../lighting/advanced/reflectionProbeP.hlsl | 179 ++-- .../common/lighting/advanced/spotLightP.hlsl | 64 +- .../lighting/advanced/vectorLightP.hlsl | 4 +- 23 files changed, 568 insertions(+), 1466 deletions(-) diff --git a/Engine/source/T3D/lighting/IBLUtilities.cpp b/Engine/source/T3D/lighting/IBLUtilities.cpp index 8f2de0efe..73d3c1580 100644 --- a/Engine/source/T3D/lighting/IBLUtilities.cpp +++ b/Engine/source/T3D/lighting/IBLUtilities.cpp @@ -3,6 +3,8 @@ #include "gfx/gfxTextureManager.h" #include "gfx/gfxTransformSaver.h" #include "gfx/bitmap/cubemapSaver.h" +#include "core/stream/fileStream.h" +#include "gfx/bitmap/imageUtils.h" namespace IBLUtilities { @@ -56,6 +58,44 @@ namespace IBLUtilities GFX->popActiveRenderTarget(); } + void GenerateAndSaveIrradianceMap(String outputPath, S32 resolution, GFXCubemapHandle cubemap, GFXCubemapHandle &cubemapOut) + { + if (outputPath.isEmpty()) + { + Con::errorf("IBLUtilities::GenerateAndSaveIrradianceMap - Cannot save to an empty path!"); + return; + } + + GFXTextureTargetRef renderTarget = GFX->allocRenderToTextureTarget(false); + + IBLUtilities::GenerateIrradianceMap(renderTarget, cubemap, cubemapOut); + + //Write it out + CubemapSaver::save(cubemapOut, outputPath); + + if (!Platform::isFile(outputPath)) + { + Con::errorf("IBLUtilities::GenerateAndSaveIrradianceMap - Failed to properly save out the baked irradiance!"); + } + } + + void SaveCubeMap(String outputPath, GFXCubemapHandle &cubemap) + { + if (outputPath.isEmpty()) + { + Con::errorf("IBLUtilities::SaveCubeMap - Cannot save to an empty path!"); + return; + } + + //Write it out + CubemapSaver::save(cubemap, outputPath); + + if (!Platform::isFile(outputPath)) + { + Con::errorf("IBLUtilities::SaveCubeMap - Failed to properly save out the baked irradiance!"); + } + } + void GeneratePrefilterMap(GFXTextureTargetRef renderTarget, GFXCubemapHandle cubemap, U32 mipLevels, GFXCubemapHandle &cubemapOut) { GFXTransformSaver saver; @@ -73,8 +113,8 @@ namespace IBLUtilities GFXShaderConstHandle* prefilterFaceSC = prefilterShader->getShaderConstHandle("$face"); GFXShaderConstHandle* prefilterRoughnessSC = prefilterShader->getShaderConstHandle("$roughness"); GFXShaderConstHandle* prefilterMipSizeSC = prefilterShader->getShaderConstHandle("$mipSize"); - GFXShaderConstHandle* prefilterResolutionSC = prefilterShader->getShaderConstHandle("$resolution"); - + GFXShaderConstHandle* prefilterResolutionSC = prefilterShader->getShaderConstHandle("$resolution"); + GFX->pushActiveRenderTarget(); GFX->setShader(prefilterShader); GFX->setShaderConstBuffer(prefilterConsts); @@ -82,10 +122,13 @@ namespace IBLUtilities U32 prefilterSize = cubemapOut->getSize(); + U32 resolutionSize = prefilterSize; + for (U32 face = 0; face < 6; face++) { prefilterConsts->setSafe(prefilterFaceSC, (S32)face); - prefilterConsts->setSafe(prefilterResolutionSC, renderTarget->getSize().x); + prefilterConsts->setSafe(prefilterResolutionSC, (S32)resolutionSize); + for (U32 mip = 0; mip < mipLevels; mip++) { S32 mipSize = prefilterSize >> mip; @@ -105,6 +148,27 @@ namespace IBLUtilities GFX->popActiveRenderTarget(); } + void GenerateAndSavePrefilterMap(String outputPath, S32 resolution, GFXCubemapHandle cubemap, U32 mipLevels, GFXCubemapHandle &cubemapOut) + { + if (outputPath.isEmpty()) + { + Con::errorf("IBLUtilities::GenerateAndSavePrefilterMap - Cannot save to an empty path!"); + return; + } + + GFXTextureTargetRef renderTarget = GFX->allocRenderToTextureTarget(false); + + IBLUtilities::GeneratePrefilterMap(renderTarget, cubemap, mipLevels, cubemapOut); + + //Write it out + CubemapSaver::save(cubemapOut, outputPath); + + if (!Platform::isFile(outputPath)) + { + Con::errorf("IBLUtilities::GenerateAndSavePrefilterMap - Failed to properly save out the baked irradiance!"); + } + } + void GenerateBRDFTexture(GFXTexHandle &textureOut) { GFXTransformSaver saver; @@ -133,6 +197,33 @@ namespace IBLUtilities GFX->popActiveRenderTarget(); } + GFXTexHandle GenerateAndSaveBRDFTexture(String outputPath, S32 resolution) + { + GFXTexHandle brdfTexture = TEXMGR->createTexture(resolution, resolution, GFXFormatR8G8B8A8, &GFXRenderTargetProfile, 1, 0); + GenerateBRDFTexture(brdfTexture); + + FileStream fs; + if (fs.open(outputPath, Torque::FS::File::Write)) + { + // Read back the render target, dxt compress it, and write it to disk. + GBitmap brdfBmp(brdfTexture.getHeight(), brdfTexture.getWidth(), false, GFXFormatR8G8B8A8); + brdfTexture.copyToBmp(&brdfBmp); + + brdfBmp.extrudeMipLevels(); + + DDSFile *brdfDDS = DDSFile::createDDSFileFromGBitmap(&brdfBmp); + ImageUtil::ddsCompress(brdfDDS, GFXFormatBC1); + + // Write result to file stream + brdfDDS->write(fs); + + delete brdfDDS; + } + fs.close(); + + return brdfTexture; + } + void bakeReflection(String outputPath, S32 resolution) { //GFXDEBUGEVENT_SCOPE(ReflectionProbe_Bake, ColorI::WHITE); @@ -464,7 +555,7 @@ namespace IBLUtilities } //If we fail to parse the cubemap for whatever reason, we really can't continue - if (!CubemapSaver::getBitmaps(cubemap, GFXFormatR8G8B8, cubeFaceBitmaps)) + if (!CubemapSaver::getBitmaps(cubemap, GFXFormatR8G8B8A8, cubeFaceBitmaps)) return; //Set up our constants @@ -570,4 +661,10 @@ namespace IBLUtilities return angle; } -}; \ No newline at end of file +}; + +DefineEngineFunction(GenerateBRDFTexture, bool, (String outputPath, S32 resolution), ("", 256), + "@brief returns true if control object is inside the fog\n\n.") +{ + return IBLUtilities::GenerateAndSaveBRDFTexture(outputPath, resolution); +} \ No newline at end of file diff --git a/Engine/source/T3D/lighting/IBLUtilities.h b/Engine/source/T3D/lighting/IBLUtilities.h index f4392d368..1bb6fd531 100644 --- a/Engine/source/T3D/lighting/IBLUtilities.h +++ b/Engine/source/T3D/lighting/IBLUtilities.h @@ -3,9 +3,14 @@ namespace IBLUtilities { void GenerateIrradianceMap(GFXTextureTargetRef renderTarget, GFXCubemapHandle cubemap, GFXCubemapHandle &cubemapOut); + void GenerateAndSaveIrradianceMap(String outputPath, S32 resolution, GFXCubemapHandle cubemap, GFXCubemapHandle &cubemapOut); void GeneratePrefilterMap(GFXTextureTargetRef renderTarget, GFXCubemapHandle cubemap, U32 mipLevels, GFXCubemapHandle &cubemapOut); + void GenerateAndSavePrefilterMap(String outputPath, S32 resolution, GFXCubemapHandle cubemap, U32 mipLevels, GFXCubemapHandle &cubemapOut); + void SaveCubeMap(String outputPath, GFXCubemapHandle &cubemap); + + GFXTexHandle GenerateAndSaveBRDFTexture(String outputPath, S32 resolution); void GenerateBRDFTexture(GFXTexHandle &textureOut); void bakeReflection(String outputPath, S32 resolution); diff --git a/Engine/source/T3D/lighting/reflectionProbe.cpp b/Engine/source/T3D/lighting/reflectionProbe.cpp index e4bcfbed5..f79362892 100644 --- a/Engine/source/T3D/lighting/reflectionProbe.cpp +++ b/Engine/source/T3D/lighting/reflectionProbe.cpp @@ -105,11 +105,9 @@ ReflectionProbe::ReflectionProbe() mTypeMask = LightObjectType | MarkerObjectType; - mProbeShapeType = ProbeInfo::Sphere; + mProbeShapeType = ProbeInfo::Box; mIndrectLightingModeType = NoIndirect; - mAmbientColor = LinearColorF(1, 1, 1, 1); - mSphericalHarmonics = LinearColorF(0, 0, 0, 1); mReflectionModeType = BakedCubemap; @@ -120,7 +118,7 @@ ReflectionProbe::ReflectionProbe() mRadius = 10; mUseCubemap = false; - mCubemap = NULL; + mStaticCubemap = NULL; mReflectionPath = ""; mProbeUniqueID = ""; @@ -138,6 +136,11 @@ ReflectionProbe::ReflectionProbe() mPrefilterSize = 64; mPrefilterMipLevels = mLog2(F32(mPrefilterSize)); + mPrefilterMap = nullptr; + mIrridianceMap = nullptr; + + mProbePosOffset = Point3F::Zero; + mEditPosOffset = false; } ReflectionProbe::~ReflectionProbe() @@ -145,8 +148,8 @@ ReflectionProbe::~ReflectionProbe() if (mEditorShapeInst) SAFE_DELETE(mEditorShapeInst); - if (mReflectionModeType != StaticCubemap && mCubemap) - mCubemap->deleteObject(); + if (mReflectionModeType != StaticCubemap && mStaticCubemap) + mStaticCubemap->deleteObject(); } //----------------------------------------------------------------------------- @@ -161,15 +164,12 @@ void ReflectionProbe::initPersistFields() addField("ProbeShape", TypeReflectProbeType, Offset(mProbeShapeType, ReflectionProbe), "The type of mesh data to use for collision queries."); addField("radius", TypeF32, Offset(mRadius, ReflectionProbe), "The name of the material used to render the mesh."); + addField("posOffset", TypePoint3F, Offset(mProbePosOffset, ReflectionProbe), ""); + + //addProtectedField("EditPosOffset", TypeBool, Offset(mEditPosOffset, ReflectionProbe), + // &_toggleEditPosOffset, &defaultProtectedGetFn, "Toggle Edit Pos Offset Mode", AbstractClassRep::FieldFlags::FIELD_ComponentInspectors); endGroup("Rendering"); - /*addGroup("IndirectLighting"); - addField("IndirectLightMode", TypeIndrectLightingModeEnum, Offset(mIndrectLightingModeType, ReflectionProbe), - "The type of mesh data to use for collision queries."); - - addField("IndirectLight", TypeColorF, Offset(mAmbientColor, ReflectionProbe), "Path of file to save and load results."); - endGroup("IndirectLighting");*/ - addGroup("Reflection"); addField("ReflectionMode", TypeReflectionModeEnum, Offset(mReflectionModeType, ReflectionProbe), "The type of mesh data to use for collision queries."); @@ -193,88 +193,10 @@ void ReflectionProbe::initPersistFields() "@note Only works for shadow mapped lights.\n\n" "@ingroup Lighting"); - /*addGroup("Internal"); - - addProtectedField("SHTerm", TypeRealString, NULL, &protectedSetSHTerms, &defaultProtectedGetFn, - "Do not modify, for internal use.", AbstractClassRep::FIELD_HideInInspectors); - - addProtectedField("SHConsts", TypeRealString, NULL, &protectedSetSHConsts, &defaultProtectedGetFn, - "Do not modify, for internal use.", AbstractClassRep::FIELD_HideInInspectors); - - endGroup("Internal");*/ - // SceneObject already handles exposing the transform Parent::initPersistFields(); } -bool ReflectionProbe::protectedSetSHTerms(void *object, const char *index, const char *data) -{ - ReflectionProbe *probe = static_cast< ReflectionProbe* >(object); - - LinearColorF term; - U32 idx; - - dSscanf(data, "%i %g %g %g", &idx, &term.red, &term.green, &term.blue); - - probe->mProbeInfo->mSHTerms[idx] = term; - - return false; -} - -bool ReflectionProbe::protectedSetSHConsts(void *object, const char *index, const char *data) -{ - ReflectionProbe *probe = static_cast< ReflectionProbe* >(object); - - dSscanf(data, "%g %g %g %g %g", &probe->mProbeInfo->mSHConstants[0], - &probe->mProbeInfo->mSHConstants[1], &probe->mProbeInfo->mSHConstants[2], &probe->mProbeInfo->mSHConstants[3], &probe->mProbeInfo->mSHConstants[4]); - - return false; -} - -void ReflectionProbe::writeFields(Stream &stream, U32 tabStop) -{ - Parent::writeFields(stream, tabStop); - - if (mIndrectLightingModeType != SphericalHarmonics) - return; - - // Now write all planes. - - stream.write(2, "\r\n"); - - for (U32 i = 0; i < 9; i++) - { - const LinearColorF shTerm = mProbeInfo->mSHTerms[i]; - - stream.writeTabs(tabStop); - - char buffer[1024]; - dMemset(buffer, 0, 1024); - - dSprintf(buffer, 1024, "SHTerm = \"%i %g %g %g\";", i, shTerm.red, shTerm.green, shTerm.blue); - - stream.writeLine((const U8*)buffer); - } - - stream.writeTabs(tabStop); - - char buffer[1024]; - dMemset(buffer, 0, 1024); - - dSprintf(buffer, 1024, "SHConsts = \"%g %g %g %g %g\";", mProbeInfo->mSHConstants[0], - mProbeInfo->mSHConstants[1], mProbeInfo->mSHConstants[2], mProbeInfo->mSHConstants[3], mProbeInfo->mSHConstants[4]); - - stream.writeLine((const U8*)buffer); -} - -bool ReflectionProbe::writeField(StringTableEntry fieldname, const char *value) -{ - if (fieldname == StringTable->insert("SHTerm") || fieldname == StringTable->insert("SHConsts")) - return false; - - return Parent::writeField(fieldname, value); -} - void ReflectionProbe::inspectPostApply() { Parent::inspectPostApply(); @@ -300,8 +222,27 @@ bool ReflectionProbe::_doBake(void *object, const char *index, const char *data) { ReflectionProbe* probe = reinterpret_cast< ReflectionProbe* >(object); - if (probe->mDirty) - probe->bake(probe->mReflectionPath, 256); + //if (probe->mDirty) + // probe->bake(probe->mReflectionPath, 256); + + ReflectionProbe *clientProbe = (ReflectionProbe*)probe->getClientObject(); + + if (clientProbe) + { + clientProbe->bake(clientProbe->mReflectionPath, 64); + } + + return false; +} + +bool ReflectionProbe::_toggleEditPosOffset(void *object, const char *index, const char *data) +{ + ReflectionProbe* probe = reinterpret_cast< ReflectionProbe* >(object); + + probe->mEditPosOffset = !probe->mEditPosOffset; + + //if (probe->mDirty) + // probe->bake(probe->mReflectionPath, 256); return false; } @@ -311,9 +252,11 @@ bool ReflectionProbe::onAdd() if (!Parent::onAdd()) return false; + mEditPosOffset = false; + mObjBox.minExtents.set(-1, -1, -1); mObjBox.maxExtents.set(1, 1, 1); - mObjScale.set(mRadius/2, mRadius/2, mRadius/2); + //mObjScale.set(mRadius/2, mRadius/2, mRadius/2); // Skip our transform... it just dirties mask bits. Parent::setTransform(mObjToWorld); @@ -333,7 +276,12 @@ bool ReflectionProbe::onAdd() // Refresh this object's material (if any) if (isClientObject()) - updateMaterial(); + { + //createClientResources(); + //updateMaterial(); + createGeometry(); + updateProbeParams(); + } setMaskBits(-1); @@ -351,7 +299,10 @@ void ReflectionProbe::onRemove() void ReflectionProbe::setTransform(const MatrixF & mat) { // Let SceneObject handle all of the matrix manipulation - Parent::setTransform(mat); + if (!mEditPosOffset) + Parent::setTransform(mat); + else + mProbePosOffset = mat.getPosition(); mDirty = true; @@ -370,6 +321,7 @@ U32 ReflectionProbe::packUpdate(NetConnection *conn, U32 mask, BitStream *stream { mathWrite(*stream, getTransform()); mathWrite(*stream, getScale()); + mathWrite(*stream, mProbePosOffset); } if (stream->writeFlag(mask & ShapeTypeMask)) @@ -379,7 +331,6 @@ U32 ReflectionProbe::packUpdate(NetConnection *conn, U32 mask, BitStream *stream if (stream->writeFlag(mask & UpdateMask)) { - stream->write(mAmbientColor); stream->write(mRadius); } @@ -420,6 +371,8 @@ void ReflectionProbe::unpackUpdate(NetConnection *conn, BitStream *stream) mathRead(*stream, &mObjScale); setTransform(mObjToWorld); + + mathRead(*stream, &mProbePosOffset); } if (stream->readFlag()) // ShapeTypeMask @@ -433,7 +386,6 @@ void ReflectionProbe::unpackUpdate(NetConnection *conn, BitStream *stream) if (stream->readFlag()) // UpdateMask { - stream->read(&mAmbientColor); stream->read(&mRadius); } @@ -474,8 +426,10 @@ void ReflectionProbe::unpackUpdate(NetConnection *conn, BitStream *stream) updateProbeParams(); - if(isMaterialDirty) + if (isMaterialDirty) + { updateMaterial(); + } } void ReflectionProbe::createGeometry() @@ -505,24 +459,19 @@ void ReflectionProbe::updateProbeParams() if (mProbeInfo == nullptr) return; - if (mIndrectLightingModeType == AmbientColor) - { - mProbeInfo->mAmbient = mAmbientColor; - } - else - { - mProbeInfo->mAmbient = LinearColorF(0, 0, 0, 0); - } + updateMaterial(); + + mProbeInfo->mAmbient = LinearColorF(0, 0, 0, 0); mProbeInfo->mProbeShapeType = mProbeShapeType; mProbeInfo->setPosition(getPosition()); //Update the bounds - mObjBox.minExtents.set(-1, -1, -1); - mObjBox.maxExtents.set(1, 1, 1); + //mObjBox.minExtents.set(-1, -1, -1); + //mObjBox.maxExtents.set(1, 1, 1); - mObjScale.set(mRadius / 2, mRadius / 2, mRadius / 2); + //mObjScale.set(mRadius / 2, mRadius / 2, mRadius / 2); // Skip our transform... it just dirties mask bits. Parent::setTransform(mObjToWorld); @@ -533,84 +482,95 @@ void ReflectionProbe::updateProbeParams() mProbeInfo->mRadius = mRadius; mProbeInfo->mIsSkylight = false; + + mProbeInfo->mProbePosOffset = mProbePosOffset; } void ReflectionProbe::updateMaterial() { + createClientResources(); + if (mReflectionModeType != DynamicCubemap) { if ((mReflectionModeType == BakedCubemap) && !mProbeUniqueID.isEmpty()) { - bool validCubemap = true; - - char fileName[256]; - dSprintf(fileName, 256, "%s%s.DDS", mReflectionPath.c_str(), mProbeUniqueID.c_str()); - - Vector fileNames; - - if (Platform::isFile(fileName)) + if (mPrefilterMap != nullptr && mPrefilterMap->mCubemap.isValid()) { - if (!mCubemap) - { - mCubemap = new CubemapData(); - mCubemap->registerObject(); - } - - mCubemap->setCubemapFile(FileName(fileName)); + mProbeInfo->mCubemap = &mPrefilterMap->mCubemap; } - else + if (mIrridianceMap != nullptr && mIrridianceMap->mCubemap.isValid()) { - validCubemap = false; + mProbeInfo->mIrradianceCubemap = &mIrridianceMap->mCubemap; } - - if (validCubemap) + if (mBrdfTexture.isValid()) { - if (mCubemap->mCubemap) - mCubemap->updateFaces(); - else - mCubemap->createMap(); - - mDirty = false; - - mProbeInfo->mCubemap = &mCubemap->mCubemap; + mProbeInfo->mBRDFTexture = &mBrdfTexture; } } else if (mReflectionModeType == StaticCubemap && !mCubemapName.isEmpty()) { - Sim::findObject(mCubemapName, mCubemap); + Sim::findObject(mCubemapName, mStaticCubemap); - mProbeInfo->mCubemap = &mCubemap->mCubemap; + mProbeInfo->mCubemap = &mStaticCubemap->mCubemap; } } else if (mReflectionModeType == DynamicCubemap && !mDynamicCubemap.isNull()) { mProbeInfo->mCubemap = &mDynamicCubemap; } - - generateTextures(); - - if (mPrefilterMap.isValid()) - { - mProbeInfo->mCubemap = &mPrefilterMap; - mProbeInfo->mIrradianceCubemap = &mIrridianceMap; - mProbeInfo->mBRDFTexture = &mBrdfTexture; - } - //calculateSHTerms(); } bool ReflectionProbe::createClientResources() { //irridiance resources - mIrridianceMap = GFX->createCubemap(); - mIrridianceMap->initDynamic(128, GFXFormatR16G16B16A16F,1); + if (!mIrridianceMap) + { + mIrridianceMap = new CubemapData(); + mIrridianceMap->registerObject(); - //prefilter resources - we share the irridiance stateblock - mPrefilterMap = GFX->createCubemap(); - mPrefilterMap->initDynamic(mPrefilterSize, GFXFormatR16G16B16A16F, mPrefilterMipLevels); + mIrridianceMap->createMap(); + } + + String irrPath = getIrradianceMapPath(); + if (Platform::isFile(irrPath)) + { + mIrridianceMap->setCubemapFile(FileName(irrPath)); + mIrridianceMap->updateFaces(); + } + + if(mIrridianceMap->mCubemap.isNull()) + Con::errorf("ReflectionProbe::createClientResources() - Unable to load baked irradiance map at %s", getIrradianceMapPath().c_str()); + + // + if (!mPrefilterMap) + { + mPrefilterMap = new CubemapData(); + mPrefilterMap->registerObject(); + + mPrefilterMap->createMap(); + } + + String prefilPath = getPrefilterMapPath(); + if (Platform::isFile(prefilPath)) + { + mPrefilterMap->setCubemapFile(FileName(prefilPath)); + mPrefilterMap->updateFaces(); + } + + if (mPrefilterMap->mCubemap.isNull()) + Con::errorf("ReflectionProbe::createClientResources() - Unable to load baked prefilter map at %s", getPrefilterMapPath().c_str()); //brdf lookup resources //make the brdf lookup texture the same size as the prefilter texture - mBrdfTexture = TEXMGR->createTexture(mPrefilterSize, mPrefilterSize, GFXFormatR16G16B16A16F, &GFXRenderTargetProfile, 1, 0); + + String brdfPath = Con::getVariable("$Core::BRDFTexture", "core/art/brdfTexture.DDS"); + + mBrdfTexture = TEXMGR->createTexture(brdfPath, &GFXTexturePersistentProfile);// TEXMGR->createTexture(mPrefilterSize, mPrefilterSize, GFXFormatR16G16B16A16F, &GFXRenderTargetProfile, 1, 0); + + if (!mBrdfTexture) + { + mBrdfTexture = IBLUtilities::GenerateAndSaveBRDFTexture(brdfPath, 512); + } mResourcesCreated = true; @@ -619,28 +579,6 @@ bool ReflectionProbe::createClientResources() void ReflectionProbe::generateTextures() { - if (!mCubemap) - return; - - if (!mResourcesCreated) - { - if (!createClientResources()) - { - Con::errorf("SkyLight::createIrridianceMap: Failed to create resources"); - return; - } - } - - GFXTextureTargetRef renderTarget = GFX->allocRenderToTextureTarget(false); - - //create irridiance cubemap - IBLUtilities::GenerateIrradianceMap(renderTarget, mCubemap->mCubemap, mIrridianceMap); - - //create prefilter cubemap (radiance) - IBLUtilities::GeneratePrefilterMap(renderTarget, mCubemap->mCubemap, mPrefilterMipLevels, mPrefilterMap); - - //create brdf lookup - IBLUtilities::GenerateBRDFTexture(mBrdfTexture); } void ReflectionProbe::prepRenderImage(SceneRenderState *state) @@ -676,7 +614,7 @@ void ReflectionProbe::prepRenderImage(SceneRenderState *state) //Register PROBEMGR->registerProbe(mProbeInfo, this); - if (ReflectionProbe::smRenderPreviewProbes && gEditingMission && mEditorShapeInst && mCubemap != nullptr) + if (ReflectionProbe::smRenderPreviewProbes && gEditingMission && mEditorShapeInst && mPrefilterMap != nullptr) { GFXTransformSaver saver; @@ -711,7 +649,7 @@ void ReflectionProbe::prepRenderImage(SceneRenderState *state) rdata.setFadeOverride(1.0f); if(mReflectionModeType != DynamicCubemap) - rdata.setCubemap(mCubemap->mCubemap); + rdata.setCubemap(mPrefilterMap->mCubemap); else rdata.setCubemap(mDynamicCubemap); @@ -724,6 +662,11 @@ void ReflectionProbe::prepRenderImage(SceneRenderState *state) // Set the world matrix to the objects render transform MatrixF mat = getRenderTransform(); mat.scale(Point3F(1, 1, 1)); + + Point3F centerPos = mat.getPosition(); + centerPos += mProbePosOffset; + mat.setPosition(centerPos); + GFX->setWorldMatrix(mat); // Animate the the shape @@ -763,7 +706,7 @@ void ReflectionProbe::_onRenderViz(ObjectRenderInst *ri, // Base the sphere color on the light color. ColorI color = ColorI::WHITE; - color.alpha = 50; + color.alpha = 25; if (mProbeShapeType == ProbeInfo::Sphere) { @@ -771,9 +714,12 @@ void ReflectionProbe::_onRenderViz(ObjectRenderInst *ri, } else { - Box3F cube(mRadius); - cube.setCenter(getPosition()); + Box3F cube(-Point3F(mRadius, mRadius, mRadius),Point3F(mRadius, mRadius, mRadius)); + cube.setCenter(getPosition()+mProbePosOffset); draw->drawCube(desc, cube, color); + cube = getWorldBox(); + draw->drawCube(desc, cube, color); + } } @@ -795,7 +741,7 @@ void ReflectionProbe::setPreviewMatParameters(SceneRenderState* renderState, Bas GFX->setTexture(0, deferredTexObject); //Set the cubemap - GFX->setCubeTexture(1, mCubemap->mCubemap); + GFX->setCubeTexture(1, mPrefilterMap->mCubemap); //Set the invViewMat MatrixSet &matrixSet = renderState->getRenderPass()->getMatrixSet(); @@ -806,332 +752,87 @@ void ReflectionProbe::setPreviewMatParameters(SceneRenderState* renderState, Bas matParams->setSafe(invViewMat, worldToCameraXfm); } -LinearColorF ReflectionProbe::decodeSH(Point3F normal) -{ - float x = normal.x; - float y = normal.y; - float z = normal.z; - - LinearColorF l00 = mProbeInfo->mSHTerms[0]; - - LinearColorF l10 = mProbeInfo->mSHTerms[1]; - LinearColorF l11 = mProbeInfo->mSHTerms[2]; - LinearColorF l12 = mProbeInfo->mSHTerms[3]; - - LinearColorF l20 = mProbeInfo->mSHTerms[4]; - LinearColorF l21 = mProbeInfo->mSHTerms[5]; - LinearColorF l22 = mProbeInfo->mSHTerms[6]; - LinearColorF l23 = mProbeInfo->mSHTerms[7]; - LinearColorF l24 = mProbeInfo->mSHTerms[8]; - - LinearColorF result = ( - l00 * mProbeInfo->mSHConstants[0] + - - l12 * mProbeInfo->mSHConstants[1] * x + - l10 * mProbeInfo->mSHConstants[1] * y + - l11 * mProbeInfo->mSHConstants[1] * z + - - l20 * mProbeInfo->mSHConstants[2] * x*y + - l21 * mProbeInfo->mSHConstants[2] * y*z + - l22 * mProbeInfo->mSHConstants[3] * (3.0*z*z - 1.0) + - l23 * mProbeInfo->mSHConstants[2] * x*z + - l24 * mProbeInfo->mSHConstants[4] * (x*x - y*y) - ); - - return LinearColorF(mMax(result.red, 0), mMax(result.green, 0), mMax(result.blue, 0)); -} - -MatrixF ReflectionProbe::getSideMatrix(U32 side) -{ - // Standard view that will be overridden below. - VectorF vLookatPt(0.0f, 0.0f, 0.0f), vUpVec(0.0f, 0.0f, 0.0f), vRight(0.0f, 0.0f, 0.0f); - - switch (side) - { - case 0: // D3DCUBEMAP_FACE_POSITIVE_X: - vLookatPt = VectorF(1.0f, 0.0f, 0.0f); - vUpVec = VectorF(0.0f, 1.0f, 0.0f); - break; - case 1: // D3DCUBEMAP_FACE_NEGATIVE_X: - vLookatPt = VectorF(-1.0f, 0.0f, 0.0f); - vUpVec = VectorF(0.0f, 1.0f, 0.0f); - break; - case 2: // D3DCUBEMAP_FACE_POSITIVE_Y: - vLookatPt = VectorF(0.0f, 1.0f, 0.0f); - vUpVec = VectorF(0.0f, 0.0f, -1.0f); - break; - case 3: // D3DCUBEMAP_FACE_NEGATIVE_Y: - vLookatPt = VectorF(0.0f, -1.0f, 0.0f); - vUpVec = VectorF(0.0f, 0.0f, 1.0f); - break; - case 4: // D3DCUBEMAP_FACE_POSITIVE_Z: - vLookatPt = VectorF(0.0f, 0.0f, 1.0f); - vUpVec = VectorF(0.0f, 1.0f, 0.0f); - break; - case 5: // D3DCUBEMAP_FACE_NEGATIVE_Z: - vLookatPt = VectorF(0.0f, 0.0f, -1.0f); - vUpVec = VectorF(0.0f, 1.0f, 0.0f); - break; - } - - // create camera matrix - VectorF cross = mCross(vUpVec, vLookatPt); - cross.normalizeSafe(); - - MatrixF rotMat(true); - rotMat.setColumn(0, cross); - rotMat.setColumn(1, vLookatPt); - rotMat.setColumn(2, vUpVec); - //rotMat.inverse(); - - return rotMat; -} - -F32 ReflectionProbe::harmonics(U32 termId, Point3F normal) -{ - F32 x = normal.x; - F32 y = normal.y; - F32 z = normal.z; - - switch(termId) - { - case 0: - return 1.0; - case 1: - return y; - case 2: - return z; - case 3: - return x; - case 4: - return x*y; - case 5: - return y*z; - case 6: - return 3.0*z*z - 1.0; - case 7: - return x*z; - default: - return x*x - y*y; - } -} - -LinearColorF ReflectionProbe::sampleSide(U32 termindex, U32 sideIndex) -{ - MatrixF sideRot = getSideMatrix(sideIndex); - - LinearColorF result = LinearColorF::ZERO; - F32 divider = 0; - - for (int y = 0; ysampleTexel(y, x); - texel = LinearColorF(mMax(texel.red, minBrightness), mMax(texel.green, minBrightness), mMax(texel.blue, minBrightness)) * Con::getFloatVariable("$pref::GI::Cubemap_Gain", 1.5); - - Point3F dir; - sideRot.mulP(normal, &dir); - - result += texel * harmonics(termindex,dir) * -normal.z; - divider += -normal.z; - } - } - - result /= divider; - - return result; -} - -// -//SH Calculations -// From http://sunandblackcat.com/tipFullView.php?l=eng&topicid=32&topic=Spherical-Harmonics-From-Cube-Texture -// With shader decode logic from https://github.com/nicknikolov/cubemap-sh -void ReflectionProbe::calculateSHTerms() -{ - if (!mCubemap || !mCubemap->mCubemap) - return; - - const VectorF cubemapFaceNormals[6] = - { - // D3DCUBEMAP_FACE_POSITIVE_X: - VectorF(1.0f, 0.0f, 0.0f), - // D3DCUBEMAP_FACE_NEGATIVE_X: - VectorF(-1.0f, 0.0f, 0.0f), - // D3DCUBEMAP_FACE_POSITIVE_Y: - VectorF(0.0f, 1.0f, 0.0f), - // D3DCUBEMAP_FACE_NEGATIVE_Y: - VectorF(0.0f, -1.0f, 0.0f), - // D3DCUBEMAP_FACE_POSITIVE_Z: - VectorF(0.0f, 0.0f, 1.0f), - // D3DCUBEMAP_FACE_NEGATIVE_Z: - VectorF(0.0f, 0.0f, -1.0f), - }; - - mCubemapResolution = mCubemap->mCubemap->getSize(); - - for (U32 i = 0; i < 6; i++) - { - mCubeFaceBitmaps[i] = new GBitmap(mCubemapResolution, mCubemapResolution, false, GFXFormatR8G8B8); - } - - //If we fail to parse the cubemap for whatever reason, we really can't continue - if (!CubemapSaver::getBitmaps(mCubemap->mCubemap, GFXFormatR8G8B8, mCubeFaceBitmaps)) - return; - - //Set up our constants - F32 L0 = Con::getFloatVariable("$pref::GI::SH_Term_L0", 1.0f); - F32 L1 = Con::getFloatVariable("$pref::GI::SH_Term_L1", 1.8f); - F32 L2 = Con::getFloatVariable("$pref::GI::SH_Term_L2", 0.83f); - F32 L2m2_L2m1_L21 = Con::getFloatVariable("$pref::GI::SH_Term_L2m2", 2.9f); - F32 L20 = Con::getFloatVariable("$pref::GI::SH_Term_L20", 0.58f); - F32 L22 = Con::getFloatVariable("$pref::GI::SH_Term_L22", 1.1f); - - mProbeInfo->mSHConstants[0] = L0; - mProbeInfo->mSHConstants[1] = L1; - mProbeInfo->mSHConstants[2] = L2 * L2m2_L2m1_L21; - mProbeInfo->mSHConstants[3] = L2 * L20; - mProbeInfo->mSHConstants[4] = L2 * L22; - - for (U32 i = 0; i < 9; i++) - { - //Clear it, just to be sure - mProbeInfo->mSHTerms[i] = LinearColorF(0.f, 0.f, 0.f); - - //Now, encode for each side - mProbeInfo->mSHTerms[i] = sampleSide(i, 0); //POS_X - mProbeInfo->mSHTerms[i] += sampleSide(i, 1); //NEG_X - mProbeInfo->mSHTerms[i] += sampleSide(i, 2); //POS_Y - mProbeInfo->mSHTerms[i] += sampleSide(i, 3); //NEG_Y - mProbeInfo->mSHTerms[i] += sampleSide(i, 4); //POS_Z - mProbeInfo->mSHTerms[i] += sampleSide(i, 5); //NEG_Z - - //Average - mProbeInfo->mSHTerms[i] /= 6; - } - - for (U32 i = 0; i < 6; i++) - SAFE_DELETE(mCubeFaceBitmaps[i]); - - bool mExportSHTerms = false; - if (mExportSHTerms) - { - for (U32 f = 0; f < 6; f++) - { - char fileName[256]; - dSprintf(fileName, 256, "%s%s_DecodedFaces_%d.png", mReflectionPath.c_str(), - mProbeUniqueID.c_str(), f); - - LinearColorF color = decodeSH(cubemapFaceNormals[f]); - - FileStream stream; - if (stream.open(fileName, Torque::FS::File::Write)) - { - GBitmap bitmap(mCubemapResolution, mCubemapResolution, false, GFXFormatR8G8B8); - - bitmap.fill(color.toColorI()); - - bitmap.writeBitmap("png", stream); - } - } - - for (U32 f = 0; f < 9; f++) - { - char fileName[256]; - dSprintf(fileName, 256, "%s%s_SHTerms_%d.png", mReflectionPath.c_str(), - mProbeUniqueID.c_str(), f); - - LinearColorF color = mProbeInfo->mSHTerms[f]; - - FileStream stream; - if (stream.open(fileName, Torque::FS::File::Write)) - { - GBitmap bitmap(mCubemapResolution, mCubemapResolution, false, GFXFormatR8G8B8); - - bitmap.fill(color.toColorI()); - - bitmap.writeBitmap("png", stream); - } - } - } -} - -F32 ReflectionProbe::texelSolidAngle(F32 aU, F32 aV, U32 width, U32 height) -{ - // transform from [0..res - 1] to [- (1 - 1 / res) .. (1 - 1 / res)] - // ( 0.5 is for texel center addressing) - const F32 U = (2.0 * (aU + 0.5) / width) - 1.0; - const F32 V = (2.0 * (aV + 0.5) / height) - 1.0; - - // shift from a demi texel, mean 1.0 / size with U and V in [-1..1] - const F32 invResolutionW = 1.0 / width; - const F32 invResolutionH = 1.0 / height; - - // U and V are the -1..1 texture coordinate on the current face. - // get projected area for this texel - const F32 x0 = U - invResolutionW; - const F32 y0 = V - invResolutionH; - const F32 x1 = U + invResolutionW; - const F32 y1 = V + invResolutionH; - const F32 angle = areaElement(x0, y0) - areaElement(x0, y1) - areaElement(x1, y0) + areaElement(x1, y1); - - return angle; -} - -F32 ReflectionProbe::areaElement(F32 x, F32 y) -{ - return mAtan2(x * y, (F32)mSqrt(x * x + y * y + 1.0)); -} - DefineEngineMethod(ReflectionProbe, postApply, void, (), , "A utility method for forcing a network update.\n") { object->inspectPostApply(); } +String ReflectionProbe::getPrefilterMapPath() +{ + if (mReflectionPath.isEmpty() || 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 ""; + } + + char fileName[256]; + dSprintf(fileName, 256, "%s%s_Prefilter.DDS", mReflectionPath.c_str(), mProbeUniqueID.c_str()); + + return fileName; +} + +String ReflectionProbe::getIrradianceMapPath() +{ + if (mReflectionPath.isEmpty() || 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 ""; + } + + char fileName[256]; + dSprintf(fileName, 256, "%s%s_Irradiance.DDS", mReflectionPath.c_str(), mProbeUniqueID.c_str()); + + return fileName; +} + void ReflectionProbe::bake(String outputPath, S32 resolution) { GFXDEBUGEVENT_SCOPE(ReflectionProbe_Bake, ColorI::WHITE); + Con::warnf("ReflectionProbe::bake() - Beginning bake!"); + + U32 startMSTime = Platform::getRealMilliseconds(); + PostEffect *preCapture = dynamic_cast(Sim::findObject("AL_PreCapture")); PostEffect *deferredShading = dynamic_cast(Sim::findObject("AL_DeferredShading")); if (preCapture) - preCapture->enable(); + { + preCapture->setShaderConst("$radius",String::ToString(mRadius)); + preCapture->setShaderConst("$captureRez", String::ToString(F32(resolution))); + preCapture->enable(); + } if (deferredShading) deferredShading->disable(); - //if (mReflectionModeType == StaticCubemap || mReflectionModeType == BakedCubemap || mReflectionModeType == SkyLight) - { - if (!mCubemap) - { - mCubemap = new CubemapData(); - mCubemap->registerObject(); - } - } + GFXCubemapHandle sceneCaptureCubemap; if (mReflectionModeType == DynamicCubemap && mDynamicCubemap.isNull()) { //mCubemap->createMap(); mDynamicCubemap = GFX->createCubemap(); - mDynamicCubemap->initDynamic(resolution, GFXFormatR8G8B8); + mDynamicCubemap->initDynamic(resolution, GFXFormatB8G8R8A8); + + sceneCaptureCubemap = mDynamicCubemap; } else if (mReflectionModeType != DynamicCubemap) { - if (mReflectionPath.isEmpty() || !mPersistentId) + //Prep our bake path + if (mReflectionPath.isEmpty()) { - if (!mPersistentId) - mPersistentId = getOrCreatePersistentId(); - - mReflectionPath = outputPath.c_str(); - - mProbeUniqueID = std::to_string(mPersistentId->getUUID().getHash()).c_str(); + Con::errorf("ReflectionProbe::bake() - Unable to bake our captures because probe doesn't have a path set"); + return; } + + if (mProbeUniqueID.isEmpty()) + { + Con::errorf("ReflectionProbe::bake() - Unable to bake our captures because probe doesn't have a unique ID set"); + return; + } + + sceneCaptureCubemap = GFX->createCubemap(); + sceneCaptureCubemap->initDynamic(resolution, GFXFormatR8G8B8A8); + //sceneCaptureCubemap->initDynamic(resolution, GFXFormatR16G16B16A16F); } bool validCubemap = true; @@ -1149,15 +850,13 @@ void ReflectionProbe::bake(String outputPath, S32 resolution) for (U32 i = 0; i < 6; ++i) { GFXTexHandle blendTex; - blendTex.set(resolution, resolution, GFXFormatR8G8B8A8, &GFXRenderTargetProfile, ""); + blendTex.set(resolution, resolution, GFXFormatR16G16B16A16, &GFXRenderTargetProfile, ""); - GFXTextureTargetRef mBaseTarget = GFX->allocRenderToTextureTarget(); + GFXTextureTargetRef baseTarget = GFX->allocRenderToTextureTarget(); GFX->clearTextureStateImmediate(0); - if (mReflectionModeType == DynamicCubemap) - mBaseTarget->attachTexture(GFXTextureTarget::Color0, mDynamicCubemap, i); - else - mBaseTarget->attachTexture(GFXTextureTarget::Color0, blendTex); + + baseTarget->attachTexture(GFXTextureTarget::Color0, sceneCaptureCubemap, i); // Standard view that will be overridden below. VectorF vLookatPt(0.0f, 0.0f, 0.0f), vUpVec(0.0f, 0.0f, 0.0f), vRight(0.0f, 0.0f, 0.0f); @@ -1198,7 +897,7 @@ void ReflectionProbe::bake(String outputPath, S32 resolution) matView.setColumn(0, cross); matView.setColumn(1, vLookatPt); matView.setColumn(2, vUpVec); - matView.setPosition(getPosition()); + matView.setPosition(getPosition()+mProbePosOffset); matView.inverse(); // set projection to 90 degrees vertical and horizontal @@ -1209,11 +908,11 @@ void ReflectionProbe::bake(String outputPath, S32 resolution) MathUtils::makeFrustum(&left, &right, &top, &bottom, M_HALFPI_F, 1.0f, nearPlane); Frustum frustum(false, left, right, top, bottom, nearPlane, farDist); - renderFrame(&mBaseTarget, matView, frustum, StaticObjectType | StaticShapeObjectType & EDITOR_RENDER_TYPEMASK, gCanvasClearColor); + renderFrame(&baseTarget, matView, frustum, StaticObjectType | StaticShapeObjectType & EDITOR_RENDER_TYPEMASK, gCanvasClearColor); - mBaseTarget->resolve(); + baseTarget->resolve(); - mCubemap->setCubeFaceTexture(i, blendTex); + //mStaticCubemap->setCubeFaceTexture(i, blendTex); } /*if (mReflectionModeType != DynamicCubemap) @@ -1246,28 +945,57 @@ void ReflectionProbe::bake(String outputPath, S32 resolution) } }*/ - if (mReflectionModeType != DynamicCubemap && validCubemap) + if (sceneCaptureCubemap.isValid()) { - if (mCubemap->mCubemap) - mCubemap->updateFaces(); - else - mCubemap->createMap(); - - char fileName[256]; - dSprintf(fileName, 256, "%s%s.DDS", mReflectionPath.c_str(), mProbeUniqueID.c_str()); - - CubemapSaver::save(mCubemap->mCubemap, fileName); - - if (!Platform::isFile(fileName)) - { - validCubemap = false; //if we didn't save right, just - Con::errorf("Failed to properly save out the skylight baked cubemap!"); - } - + validCubemap = true; mDirty = false; } + else + { + validCubemap = false; + } - //calculateSHTerms(); + /*if (mReflectionModeType != DynamicCubemap && validCubemap) + { + if (mStaticCubemap->mCubemap) + mStaticCubemap->updateFaces(); + else + mStaticCubemap->createMap(); + + if (mStaticCubemap->mCubemap.isNull()) + validCubemap = false; + + mDirty = false; + }*/ + + //Now, save out the maps + //create irridiance cubemap + if (validCubemap) + { + bool se = isServerObject(); + + //Just to ensure we're prepped for the generation + createClientResources(); + + //Prep it with whatever resolution we've dictated for our bake + mIrridianceMap->mCubemap->initDynamic(resolution, GFXFormatR8G8B8A8); + mPrefilterMap->mCubemap->initDynamic(resolution, GFXFormatR8G8B8A8); + + //IBLUtilities::GenerateAndSaveIrradianceMap(getIrradianceMapPath(), resolution, sceneCaptureCubemap, mIrridianceMap->mCubemap); + //IBLUtilities::GenerateAndSavePrefilterMap(getPrefilterMapPath(), resolution, sceneCaptureCubemap, mPrefilterMipLevels, mPrefilterMap->mCubemap); + + GFXTextureTargetRef renderTarget = GFX->allocRenderToTextureTarget(false); + + IBLUtilities::GenerateIrradianceMap(renderTarget, sceneCaptureCubemap, mIrridianceMap->mCubemap); + IBLUtilities::GeneratePrefilterMap(renderTarget, sceneCaptureCubemap, mPrefilterMipLevels, mPrefilterMap->mCubemap); + + IBLUtilities::SaveCubeMap(getIrradianceMapPath(), mIrridianceMap->mCubemap); + IBLUtilities::SaveCubeMap(getPrefilterMapPath(), mPrefilterMap->mCubemap); + } + else + { + Con::errorf("ReflectionProbe::bake() - Didn't generate a valid scene capture cubemap, unable to generate prefilter and irradiance maps!"); + } ReflectionProbe::smRenderReflectionProbes = probeRenderState; setMaskBits(-1); @@ -1276,10 +1004,21 @@ void ReflectionProbe::bake(String outputPath, S32 resolution) preCapture->disable(); if (deferredShading) deferredShading->enable(); + + U32 endMSTime = Platform::getRealMilliseconds(); + F32 diffTime = F32(endMSTime - startMSTime); + + Con::warnf("ReflectionProbe::bake() - Finished bake! Took %g milliseconds", diffTime); } DefineEngineMethod(ReflectionProbe, Bake, void, (String outputPath, S32 resolution), ("", 256), "@brief returns true if control object is inside the fog\n\n.") { - object->bake(outputPath, resolution); + ReflectionProbe *clientProbe = (ReflectionProbe*)object->getClientObject(); + + if (clientProbe) + { + clientProbe->bake(outputPath, resolution); + } + //object->bake(outputPath, resolution); } \ No newline at end of file diff --git a/Engine/source/T3D/lighting/reflectionProbe.h b/Engine/source/T3D/lighting/reflectionProbe.h index 1fa3fad8a..3baa08239 100644 --- a/Engine/source/T3D/lighting/reflectionProbe.h +++ b/Engine/source/T3D/lighting/reflectionProbe.h @@ -78,7 +78,7 @@ public: DynamicCubemap = 5, }; -private: +protected: // Networking masks // We need to implement a mask specifically to handle @@ -115,24 +115,24 @@ private: //Indirect Lighting Contribution stuff IndrectLightingModeType mIndrectLightingModeType; - LinearColorF mAmbientColor; - LinearColorF mSphericalHarmonics; //Reflection Contribution stuff ReflectionModeType mReflectionModeType; F32 mRadius; + Point3F mProbePosOffset; + bool mEditPosOffset; String mCubemapName; - CubemapData *mCubemap; + CubemapData *mStaticCubemap; GFXCubemapHandle mDynamicCubemap; bool mUseCubemap; //irridiance resources - GFXCubemapHandle mIrridianceMap; + CubemapData *mIrridianceMap; //prefilter resources - GFXCubemapHandle mPrefilterMap; + CubemapData *mPrefilterMap; U32 mPrefilterMipLevels; U32 mPrefilterSize; @@ -190,17 +190,12 @@ public: static bool _setEnabled(void *object, const char *index, const char *data); static bool _doBake(void *object, const char *index, const char *data); - - static bool protectedSetSHTerms(void *object, const char *index, const char *data); - static bool protectedSetSHConsts(void *object, const char *index, const char *data); + static bool _toggleEditPosOffset(void *object, const char *index, const char *data); // Handle when we are added to the scene and removed from the scene bool onAdd(); void onRemove(); - virtual void writeFields(Stream &stream, U32 tabStop); - virtual bool writeField(StringTableEntry fieldname, const char *value); - // Override this so that we can dirty the network flag when it is called void setTransform(const MatrixF &mat); @@ -240,29 +235,9 @@ public: void setPreviewMatParameters(SceneRenderState* renderState, BaseMatInstance* mat); - //Spherical Harmonics - void calculateSHTerms(); - F32 texelSolidAngle(F32 aU, F32 aV, U32 width, U32 height); - F32 areaElement(F32 x, F32 y); - - // - MatrixF getSideMatrix(U32 side); - LinearColorF decodeSH(Point3F normal); - - // - void calcDirectionVector(U32 face, U32 face_x, U32 face_y, F32& out_x, F32& out_y, F32& out_z) const; - F32 calcSolidAngle(U32 face, U32 x, U32 y) const; - LinearColorF sampleFace(U32 face, F32 s, F32 t); - LinearColorF readTexelClamped(U32 face, U32 x, U32 y); - void computeTexCoords(F32 x, F32 y, F32 z, U32& out_face, F32& out_s, F32& out_t); - LinearColorF readTexel(U32 face, U32 x, U32 y) const; - - // - LinearColorF sampleSide(U32 termindex, U32 sideIndex); - F32 harmonics(U32 termId, Point3F normal); - - //Baking + String getPrefilterMapPath(); + String getIrradianceMapPath(); void bake(String outputPath, S32 resolution); }; diff --git a/Engine/source/T3D/lighting/skylight.cpp b/Engine/source/T3D/lighting/skylight.cpp index b6ca9120f..5d25283ff 100644 --- a/Engine/source/T3D/lighting/skylight.cpp +++ b/Engine/source/T3D/lighting/skylight.cpp @@ -59,7 +59,6 @@ extern bool gEditingMission; extern ColorI gCanvasClearColor; bool Skylight::smRenderSkylights = true; -bool Skylight::smRenderPreviewProbes = true; IMPLEMENT_CO_NETOBJECT_V1(Skylight); @@ -74,54 +73,16 @@ ConsoleDocClass(Skylight, "See the C++ code for implementation details.\n\n" "@ingroup Examples\n"); -ImplementEnumType(SkylightReflectionModeEnum, - "Type of mesh data available in a shape.\n" - "@ingroup gameObjects") -{ Skylight::StaticCubemap, "Static Cubemap", "Uses a static CubemapData" }, -{ Skylight::BakedCubemap, "Baked Cubemap", "Uses a cubemap baked from the probe's current position" }, - EndImplementEnumType; - //----------------------------------------------------------------------------- // Object setup and teardown //----------------------------------------------------------------------------- -Skylight::Skylight() +Skylight::Skylight() : ReflectionProbe() { - // Flag this object so that it will always - // be sent across the network to clients - mNetFlags.set(Ghostable | ScopeAlways); - mTypeMask = LightObjectType | MarkerObjectType; - - mReflectionModeType = StaticCubemap; - - mEnabled = true; - mBake = false; - mDirty = false; - - mCubemap = NULL; - mReflectionPath = ""; - mProbeUniqueID = ""; - - mEditorShapeInst = NULL; - mEditorShape = NULL; - - mIrridianceMap = NULL; - mPrefilterMap = NULL; - mBrdfTexture = NULL; - mResourcesCreated = false; - mPrefilterSize = 512; - mPrefilterMipLevels = 6; - - mProbeInfo = new ProbeInfo(); } Skylight::~Skylight() { - if (mEditorShapeInst) - SAFE_DELETE(mEditorShapeInst); - - if (mReflectionModeType != StaticCubemap && mCubemap) - mCubemap->deleteObject(); } //----------------------------------------------------------------------------- @@ -129,34 +90,6 @@ Skylight::~Skylight() //----------------------------------------------------------------------------- void Skylight::initPersistFields() { - addGroup("Rendering"); - addProtectedField("enabled", TypeBool, Offset(mEnabled, Skylight), - &_setEnabled, &defaultProtectedGetFn, "Regenerate Voxel Grid"); - endGroup("Rendering"); - - addGroup("Reflection"); - //addField("ReflectionMode", TypeSkylightReflectionModeEnum, Offset(mReflectionModeType, Skylight), - // "The type of mesh data to use for collision queries."); - - //addField("reflectionPath", TypeImageFilename, Offset(mReflectionPath, Skylight), - // "The type of mesh data to use for collision queries."); - - addField("StaticCubemap", TypeCubemapName, Offset(mCubemapName, Skylight), "Cubemap used instead of reflection texture if fullReflect is off."); - - //addProtectedField("Bake", TypeBool, Offset(mBake, Skylight), - // &_doBake, &defaultProtectedGetFn, "Regenerate Voxel Grid", AbstractClassRep::FieldFlags::FIELD_ComponentInspectors); - endGroup("Reflection"); - - Con::addVariable("$Light::renderSkylights", TypeBool, &Skylight::smRenderSkylights, - "Toggles rendering of light frustums when the light is selected in the editor.\n\n" - "@note Only works for shadow mapped lights.\n\n" - "@ingroup Lighting"); - - Con::addVariable("$Light::renderPreviewProbes", TypeBool, &Skylight::smRenderPreviewProbes, - "Toggles rendering of light frustums when the light is selected in the editor.\n\n" - "@note Only works for shadow mapped lights.\n\n" - "@ingroup Lighting"); - // SceneObject already handles exposing the transform Parent::initPersistFields(); } @@ -172,64 +105,16 @@ void Skylight::inspectPostApply() setMaskBits(-1); } -bool Skylight::_setEnabled(void *object, const char *index, const char *data) -{ - Skylight* probe = reinterpret_cast< Skylight* >(object); - - probe->mEnabled = dAtob(data); - probe->setMaskBits(-1); - - return true; -} - -bool Skylight::_doBake(void *object, const char *index, const char *data) -{ - Skylight* probe = reinterpret_cast< Skylight* >(object); - - if (probe->mDirty) - probe->bake(probe->mReflectionPath, 256); - - return false; -} - bool Skylight::onAdd() { if (!Parent::onAdd()) return false; - mObjBox.minExtents.set(-1, -1, -1); - mObjBox.maxExtents.set(1, 1, 1); - - // Skip our transform... it just dirties mask bits. - Parent::setTransform(mObjToWorld); - - resetWorldBox(); - - // Add this object to the scene - addToScene(); - - if (isServerObject()) - { - if (!mPersistentId) - mPersistentId = getOrCreatePersistentId(); - - mProbeUniqueID = std::to_string(mPersistentId->getUUID().getHash()).c_str(); - } - - // Refresh this object's material (if any) - if (isClientObject()) - updateMaterial(); - - setMaskBits(-1); - return true; } void Skylight::onRemove() { - // Remove this object from the scene - removeFromScene(); - Parent::onRemove(); } @@ -250,39 +135,6 @@ U32 Skylight::packUpdate(NetConnection *conn, U32 mask, BitStream *stream) // Allow the Parent to get a crack at writing its info U32 retMask = Parent::packUpdate(conn, mask, stream); - if (stream->writeFlag(mask & InitialUpdateMask)) - { - //initial work, just in case? - } - - // Write our transform information - if (stream->writeFlag(mask & TransformMask)) - { - mathWrite(*stream, getTransform()); - mathWrite(*stream, getScale()); - } - - /*if (stream->writeFlag(mask & BakeInfoMask)) - { - stream->write(mReflectionPath); - stream->write(mProbeUniqueID); - }*/ - - if (stream->writeFlag(mask & EnabledMask)) - { - stream->writeFlag(mEnabled); - } - - /*if (stream->writeFlag(mask & ModeMask)) - { - stream->write((U32)mReflectionModeType); - }*/ - - if (stream->writeFlag(mask & CubemapMask)) - { - stream->write(mCubemapName); - } - return retMask; } @@ -290,72 +142,6 @@ void Skylight::unpackUpdate(NetConnection *conn, BitStream *stream) { // Let the Parent read any info it sent Parent::unpackUpdate(conn, stream); - - if (stream->readFlag()) - { - //some initial work? - createGeometry(); - } - - if (stream->readFlag()) // TransformMask - { - mathRead(*stream, &mObjToWorld); - mathRead(*stream, &mObjScale); - - setTransform(mObjToWorld); - } - - /*if (stream->readFlag()) // BakeInfoMask - { - stream->read(&mReflectionPath); - stream->read(&mProbeUniqueID); - }*/ - - if (stream->readFlag()) // EnabledMask - { - mEnabled = stream->readFlag(); - } - - bool isMaterialDirty = false; - - /*if (stream->readFlag()) // ModeMask - { - U32 reflectModeType = StaticCubemap; - stream->read(&reflectModeType); - mReflectionModeType = (ReflectionModeType)reflectModeType; - - isMaterialDirty = true; - }*/ - - if (stream->readFlag()) // CubemapMask - { - stream->read(&mCubemapName); - - isMaterialDirty = true; - } - - updateProbeParams(); - - if(isMaterialDirty) - updateMaterial(); -} - -void Skylight::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()); - } } //----------------------------------------------------------------------------- @@ -367,18 +153,12 @@ void Skylight::updateProbeParams() if (mProbeInfo == nullptr) return; - mProbeInfo->mIntensity = 1; - - mProbeInfo->mAmbient = LinearColorF(0, 0, 0, 0); + Parent::updateProbeParams(); mProbeInfo->mProbeShapeType = ProbeInfo::Sphere; mProbeInfo->setPosition(getPosition()); - //Update the bounds - mObjBox.minExtents.set(-1, -1, -1); - mObjBox.maxExtents.set(1, 1, 1); - // Skip our transform... it just dirties mask bits. Parent::setTransform(mObjToWorld); @@ -395,197 +175,12 @@ void Skylight::updateProbeParams() setGlobalBounds(); + mProbeInfo->mAmbient = LinearColorF(1, 1, 1, 1); + mProbeInfo->mIsSkylight = true; mProbeInfo->mScore = -1.0f; //sky comes first } -bool Skylight::createClientResources() -{ - //irridiance resources - mIrridianceMap = GFX->createCubemap(); - mIrridianceMap->initDynamic(128, GFXFormatR16G16B16A16F, 1); - - //prefilter resources - we share the irridiance stateblock - mPrefilterMap = GFX->createCubemap(); - mPrefilterMap->initDynamic(mPrefilterSize, GFXFormatR16G16B16A16F, mPrefilterMipLevels); - - //brdf lookup resources - //make the brdf lookup texture the same size as the prefilter texture - mBrdfTexture = TEXMGR->createTexture(mPrefilterSize, mPrefilterSize, GFXFormatR16G16B16A16F, &GFXRenderTargetProfile, 1, 0); - - mResourcesCreated = true; - - return true; -} - -void Skylight::updateMaterial() -{ - if ((mReflectionModeType == BakedCubemap) && !mProbeUniqueID.isEmpty()) - { - bool validCubemap = true; - - char fileName[256]; - dSprintf(fileName, 256, "%s%s.DDS", mReflectionPath.c_str(), mProbeUniqueID.c_str()); - - Vector fileNames; - - if (Platform::isFile(fileName)) - { - if (!mCubemap) - { - mCubemap = new CubemapData(); - mCubemap->registerObject(); - } - - mCubemap->setCubemapFile(FileName(fileName)); - } - else - { - validCubemap = false; - } - - if (validCubemap) - { - if (mCubemap->mCubemap) - mCubemap->updateFaces(); - else - mCubemap->createMap(); - - mDirty = false; - - mProbeInfo->mCubemap = &mCubemap->mCubemap; - } - - /*for (U32 i = 0; i < 6; ++i) - { - char faceFile[256]; - dSprintf(faceFile, sizeof(faceFile), "%s%s_%i.png", mReflectionPath.c_str(), - mProbeUniqueID.c_str(), i); - - if (Platform::isFile(faceFile)) - { - fileNames.push_back(FileName(faceFile)); - } - else - { - validCubemap = false; - break; - } - } - - if (validCubemap) - { - if (!mCubemap) - { - mCubemap = new CubemapData(); - mCubemap->registerObject(); - } - - for(U32 i=0; i < 6; i++) - mCubemap->setCubeFaceFile(i, fileNames[i]); - - mCubemap->createMap(); - mCubemap->updateFaces(); - - mProbeInfo->mCubemap = &mCubemap->mCubemap; - }*/ - } - else if (mReflectionModeType == StaticCubemap && !mCubemapName.isEmpty()) - { - Sim::findObject(mCubemapName, mCubemap); - - if (!mCubemap) - return; - - if (mCubemap->mCubemap) - mCubemap->updateFaces(); - else - mCubemap->createMap(); - - mProbeInfo->mCubemap = &mCubemap->mCubemap; - } - - //calculateSHTerms(); - - generateTextures(); - - //Now that the work is done, assign the relevent maps - if (mPrefilterMap.isValid()) - { - mProbeInfo->mCubemap = &mPrefilterMap; - mProbeInfo->mIrradianceCubemap = &mIrridianceMap; - mProbeInfo->mBRDFTexture = &mBrdfTexture; - } -} - -void Skylight::generateTextures() -{ - if (!mCubemap) - return; - - if (!mResourcesCreated) - { - if (!createClientResources()) - { - Con::errorf("SkyLight::createIrridianceMap: Failed to create resources"); - return; - } - } - - //GFXTransformSaver saver; - - GFXTextureTargetRef renderTarget = GFX->allocRenderToTextureTarget(false); - - IBLUtilities::GenerateIrradianceMap(renderTarget, mCubemap->mCubemap, mIrridianceMap); - - //Write it out - char fileName[256]; - dSprintf(fileName, 256, "levels/test/irradiance.DDS"); - - CubemapSaver::save(mIrridianceMap, fileName); - - if (!Platform::isFile(fileName)) - { - Con::errorf("Failed to properly save out the skylight baked irradiance!"); - } - - //create prefilter cubemap (radiance) - IBLUtilities::GeneratePrefilterMap(renderTarget, mCubemap->mCubemap, mPrefilterMipLevels, mPrefilterMap); - - //Write it out - fileName[256]; - dSprintf(fileName, 256, "levels/test/prefilter.DDS"); - - CubemapSaver::save(mPrefilterMap, fileName); - - if (!Platform::isFile(fileName)) - { - Con::errorf("Failed to properly save out the skylight baked irradiance!"); - } - - //create brdf lookup - IBLUtilities::GenerateBRDFTexture(mBrdfTexture); - - /*FileStream fs; - if (fs.open("levels/test/brdf.DDS", Torque::FS::File::Write)) - { - // Read back the render target, dxt compress it, and write it to disk. - GBitmap brdfBmp(mBrdfTexture.getHeight(), mBrdfTexture.getWidth(), false, GFXFormatR8G8B8A8); - mBrdfTexture.copyToBmp(&brdfBmp); - - brdfBmp.extrudeMipLevels(); - - DDSFile *brdfDDS = DDSFile::createDDSFileFromGBitmap(&brdfBmp); - ImageUtil::ddsCompress(brdfDDS, GFXFormatBC1); - - // Write result to file stream - brdfDDS->write(fs); - - delete brdfDDS; - } - fs.close();*/ -} - void Skylight::prepRenderImage(SceneRenderState *state) { if (!mEnabled || !Skylight::smRenderSkylights) @@ -606,7 +201,7 @@ void Skylight::prepRenderImage(SceneRenderState *state) PROBEMGR->registerSkylight(mProbeInfo, this); - if (Skylight::smRenderPreviewProbes && gEditingMission && mEditorShapeInst && mCubemap != nullptr) + if (Skylight::smRenderPreviewProbes && gEditingMission && mEditorShapeInst && mPrefilterMap != nullptr) { GFXTransformSaver saver; @@ -670,230 +265,11 @@ void Skylight::prepRenderImage(SceneRenderState *state) void Skylight::setPreviewMatParameters(SceneRenderState* renderState, BaseMatInstance* mat) { - if (!mat->getFeatures().hasFeature(MFT_isDeferred)) - return; - - //Set up the params - MaterialParameters *matParams = mat->getMaterialParameters(); - - //Get the deferred render target - NamedTexTarget* deferredTexTarget = NamedTexTarget::find("deferred"); - - GFXTextureObject *deferredTexObject = deferredTexTarget->getTexture(); - if (!deferredTexObject) - return; - - GFX->setTexture(0, deferredTexObject); - - //Set the cubemap - GFX->setCubeTexture(1, mCubemap->mCubemap); - - //Set the invViewMat - MatrixSet &matrixSet = renderState->getRenderPass()->getMatrixSet(); - const MatrixF &worldToCameraXfm = matrixSet.getWorldToCamera(); - - MaterialParameterHandle *invViewMat = mat->getMaterialParameterHandle("$invViewMat"); - - matParams->setSafe(invViewMat, worldToCameraXfm); + Parent::setPreviewMatParameters(renderState, mat); } DefineEngineMethod(Skylight, postApply, void, (), , "A utility method for forcing a network update.\n") { object->inspectPostApply(); -} - -void Skylight::bake(String outputPath, S32 resolution) -{ - GFXDEBUGEVENT_SCOPE(Skylight_Bake, ColorI::WHITE); - - PostEffect *preCapture = dynamic_cast(Sim::findObject("AL_PreCapture")); - PostEffect *deferredShading = dynamic_cast(Sim::findObject("AL_DeferredShading")); - if (preCapture) - preCapture->enable(); - if (deferredShading) - deferredShading->disable(); - - //if (mReflectionModeType == StaticCubemap || mReflectionModeType == BakedCubemap || mReflectionModeType == SkyLight) - { - if (!mCubemap) - { - mCubemap = new CubemapData(); - mCubemap->registerObject(); - } - } - - if (mReflectionModeType == BakedCubemap) - { - if (mReflectionPath.isEmpty() || !mPersistentId) - { - if (!mPersistentId) - mPersistentId = getOrCreatePersistentId(); - - mReflectionPath = outputPath.c_str(); - - mProbeUniqueID = std::to_string(mPersistentId->getUUID().getHash()).c_str(); - } - } - - bool validCubemap = true; - - // Save the current transforms so we can restore - // it for child control rendering below. - GFXTransformSaver saver; - - //bool saveEditingMission = gEditingMission; - //gEditingMission = false; - - //Set this to true to use the prior method where it goes through the SPT_Reflect path for the bake - bool probeRenderState = Skylight::smRenderSkylights; - Skylight::smRenderSkylights = false; - for (U32 i = 0; i < 6; ++i) - { - GFXTexHandle blendTex; - blendTex.set(resolution, resolution, GFXFormatR8G8B8A8, &GFXRenderTargetProfile, ""); - - GFXTextureTargetRef mBaseTarget = GFX->allocRenderToTextureTarget(); - - GFX->clearTextureStateImmediate(0); - mBaseTarget->attachTexture(GFXTextureTarget::Color0, blendTex); - - // Standard view that will be overridden below. - VectorF vLookatPt(0.0f, 0.0f, 0.0f), vUpVec(0.0f, 0.0f, 0.0f), vRight(0.0f, 0.0f, 0.0f); - - switch (i) - { - case 0: // D3DCUBEMAP_FACE_POSITIVE_X: - vLookatPt = VectorF(1.0f, 0.0f, 0.0f); - vUpVec = VectorF(0.0f, 1.0f, 0.0f); - break; - case 1: // D3DCUBEMAP_FACE_NEGATIVE_X: - vLookatPt = VectorF(-1.0f, 0.0f, 0.0f); - vUpVec = VectorF(0.0f, 1.0f, 0.0f); - break; - case 2: // D3DCUBEMAP_FACE_POSITIVE_Y: - vLookatPt = VectorF(0.0f, 1.0f, 0.0f); - vUpVec = VectorF(0.0f, 0.0f, -1.0f); - break; - case 3: // D3DCUBEMAP_FACE_NEGATIVE_Y: - vLookatPt = VectorF(0.0f, -1.0f, 0.0f); - vUpVec = VectorF(0.0f, 0.0f, 1.0f); - break; - case 4: // D3DCUBEMAP_FACE_POSITIVE_Z: - vLookatPt = VectorF(0.0f, 0.0f, 1.0f); - vUpVec = VectorF(0.0f, 1.0f, 0.0f); - break; - case 5: // D3DCUBEMAP_FACE_NEGATIVE_Z: - vLookatPt = VectorF(0.0f, 0.0f, -1.0f); - vUpVec = VectorF(0.0f, 1.0f, 0.0f); - break; - } - - // create camera matrix - VectorF cross = mCross(vUpVec, vLookatPt); - cross.normalizeSafe(); - - MatrixF matView(true); - matView.setColumn(0, cross); - matView.setColumn(1, vLookatPt); - matView.setColumn(2, vUpVec); - matView.setPosition(getPosition()); - matView.inverse(); - - // set projection to 90 degrees vertical and horizontal - F32 left, right, top, bottom; - F32 nearPlane = 100.f; - F32 farDist = 10000.f; - - MathUtils::makeFrustum(&left, &right, &top, &bottom, M_HALFPI_F, 1.0f, nearPlane); - Frustum frustum(false, left, right, top, bottom, nearPlane, farDist); - - renderFrame(&mBaseTarget, matView, frustum, StaticObjectType | StaticShapeObjectType & EDITOR_RENDER_TYPEMASK, ColorI::RED); - - mBaseTarget->resolve(); - - mCubemap->setCubeFaceTexture(i, blendTex); - - char fileName[256]; - dSprintf(fileName, 256, "%s%s_%i.png", mReflectionPath.c_str(), - mProbeUniqueID.c_str(), i); - - FileStream stream; - if (!stream.open(fileName, Torque::FS::File::Write)) - { - Con::errorf("ReflectionProbe::bake(): Couldn't open cubemap face file fo writing " + String(fileName)); - if (preCapture) - preCapture->disable(); - if (deferredShading) - deferredShading->enable(); - return; - } - - GBitmap bitmap(blendTex->getWidth(), blendTex->getHeight(), false, GFXFormatR8G8B8); - blendTex->copyToBmp(&bitmap); - bitmap.writeBitmap("png", stream); - - if (Platform::isFile(fileName) && mCubemap) - { - mCubemap->setCubeFaceFile(i, FileName(fileName)); - } - else - { - validCubemap = false; - break; - } - - bitmap.deleteImage(); - } - - if (validCubemap) - { - if (mCubemap->mCubemap) - mCubemap->updateFaces(); - else - mCubemap->createMap(); - - char fileName[256]; - dSprintf(fileName, 256, "%s%s.DDS", mReflectionPath.c_str(), mProbeUniqueID.c_str()); - - CubemapSaver::save(mCubemap->mCubemap, fileName); - - if (!Platform::isFile(fileName)) - { - validCubemap = false; //if we didn't save right, just - Con::errorf("Failed to properly save out the skylight baked cubemap!"); - } - } - - if (validCubemap) - { - mDirty = false; - - //remove the temp files - for (U32 i = 0; i < 6; i++) - { - char fileName[256]; - dSprintf(fileName, 256, "%s%s_%i.png", mReflectionPath.c_str(), - mProbeUniqueID.c_str(), i); - - Platform::fileDelete(fileName); - } - } - - //calculateSHTerms(); - - Skylight::smRenderSkylights = probeRenderState; - setMaskBits(-1); - - if (preCapture) - preCapture->disable(); - - if (deferredShading) - deferredShading->enable(); -} - -DefineEngineMethod(Skylight, Bake, void, (String outputPath, S32 resolution), ("", 256), - "@brief returns true if control object is inside the fog\n\n.") -{ - object->bake(outputPath, resolution); } \ No newline at end of file diff --git a/Engine/source/T3D/lighting/skylight.h b/Engine/source/T3D/lighting/skylight.h index f71c2eeeb..9fc37334c 100644 --- a/Engine/source/T3D/lighting/skylight.h +++ b/Engine/source/T3D/lighting/skylight.h @@ -23,8 +23,8 @@ #ifndef SKYLIGHT_H #define SKYLIGHT_H -#ifndef _SCENEOBJECT_H_ -#include "scene/sceneObject.h" +#ifndef REFLECTIONPROBE_H +#include "T3D/lighting/reflectionProbe.h" #endif #ifndef _GFXVERTEXBUFFER_H_ #include "gfx/gfxVertexBuffer.h" @@ -57,83 +57,14 @@ class BaseMatInstance; // actual setup and rendering for you. //----------------------------------------------------------------------------- -class Skylight : public SceneObject +class Skylight : public ReflectionProbe { - typedef SceneObject Parent; - -public: - - enum IndrectLightingModeType - { - NoIndirect = 0, - AmbientColor = 1, - SphericalHarmonics = 2 - }; - - enum ReflectionModeType - { - StaticCubemap = 1, - BakedCubemap = 2 - }; + typedef ReflectionProbe Parent; private: - // Networking masks - // We need to implement a mask specifically to handle - // updating our transform from the server object to its - // client-side "ghost". We also need to implement a - // maks for handling editor updates to our properties - // (like material). - enum MaskBits - { - TransformMask = Parent::NextFreeMask << 0, - UpdateMask = Parent::NextFreeMask << 1, - EnabledMask = Parent::NextFreeMask << 2, - CubemapMask = Parent::NextFreeMask << 3, - ModeMask = Parent::NextFreeMask << 4, - RadiusMask = Parent::NextFreeMask << 5, - ShapeTypeMask = Parent::NextFreeMask << 6, - BakeInfoMask = Parent::NextFreeMask << 7, - NextFreeMask = Parent::NextFreeMask << 8 - }; - - bool mBake; - bool mEnabled; - bool mDirty; - - Resource mEditorShape; - TSShapeInstance* mEditorShapeInst; - - //-------------------------------------------------------------------------- - // Rendering variables - //-------------------------------------------------------------------------- - ProbeInfo* mProbeInfo; - - //Reflection Contribution stuff - ReflectionModeType mReflectionModeType; - - String mCubemapName; - CubemapData *mCubemap; - - String mReflectionPath; - String mProbeUniqueID; - - //Debug rendering + //Debug rendering static bool smRenderSkylights; - static bool smRenderPreviewProbes; - - //irridiance resources - GFXCubemapHandle mIrridianceMap; - - //prefilter resources - GFXCubemapHandle mPrefilterMap; - U32 mPrefilterMipLevels; - U32 mPrefilterSize; - - //brdflookup resources - shares the texture target with the prefilter - GFXTexHandle mBrdfTexture; - - bool mResourcesCreated; public: Skylight(); @@ -156,9 +87,6 @@ public: // from the server object to the client virtual void inspectPostApply(); - static bool _setEnabled(void *object, const char *index, const char *data); - static bool _doBake(void *object, const char *index, const char *data); - // Handle when we are added to the scene and removed from the scene bool onAdd(); void onRemove(); @@ -181,32 +109,12 @@ public: // minimizing texture, state, and shader switching by grouping objects that // use the same Materials. //-------------------------------------------------------------------------- - - // Create the geometry for rendering - void createGeometry(); - - bool createClientResources(); - - // Get the Material instance - void updateMaterial(); - - void generateTextures(); - 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); - - //Baking - void bake(String outputPath, S32 resolution); }; -typedef Skylight::IndrectLightingModeType SkylightIndrectLightingModeEnum; -DefineEnumType(SkylightIndrectLightingModeEnum); - -typedef Skylight::ReflectionModeType SkylightReflectionModeEnum; -DefineEnumType(SkylightReflectionModeEnum); - #endif // _Skylight_H_ \ No newline at end of file diff --git a/Engine/source/gfx/bitmap/cubemapSaver.h b/Engine/source/gfx/bitmap/cubemapSaver.h index f99886423..1361f75ba 100644 --- a/Engine/source/gfx/bitmap/cubemapSaver.h +++ b/Engine/source/gfx/bitmap/cubemapSaver.h @@ -33,7 +33,7 @@ namespace CubemapSaver { // save cubemap handle to a dds cubemap with optional compression - bool save(GFXCubemapHandle cubemap, const Torque::Path &path, GFXFormat compressionFormat = GFXFormat_FIRST); + bool save(GFXCubemapHandle cubemap, const Torque::Path &path, GFXFormat compressionFormat = GFXFormatR8G8B8A8); bool getBitmaps(GFXCubemapHandle cubemap, GFXFormat compressionFormat, GBitmap* faceBitmaps[6]); }; diff --git a/Engine/source/gfx/gfxEnums.h b/Engine/source/gfx/gfxEnums.h index 464e5fc59..f5c233990 100644 --- a/Engine/source/gfx/gfxEnums.h +++ b/Engine/source/gfx/gfxEnums.h @@ -496,7 +496,7 @@ enum GFXTextureTransformFlags // CodeReview: This number is used for the declaration of variables, but it // should *not* be used for any run-time purposes [7/2/2007 Pat] -#define TEXTURE_STAGE_COUNT 32 +#define TEXTURE_STAGE_COUNT 16 enum GFXSamplerState { diff --git a/Engine/source/lighting/probeManager.cpp b/Engine/source/lighting/probeManager.cpp index d3cc41f5e..5b7b7af76 100644 --- a/Engine/source/lighting/probeManager.cpp +++ b/Engine/source/lighting/probeManager.cpp @@ -55,7 +55,8 @@ ProbeInfo::ProbeInfo() mIrradianceCubemap(NULL), mBRDFTexture(NULL), mRadius(1.0f), - mIntensity(1.0f) + mIntensity(1.0f), + mProbePosOffset(0,0,0) { for (U32 i = 0; i < 5; ++i) { diff --git a/Engine/source/lighting/probeManager.h b/Engine/source/lighting/probeManager.h index 587af580b..75291e815 100644 --- a/Engine/source/lighting/probeManager.h +++ b/Engine/source/lighting/probeManager.h @@ -68,6 +68,7 @@ struct ProbeInfo F32 mIntensity; Box3F mBounds; + Point3F mProbePosOffset; GFXCubemapHandle *mCubemap; diff --git a/Engine/source/renderInstance/renderPassManager.h b/Engine/source/renderInstance/renderPassManager.h index 85498e37c..38422329c 100644 --- a/Engine/source/renderInstance/renderPassManager.h +++ b/Engine/source/renderInstance/renderPassManager.h @@ -487,6 +487,7 @@ struct ProbeRenderInst : public RenderInst F32 mIntensity; Box3F mBounds; + Point3F mProbePosOffset; GFXCubemapHandle *mCubemap; diff --git a/Engine/source/renderInstance/renderProbeMgr.cpp b/Engine/source/renderInstance/renderProbeMgr.cpp index 120c4df00..74b230562 100644 --- a/Engine/source/renderInstance/renderProbeMgr.cpp +++ b/Engine/source/renderInstance/renderProbeMgr.cpp @@ -490,6 +490,7 @@ RenderProbeMgr::ReflectProbeMaterialInfo::ReflectProbeMaterialInfo(const String useCubemap = matInstance->getMaterialParameterHandle("$useCubemap"); cubemap = matInstance->getMaterialParameterHandle("$cubeMap"); + cubeMips = matInstance->getMaterialParameterHandle("$cubeMips"); eyePosWorld = matInstance->getMaterialParameterHandle("$eyePosWorld"); bbMin = matInstance->getMaterialParameterHandle("$bbMin"); @@ -545,7 +546,7 @@ void RenderProbeMgr::ReflectProbeMaterialInfo::setProbeParameters(const ProbeRen matParams->setSafe(radius, probeInfo->mRadius); - Point3F probePos = probeInfo->getPosition(); + Point3F probePos = probeInfo->getPosition() + probeInfo->mProbePosOffset; //worldViewOnly.mulP(probeInfo->getPosition(), &probePos); matParams->setSafe(probeWSPos, probePos); @@ -606,6 +607,10 @@ void RenderProbeMgr::ReflectProbeMaterialInfo::setProbeParameters(const ProbeRen GFX->setTexture(4, NULL); } + if(probeInfo->mCubemap->isValid()) + matParams->setSafe(cubeMips, mPow(probeInfo->mCubemap->getPointer()->getMipMapLevels(),2.0f)); + else + matParams->setSafe(cubeMips, F32(0.0)); matParams->setSafe(eyePosWorld, renderState->getCameraPosition()); matParams->setSafe(bbMin, probeInfo->mBounds.minExtents); @@ -659,7 +664,7 @@ bool ReflectProbeMatInstance::setupPass(SceneRenderState *state, const SceneData desc.setZReadWrite(false); desc.zWriteEnable = false; desc.setCullMode(GFXCullNone); - desc.setBlend(true, GFXBlendOne, GFXBlendOne); + desc.setBlend(true, GFXBlendSrcAlpha, GFXBlendOne); mProjectionState = GFX->createStateBlock(desc); } // Now override stateblock with our own diff --git a/Engine/source/renderInstance/renderProbeMgr.h b/Engine/source/renderInstance/renderProbeMgr.h index fe1d196c2..31fdddffe 100644 --- a/Engine/source/renderInstance/renderProbeMgr.h +++ b/Engine/source/renderInstance/renderProbeMgr.h @@ -107,6 +107,7 @@ protected: MaterialParameterHandle *useCubemap; MaterialParameterHandle *cubemap; + MaterialParameterHandle *cubeMips; MaterialParameterHandle *eyePosWorld; MaterialParameterHandle *bbMin; diff --git a/Templates/Full/game/core/scripts/client/lighting/advanced/deferredShading.cs b/Templates/Full/game/core/scripts/client/lighting/advanced/deferredShading.cs index 26940f47c..5c0ab2f00 100644 --- a/Templates/Full/game/core/scripts/client/lighting/advanced/deferredShading.cs +++ b/Templates/Full/game/core/scripts/client/lighting/advanced/deferredShading.cs @@ -54,6 +54,24 @@ new ShaderData( AL_DeferredShader ) pixVersion = 2.0; }; +new GFXStateBlockData( AL_DeferredCaptureState : PFX_DefaultStateBlock ) +{ + blendEnable = false; + + separateAlphaBlendDefined = true; + separateAlphaBlendEnable = true; + separateAlphaBlendSrc = GFXBlendSrcAlpha; + separateAlphaBlendDest = GFXBlendDestAlpha; + separateAlphaBlendOp = GFXBlendOpMin; + + samplersDefined = true; + samplerStates[0] = SamplerWrapLinear; + samplerStates[1] = SamplerWrapLinear; + samplerStates[2] = SamplerWrapLinear; + samplerStates[3] = SamplerWrapLinear; + samplerStates[4] = SamplerWrapLinear; +}; + new ShaderData( AL_ProbeShader ) { DXVertexShaderFile = "shaders/common/postFx/postFxV.hlsl"; @@ -76,7 +94,7 @@ singleton PostEffect( AL_PreCapture ) renderTime = "PFXBeforeBin"; renderBin = "ProbeBin"; shader = AL_ProbeShader; - stateBlock = AL_DeferredShadingState; + stateBlock = AL_DeferredCaptureState; texture[0] = "#color"; texture[1] = "#diffuseLighting"; texture[2] = "#matinfo"; diff --git a/Templates/Full/game/core/scripts/client/lighting/advanced/shaders.cs b/Templates/Full/game/core/scripts/client/lighting/advanced/shaders.cs index 5ec7375d9..b949624ad 100644 --- a/Templates/Full/game/core/scripts/client/lighting/advanced/shaders.cs +++ b/Templates/Full/game/core/scripts/client/lighting/advanced/shaders.cs @@ -26,7 +26,7 @@ new GFXStateBlockData( AL_VectorLightState ) { blendDefined = true; blendEnable = true; - blendSrc = GFXBlendOne; + blendSrc = GFXBlendSrcAlpha; blendDest = GFXBlendOne; blendOp = GFXBlendOpAdd; @@ -102,7 +102,7 @@ new GFXStateBlockData( AL_ConvexLightState ) { blendDefined = true; blendEnable = true; - blendSrc = GFXBlendOne; + blendSrc = GFXBlendSrcAlpha; blendDest = GFXBlendOne; blendOp = GFXBlendOpAdd; @@ -294,7 +294,7 @@ new GFXStateBlockData( AL_ProbeState ) { blendDefined = true; blendEnable = true; - blendSrc = GFXBlendOne; + blendSrc = GFXBlendSrcAlpha; blendDest = GFXBlendOne; blendOp = GFXBlendOpAdd; diff --git a/Templates/Full/game/shaders/common/lighting/advanced/gl/deferredShadingP.glsl b/Templates/Full/game/shaders/common/lighting/advanced/gl/deferredShadingP.glsl index 3d6a79ee8..3005fb415 100644 --- a/Templates/Full/game/shaders/common/lighting/advanced/gl/deferredShadingP.glsl +++ b/Templates/Full/game/shaders/common/lighting/advanced/gl/deferredShadingP.glsl @@ -42,26 +42,29 @@ void main() return; } - vec3 colorBuffer = texture( colorBufferTex, uv0 ).rgb; //albedo + vec3 albedo = texture( colorBufferTex, uv0 ).rgb; //albedo vec4 matInfo = texture( matInfoTex, uv0 ); //flags|smoothness|ao|metallic + bool emissive = getFlag(matInfo.r, 0); if (emissive) { - OUT_col = float4(colorBuffer, 1.0); + OUT_col = float4(albedo, 1.0); return; } - vec4 diffuseLighting = texture( diffuseLightingBuffer, uv0 ); //shadowmap*specular - - vec3 specularLighting = texture( specularLightingBuffer, uv0 ).rgb; //environment mapping*lightmaps + vec4 diffuse = texture( diffuseLightingBuffer, uv0 ); //shadowmap*specular + vec4 specular = texture( specularLightingBuffer, uv0 ); //environment mapping*lightmaps + float metalness = matInfo.a; - - float frez = diffuseLighting.a; - vec3 diffuseColor = colorBuffer - (colorBuffer * metalness); - vec3 reflectColor = specularLighting*colorBuffer; - colorBuffer = diffuseColor+lerp(reflectColor,specularLighting,frez); - colorBuffer *= max(diffuseLighting.rgb,vec3(0,0,0)); + vec3 diffuseColor = albedo - (albedo * metalness); + vec3 specularColor = lerp(float3(0.04,0.04,0.04), albedo, metalness); + + vec3 light = (diffuseColor * diffuse.rgb) + (specularColor * specular.rgb); + + //albedo = diffuseColor+lerp(reflectColor,indiffuseLighting,frez); + //albedo *= max(diffuseLighting.rgb,vec3(0,0,0)); - OUT_col = hdrEncode(vec4(colorBuffer,1.0)); + //OUT_col = hdrEncode(vec4(colorBuffer,1.0)); + OUT_col = hdrEncode(vec4(light, 1.0)); } diff --git a/Templates/Full/game/shaders/common/lighting/advanced/gl/lightingUtils.glsl b/Templates/Full/game/shaders/common/lighting/advanced/gl/lightingUtils.glsl index 08af9231b..a7860397b 100644 --- a/Templates/Full/game/shaders/common/lighting/advanced/gl/lightingUtils.glsl +++ b/Templates/Full/game/shaders/common/lighting/advanced/gl/lightingUtils.glsl @@ -33,34 +33,6 @@ float attenuate( vec4 lightColor, vec2 attParams, float dist ) #endif } -// Calculate the specular coefficent -// -// pxlToLight - Normalized vector representing direction from the pixel being lit, to the light source, in world space -// normal - Normalized surface normal -// pxlToEye - Normalized vector representing direction from pixel being lit, to the camera, in world space -// specPwr - Specular exponent -// specularScale - A scalar on the specular output used in RGB accumulation. -// -float calcSpecular( vec3 pxlToLight, vec3 normal, vec3 pxlToEye, float specPwr, float specularScale ) -{ -#ifdef PHONG_SPECULAR - // (R.V)^c - float specVal = dot( normalize( -reflect( pxlToLight, normal ) ), pxlToEye ); -#else - // (N.H)^c [Blinn-Phong, TGEA style, default] - float specVal = dot( normal, normalize( pxlToLight + pxlToEye ) ); -#endif - -#ifdef ACCUMULATE_LUV - return pow( max( specVal, 0.00001f ), specPwr ); -#else - // If this is RGB accumulation, than there is no facility for the luminance - // of the light to play in to the specular intensity. In LUV, the luminance - // of the light color gets rolled into N.L * Attenuation - return specularScale * pow( max( specVal, 0.00001f ), specPwr ); -#endif -} - vec3 getDistanceVectorToPlane( vec3 origin, vec3 direction, vec4 plane ) { float denum = dot( plane.xyz, direction.xyz ); diff --git a/Templates/Full/game/shaders/common/lighting/advanced/pointLightP.hlsl b/Templates/Full/game/shaders/common/lighting/advanced/pointLightP.hlsl index b14e90cb0..5022b2ec3 100644 --- a/Templates/Full/game/shaders/common/lighting/advanced/pointLightP.hlsl +++ b/Templates/Full/game/shaders/common/lighting/advanced/pointLightP.hlsl @@ -156,7 +156,6 @@ PS_OUTPUT main(ConvexConnectP IN) bool emissive = getFlag(matInfo.r, 0); if (emissive) { - //return float4(0.0, 0.0, 0.0, 0.0); return Output; } @@ -274,16 +273,16 @@ PS_OUTPUT main(ConvexConnectP IN) //diffuse float disDiff = Fr_DisneyDiffuse(dotNVa, dotNLa, dotLHa, roughness); - float3 diffuse = float3(disDiff, disDiff, disDiff) / M_PI_F;// alternative: (lightColor * dotNL) / Pi; - //specular + float3 diffuse = float3(disDiff, disDiff, disDiff) / M_PI_F; + //specular float3 specular = directSpecular(normal, v, l, roughness, 1.0) * lightColor.rgb; if (nDotL<0) shadowed = 0; float Sat_NL_Att = saturate( nDotL * shadowed ) * lightBrightness; //output - Output.diffuse = float4(diffuse * lightBrightness*shadowed, Sat_NL_Att); - Output.spec = float4(specular * lightBrightness*shadowed, Sat_NL_Att); + Output.diffuse = float4(diffuse * lightBrightness, Sat_NL_Att*shadowed); + Output.spec = float4(specular * lightBrightness, Sat_NL_Att*shadowed); return Output; } diff --git a/Templates/Full/game/shaders/common/lighting/advanced/prefilterP.hlsl b/Templates/Full/game/shaders/common/lighting/advanced/prefilterP.hlsl index 17dfac8d2..eeeb670c2 100644 --- a/Templates/Full/game/shaders/common/lighting/advanced/prefilterP.hlsl +++ b/Templates/Full/game/shaders/common/lighting/advanced/prefilterP.hlsl @@ -86,13 +86,13 @@ float3 ImportanceSampleGGX(float2 Xi, float3 N) return normalize(sampleVec); } -float3 prefilterEnvMap(float3 R) +float4 prefilterEnvMap(float3 R) { int sampleCount = resolution*2; float3 N = R; float3 V = R; float totalWeight = 0.0; - float3 prefilteredColor = float3(0.0, 0.0, 0.0); + float4 prefilteredColor = float4(0.0, 0.0, 0.0, 0.0); for (int i = 0; i < sampleCount; ++i) { @@ -114,7 +114,7 @@ float3 prefilterEnvMap(float3 R) float mipLevel = roughness == 0.0 ? 0.0 : 0.5 * log2(saSample / saTexel); - prefilteredColor += TORQUE_TEXCUBELOD(environmentMap, float4(L, mipLevel)).rgb * NdotL; + prefilteredColor += TORQUE_TEXCUBELOD(environmentMap, float4(L, mipLevel)) * NdotL; totalWeight += NdotL; } @@ -126,5 +126,5 @@ float3 prefilterEnvMap(float3 R) float4 main(ConnectData IN) : TORQUE_TARGET0 { float3 N = getCubeDir(face, IN.uv); - return float4(prefilterEnvMap(N), 1.0); + return prefilterEnvMap(N); } \ No newline at end of file diff --git a/Templates/Full/game/shaders/common/lighting/advanced/probeShadingP.hlsl b/Templates/Full/game/shaders/common/lighting/advanced/probeShadingP.hlsl index 3007819c5..c6e8b50c3 100644 --- a/Templates/Full/game/shaders/common/lighting/advanced/probeShadingP.hlsl +++ b/Templates/Full/game/shaders/common/lighting/advanced/probeShadingP.hlsl @@ -30,12 +30,14 @@ TORQUE_UNIFORM_SAMPLER2D(matInfoTex,2); TORQUE_UNIFORM_SAMPLER2D(specularLightingBuffer,3); TORQUE_UNIFORM_SAMPLER2D(deferredTex,4); +uniform float radius; +uniform float2 targetSize; +uniform int captureRez; float4 main( PFXVertToPix IN) : TORQUE_TARGET0 { float depth = TORQUE_DEFERRED_UNCONDITION( deferredTex, IN.uv0 ).w; if (depth>0.9999) - return float4(0,0,0,0); - + clip(-1); float3 colorBuffer = TORQUE_TEX2D( colorBufferTex, IN.uv0 ).rgb; //albedo float4 matInfo = TORQUE_TEX2D(matInfoTex, IN.uv0); //flags|smoothness|ao|metallic @@ -47,6 +49,12 @@ float4 main( PFXVertToPix IN) : TORQUE_TARGET0 float4 diffuseLighting = TORQUE_TEX2D( diffuseLightingBuffer, IN.uv0 ); //shadowmap*specular colorBuffer *= diffuseLighting.rgb; + float2 relUV = IN.uv0*targetSize/captureRez; - return hdrEncode( float4(colorBuffer.rgb, 1.0) ); + //we use a 1k depth range in the capture frustum. + //reduce that a bit to get something resembling depth fidelity out of 8 bits + depth*=2000/radius; + + float rLen = length(float3(relUV,depth)-float3(0.5,0.5,0)); + return hdrEncode( float4(colorBuffer,rLen)); } diff --git a/Templates/Full/game/shaders/common/lighting/advanced/reflectionProbeP.hlsl b/Templates/Full/game/shaders/common/lighting/advanced/reflectionProbeP.hlsl index f18020639..26eb626f4 100644 --- a/Templates/Full/game/shaders/common/lighting/advanced/reflectionProbeP.hlsl +++ b/Templates/Full/game/shaders/common/lighting/advanced/reflectionProbeP.hlsl @@ -18,6 +18,7 @@ TORQUE_UNIFORM_SAMPLER2D(matInfoBuffer, 1); TORQUE_UNIFORM_SAMPLERCUBE(cubeMap, 2); TORQUE_UNIFORM_SAMPLERCUBE(irradianceCubemap, 3); TORQUE_UNIFORM_SAMPLER2D(BRDFTexture, 4); +uniform float cubeMips; uniform float4 rtParams0; @@ -36,32 +37,19 @@ uniform float3 bbMax; uniform float useSphereMode; -float3 iblSpecular(float3 v, float3 n, float roughness) -{ - float3 R = reflect(v, n); - const float MAX_REFLECTION_LOD = 6.0; - float3 prefilteredColor = TORQUE_TEXCUBELOD(cubeMap, float4(R, roughness * MAX_REFLECTION_LOD)).rgb; - float2 envBRDF = TORQUE_TEX2D(BRDFTexture, float2(max(dot(n, v), 0.0), roughness)).rg; - //return prefilteredColor * (envBRDF.x + envBRDF.y); - return prefilteredColor; -} - // Box Projected IBL Lighting // Based on: http://www.gamedev.net/topic/568829-box-projected-cubemap-environment-mapping/ - +// and https://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/ float3 boxProject(float3 wsPosition, float3 reflectDir, float3 boxWSPos, float3 boxMin, float3 boxMax) { - float3 nrdir = normalize(reflectDir); - float3 rbmax = (boxMax - wsPosition) / nrdir; - float3 rbmin = (boxMin - wsPosition) / nrdir; - - float3 rbminmax; - rbminmax.x = (nrdir.x > 0.0) ? rbmax.x : rbmin.x; - rbminmax.y = (nrdir.y > 0.0) ? rbmax.y : rbmin.y; - rbminmax.z = (nrdir.z > 0.0) ? rbmax.z : rbmin.z; - - float fa = min(min(rbminmax.x, rbminmax.y), rbminmax.z); - float3 posonbox = wsPosition + nrdir * fa; + float3 nrdir = reflectDir; + float3 offset = wsPosition; + float3 plane1vec = (boxMax - offset) / nrdir; + float3 plane2vec = (boxMin - offset) / nrdir; + + float3 furthestPlane = max(plane1vec, plane2vec); + float dist = min(min(furthestPlane.x, furthestPlane.y), furthestPlane.z); + float3 posonbox = offset + nrdir * dist; return posonbox - boxWSPos; } @@ -83,23 +71,22 @@ float3 iblBoxDiffuse(float3 normal, float3 iblBoxSpecular(float3 normal, float3 wsPos, float roughness, - float3 viewDir, + float3 surfToEye, TORQUE_SAMPLER2D(brdfTexture), TORQUE_SAMPLERCUBE(radianceCube), float3 boxPos, float3 boxMin, float3 boxMax) { - float3 v = viewDir; - float3 n = normalize(normal); - float ndotv = clamp(dot(n, v), 0.0, 1.0); + float ndotv = clamp(dot(normal, surfToEye), 0.0, 1.0); // BRDF float2 brdf = TORQUE_TEX2D(brdfTexture, float2(roughness, ndotv)).xy; // Radiance (Specular) - float lod = roughness * 6.0; - float3 r = 2.0 * ndotv * n - v; // reflect(v, n); + float maxmip = pow(cubeMips+1,2); + float lod = roughness*maxmip; + float3 r = reflect(surfToEye, normal); float3 cubeR = normalize(r); cubeR = boxProject(wsPos, cubeR, boxPos, boxMin, boxMax); @@ -114,6 +101,57 @@ struct PS_OUTPUT float4 spec: TORQUE_TARGET1; }; +float defineSphereSpaceInfluence(float3 centroidPosVS, float rad, float2 atten, float3 surfPosVS, float3 norm) +{ + // Build light vec, get length, clip pixel if needed + float3 lightVec = centroidPosVS - surfPosVS; + float lenLightV = length( lightVec ); + if (( rad - lenLightV )<0) + return -1; + + // Get the attenuated falloff. + float attn = attenuate( float4(1,1,1,1), atten, lenLightV ); + if ((attn - 1e-6)<0) + return -1; + + // Normalize lightVec + lightVec = lightVec /= lenLightV; + + // If we can do dynamic branching then avoid wasting + // fillrate on pixels that are backfacing to the light. + float nDotL = abs(dot( lightVec, norm )); + + return saturate( nDotL * attn ); +} + +float defineBoxSpaceInfluence(float3 surfPosWS, float3 probePos, float rad, float2 atten) //atten currently unused +{ + float3 boxMin = probePos-(float3(0.5,0.5,0.5)*rad); + float3 boxMax = probePos+(float3(0.5,0.5,0.5)*rad); + //Try to clip anything that falls outside our box as well + //TODO: Make it support rotated boxes as well + if(surfPosWS.x > boxMax.x || surfPosWS.y > boxMax.y || surfPosWS.z > boxMax.z || + surfPosWS.x < boxMin.x || surfPosWS.y < boxMin.y || surfPosWS.z < boxMin.z) + return -1; + + float blendVal = 1; + //float3 atten = min(boxMax-surfPosWS,surfPosWS-boxMin); + //blendVal = min(min(atten.x,atten.y),atten.z); + return blendVal; +} + +float defineDepthInfluence(float3 probePosWS, float3 surfPosWS, TORQUE_SAMPLERCUBE(radianceCube)) +{ + //TODO properly: filter out pixels projected uppon by probes behind walls by looking up the depth stored in the probes cubemap alpha + //and comparing legths + float3 probeToSurf = probePosWS-surfPosWS; + + float depthRef = TORQUE_TEXCUBELOD(cubeMap, float4(-probeToSurf,0)).a*radius; + float dist = length( probeToSurf ); + + return depthRef-dist; +} + PS_OUTPUT main( ConvexConnectP IN ) { PS_OUTPUT Output = (PS_OUTPUT)0; @@ -121,7 +159,6 @@ PS_OUTPUT main( ConvexConnectP IN ) // Compute scene UV float3 ssPos = IN.ssPos.xyz / IN.ssPos.w; - //float4 hardCodedRTParams0 = float4(0,0.0277777780,1,0.972222209); float2 uvScene = getUVFromSSPos( ssPos, rtParams0 ); // Matinfo flags @@ -137,10 +174,6 @@ PS_OUTPUT main( ConvexConnectP IN ) // Need world-space normal. float3 wsNormal = mul(float4(normal, 1), invViewMat).rgb; - float4 color = float4(1, 1, 1, 1); - float4 ref = float4(0,0,0,0); - float alpha = 1; - float3 eyeRay = getDistanceVectorToPlane( -vsFarPlane.w, IN.vsEyeDir.xyz, vsFarPlane ); float3 viewSpacePos = eyeRay * depth; @@ -148,70 +181,28 @@ PS_OUTPUT main( ConvexConnectP IN ) // Use eye ray to get ws pos float3 worldPos = float3(eyePosWorld + wsEyeRay * depth); - float smoothness = min((1.0 - matInfo.b)*11.0 + 1.0, 8.0);//bump up to 8 for finalization - - if(useSphereMode) + + float blendVal = 1.0; + + //clip bounds and (TODO properly: set falloff) + if(useSphereMode) { - // Build light vec, get length, clip pixel if needed - float3 lightVec = probeLSPos - viewSpacePos; - float lenLightV = length( lightVec ); - clip( radius - lenLightV ); - - // Get the attenuated falloff. - float atten = attenuate( float4(1,1,1,1), attenuation, lenLightV ); - clip( atten - 1e-6 ); - - // Normalize lightVec - lightVec = normalize(lightVec); - - // If we can do dynamic branching then avoid wasting - // fillrate on pixels that are backfacing to the light. - float nDotL = abs(dot( lightVec, normal )); - - float Sat_NL_Att = saturate( nDotL * atten ); - - float3 reflectionVec = reflect(IN.wsEyeDir, float4(wsNormal,nDotL)).xyz; - - float3 nrdir = normalize(reflectionVec); - float3 rbmax = (bbMax - worldPos.xyz) / nrdir; - float3 rbmin = (bbMin - worldPos.xyz) / nrdir; - - float3 rbminmax = (nrdir > 0.0) ? rbmax : rbmin; - float fa = min(min(rbminmax.x,rbminmax.y),rbminmax.z); - if (dot( lightVec, normal )<0.0f) - clip(fa); - - float3 posOnBox = worldPos.xyz + nrdir * fa; - reflectionVec = posOnBox - probeWSPos; - - reflectionVec = mul(probeWSPos,reflectionVec); - - ref = float4(reflectionVec, smoothness); - - alpha = Sat_NL_Att; - float roughness = 1 - matInfo.b; - - float3 irradiance = TORQUE_TEXCUBELOD(irradianceCubemap, ref).rgb; - - float3 specular = TORQUE_TEXCUBELOD(cubeMap, ref).rgb;// iblSpecular(wsEyeRay, wsNormal, roughness); - - Output.diffuse = float4(irradiance.rgb, alpha); - Output.spec = float4(specular.rgb, alpha); - - return Output; + blendVal = defineSphereSpaceInfluence(probeLSPos, radius, attenuation, viewSpacePos, normal); } else { - //Try to clip anything that falls outside our box as well - //TODO: Make it support rotated boxes as well - if(worldPos.x > bbMax.x || worldPos.y > bbMax.y || worldPos.z > bbMax.z || - worldPos.x < bbMin.x || worldPos.y < bbMin.y || worldPos.z < bbMin.z) - clip(-1); - - float blendVal = 1.0; - float3 pixDir = normalize(eyePosWorld.xyz - worldPos.xyz); - Output.diffuse = float4(iblBoxDiffuse(wsNormal, worldPos, TORQUE_SAMPLERCUBE_MAKEARG(irradianceCubemap), probeWSPos, bbMin, bbMax), blendVal); - Output.spec = float4(iblBoxSpecular(wsNormal, worldPos, 1.0 - matInfo.b, pixDir, TORQUE_SAMPLER2D_MAKEARG(BRDFTexture), TORQUE_SAMPLERCUBE_MAKEARG(cubeMap), probeWSPos, bbMin, bbMax), blendVal); - return Output; + blendVal = defineBoxSpaceInfluence(worldPos, probeWSPos, radius*2, attenuation); } + clip(blendVal); + + //flip me on to have probes filter by depth + //clip(defineDepthInfluence(probeWSPos, worldPos, TORQUE_SAMPLERCUBE_MAKEARG(cubeMap))); + + + //render into the bound space defined above + float3 surfToEye = normalize(worldPos.xyz-eyePosWorld.xyz); + Output.diffuse = float4(iblBoxDiffuse(wsNormal, worldPos, TORQUE_SAMPLERCUBE_MAKEARG(irradianceCubemap), probeWSPos, bbMin, bbMax), blendVal); + Output.spec = float4(iblBoxSpecular(wsNormal, worldPos, 1.0 - matInfo.b, surfToEye, TORQUE_SAMPLER2D_MAKEARG(BRDFTexture), TORQUE_SAMPLERCUBE_MAKEARG(cubeMap), probeWSPos, bbMin, bbMax), blendVal); + + return Output; } diff --git a/Templates/Full/game/shaders/common/lighting/advanced/spotLightP.hlsl b/Templates/Full/game/shaders/common/lighting/advanced/spotLightP.hlsl index 1ddfc0c55..5a1717fc0 100644 --- a/Templates/Full/game/shaders/common/lighting/advanced/spotLightP.hlsl +++ b/Templates/Full/game/shaders/common/lighting/advanced/spotLightP.hlsl @@ -73,8 +73,15 @@ uniform float4x4 dynamicViewToLightProj; uniform float2 lightAttenuation; uniform float shadowSoftness; -float4 main( ConvexConnectP IN ) : TORQUE_TARGET0 +struct PS_OUTPUT +{ + float4 diffuse: TORQUE_TARGET0; + float4 spec: TORQUE_TARGET1; +}; + +PS_OUTPUT main( ConvexConnectP IN ) : TORQUE_TARGET0 { + PS_OUTPUT Output = (PS_OUTPUT)0; // Compute scene UV float3 ssPos = IN.ssPos.xyz / IN.ssPos.w; float2 uvScene = getUVFromSSPos( ssPos, rtParams0 ); @@ -85,7 +92,7 @@ float4 main( ConvexConnectP IN ) : TORQUE_TARGET0 bool emissive = getFlag(matInfo.r, 0); if (emissive) { - return float4(0.0, 0.0, 0.0, 0.0); + return Output; } float4 colorSample = TORQUE_TEX2D( colorBuffer, uvScene ); @@ -181,36 +188,31 @@ float4 main( ConvexConnectP IN ) : TORQUE_TARGET0 // NOTE: Do not clip on fully shadowed pixels as it would // cause the hardware occlusion query to disable the shadow. - // Specular term - float specular = 0; + float3 l = normalize(-lightDirection); + float3 v = eyeRay;// normalize(eyePosWorld - worldPos.xyz); + + float3 h = normalize(v + l); + float dotNLa = clamp(dot(normal, l), 0.0, 1.0); + float dotNVa = clamp(dot(normal, v), 0.0, 1.0); + float dotNHa = clamp(dot(normal, h), 0.0, 1.0); + float dotHVa = clamp(dot(normal, v), 0.0, 1.0); + float dotLHa = clamp(dot(l, h), 0.0, 1.0); + + float roughness = matInfo.g; + float metalness = matInfo.b; + + //diffuse + float disDiff = Fr_DisneyDiffuse(dotNVa, dotNLa, dotLHa, roughness); + float3 diffuse = float3(disDiff, disDiff, disDiff) / M_PI_F; + //specular + float3 specular = directSpecular(normal, v, l, roughness, 1.0) * lightColor.rgb; - float3 lightVec = lightPosition - viewSpacePos; - float4 real_specular = EvalBDRF( float3( 1.0, 1.0, 1.0 ), - lightcol, - lightVec, - viewSpacePos, - normal, - 1.0-matInfo.b, - matInfo.a ); - float3 lightColorOut = real_specular.rgb * lightBrightness * shadowed* atten; - float Sat_NL_Att = saturate( nDotL * atten * shadowed ) * lightBrightness; - float4 addToResult = 0.0; + if (nDotL<0) shadowed = 0; + float Sat_NL_Att = saturate( nDotL * shadowed ) * lightBrightness; + //output + Output.diffuse = float4(diffuse * lightBrightness, Sat_NL_Att*shadowed); + Output.spec = float4(specular * lightBrightness, Sat_NL_Att*shadowed); - // TODO: This needs to be removed when lightmapping is disabled - // as its extra work per-pixel on dynamic lit scenes. - // - // Special lightmapping pass. - if ( lightMapParams.a < 0.0 ) - { - // This disables shadows on the backsides of objects. - shadowed = nDotL < 0.0f ? 1.0f : shadowed; - - Sat_NL_Att = 1.0f; - shadowed = lerp( 1.0f, shadowed, atten ); - lightColorOut = shadowed; - specular *= lightBrightness; - addToResult = ( 1.0 - shadowed ) * abs(lightMapParams); - } - return float4((lightColorOut*Sat_NL_Att+subsurface*(1.0-Sat_NL_Att)+addToResult.rgb),real_specular.a); + return Output; } diff --git a/Templates/Full/game/shaders/common/lighting/advanced/vectorLightP.hlsl b/Templates/Full/game/shaders/common/lighting/advanced/vectorLightP.hlsl index 2a6b04ecf..9cc88a416 100644 --- a/Templates/Full/game/shaders/common/lighting/advanced/vectorLightP.hlsl +++ b/Templates/Full/game/shaders/common/lighting/advanced/vectorLightP.hlsl @@ -314,8 +314,8 @@ PS_OUTPUT main(FarFrustumQuadConnectP IN) float finalShadowed = shadowed; //output - Output.diffuse = float4(diffuse * (lightBrightness*shadowed), dotNLa); - Output.spec = float4(specular * (lightBrightness*shadowed), dotNLa); + Output.diffuse = float4(diffuse * (lightBrightness), dotNLa*shadowed); + Output.spec = float4(specular * (lightBrightness), dotNLa*shadowed); return Output; }