VolumetricFog.cpp
Engine/source/environment/VolumetricFog.cpp
Public Defines
define
COLBOX_SCALE() (1.02f, 1.02f, 1.02f)
Public Functions
ConsoleDocClass(VolumetricFog , "@brief Volumetric Fog <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a5df911aaca43421a25e32c3002befbc4">Object</a> class. Main class defining the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Volumetric\n</a>" "Fog objects in the scene. Used in conjunction with the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">VolumetricFogRTManager\n</a>" "class which is responsible <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the <a href="/coding/file/tsshapeconstruct_8cpp/#tsshapeconstruct_8cpp_1a21625ca11566389388a748ad1acc0990">required</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">rendertargets.\n\n</a>" "Methods (exposed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> script):\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " setFogColorF(color) Changes the overall fog color (color.rgba range 0.0 - 1.0).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>;" " setFogColor(color) Changes the overall fog color color.rgba range 0 - 255)
DefineEngineMethod(VolumetricFog , isInsideFog , bool , () , "@brief returns true <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> object is inside the fog\n\n." )
DefineEngineMethod(VolumetricFog , SetFogColor , void , (ColorI new_color) )
DefineEngineMethod(VolumetricFog , SetFogColorF , void , (LinearColorF new_color) )
DefineEngineMethod(VolumetricFog , SetFogDensity , void , (F32 new_density) , "@brief Changes the density of the fog\n\n." "@params new_density the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> fog density." )
DefineEngineMethod(VolumetricFog , SetFogGlow , void , (bool on_off, F32 strength) , "@brief Changes the glow postfx when inside the fog\n\n." "@params on_off set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> true <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> enable <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">glow.\n</a>" "@params strength glow <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">strength.\n</a>" )
DefineEngineMethod(VolumetricFog , SetFogLightray , void , (bool on_off, F32 strength) , "@brief Changes the lightrays postfx when inside the fog\n\n." "@params on_off set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> true <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> modification of the lightray <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">postfx.\n</a>" "@params strength lightray <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">strength.\n</a>" )
DefineEngineMethod(VolumetricFog , SetFogModulation , void , (F32 new_strenght, Point2F new_speed1, Point2F new_speed2) , "@brief Changes the modulation of the fog\n\n." "@params new_strenght the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> strength of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">modulation.\n</a>" "@params new_speed1 the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> speed (x y) of the modulation layer 1.\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@params new_speed2 the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> speed (x y) of the modulation layer 2.\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )
IMPLEMENT_CALLBACK(VolumetricFog , onEnterFog , void , (SimObjectId obj) , (obj) , "@brief Called when an object enters the volume of the Fog <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">instance.\n\n</a>" "@param obj the controlobject entering the fog." )
IMPLEMENT_CALLBACK(VolumetricFog , onLeaveFog , void , (SimObjectId obj) , (obj) , "@brief Called when an object left the volume of the Fog <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">instance.\n\n</a>" "@param obj the controlobject leaving the fog." )
Detailed Description
Public Defines
COLBOX_SCALE() (1.02f, 1.02f, 1.02f)
Public Functions
ConsoleDocClass(VolumetricFog , "@brief Volumetric Fog <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a5df911aaca43421a25e32c3002befbc4">Object</a> class. Main class defining the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Volumetric\n</a>" "Fog objects in the scene. Used in conjunction with the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">VolumetricFogRTManager\n</a>" "class which is responsible <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the <a href="/coding/file/tsshapeconstruct_8cpp/#tsshapeconstruct_8cpp_1a21625ca11566389388a748ad1acc0990">required</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">rendertargets.\n\n</a>" "Methods (exposed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> script):\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " setFogColorF(color) Changes the overall fog color (color.rgba range 0.0 - 1.0).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>;" " setFogColor(color) Changes the overall fog color color.rgba range 0 - 255)
DefineEngineMethod(VolumetricFog , isInsideFog , bool , () , "@brief returns true <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> object is inside the fog\n\n." )
DefineEngineMethod(VolumetricFog , SetFogColor , void , (ColorI new_color) )
DefineEngineMethod(VolumetricFog , SetFogColorF , void , (LinearColorF new_color) )
DefineEngineMethod(VolumetricFog , SetFogDensity , void , (F32 new_density) , "@brief Changes the density of the fog\n\n." "@params new_density the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> fog density." )
DefineEngineMethod(VolumetricFog , SetFogGlow , void , (bool on_off, F32 strength) , "@brief Changes the glow postfx when inside the fog\n\n." "@params on_off set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> true <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> enable <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">glow.\n</a>" "@params strength glow <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">strength.\n</a>" )
DefineEngineMethod(VolumetricFog , SetFogLightray , void , (bool on_off, F32 strength) , "@brief Changes the lightrays postfx when inside the fog\n\n." "@params on_off set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> true <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> modification of the lightray <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">postfx.\n</a>" "@params strength lightray <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">strength.\n</a>" )
DefineEngineMethod(VolumetricFog , SetFogModulation , void , (F32 new_strenght, Point2F new_speed1, Point2F new_speed2) , "@brief Changes the modulation of the fog\n\n." "@params new_strenght the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> strength of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">modulation.\n</a>" "@params new_speed1 the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> speed (x y) of the modulation layer 1.\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@params new_speed2 the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> speed (x y) of the modulation layer 2.\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )
IMPLEMENT_CALLBACK(VolumetricFog , onEnterFog , void , (SimObjectId obj) , (obj) , "@brief Called when an object enters the volume of the Fog <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">instance.\n\n</a>" "@param obj the controlobject entering the fog." )
IMPLEMENT_CALLBACK(VolumetricFog , onLeaveFog , void , (SimObjectId obj) , (obj) , "@brief Called when an object left the volume of the Fog <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">instance.\n\n</a>" "@param obj the controlobject leaving the fog." )
IMPLEMENT_CO_NETOBJECT_V1(VolumetricFog )
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "environment/VolumetricFog.h" 25#include "windowManager/platformWindowMgr.h" 26#include "gfx/gfxTransformSaver.h" 27#include "renderInstance/renderPassManager.h" 28#include "math/mathIO.h" 29#include "materials/shaderData.h" 30#include "math/util/matrixSet.h" 31#include "core/resourceManager.h" 32#include "core/stream/bitStream.h" 33#include "T3D/gameBase/gameConnection.h" 34#include "T3D/shapeBase.h" 35#include "ts/tsShapeInstance.h" 36#include "console/engineAPI.h" 37#include "gui/core/guiCanvas.h" 38#include "VolumetricFogRTManager.h" 39#include "lighting/lightInfo.h" 40#include "lighting/lightManager.h" 41 42#define COLBOX_SCALE Point3F(1.02f, 1.02f, 1.02f) 43 44IMPLEMENT_CO_NETOBJECT_V1(VolumetricFog); 45 46ConsoleDocClass(VolumetricFog, 47"@brief Volumetric Fog Object class. Main class defining the Volumetric\n" 48"Fog objects in the scene. Used in conjunction with the VolumetricFogRTManager\n" 49"class which is responsible for the required rendertargets.\n\n" 50"Methods (exposed to script):\n" 51" setFogColorF(color) Changes the overall fog color (color.rgba range 0.0 - 1.0).\n;" 52" setFogColor(color) Changes the overall fog color color.rgba range 0 - 255).\n;" 53" setFogDensity(density) Changes the overall fog density.\n" 54" setFogModulation(strength, speed1, speed2) changes the strength\n" 55" and the speeds of the 2 animation layers.\n\n" 56"Callbacks:\n" 57"onEnterFog triggered whenever the controlobject (Player or Camera) enters the Fog.\n" 58" (current Fog object and the controlobject are exposed to script.\n" 59"onLeaveFog triggered whenever the controlobject (Player or Camera) left the Fog.\n" 60" (current Fog object and the controlobject are exposed to script.\n\n" 61"@tsexample\n" 62" new VolumetricFog()\n" 63" {\n" 64" shapeName = \"art/environment/FogRCube.dts\";\n" 65" fogColor = \"200 200 200 128\";\n" 66" fogDensity = \"0.2\";\n" 67" ignoreWater = \"0\";\n" 68" MinSize = \"250\";\n" 69" FadeSize = \"750\";\n" 70" texture = \"art/environment/FogMod_heavy.dds\";\n" 71" tiles = \"1.5\";\n" 72" modStrength = \"0.2\";\n" 73" PrimSpeed = \"-0.01 0.04\";\n" 74" SecSpeed = \"0.02 -0.02\";\n" 75" position = \"748.644 656.371 65.3506\"; \n" 76" rotation = \"0 0 1 20.354\";\n" 77" scale = \"40 30 6\";\n" 78" };\n" 79"@endtsexample\n" 80); 81 82IMPLEMENT_CALLBACK(VolumetricFog, onEnterFog, void, (SimObjectId obj), (obj), 83"@brief Called when an object enters the volume of the Fog instance.\n\n" 84 85"@param obj the controlobject entering the fog."); 86 87IMPLEMENT_CALLBACK(VolumetricFog, onLeaveFog, void, (SimObjectId obj), (obj), 88"@brief Called when an object left the volume of the Fog instance.\n\n" 89 90"@param obj the controlobject leaving the fog."); 91 92 93VolumetricFog::VolumetricFog() 94{ 95 AssertFatal(VFRTM != NULL, "VolumetricFog Fatal Error: No Manager found"); 96 97 if (!VFRTM->IsInitialized()) 98 VFRTM->Init(); 99 100 mNetFlags.set(Ghostable | ScopeAlways); 101 102 mTypeMask |= EnvironmentObjectType | StaticObjectType; 103 104 mDeferredTarget = NULL; 105 mDepthBufferTarget = NULL; 106 mFrontBufferTarget = NULL; 107 108 z_buf = NULL; 109 mTexture = NULL; 110 111 mIsVBDirty = false; 112 mIsPBDirty = false; 113 114 mFogColor.set(200, 200, 200, 255); 115 mFogDensity = 0.3f; 116 mIgnoreWater = false; 117 mReflect = false; 118 mCamInFog = false; 119 mResizing = false; 120 mFogReflStrength = 20.0; 121 mUseGlow = false; 122 mGlowStrength = 0.3f; 123 mGlowing = 0; 124 mModifLightRays = false; 125 mLightRayMod = 1.0f; 126 mOldLightRayStrength = 0.1f; 127 128 mShapeName = ""; 129 mShapeLoaded = false; 130 mMinDisplaySize = 10.0f; 131 mFadeSize = 0.0f; 132 mCurDetailLevel = 0; 133 mNumDetailLevels = 0; 134 det_size.clear(); 135 136 mTextureName = ""; 137 mIsTextured = false; 138 mStrength = 0.5f; 139 mTexTiles = 1.0f; 140 mSpeed1.set(0.5f, 0.0f); 141 mSpeed2.set(0.1f, 0.1f); 142 143 mShapeAsset = StringTable->EmptyString(); 144 mShapeAssetId = StringTable->EmptyString(); 145} 146 147VolumetricFog::~VolumetricFog() 148{ 149 if (!isClientObject()) 150 return; 151 152 for (S32 i = 0; i < det_size.size(); i++) 153 { 154 if (det_size[i].indices != NULL) 155 delete(det_size[i].indices); 156 if (det_size[i].piArray != NULL) 157 delete(det_size[i].piArray); 158 if (det_size[i].verts != NULL) 159 delete [] (det_size[i].verts); 160 } 161 det_size.clear(); 162 163 z_buf = NULL; 164 165 if (!mTexture.isNull()) 166 mTexture.free(); 167} 168 169void VolumetricFog::initPersistFields() 170{ 171 addGroup("VolumetricFogData"); 172 addProtectedField("shapeAsset", TypeShapeAssetPtr, Offset(mShapeAsset, VolumetricFog), 173 &VolumetricFog::_setShapeAsset, &defaultProtectedGetFn, "The source shape asset."); 174 175 addField("shapeName", TypeShapeFilename, Offset(mShapeName, VolumetricFog), 176 "Path and filename of the model file (.DTS, .DAE) to use for this Volume.", AbstractClassRep::FieldFlags::FIELD_HideInInspectors ); 177 178 addField("FogColor", TypeColorI, Offset(mFogColor, VolumetricFog), 179 "Fog color RGBA (Alpha is ignored)"); 180 addField("FogDensity", TypeF32, Offset(mFogDensity, VolumetricFog), 181 "Overal fog density value (0 disables the fog)."); 182 addField("IgnoreWater", TypeBool, Offset(mIgnoreWater, VolumetricFog), 183 "Set to true if volumetric fog should continue while submerged."); 184 addField("MinSize", TypeF32, Offset(mMinDisplaySize, VolumetricFog), 185 "Min size (in pixels) for fog to be rendered."); 186 addField("FadeSize", TypeF32, Offset(mFadeSize, VolumetricFog), 187 "Object size in pixels at which the FX-fading kicks in (0 disables fading)."); 188 endGroup("VolumetricFogData"); 189 190 addGroup("VolumetricFogModulation"); 191 addField("texture", TypeImageFilename, Offset(mTextureName, VolumetricFog), 192 "A texture which contains Fogdensity modulator in the red channel and color with 1-green channel. No texture disables modulation."); 193 addField("tiles", TypeF32, Offset(mTexTiles, VolumetricFog), 194 "How many times the texture is mapped to the object."); 195 addField("modStrength", TypeF32, Offset(mStrength, VolumetricFog), 196 "Overall strength of the density modulation (0 disables modulation)."); 197 addField("PrimSpeed", TypePoint2F, Offset(mSpeed1, VolumetricFog), 198 "Overall primary speed of the density modulation (x-speed(u) y-speed(v))"); 199 addField("SecSpeed", TypePoint2F, Offset(mSpeed2, VolumetricFog), 200 "Overall secundary speed of the density modulation (x-speed(u) y-speed(v))"); 201 endGroup("VolumetricFogModulation"); 202 203 addGroup("Reflections"); 204 addField("Reflectable", TypeBool, Offset(mReflect, VolumetricFog), 205 "Set to true if volumetric fog should be reflected."); 206 addField("ReflectStrength", TypeF32, Offset(mFogReflStrength, VolumetricFog), 207 "Strength of the reflections (0 disables the fog)."); 208 endGroup("Reflections"); 209 210 addGroup("PostFX"); 211 addField("useGlow", TypeBool, Offset(mUseGlow, VolumetricFog), 212 "Set to true if volumetric fog should use glow PostFX."); 213 addField("glowStrength", TypeF32, Offset(mGlowStrength, VolumetricFog), 214 "Overall strength of the glow PostFX."); 215 addField("modLightRay", TypeBool, Offset(mModifLightRays, VolumetricFog), 216 "Set to true if volumetric fog should modify the brightness of the Lightrays."); 217 addField("lightRayMod", TypeF32, Offset(mLightRayMod, VolumetricFog), 218 "Modifier for LightRay PostFX when inside Fog."); 219 endGroup("PostFX"); 220 Parent::initPersistFields(); 221} 222 223bool VolumetricFog::_setShapeAsset(void* obj, const char* index, const char* data) 224{ 225 VolumetricFog* fog = static_cast<VolumetricFog*>(obj);// ->setFile(FileName(data)); 226 227 fog->setShapeAsset(StringTable->insert(data)); 228 229 return false; 230} 231 232void VolumetricFog::inspectPostApply() 233{ 234 Parent::inspectPostApply(); 235 mSpeed.set(mSpeed1.x, mSpeed1.y, mSpeed2.x, mSpeed2.y); 236 setMaskBits(VolumetricFogMask | FogColorMask | FogDensityMask | FogModulationMask | FogPostFXMask | FogShapeMask); 237} 238 239bool VolumetricFog::onAdd() 240{ 241 if (!Parent::onAdd()) 242 return false; 243 244 if (!VFRTM->IsInitialized()) 245 { 246 Con::errorf("No VolumetricFogRTManager present!!"); 247 return false; 248 } 249 250 resetWorldBox(); 251 252 mShapeLoaded = LoadShape(); 253 254 setRenderTransform(mObjToWorld); 255 256 addToScene(); 257 ColBox.set(getTransform(), (mObjBox.getExtents() * getScale() * COLBOX_SCALE)); 258 mObjSize = mWorldBox.getGreatestDiagonalLength(); 259 mObjScale = getScale(); 260 mTexTiles = mAbs(mTexTiles); 261 mSpeed.set(mSpeed1.x, mSpeed1.y, mSpeed2.x, mSpeed2.y); 262 mInvScale = (1.0f / getMax(getMax(mObjScale.x, mObjScale.y), mObjScale.z)); 263 264 VFRTM->IncFogObjects(); 265 266 if (isClientObject()) 267 { 268 conn = GameConnection::getConnectionToServer(); 269 if (!conn) 270 { 271 Con::errorf("VolumetricFog::onAdd - No Serverconnection"); 272 return false; 273 } 274 275 glowFX = static_cast<PostEffect*>(Sim::findObject("VolFogGlowPostFx")); 276 277 mOldLightRayStrength = Con::getFloatVariable("$LightRayPostFX::brightScalar",1.0f); 278 279 GuiCanvas* cv = dynamic_cast<GuiCanvas*>(Sim::findObject("Canvas")); 280 if (cv == NULL) 281 { 282 Con::errorf("VolumetricFog::onAdd - Canvas not found!!"); 283 return false; 284 } 285 mPlatformWindow = cv->getPlatformWindow(); 286 VolumetricFogRTManager::getVolumetricFogRTMResizeSignal().notify(this, &VolumetricFog::handleResize); 287 GuiCanvas::getCanvasSizeChangeSignal().notify(this, &VolumetricFog::handleCanvasResize); 288 289 InitTexture(); 290 return setupRenderer(); 291 } 292 293 return true; 294} 295 296void VolumetricFog::onRemove() 297{ 298 if (isClientObject()) 299 { 300 if (isTicking()) 301 { 302 setProcessTick(false); 303 if (mGlowing != 0) 304 { 305 mGlowing = 0; 306 glowFX->disable(); 307 } 308 _leaveFog(dynamic_cast<ShapeBase*>(conn->getControlObject())); 309 } 310 VolumetricFogRTManager::getVolumetricFogRTMResizeSignal().remove(this, &VolumetricFog::handleResize); 311 GuiCanvas::getCanvasSizeChangeSignal().remove(this, &VolumetricFog::handleCanvasResize); 312 } 313 removeFromScene(); 314 VFRTM->DecFogObjects(); 315 Parent::onRemove(); 316} 317void VolumetricFog::handleCanvasResize(GuiCanvas* canvas) 318{ 319 UpdateBuffers(0,true); 320} 321 322void VolumetricFog::handleResize(VolumetricFogRTManager *RTM, bool resize) 323{ 324 if (resize) 325 { 326 mResizing = true; 327 RTM->FogAnswered(); 328 } 329 else 330 mResizing = false; 331 332 if (mIsTextured) 333 { 334 F32 width = (F32)mPlatformWindow->getClientExtent().x; 335 F32 height = (F32)mPlatformWindow->getClientExtent().y; 336 337 mTexScale.x = 2.0f - ((F32)mTexture.getWidth() / width); 338 mTexScale.y = 2.0f - ((F32)mTexture.getHeight() / height); 339 } 340 341 UpdateBuffers(0,true); 342} 343 344//----------------------------------------------------------------------------- 345// Loadshape extracted from TSMesh and TSShapeInstance 346//----------------------------------------------------------------------------- 347 348bool VolumetricFog::setShapeAsset(const StringTableEntry shapeAssetId) 349{ 350 mShapeAssetId = shapeAssetId; 351 352 LoadShape(); 353 return true; 354} 355 356bool VolumetricFog::LoadShape() 357{ 358 GFXPrimitiveType GFXdrawTypes[] = { GFXTriangleList, GFXTriangleStrip }; 359 360 Resource<TSShape> mShape; 361 if (mShapeAssetId != StringTable->EmptyString()) 362 { 363 mShapeAsset = mShapeAssetId; 364 365 if (mShapeAsset.isNull()) 366 { 367 Con::errorf("[TSStatic] Failed to load shape asset."); 368 return false; 369 } 370 371 mShape = mShapeAsset->getShapeResource(); 372 373 if (!mShape) 374 { 375 Con::errorf("TSStatic::_createShape() - Shape Asset had no valid shape!"); 376 return false; 377 } 378 } 379 else 380 { 381 if (!mShapeName || mShapeName[0] == '\0') 382 { 383 Con::errorf("VolumetricFog::LoadShape() - No shape name! Volumetric Fog will not be rendered!"); 384 return false; 385 } 386 387 // Load shape, server side only reads bounds and radius 388 mShape = ResourceManager::get().load(mShapeName); 389 } 390 391 if (bool(mShape) == false) 392 { 393 Con::errorf("VolumetricFog::LoadShape() - Unable to load shape: %s", mShapeName); 394 return false; 395 } 396 397 mObjBox = mShape->mBounds; 398 mRadius = mShape->mRadius; 399 resetWorldBox(); 400 401 if (!isClientObject()) 402 return false; 403 404 TSShapeInstance *mShapeInstance = new TSShapeInstance(mShape, false); 405 meshes mesh_detail; 406 407 for (S32 i = 0; i < det_size.size(); i++) 408 { 409 if (det_size[i].indices != NULL) 410 delete(det_size[i].indices); 411 if (det_size[i].piArray != NULL) 412 delete(det_size[i].piArray); 413 if (det_size[i].verts != NULL) 414 delete [] (det_size[i].verts); 415 } 416 det_size.clear(); 417 418 // browsing model for detail levels 419 420 for (U32 i = 0; i < mShape->details.size(); i++) 421 { 422 const TSDetail *detail = &mShape->details[i]; 423 mesh_detail.det_size = detail->size; 424 mesh_detail.sub_shape = detail->subShapeNum; 425 mesh_detail.obj_det = detail->objectDetailNum; 426 mesh_detail.verts = NULL; 427 mesh_detail.piArray = NULL; 428 mesh_detail.indices = NULL; 429 if (detail->size >= 0.0f && detail->subShapeNum >= 0) 430 det_size.push_back(mesh_detail); 431 } 432 433 for (U32 i = 0; i < det_size.size(); i++) 434 { 435 const S32 ss = det_size[i].sub_shape; 436 if (ss >= 0) 437 { 438 const S32 start = mShape->subShapeFirstObject[ss]; 439 const S32 end = start + mShape->subShapeNumObjects[ss]; 440 for (S32 j = start; j < end; j++) 441 { 442 // Loading shape, only the first mesh for each detail will be used! 443 TSShapeInstance::MeshObjectInstance *meshObj = &mShapeInstance->mMeshObjects[j]; 444 if (!meshObj) 445 continue; 446 TSMesh *mesh = meshObj->getMesh(det_size[i].obj_det); 447 if (mesh != NULL) 448 { 449 const U32 numNrms = mesh->mNumVerts; 450 GFXVertexPNTT *tmpVerts = NULL; 451 tmpVerts = new GFXVertexPNTT[numNrms]; 452 mIsVBDirty = true; 453 for (U32 k = 0; k < numNrms; k++) 454 { 455 const TSMesh::__TSMeshVertexBase &vd = mesh->mVertexData.getBase(k); 456 Point3F norm = vd.normal(); 457 Point3F vert = vd.vert(); 458 Point2F uv = vd.tvert(); 459 tmpVerts[k].point = vert; 460 tmpVerts[k].texCoord = uv; 461 tmpVerts[k].normal = norm; 462 } 463 det_size[i].verts = tmpVerts; 464 det_size[i].num_verts = numNrms; 465 466 det_size[i].piArray = new Vector<GFXPrimitive>(); 467 GFXPrimitive pInfo; 468 469 det_size[i].indices = new Vector<U32>(); 470 471 for (U32 k = 0; k < mesh->mIndices.size(); k++) 472 det_size[i].indices->push_back(mesh->mIndices[k]); 473 474 U32 primitivesSize = mesh->mPrimitives.size(); 475 for (U32 k = 0; k < primitivesSize; k++) 476 { 477 const TSDrawPrimitive & draw = mesh->mPrimitives[k]; 478 GFXPrimitiveType drawType = GFXdrawTypes[draw.matIndex >> 30]; 479 switch (drawType) 480 { 481 case GFXTriangleList: 482 pInfo.type = drawType; 483 pInfo.numPrimitives = draw.numElements / 3; 484 pInfo.startIndex = draw.start; 485 // Use the first index to determine which 16-bit address space we are operating in 486 pInfo.startVertex = mesh->mIndices[draw.start] & 0xFFFF0000; 487 pInfo.minIndex = pInfo.startVertex; 488 pInfo.numVertices = getMin((U32)0x10000, mesh->mNumVerts - pInfo.startVertex); 489 break; 490 case GFXTriangleStrip: 491 pInfo.type = drawType; 492 pInfo.numPrimitives = draw.numElements - 2; 493 pInfo.startIndex = draw.start; 494 // Use the first index to determine which 16-bit address space we are operating in 495 pInfo.startVertex = mesh->mIndices[draw.start] & 0xFFFF0000; 496 pInfo.minIndex = pInfo.startVertex; 497 pInfo.numVertices = getMin((U32)0x10000, mesh->mNumVerts - pInfo.startVertex); 498 break; 499 default: 500 Con::errorf("VolumetricFog::LoadShape Unknown drawtype!?!"); 501 return false; 502 break; 503 } 504 det_size[i].piArray->push_back(pInfo); 505 j = end; 506 } 507 } 508 else 509 { 510 Con::errorf("VolumetricFog::LoadShape Error loading mesh from shape!"); 511 delete mShapeInstance; 512 return false; 513 } 514 mIsVBDirty = true; 515 mIsPBDirty = true; 516 } 517 } 518 } 519 520 mNumDetailLevels = det_size.size(); 521 mCurDetailLevel = 0; 522 UpdateBuffers(mCurDetailLevel); 523 delete mShapeInstance; 524 525 return true; 526} 527 528//----------------------------------------------------------------------------- 529// UpdateBuffers called whenever detaillevel changes (LOD) 530//----------------------------------------------------------------------------- 531 532 533bool VolumetricFog::UpdateBuffers(U32 dl, bool force) 534{ 535 if (mVB.isNull() || mIsVBDirty || dl != mCurDetailLevel || force) 536 { 537 mVB.set(GFX, det_size[dl].num_verts, GFXBufferTypeDynamic); 538 mIsVBDirty = false; 539 } 540 GFXVertexPNTT *vertPtr = mVB.lock(); 541 if (!vertPtr) 542 { 543 mVB.unlock(); 544 return false; 545 } 546 dMemcpy(vertPtr, det_size[dl].verts, sizeof (GFXVertexPNTT)* det_size[dl].num_verts); 547 mVB.unlock(); 548 549 if (mIsPBDirty || mPB.isNull() || dl != mCurDetailLevel || force) 550 { 551 #ifdef TORQUE_DEBUG 552 mPB.set(GFX, det_size[dl].indices->size(), det_size[dl].piArray->size(), GFXBufferTypeDynamic, avar("%s() - VolFogPrimBuffer (line %d)", __FUNCTION__, __LINE__)); 553 #else 554 mPB.set(GFX, det_size[dl].indices->size(), det_size[dl].piArray->size(), GFXBufferTypeDynamic); 555 #endif 556 U16 *ibIndices = NULL; 557 GFXPrimitive *piInput = NULL; 558 mPB.lock(&ibIndices, &piInput); 559 dCopyArray(ibIndices, det_size[dl].indices->address(), det_size[dl].indices->size()); 560 dMemcpy(piInput, det_size[dl].piArray->address(), det_size[dl].piArray->size() * sizeof(GFXPrimitive)); 561 mPB.unlock(); 562 mIsPBDirty = false; 563 } 564 mCurDetailLevel = dl; 565 return true; 566} 567 568U32 VolumetricFog::packUpdate(NetConnection *con, U32 mask, BitStream *stream) 569{ 570 U32 retMask = Parent::packUpdate(con, mask, stream); 571 if (stream->writeFlag(mask & FogColorMask)) 572 stream->write(mFogColor); 573 if (stream->writeFlag(mask & FogDensityMask)) 574 stream->write(mFogDensity); 575 if (stream->writeFlag(mask & FogModulationMask)) 576 { 577 stream->write(mTextureName); 578 mTexTiles = mFabs(mTexTiles); 579 stream->write(mTexTiles); 580 stream->write(mStrength); 581 mathWrite(*stream, mSpeed); 582 } 583 if (stream->writeFlag(mask & FogPostFXMask)) 584 { 585 stream->writeFlag(mUseGlow); 586 stream->write(mGlowStrength); 587 stream->writeFlag(mModifLightRays); 588 stream->write(mLightRayMod); 589 } 590 if (stream->writeFlag(mask & VolumetricFogMask)) 591 { 592 stream->writeFlag(mIgnoreWater); 593 stream->writeFlag(mReflect); 594 stream->write(mFogReflStrength); 595 stream->writeFlag(mResizing); 596 stream->write(mMinDisplaySize); 597 stream->write(mFadeSize); 598 } 599 if (stream->writeFlag(mask & FogShapeMask)) 600 { 601 stream->writeString(mShapeAssetId); 602 stream->writeString(mShapeName); 603 mathWrite(*stream, getTransform()); 604 mathWrite(*stream, getScale()); 605 606 Resource<TSShape> mShape; 607 608 if (mShapeAssetId != StringTable->EmptyString()) 609 { 610 mShape = mShapeAsset->getShapeResource(); 611 } 612 else if (mShapeName && mShapeName[0] != '\0') 613 { 614 mShape = ResourceManager::get().load(mShapeName); 615 } 616 617 if (bool(mShape) == false) 618 return retMask; 619 620 mObjBox = mShape->mBounds; 621 mRadius = mShape->mRadius; 622 resetWorldBox(); 623 mObjSize = mWorldBox.getGreatestDiagonalLength(); 624 mObjScale = getScale(); 625 mInvScale = (1.0f / getMax(getMax(mObjScale.x, mObjScale.y), mObjScale.z)); 626 } 627 return retMask; 628} 629 630void VolumetricFog::unpackUpdate(NetConnection *con, BitStream *stream) 631{ 632 Parent::unpackUpdate(con, stream); 633 MatrixF mat; 634 VectorF scale; 635 VectorF mOldScale = getScale(); 636 String oldTextureName = mTextureName; 637 StringTableEntry oldShapeAsset = mShapeAssetId; 638 StringTableEntry oldShape = mShapeName; 639 640 if (stream->readFlag())// Fog color 641 stream->read(&mFogColor); 642 if (stream->readFlag())// Fog Density 643 { 644 stream->read(&mFogDensity); 645 if (isTicking()) 646 { 647 char buf[20]; 648 dSprintf(buf, sizeof(buf), "%3.7f", mFogDensity); 649 Con::setVariable("$VolumetricFog::density", buf); 650 } 651 } 652 if (stream->readFlag())// Fog Modulation 653 { 654 stream->read(&mTextureName); 655 stream->read(&mTexTiles); 656 mTexTiles = mFabs(mTexTiles); 657 stream->read(&mStrength); 658 mathRead(*stream, &mSpeed); 659 mSpeed1.set(mSpeed.x, mSpeed.y); 660 mSpeed2.set(mSpeed.z, mSpeed.w); 661 662 if (isProperlyAdded()) 663 { 664 if (oldTextureName != mTextureName) 665 InitTexture(); 666 if (oldTextureName.isNotEmpty() && mTextureName.isEmpty()) 667 { 668 mIsTextured = false; 669 mTexture.free(); 670 } 671 } 672 } 673 if (stream->readFlag())//Fog PostFX 674 { 675 mUseGlow = stream->readFlag(); 676 stream->read(&mGlowStrength); 677 mModifLightRays = stream->readFlag(); 678 stream->read(&mLightRayMod); 679 if (isTicking()) 680 { 681 char glowStrBuf[20]; 682 dSprintf(glowStrBuf, sizeof(glowStrBuf), "%3.7f", mGlowStrength); 683 Con::setVariable("$VolFogGlowPostFx::glowStrength", glowStrBuf); 684 if (mUseGlow && !glowFX->isEnabled()) 685 glowFX->enable(); 686 if (!mUseGlow && glowFX->isEnabled()) 687 glowFX->disable(); 688 689 F32 rayStrength = mOldLightRayStrength; 690 if (mModifLightRays) 691 rayStrength *= mLightRayMod; 692 char rayStrBuf[20]; 693 dSprintf(rayStrBuf, sizeof(rayStrBuf), "%3.7f", rayStrength); 694 Con::setVariable("$LightRayPostFX::brightScalar", rayStrBuf); 695 } 696 } 697 if (stream->readFlag())//Volumetric Fog 698 { 699 mIgnoreWater = stream->readFlag(); 700 mReflect = stream->readFlag(); 701 stream->read(&mFogReflStrength); 702 mResizing = stream->readFlag(); 703 stream->read(&mMinDisplaySize); 704 stream->read(&mFadeSize); 705 } 706 if (stream->readFlag())//Fog shape 707 { 708 char buffer[256]; 709 stream->readString(buffer); 710 mShapeAssetId = StringTable->insert(buffer); 711 712 mShapeName = stream->readSTString(); 713 mathRead(*stream, &mat); 714 mathRead(*stream, &scale); 715 if (strcmp(oldShapeAsset, mShapeAssetId) != 0 || strcmp(oldShape, mShapeName) != 0) 716 { 717 mIsVBDirty = true; 718 mShapeLoaded = LoadShape(); 719 } 720 setScale(scale); 721 setTransform(mat); 722 ColBox.set(getTransform(), (mObjBox.getExtents() * getScale() * COLBOX_SCALE)); 723 mObjSize = mWorldBox.getGreatestDiagonalLength(); 724 mObjScale = getScale(); 725 mInvScale = (1.0f / getMax(getMax(mObjScale.x, mObjScale.y), mObjScale.z)); 726 } 727} 728 729void VolumetricFog::processTick(const Move* move) 730{ 731 Parent::processTick(move); 732 mCounter++; 733 if ( mGlowing==1 && mCurGlow < mGlowStrength ) 734 { 735 mCurGlow += (mGlowStrength / 10.0); 736 char buf[20]; 737 dSprintf(buf, sizeof(buf), "%3.7f", mCurGlow); 738 Con::setVariable("$VolFogGlowPostFx::glowStrength", buf); 739 } 740 else if ( mGlowing == 2 && mCurGlow > 0.0f ) 741 { 742 mCurGlow -= (mGlowStrength / 5.0f); 743 if (mCurGlow <= 0.0f) 744 { 745 glowFX->disable(); 746 mGlowing = 0; 747 setProcessTick(false); 748 return; 749 } 750 else 751 { 752 char buf[20]; 753 dSprintf(buf, sizeof(buf), "%3.7f", mCurGlow); 754 Con::setVariable("$VolFogGlowPostFx::glowStrength", buf); 755 } 756 } 757 if (mCounter == 3) 758 { 759 ShapeBase* control = dynamic_cast<ShapeBase*>(conn->getControlObject()); 760 if (!control) 761 return; 762 MatrixF xfm; 763 control->getRenderEyeTransform(&xfm); 764 Point3F pos = xfm.getPosition(); 765 if (!ColBox.isContained(pos)) 766 _leaveFog(control); 767 mCounter = 0; 768 } 769} 770 771void VolumetricFog::_enterFog(ShapeBase *control) 772{ 773 if (mUseGlow) 774 { 775 if (glowFX) 776 { 777 mCurGlow = 0.0f; 778 Con::setVariable("$VolFogGlowPostFx::glowStrength", "0.0"); 779 glowFX->enable(); 780 mGlowing = 1; 781 } 782 } 783 if (mModifLightRays) 784 { 785 char buf[20]; 786 dSprintf(buf, sizeof(buf), "%3.7f", mOldLightRayStrength * mLightRayMod); 787 Con::setVariable("$LightRayPostFX::brightScalar", buf); 788 } 789 mCounter = 0; 790 char buf[20]; 791 dSprintf(buf, sizeof(buf), "%3.7f", mFogDensity); 792 Con::setVariable("$VolumetricFog::density", buf); 793 setProcessTick(true); 794 if (control) 795 onEnterFog_callback(control->getId()); 796} 797 798void VolumetricFog::_leaveFog(ShapeBase *control) 799{ 800 mCamInFog = false; 801 Con::setVariable("$VolumetricFog::density", "0.0"); 802 if (mModifLightRays) 803 { 804 char buf[20]; 805 dSprintf(buf, sizeof(buf), "%3.7f", mOldLightRayStrength); 806 Con::setVariable("$LightRayPostFX::brightScalar", buf); 807 } 808 if (mUseGlow) 809 { 810 if (glowFX && mGlowing != 2) 811 { 812 mCurGlow = mGlowStrength; 813 mGlowing = 2; 814 if (control) 815 onLeaveFog_callback(control->getId()); 816 } 817 } 818 else 819 { 820 setProcessTick(false); 821 if (control) 822 onLeaveFog_callback(control->getId()); 823 } 824} 825 826//----------------------------------------------------------------------------- 827// Setting up the renderers 828//----------------------------------------------------------------------------- 829 830bool VolumetricFog::setupRenderer() 831{ 832 // Search for the deferred rendertarget and shadermacros. 833 mDeferredTarget = NamedTexTarget::find("deferred"); 834 if (!mDeferredTarget.isValid()) 835 { 836 Con::errorf("VolumetricFog::setupRenderer - could not find DeferredTarget"); 837 return false; 838 } 839 840 Vector<GFXShaderMacro> macros; 841 if (mDeferredTarget) 842 mDeferredTarget->getShaderMacros(¯os); 843 844 // Search the depth and frontbuffers which are created by the VolumetricFogRTManager 845 846 mDepthBufferTarget = NamedTexTarget::find("volfogdepth"); 847 if (!mDepthBufferTarget.isValid()) 848 { 849 Con::errorf("VolumetricFog::setupRenderer - could not find depthbuffer"); 850 return false; 851 } 852 853 mFrontBufferTarget = NamedTexTarget::find("volfogfront"); 854 if (!mFrontBufferTarget.isValid()) 855 { 856 Con::errorf("VolumetricFog::setupRenderer - could not find frontbuffer"); 857 return false; 858 } 859 860 // Find and setup the deferred Shader 861 862 ShaderData *shaderData; 863 mDeferredShader = Sim::findObject("VolumetricFogDeferredShader", shaderData) ? 864 shaderData->getShader() : NULL; 865 if (!mDeferredShader) 866 { 867 Con::errorf("VolumetricFog::setupRenderer - could not find VolumetricFogDeferredShader"); 868 return false; 869 } 870 871 // Create ShaderConstBuffer and Handles 872 873 mPPShaderConsts = mDeferredShader->allocConstBuffer(); 874 if (mPPShaderConsts.isNull()) 875 { 876 Con::errorf("VolumetricFog::setupRenderer - could not allocate ShaderConstants 1."); 877 return false; 878 } 879 880 mPPModelViewProjSC = mDeferredShader->getShaderConstHandle("$modelView"); 881 882 // Find and setup the VolumetricFog Shader 883 884 shaderData = NULL; 885 mShader = Sim::findObject("VolumetricFogShader", shaderData) ? 886 shaderData->getShader(macros) : NULL; 887 if (!mShader) 888 { 889 Con::errorf("VolumetricFog::setupRenderer - could not find VolumetricFogShader"); 890 return false; 891 } 892 893 // Create ShaderConstBuffer and Handles 894 895 mShaderConsts = mShader->allocConstBuffer(); 896 if (mShaderConsts.isNull()) 897 { 898 Con::errorf("VolumetricFog::setupRenderer - could not allocate ShaderConstants 2."); 899 return false; 900 } 901 902 mModelViewProjSC = mShader->getShaderConstHandle("$modelView"); 903 mFadeSizeSC = mShader->getShaderConstHandle("$fadesize"); 904 mFogColorSC = mShader->getShaderConstHandle("$fogColor"); 905 mFogDensitySC = mShader->getShaderConstHandle("$fogDensity"); 906 mPreBias = mShader->getShaderConstHandle("$preBias"); 907 mAccumTime = mShader->getShaderConstHandle("$accumTime"); 908 mIsTexturedSC = mShader->getShaderConstHandle("$textured"); 909 mTexTilesSC = mShader->getShaderConstHandle("$numtiles"); 910 mModStrengthSC = mShader->getShaderConstHandle("$modstrength"); 911 mModSpeedSC = mShader->getShaderConstHandle("$modspeed"); 912 mViewPointSC = mShader->getShaderConstHandle("$viewpoint"); 913 mTexScaleSC = mShader->getShaderConstHandle("$texscale"); 914 mAmbientColorSC = mShader->getShaderConstHandle("$ambientColor"); 915 916 // Find and setup the reflection Shader 917 918 shaderData = NULL; 919 mReflectionShader = Sim::findObject("VolumetricFogReflectionShader", shaderData) ? 920 shaderData->getShader() : NULL; 921 if (!mReflectionShader) 922 { 923 Con::errorf("VolumetricFog::setupRenderer - could not find VolumetricFogReflectionShader"); 924 return false; 925 } 926 927 mReflShaderConsts = mReflectionShader->allocConstBuffer(); 928 if (mReflShaderConsts.isNull()) 929 { 930 Con::errorf("VolumetricFog::setupRenderer - could not allocate ShaderConstants for VolumetricFogReflectionShader."); 931 return false; 932 } 933 934 mReflModelViewProjSC = mReflectionShader->getShaderConstHandle("$modelView"); 935 mReflFogColorSC = mReflectionShader->getShaderConstHandle("$fogColor"); 936 mReflFogDensitySC = mReflectionShader->getShaderConstHandle("$fogDensity"); 937 mReflFogStrengthSC = mReflectionShader->getShaderConstHandle("$reflStrength"); 938 939 // Create the deferred StateBlock 940 941 desc_preD.setCullMode(GFXCullCW); 942 desc_preD.setBlend(true); 943 desc_preD.setZReadWrite(false, false); 944 desc_preD.stencilEnable = false; 945 desc_preF.setCullMode(GFXCullCCW); 946 desc_preF.setBlend(true); 947 desc_preF.setZReadWrite(true, false); 948 desc_preF.stencilEnable = false; 949 950 // Create the VolumetricFog StateBlock 951 952 descD.setCullMode(GFXCullCW); 953 descD.setBlend(true); 954 descD.setZReadWrite(false, false);// desc.setZReadWrite(true, false); 955 956 // deferredBuffer sampler 957 descD.samplersDefined = true; 958 descD.samplers[0].addressModeU = GFXAddressClamp; 959 descD.samplers[0].addressModeV = GFXAddressClamp; 960 descD.samplers[0].addressModeW = GFXAddressClamp; 961 descD.samplers[0].magFilter = GFXTextureFilterLinear; 962 descD.samplers[0].minFilter = GFXTextureFilterLinear; 963 descD.samplers[0].mipFilter = GFXTextureFilterLinear; 964 965 // DepthBuffer sampler 966 descD.samplers[1].addressModeU = GFXAddressClamp; 967 descD.samplers[1].addressModeV = GFXAddressClamp; 968 descD.samplers[1].addressModeW = GFXAddressClamp; 969 descD.samplers[1].magFilter = GFXTextureFilterLinear; 970 descD.samplers[1].minFilter = GFXTextureFilterLinear; 971 descD.samplers[1].mipFilter = GFXTextureFilterLinear; 972 973 // FrontBuffer sampler 974 descD.samplers[2].addressModeU = GFXAddressClamp; 975 descD.samplers[2].addressModeV = GFXAddressClamp; 976 descD.samplers[2].addressModeW = GFXAddressClamp; 977 descD.samplers[2].magFilter = GFXTextureFilterLinear; 978 descD.samplers[2].minFilter = GFXTextureFilterLinear; 979 descD.samplers[2].mipFilter = GFXTextureFilterLinear; 980 981 // animated density modifier map sampler 982 descD.samplers[3].addressModeU = GFXAddressWrap; 983 descD.samplers[3].addressModeV = GFXAddressWrap; 984 descD.samplers[3].addressModeW = GFXAddressWrap; 985 descD.samplers[3].magFilter = GFXTextureFilterLinear; 986 descD.samplers[3].minFilter = GFXTextureFilterLinear; 987 descD.samplers[3].mipFilter = GFXTextureFilterLinear; 988 989 dMemcpy(&descF, &descD, sizeof(GFXStateBlockDesc)); 990 descF.setCullMode(GFXCullCCW); 991 descF.setBlend(true); 992 descF.setZReadWrite(true, false); 993 994 desc_refl.setCullMode(GFXCullCCW); 995 desc_refl.setBlend(true); 996 desc_refl.setZReadWrite(true, false); 997 998 mStateblock_preD = GFX->createStateBlock(desc_preD); 999 mStateblock_preF = GFX->createStateBlock(desc_preF); 1000 mStateblockD = GFX->createStateBlock(descD); 1001 mStateblockF = GFX->createStateBlock(descF); 1002 mStateblock_refl = GFX->createStateBlock(desc_refl); 1003 1004 // Create Rendertarget 1005 1006 z_buf = GFX->allocRenderToTextureTarget(); 1007 if (z_buf == NULL) 1008 { 1009 Con::errorf("VolumetricFog::setupRenderer - Could not create Render Target"); 1010 return false; 1011 } 1012 1013 return true; 1014} 1015 1016void VolumetricFog::prepRenderImage(SceneRenderState *state) 1017{ 1018 if (!mShapeLoaded || mFogDensity <= 0.0f || mResizing) 1019 return; 1020 1021 if (!state->isDiffusePass()) 1022 { 1023 if (!state->isReflectPass()) 1024 return; 1025 } 1026 1027 PROFILE_SCOPE(VolumetricFog_prepRenderImage); 1028 1029 ShapeBase* control = dynamic_cast<ShapeBase*>(conn->getControlObject()); 1030 if (!control || (control->getWaterCoverage() >= 0.9f && !mIgnoreWater)) 1031 return; 1032 1033 camPos = state->getCameraPosition(); 1034 F32 dist = (camPos - getBoxCenter()).len(); 1035 F32 scaleFactor = dist * mInvScale; 1036 if (scaleFactor <= 0.0f) 1037 { 1038 if (mCurDetailLevel != 0) 1039 UpdateBuffers(0); 1040 } 1041 const F32 pixelScale = state->getViewport().extent.y / 300.0f; 1042 1043 mPixelSize = (mRadius / scaleFactor) * state->getWorldToScreenScale().y * pixelScale; 1044 if (mPixelSize < mMinDisplaySize) 1045 return; 1046 if (mNumDetailLevels > 1) 1047 { 1048 if ((mCurDetailLevel < mNumDetailLevels - 1) && (det_size[mCurDetailLevel].det_size > mPixelSize)) 1049 UpdateBuffers(mCurDetailLevel + 1); 1050 else if (mCurDetailLevel > 0) 1051 { 1052 if (mPixelSize >= det_size[mCurDetailLevel - 1].det_size) 1053 UpdateBuffers(mCurDetailLevel - 1); 1054 } 1055 } 1056 1057 if (state->isReflectPass() && mReflect) 1058 { 1059 ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>(); 1060 ri->renderDelegate.bind(this, &VolumetricFog::reflect_render); 1061 ri->type = RenderPassManager::RIT_VolumetricFog; 1062 ri->translucentSort = true; 1063 ri->sortDistSq = getRenderWorldBox().getSqDistanceToPoint(camPos); 1064 if (dist < 1.0f) 1065 ri->defaultKey = 1; 1066 else 1067 ri->defaultKey = U32(dist); 1068 state->getRenderPass()->addInst(ri); 1069 return; 1070 } 1071 else if (state->isDiffusePass()) 1072 { 1073 viewDist = state->getFarPlane(); 1074 mFOV = state->getCameraFrustum().getFov() / M_PI_F; 1075 Point3F mEyeVec = state->getVectorEye() * viewDist; 1076 1077 mViewPoint.x = ((mAtan2(mEyeVec.x, mEyeVec.y) / M_PI_F) + 1.0f) * mTexTiles; 1078 mViewPoint.y = (0.5f - (mAsin(mEyeVec.z) / M_PI_F)) * mTexTiles; 1079 1080 bool isInside = ColBox.isContained(camPos); 1081 if (isInside && !mCamInFog) 1082 { 1083 mCamInFog = true; 1084 _enterFog(control); 1085 } 1086 else if (!isInside && mCamInFog) 1087 mCamInFog = false; 1088 1089 ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>(); 1090 ri->renderDelegate.bind(this, &VolumetricFog::render); 1091 ri->type = RenderPassManager::RIT_VolumetricFog; 1092 ri->translucentSort = true; 1093 ri->sortDistSq = getRenderWorldBox().getSqDistanceToPoint(camPos); 1094 if (dist < 1.0f) 1095 ri->defaultKey = 1; 1096 else 1097 ri->defaultKey = U32(dist); 1098 state->getRenderPass()->addInst(ri); 1099 return; 1100 } 1101 return; 1102} 1103 1104void VolumetricFog::render(ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat) 1105{ 1106 if (overrideMat || !mShapeLoaded || !isClientObject() || mResizing) 1107 return; 1108 1109 PROFILE_SCOPE(VolumetricFog_Render); 1110 1111 GFXTransformSaver saver; 1112 GFX->setVertexBuffer(mVB); 1113 GFX->setPrimitiveBuffer(mPB); 1114 1115 MatrixF mat = getRenderTransform(); 1116 mat.scale(mObjScale); 1117 GFX->multWorld(mat); 1118 1119 GFX->setShader(mDeferredShader); 1120 GFX->setShaderConstBuffer(mPPShaderConsts); 1121 GFX->setStateBlock(mStateblock_preD); 1122 1123 // Set all the shader consts... 1124 1125 MatrixF xform(GFX->getProjectionMatrix()); 1126 xform *= GFX->getViewMatrix(); 1127 xform *= GFX->getWorldMatrix(); 1128 1129 mPPShaderConsts->setSafe(mPPModelViewProjSC, xform); 1130 1131 const LinearColorF &sunlight = state->getAmbientLightColor(); 1132 1133 Point3F ambientColor(sunlight.red, sunlight.green, sunlight.blue); 1134 mShaderConsts->setSafe(mAmbientColorSC, ambientColor); 1135 1136 GFXTextureObject *mDepthBuffer = mDepthBufferTarget ? mDepthBufferTarget->getTexture(0) : NULL; 1137 GFXTextureObject *mFrontBuffer = mFrontBufferTarget ? mFrontBufferTarget->getTexture(0) : NULL; 1138 1139 GFX->pushActiveRenderTarget(); 1140 1141 //render backside to target mDepthBuffer 1142 z_buf->attachTexture(GFXTextureTarget::DepthStencil, GFXTextureTarget::sDefaultDepthStencil); 1143 z_buf->attachTexture(GFXTextureTarget::Color0, mDepthBuffer); 1144 1145 GFX->setActiveRenderTarget(z_buf); 1146 GFX->clear(GFXClearStencil | GFXClearTarget , ColorI(0,0,0,0), 1.0f, 0); 1147 1148 GFX->drawPrimitive(0); 1149 z_buf->resolve(); 1150 1151 //render frontside to target mFrontBuffer 1152 z_buf->attachTexture(GFXTextureTarget::DepthStencil, GFXTextureTarget::sDefaultDepthStencil); 1153 z_buf->attachTexture(GFXTextureTarget::Color0, mFrontBuffer); 1154 GFX->clear(GFXClearStencil | GFXClearTarget, ColorI(0, 0, 0, 0), 1.0f, 0); 1155 1156 GFX->setStateBlock(mStateblock_preF); 1157 1158 GFX->drawPrimitive(0); 1159 z_buf->resolve(); 1160 1161 GFX->popActiveRenderTarget(); 1162 z_buf->attachTexture(GFXTextureTarget::Color0, NULL); 1163 1164 //render Volumetric Fog 1165 GFX->setShader(mShader); 1166 GFX->setShaderConstBuffer(mShaderConsts); 1167 1168 mShaderConsts->setSafe(mModelViewProjSC, xform); 1169 if (mFadeSize > 0.0f) 1170 mShaderConsts->setSafe(mFadeSizeSC, mClampF(mPixelSize / mFadeSize, 0.0f, 1.0f)); 1171 else 1172 mShaderConsts->setSafe(mFadeSizeSC, 1.0f); 1173 mShaderConsts->setSafe(mFogColorSC, mFogColor); 1174 mShaderConsts->setSafe(mFogDensitySC, mFogDensity); 1175 mShaderConsts->setSafe(mPreBias, viewDist); 1176 mShaderConsts->setSafe(mAccumTime, (F32)Sim::getCurrentTime() / 1000.0f); 1177 mShaderConsts->setSafe(mModStrengthSC, mStrength); 1178 mShaderConsts->setSafe(mModSpeedSC, mSpeed); 1179 mShaderConsts->setSafe(mViewPointSC, mViewPoint); 1180 mShaderConsts->setSafe(mTexScaleSC, mTexScale * mFOV); 1181 mShaderConsts->setSafe(mTexTilesSC, mTexTiles); 1182 1183 GFXTextureObject *deferredtex = mDeferredTarget ? mDeferredTarget->getTexture(0) : NULL; 1184 1185 GFX->setTexture(0, deferredtex); 1186 GFX->setTexture(1, mDepthBuffer); 1187 GFX->setTexture(2, mFrontBuffer); 1188 1189 if (mIsTextured && mStrength > 0.0f) 1190 { 1191 GFX->setTexture(3, mTexture); 1192 mShaderConsts->setSafe(mIsTexturedSC, 1.0f); 1193 } 1194 else 1195 mShaderConsts->setSafe(mIsTexturedSC, 0.0f); 1196 1197 if (mCamInFog) 1198 { 1199 /*GFXLockedRect *rect=mDepthBuffer->lock(); 1200 U32 pixoffset = 0;// 1572864 + (512 * 4); 1201 U8 red = rect->bits[pixoffset]; 1202 U8 green = rect->bits[pixoffset+1]; 1203 U8 blue = rect->bits[pixoffset+2]; 1204 U8 alpha = rect->bits[pixoffset+3]; 1205 mDepthBuffer->unlock(); 1206 S32 lval = ((alpha << 24) + (blue << 16) + (green << 8) + (red)); 1207 F32 fval = ((F32)lval / S32_MAX); 1208 Con::printf("Color %d %d %d %d %d %f", red, green, blue, alpha, lval, fval);*/ 1209 GFX->setStateBlock(mStateblockD); 1210 } 1211 else 1212 GFX->setStateBlock(mStateblockF); 1213 1214 GFX->drawPrimitive(0); 1215 1216 // Ensure these two textures are NOT bound to the pixel shader input on the second run as they are used as pixel shader outputs (render targets). 1217 GFX->clearTextureStateImmediate(1); //mDepthBuffer 1218 GFX->clearTextureStateImmediate(2); //mFrontBuffer 1219} 1220 1221void VolumetricFog::reflect_render(ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat) 1222{ 1223 if (overrideMat || !mShapeLoaded || !isClientObject() || mResizing || (mFogReflStrength==0.0f)) 1224 return; 1225 1226 GFXTransformSaver saver; 1227 GFX->setVertexBuffer(mVB); 1228 GFX->setPrimitiveBuffer(mPB); 1229 1230 MatrixF mat = getRenderTransform(); 1231 mat.scale(mObjScale); 1232 GFX->multWorld(mat); 1233 1234 GFX->setShader(mReflectionShader); 1235 GFX->setShaderConstBuffer(mReflShaderConsts); 1236 GFX->setStateBlock(mStateblock_refl); 1237 1238 // Set all the shader consts... 1239 MatrixF xform(GFX->getProjectionMatrix()); 1240 xform *= GFX->getViewMatrix(); 1241 xform *= GFX->getWorldMatrix(); 1242 1243 mReflShaderConsts->setSafe(mReflModelViewProjSC, xform); 1244 mReflShaderConsts->setSafe(mReflFogColorSC, mFogColor); 1245 mReflShaderConsts->setSafe(mReflFogDensitySC, mFogDensity); 1246 mReflShaderConsts->setSafe(mReflFogStrengthSC, mFogReflStrength); 1247 1248 GFX->drawPrimitive(0); 1249} 1250 1251//----------------------------------------------------------------------------- 1252// InitTexture is called whenever a modulation texture is added to the object 1253//----------------------------------------------------------------------------- 1254 1255void VolumetricFog::InitTexture() 1256{ 1257 mIsTextured = false; 1258 1259 if (mTextureName.isNotEmpty()) 1260 mTexture.set(mTextureName, &GFXStaticTextureSRGBProfile, "VolumetricFogMod"); 1261 1262 if (!mTexture.isNull()) 1263 { 1264 mIsTextured = true; 1265 1266 F32 width = (F32)mPlatformWindow->getClientExtent().x; 1267 F32 height = (F32)mPlatformWindow->getClientExtent().y; 1268 1269 mTexScale.x = 2.0f - ((F32)mTexture.getWidth() / width); 1270 mTexScale.y = 2.0f - ((F32)mTexture.getHeight() / height); 1271 } 1272} 1273 1274void VolumetricFog::setFogColor(LinearColorF color) 1275{ 1276 mFogColor.set(255 * color.red,255 * color.green,255 * color.blue); 1277 setMaskBits(FogColorMask); 1278} 1279 1280void VolumetricFog::setFogColor(ColorI color) 1281{ 1282 mFogColor = color; 1283 setMaskBits(FogColorMask); 1284} 1285 1286void VolumetricFog::setFogDensity(F32 density) 1287{ 1288 if (density < 0.0f) 1289 density = 0.0f; 1290 mFogDensity = density; 1291 setMaskBits(FogDensityMask); 1292} 1293 1294void VolumetricFog::setFogModulation(F32 strength,Point2F speed1,Point2F speed2) 1295{ 1296 mStrength = strength; 1297 mSpeed1 = speed1; 1298 mSpeed2 = speed2; 1299 mSpeed.set(speed1.x, speed1.y, speed2.x, speed2.y); 1300 setMaskBits(FogModulationMask); 1301} 1302 1303void VolumetricFog::setFogGlow(bool on_off, F32 strength) 1304{ 1305 mUseGlow = on_off; 1306 mGlowStrength = strength; 1307 setMaskBits(FogPostFXMask); 1308} 1309 1310void VolumetricFog::setFogLightray(bool on_off, F32 strength) 1311{ 1312 mModifLightRays = on_off; 1313 mLightRayMod = strength; 1314 setMaskBits(FogPostFXMask); 1315} 1316 1317bool VolumetricFog::isInsideFog() 1318{ 1319 return mCamInFog; 1320} 1321 1322DefineEngineMethod(VolumetricFog, SetFogColorF, void, (LinearColorF new_color), , 1323"@brief Changes the color of the fog\n\n." 1324"@params new_color the new fog color (rgb 0.0 - 1.0, a is ignored.") 1325{ 1326 object->setFogColor(new_color); 1327} 1328 1329DefineEngineMethod(VolumetricFog, SetFogColor, void, (ColorI new_color), , 1330"@brief Changes the color of the fog\n\n." 1331"@params new_color the new fog color (rgb 0-255, a is ignored.") 1332{ 1333 object->setFogColor(new_color); 1334} 1335 1336DefineEngineMethod(VolumetricFog, SetFogDensity, void, (F32 new_density), , 1337"@brief Changes the density of the fog\n\n." 1338"@params new_density the new fog density.") 1339{ 1340 object->setFogDensity(new_density); 1341} 1342 1343DefineEngineMethod(VolumetricFog, SetFogModulation, void, (F32 new_strenght, Point2F new_speed1, Point2F new_speed2), , 1344"@brief Changes the modulation of the fog\n\n." 1345"@params new_strenght the new strength of the modulation.\n" 1346"@params new_speed1 the new speed (x y) of the modulation layer 1.\n" 1347"@params new_speed2 the new speed (x y) of the modulation layer 2.\n") 1348{ 1349 object->setFogModulation(new_strenght, new_speed1, new_speed2); 1350} 1351 1352DefineEngineMethod(VolumetricFog, SetFogGlow, void, (bool on_off,F32 strength), , 1353"@brief Changes the glow postfx when inside the fog\n\n." 1354"@params on_off set to true to enable glow.\n" 1355"@params strength glow strength.\n") 1356{ 1357 object->setFogGlow(on_off, strength); 1358} 1359 1360DefineEngineMethod(VolumetricFog, SetFogLightray, void, (bool on_off, F32 strength), , 1361"@brief Changes the lightrays postfx when inside the fog\n\n." 1362"@params on_off set to true to modification of the lightray postfx.\n" 1363"@params strength lightray strength.\n") 1364{ 1365 object->setFogLightray(on_off, strength); 1366} 1367 1368DefineEngineMethod(VolumetricFog, isInsideFog, bool, (), , 1369"@brief returns true if control object is inside the fog\n\n.") 1370{ 1371 return object->isInsideFog(); 1372} 1373