From 4417462499dffc0956ced889e29f65758207a747 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 21 Feb 2024 07:40:57 +0000 Subject: [PATCH] Add support for both ies and cookie Both ies and cookies can now exist on a light We are still not using all the capabilities of an IES profile, such as candela and luminance values we are just using them as a mask for the moment Issues compiling on mac and linux, will need to update the ies-loader to use torque methods instead of std:: --- Engine/source/core/util/tDictionary.h | 20 ++++++++++ .../advanced/advancedLightBinManager.cpp | 14 ++++--- .../advanced/advancedLightBinManager.h | 4 +- .../advanced/advancedLightManager.cpp | 15 ++++++++ .../lighting/shadowMap/lightShadowMap.cpp | 37 ++++++++++++++++++- .../lighting/shadowMap/lightShadowMap.h | 7 ++++ Engine/source/materials/materialDefinition.h | 1 + .../materials/processedCustomMaterial.cpp | 8 ++++ .../lighting/advanced/pointLightP.hlsl | 34 ++++++++++++----- .../shaders/lighting/advanced/spotLightP.hlsl | 29 ++++++++++----- 10 files changed, 142 insertions(+), 27 deletions(-) diff --git a/Engine/source/core/util/tDictionary.h b/Engine/source/core/util/tDictionary.h index 901990289..4af0d6037 100644 --- a/Engine/source/core/util/tDictionary.h +++ b/Engine/source/core/util/tDictionary.h @@ -65,6 +65,21 @@ struct CompoundKey3 bool operator==(const CompoundKey3 & compound) const { return key1==compound.key1 && key2==compound.key2 && key3==compound.key3; } }; +template +struct CompoundKey4 +{ + A key1; + B key2; + C key3; + D key4; + + CompoundKey4() {}; + CompoundKey4(const A& a, const B& b, const C& c, const D& d) { key1 = a; key2 = b; key3 = c; key4 = d;}; + + bool operator==(const CompoundKey4& compound) const { return key1 == compound.key1 && key2 == compound.key2 && key3 == compound.key3 && key4 == compound.key4; } +}; + + namespace DictHash { @@ -110,6 +125,11 @@ namespace DictHash return hash(compound.key1) + hash(compound.key2) + hash(compound.key3); } + template + inline U32 hash(const CompoundKey4& compound) + { + return hash(compound.key1) + hash(compound.key2) + hash(compound.key3) + hash(compound.key4); + } U32 nextPrime(U32); }; diff --git a/Engine/source/lighting/advanced/advancedLightBinManager.cpp b/Engine/source/lighting/advanced/advancedLightBinManager.cpp index 998bc2bcf..431ec28ad 100644 --- a/Engine/source/lighting/advanced/advancedLightBinManager.cpp +++ b/Engine/source/lighting/advanced/advancedLightBinManager.cpp @@ -253,7 +253,7 @@ void AdvancedLightBinManager::addLight( LightInfo *light ) LightBinEntry lEntry; lEntry.lightInfo = light; lEntry.shadowMap = lsm; - lEntry.lightMaterial = _getLightMaterial( lightType, shadowType, lsp->hasCookieTex() ); + lEntry.lightMaterial = _getLightMaterial( lightType, shadowType, lsp->hasCookieTex(), lsp->hasIesProfile() ); if( lightType == LightInfo::Spot ) lEntry.vertBuffer = mLightManager->getConeMesh( lEntry.numPrims, lEntry.primBuffer ); @@ -399,9 +399,9 @@ void AdvancedLightBinManager::render( SceneRenderState *state ) sunLight->getCastShadows() && !disableShadows && sunLight->getExtended() ) - vectorMatInfo = _getLightMaterial( LightInfo::Vector, ShadowType_PSSM, false ); + vectorMatInfo = _getLightMaterial( LightInfo::Vector, ShadowType_PSSM ); else - vectorMatInfo = _getLightMaterial( LightInfo::Vector, ShadowType_None, false ); + vectorMatInfo = _getLightMaterial( LightInfo::Vector, ShadowType_None ); // Initialize and set the per-frame parameters after getting // the vector light material as we use lazy creation. @@ -513,12 +513,13 @@ void AdvancedLightBinManager::render( SceneRenderState *state ) AdvancedLightBinManager::LightMaterialInfo* AdvancedLightBinManager::_getLightMaterial( LightInfo::Type lightType, ShadowType shadowType, - bool useCookieTex ) + bool useCookieTex, + bool isPhotometric) { PROFILE_SCOPE( AdvancedLightBinManager_GetLightMaterial ); // Build the key. - const LightMatKey key( lightType, shadowType, useCookieTex ); + const LightMatKey key( lightType, shadowType, useCookieTex, isPhotometric ); // See if we've already built this one. LightMatTable::Iterator iter = mLightMaterials.find( key ); @@ -558,6 +559,9 @@ AdvancedLightBinManager::LightMaterialInfo* AdvancedLightBinManager::_getLightMa if ( useCookieTex ) shadowMacros.push_back( GFXShaderMacro( "USE_COOKIE_TEX" ) ); + if(isPhotometric) + shadowMacros.push_back(GFXShaderMacro("UES_PHOTOMETRIC_MASK")); + // Its safe to add the PSSM debug macro to all the materials. if ( smPSSMDebugRender ) shadowMacros.push_back( GFXShaderMacro( "PSSM_DEBUG_RENDER" ) ); diff --git a/Engine/source/lighting/advanced/advancedLightBinManager.h b/Engine/source/lighting/advanced/advancedLightBinManager.h index 4d04f3cfc..71131a1d3 100644 --- a/Engine/source/lighting/advanced/advancedLightBinManager.h +++ b/Engine/source/lighting/advanced/advancedLightBinManager.h @@ -233,14 +233,14 @@ protected: static const GFXVertexFormat* smLightMatVertex[LightInfo::Count]; - typedef CompoundKey3 LightMatKey; + typedef CompoundKey4 LightMatKey; typedef HashTable LightMatTable; /// The fixed table of light material info. LightMatTable mLightMaterials; - LightMaterialInfo* _getLightMaterial( LightInfo::Type lightType, ShadowType shadowType, bool useCookieTex ); + LightMaterialInfo* _getLightMaterial( LightInfo::Type lightType, ShadowType shadowType, bool useCookieTex = false, bool isPhotometric = false ); /// void _onShadowFilterChanged(); diff --git a/Engine/source/lighting/advanced/advancedLightManager.cpp b/Engine/source/lighting/advanced/advancedLightManager.cpp index 47c8d3d36..6d7ea9d7e 100644 --- a/Engine/source/lighting/advanced/advancedLightManager.cpp +++ b/Engine/source/lighting/advanced/advancedLightManager.cpp @@ -277,6 +277,7 @@ void AdvancedLightManager::_initLightFields() DEFINE_LIGHT_FIELD( attenuationRatio, TypePoint3F, NULL ); DEFINE_LIGHT_FIELD( shadowType, TYPEID< ShadowType >(), ConsoleBaseType::getType( TYPEID< ShadowType >() )->getEnumTable() ); DEFINE_LIGHT_FIELD( texSize, TypeS32, NULL ); + DEFINE_LIGHT_FIELD( iesProfile, TypeStringFilename, NULL ); DEFINE_LIGHT_FIELD( cookie, TypeStringFilename, NULL ); DEFINE_LIGHT_FIELD( numSplits, TypeS32, NULL ); DEFINE_LIGHT_FIELD( logWeight, TypeF32, NULL ); @@ -300,6 +301,9 @@ void AdvancedLightManager::_initLightFields() ADD_LIGHT_FIELD( "shadowType", TYPEID< ShadowType >(), shadowType, "The type of shadow to use on this light." ); + ADD_LIGHT_FIELD("iesProfile", TypeStringFilename, iesProfile, + "A photometric profile for the light."); + ADD_LIGHT_FIELD( "cookie", TypeStringFilename, cookie, "A custom pattern texture which is projected from the light." ); @@ -496,6 +500,17 @@ bool AdvancedLightManager::setTextureStage( const SceneData &sgData, return true; } + else if (currTexFlag == Material::PhotometricMask) + { + S32 reg = lsc->mIesProfileSC->getSamplerRegister(); + if (reg != -1 && sgData.lights[0]) + { + ShadowMapParams* p = sgData.lights[0]->getExtended(); + GFX->setTexture(reg, p->getIesProfileTex()); + } + + return true; + } return false; } diff --git a/Engine/source/lighting/shadowMap/lightShadowMap.cpp b/Engine/source/lighting/shadowMap/lightShadowMap.cpp index 9ecde8c97..6f10bf6a1 100644 --- a/Engine/source/lighting/shadowMap/lightShadowMap.cpp +++ b/Engine/source/lighting/shadowMap/lightShadowMap.cpp @@ -269,7 +269,8 @@ bool LightShadowMap::setTextureStage( U32 currTexFlag, LightingShaderConstants* GFX->setTexture( reg, mShadowMapTex); return true; - } else if ( currTexFlag == Material::DynamicLightMask ) + } + else if ( currTexFlag == Material::DynamicLightMask ) { S32 reg = lsc->mCookieMapSC->getSamplerRegister(); if ( reg != -1 ) @@ -284,6 +285,17 @@ bool LightShadowMap::setTextureStage( U32 currTexFlag, LightingShaderConstants* return true; } + else if (currTexFlag == Material::PhotometricMask) + { + S32 reg = lsc->mIesProfileSC->getSamplerRegister(); + if (reg != -1) + { + ShadowMapParams* p = mLight->getExtended(); + GFX->setTexture(reg, p->getIesProfileTex()); + } + + return true; + } return false; } @@ -430,6 +442,7 @@ LightingShaderConstants::LightingShaderConstants() mShadowMapSC(NULL), mShadowMapSizeSC(NULL), mCookieMapSC(NULL), + mIesProfileSC(NULL), mRandomDirsConst(NULL), mShadowSoftnessConst(NULL), mAtlasXOffsetSC(NULL), @@ -490,6 +503,7 @@ void LightingShaderConstants::init(GFXShader* shader) mShadowMapSizeSC = shader->getShaderConstHandle("$shadowMapSize"); mCookieMapSC = shader->getShaderConstHandle("$cookieMap"); + mIesProfileSC = shader->getShaderConstHandle("$iesProfile"); mShadowSoftnessConst = shader->getShaderConstHandle("$shadowSoftness"); mAtlasXOffsetSC = shader->getShaderConstHandle("$atlasXOffset"); @@ -542,7 +556,8 @@ ShadowMapParams::ShadowMapParams( LightInfo *light ) fadeStartDist = 75.0f; lastSplitTerrainOnly = false; mQuery = GFX->createOcclusionQuery(); - cookie = StringTable->EmptyString();; + cookie = StringTable->EmptyString(); + iesProfile = StringTable->EmptyString(); _validate(); } @@ -662,6 +677,22 @@ GFXTextureObject* ShadowMapParams::getCookieTex() return mCookieTex.getPointer(); } +GFXTextureObject* ShadowMapParams::getIesProfileTex() +{ + if (hasIesProfile() && + (mIesTex.isNull() || + iesProfile != StringTable->insert(mIesTex->getPath().c_str()))) + { + mIesTex.set(iesProfile, + &GFXStaticTextureSRGBProfile, + "ShadowMapParams::getIesProfileTex()"); + } + else if (!hasIesProfile()) + mIesTex = NULL; + + return mIesTex.getPointer(); +} + GFXCubemap* ShadowMapParams::getCookieCubeTex() { if ( hasCookieTex() && @@ -695,6 +726,7 @@ void ShadowMapParams::packUpdate( BitStream *stream ) const stream->write( texSize ); stream->writeString( cookie ); + stream->writeString( iesProfile ); stream->write( numSplits ); stream->write( logWeight ); @@ -725,6 +757,7 @@ void ShadowMapParams::unpackUpdate( BitStream *stream ) stream->read( &texSize ); cookie = stream->readSTString(); + iesProfile = stream->readSTString(); stream->read( &numSplits ); stream->read( &logWeight ); diff --git a/Engine/source/lighting/shadowMap/lightShadowMap.h b/Engine/source/lighting/shadowMap/lightShadowMap.h index 57870ac62..a25ff7ec2 100644 --- a/Engine/source/lighting/shadowMap/lightShadowMap.h +++ b/Engine/source/lighting/shadowMap/lightShadowMap.h @@ -99,6 +99,7 @@ struct LightingShaderConstants GFXShaderConstHandle* mShadowMapSizeSC; GFXShaderConstHandle* mCookieMapSC; + GFXShaderConstHandle* mIesProfileSC; GFXShaderConstHandle* mRandomDirsConst; GFXShaderConstHandle* mShadowSoftnessConst; @@ -289,11 +290,14 @@ public: LightShadowMap* getOrCreateShadowMap(); bool hasCookieTex() const { return cookie != StringTable->EmptyString(); } + bool hasIesProfile() const { return iesProfile != StringTable->EmptyString(); } GFXOcclusionQuery* getOcclusionQuery() const { return mQuery; } GFXTextureObject* getCookieTex(); + GFXTextureObject* getIesProfileTex(); + GFXCubemap* getCookieCubeTex(); // Validates the parameters after a field is changed. @@ -313,6 +317,8 @@ protected: GFXCubemapHandle mCookieCubeTex; + GFXTexHandle mIesTex; + public: // We're leaving these public for easy access @@ -326,6 +332,7 @@ public: /// StringTableEntry cookie; + StringTableEntry iesProfile; /// @} diff --git a/Engine/source/materials/materialDefinition.h b/Engine/source/materials/materialDefinition.h index afb68564d..504fecaa6 100644 --- a/Engine/source/materials/materialDefinition.h +++ b/Engine/source/materials/materialDefinition.h @@ -94,6 +94,7 @@ public: Misc, DynamicLight, DynamicLightMask, + PhotometricMask, NormalizeCube, TexTarget, AccuMap, diff --git a/Engine/source/materials/processedCustomMaterial.cpp b/Engine/source/materials/processedCustomMaterial.cpp index e2657b349..15772c078 100644 --- a/Engine/source/materials/processedCustomMaterial.cpp +++ b/Engine/source/materials/processedCustomMaterial.cpp @@ -94,6 +94,14 @@ void ProcessedCustomMaterial::_setStageData() continue; } + if (filename.equal(String("$photometricmask"), String::NoCase)) + { + rpd->mTexType[i] = Material::PhotometricMask; + rpd->mSamplerNames[i] = mCustomMaterial->mSamplerNames[i]; + mMaxTex = i + 1; + continue; + } + if(filename.equal(String("$lightmap"), String::NoCase)) { rpd->mTexType[i] = Material::Lightmap; diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/pointLightP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/pointLightP.hlsl index 52931ed15..de3d3433f 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/pointLightP.hlsl +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/pointLightP.hlsl @@ -107,10 +107,13 @@ TORQUE_UNIFORM_SAMPLER2D(shadowMap, 1); #include "softShadow.hlsl" TORQUE_UNIFORM_SAMPLER2D(colorBuffer, 3); TORQUE_UNIFORM_SAMPLER2D(matInfoBuffer, 4); -#ifdef USE_COOKIE_TEX /// The texture for cookie rendering. +#ifdef SHADOW_CUBE +TORQUE_UNIFORM_SAMPLERCUBE(cookieMap, 5); +#else TORQUE_UNIFORM_SAMPLER2D(cookieMap, 5); #endif +TORQUE_UNIFORM_SAMPLER2D(iesProfile, 6); uniform float4 rtParams0; uniform float4 lightColor; @@ -159,8 +162,8 @@ float4 main( ConvexConnectP IN ) : SV_TARGET { float distToLight = dist / lightRange; SurfaceToLight surfaceToLight = createSurfaceToLight(surface, L); - - float shadow = 1.0; + float3 lightCol = lightColor.rgb; + float shadow = 1.0; #ifndef NO_SHADOW if (getFlag(surface.matFlag, 0)) //also skip if we don't recieve shadows { @@ -176,8 +179,21 @@ float4 main( ConvexConnectP IN ) : SV_TARGET #endif } #endif // !NO_SHADOW - - float3 lightCol = lightColor.rgb; + #ifdef USE_COOKIE_TEX + // Lookup the cookie sample. + #ifdef SHADOW_CUBE + float4 cookie = TORQUE_TEXCUBE(cookieMap, mul(worldToLightProj, -surfaceToLight.L)); + #else + float2 cookieCoord = decodeShadowCoord( mul( worldToLightProj, -surfaceToLight.L ) ).xy; + float4 cookie = TORQUE_TEX2D(cookieMap, cookieCoord); + #endif + // Multiply the light with the cookie tex. + lightCol *= cookie.rgb; + // Use a maximum channel luminance to attenuate + // the lighting else we get specular in the dark + // regions of the cookie texture. + lightCol *= max(cookie.r, max(cookie.g, cookie.b)); + #endif #ifdef DIFFUSE_LIGHT_VIZ float attenuation = getDistanceAtt(surfaceToLight.Lu, radius); float3 factor = lightColor * max(surfaceToLight.NdotL, 0) * shadow * lightIntensity * attenuation; @@ -210,13 +226,13 @@ float4 main( ConvexConnectP IN ) : SV_TARGET //get punctual light contribution lighting = getPunctualLight(surface, surfaceToLight, lightCol, lightBrightness, lightInvSqrRange, shadow); - #ifdef USE_COOKIE_TEX + #ifdef UES_PHOTOMETRIC_MASK // Lookup the cookie sample.d float cosTheta = dot(-surfaceToLight.L, lightDirection); float angle = acos(cosTheta) * ( M_1OVER_PI_F); - float cookie = TORQUE_TEX2D(cookieMap, float2(angle, 0.0)).r; - // Multiply the light with the cookie tex. - lighting *= cookie; + float iesMask = TORQUE_TEX2D(iesProfile, float2(angle, 0.0)).r; + // Multiply the light with the iesMask tex. + lighting *= iesMask; #endif } diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/spotLightP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/spotLightP.hlsl index 22b2275d5..efd07fa30 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/spotLightP.hlsl +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/spotLightP.hlsl @@ -42,11 +42,10 @@ TORQUE_UNIFORM_SAMPLER2D(shadowMap, 1); #include "softShadow.hlsl" TORQUE_UNIFORM_SAMPLER2D(colorBuffer, 3); TORQUE_UNIFORM_SAMPLER2D(matInfoBuffer, 4); -#ifdef USE_COOKIE_TEX /// The texture for cookie rendering. TORQUE_UNIFORM_SAMPLER2D(cookieMap, 5); +TORQUE_UNIFORM_SAMPLER2D(iesProfile, 6); -#endif uniform float4 rtParams0; uniform float lightBrightness; @@ -96,8 +95,7 @@ float4 main( ConvexConnectP IN ) : SV_TARGET if(dist < lightRange) { SurfaceToLight surfaceToLight = createSurfaceToLight(surface, L); - float3 lightCol = lightColor.rgb; - + float shadow = 1.0; #ifndef NO_SHADOW if (getFlag(surface.matFlag, 0)) //also skip if we don't recieve shadows @@ -109,10 +107,23 @@ float4 main( ConvexConnectP IN ) : SV_TARGET //distance to light in shadow map space float distToLight = pxlPosLightProj.z / lightRange; shadow = softShadow_filter(TORQUE_SAMPLER2D_MAKEARG(shadowMap), ssPos.xy, shadowCoord, shadowSoftness, distToLight, surfaceToLight.NdotL, lightParams.y); - } #endif + float3 lightCol = lightColor.rgb; + #ifdef USE_COOKIE_TEX + float4 pxlPosLightProj = mul( worldToLightProj, float4( surface.P, 1 ) ); + float2 cookieCoord = ( ( pxlPosLightProj.xy / pxlPosLightProj.w ) * 0.5 ) + float2( 0.5, 0.5 ); + // Lookup the cookie sample. + float4 cookie = TORQUE_TEX2D(cookieMap, cookieCoord); + // Multiply the light with the cookie tex. + lightCol *= cookie.rgb; + // Use a maximum channel luminance to attenuate + // the lighting else we get specular in the dark + // regions of the cookie texture. + lightCol *= max(cookie.r, max(cookie.g, cookie.b)); + #endif + #ifdef DIFFUSE_LIGHT_VIZ float attenuation = getDistanceAtt(surfaceToLight.Lu, radius); float3 factor = lightColor * max(surfaceToLight.NdotL, 0) * shadow * lightIntensity * attenuation; @@ -144,13 +155,13 @@ float4 main( ConvexConnectP IN ) : SV_TARGET //get spot light contribution lighting = getSpotlight(surface, surfaceToLight, lightCol, lightBrightness, lightInvSqrRange, lightDirection, lightSpotParams, shadow); - #ifdef USE_COOKIE_TEX + #ifdef UES_PHOTOMETRIC_MASK // Lookup the cookie sample.d float cosTheta = dot(-surfaceToLight.L, lightDirection); float angle = acos(cosTheta) * ( M_1OVER_PI_F); - float cookie = TORQUE_TEX2D(cookieMap, float2(angle, 0.0)).r; - // Multiply the light with the cookie tex. - lighting *= cookie; + float iesMask = TORQUE_TEX2D(iesProfile, float2(angle, 0.0)).r; + // Multiply the light with the iesMask tex. + lighting *= iesMask; #endif }