scatterSky.cpp
Engine/source/environment/scatterSky.cpp
Public Functions
ConsoleDocClass(ScatterSky , "@brief Represents both the sun and sky <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> scenes with <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> dynamic time of <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">day.\n\n</a>" "%<a href="/coding/class/classscattersky/">ScatterSky</a> renders as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> dome shaped mesh which is camera relative and always overhead. " "It is intended <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be part of the background of your scene and renders before all " "other objects <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">types.\n\n</a>" "%<a href="/coding/class/classscattersky/">ScatterSky</a> is designed <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> outdoor scenes which need <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> transition fluidly " "between radically different times of day. It will respond <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> time changes " "originating from <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classtimeofday/">TimeOfDay</a> object or the elevation field can be directly " "<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">adjusted.\n\n</a>" "During day, %<a href="/coding/class/classscattersky/">ScatterSky</a> uses atmosphereic sunlight scattering " "aproximations <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> generate <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> sky gradient and sun corona. It also calculates " "the fog color, ambient color, and sun color, which are used <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> scene " "lighting. This is user controlled by fields within the <a href="/coding/class/classscattersky/">ScatterSky</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">group.\n\n</a>" "During night, %<a href="/coding/class/classscattersky/">ScatterSky</a> supports can transition <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> night sky cubemap and " "moon sprite. The user can <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> this and night time colors used <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> scene " "lighting with fields within the Night <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">group.\n\n</a>" "A scene with <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classscattersky/">ScatterSky</a> should not have any other sky or sun objects " "as it already fulfills both <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">roles.\n\n</a>" "%<a href="/coding/class/classscattersky/">ScatterSky</a> is intended <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be used with <a href="/coding/class/classcloudlayer/">CloudLayer</a> and <a href="/coding/class/classtimeofday/">TimeOfDay</a> as part of " "<a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> scene with dynamic lighting. Having <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> %<a href="/coding/class/classscattersky/">ScatterSky</a> without <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> changing " "time of day would unnecessarily give up artistic <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> compared and fillrate " "compared <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classskybox/">SkyBox</a>+<a href="/coding/class/classsun/">Sun</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">setup.\n\n</a>" " @ingroup Atmosphere" )
DefineEngineMethod(ScatterSky , applyChanges , void , () , "Apply <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> full network update of all fields <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> all clients." )
Detailed Description
Public Functions
ConsoleDocClass(ScatterSky , "@brief Represents both the sun and sky <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> scenes with <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> dynamic time of <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">day.\n\n</a>" "%<a href="/coding/class/classscattersky/">ScatterSky</a> renders as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> dome shaped mesh which is camera relative and always overhead. " "It is intended <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be part of the background of your scene and renders before all " "other objects <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">types.\n\n</a>" "%<a href="/coding/class/classscattersky/">ScatterSky</a> is designed <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> outdoor scenes which need <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> transition fluidly " "between radically different times of day. It will respond <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> time changes " "originating from <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classtimeofday/">TimeOfDay</a> object or the elevation field can be directly " "<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">adjusted.\n\n</a>" "During day, %<a href="/coding/class/classscattersky/">ScatterSky</a> uses atmosphereic sunlight scattering " "aproximations <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> generate <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> sky gradient and sun corona. It also calculates " "the fog color, ambient color, and sun color, which are used <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> scene " "lighting. This is user controlled by fields within the <a href="/coding/class/classscattersky/">ScatterSky</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">group.\n\n</a>" "During night, %<a href="/coding/class/classscattersky/">ScatterSky</a> supports can transition <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> night sky cubemap and " "moon sprite. The user can <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> this and night time colors used <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> scene " "lighting with fields within the Night <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">group.\n\n</a>" "A scene with <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classscattersky/">ScatterSky</a> should not have any other sky or sun objects " "as it already fulfills both <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">roles.\n\n</a>" "%<a href="/coding/class/classscattersky/">ScatterSky</a> is intended <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be used with <a href="/coding/class/classcloudlayer/">CloudLayer</a> and <a href="/coding/class/classtimeofday/">TimeOfDay</a> as part of " "<a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> scene with dynamic lighting. Having <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> %<a href="/coding/class/classscattersky/">ScatterSky</a> without <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> changing " "time of day would unnecessarily give up artistic <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> compared and fillrate " "compared <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classskybox/">SkyBox</a>+<a href="/coding/class/classsun/">Sun</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">setup.\n\n</a>" " @ingroup Atmosphere" )
DefineEngineMethod(ScatterSky , applyChanges , void , () , "Apply <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> full network update of all fields <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> all clients." )
IMPLEMENT_CO_NETOBJECT_V1(ScatterSky )
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 "platform/platform.h" 25#include "scatterSky.h" 26 27#include "core/stream/bitStream.h" 28#include "console/consoleTypes.h" 29#include "console/engineAPI.h" 30#include "sim/netConnection.h" 31#include "math/util/sphereMesh.h" 32#include "math/mathUtils.h" 33#include "math/util/matrixSet.h" 34#include "scene/sceneRenderState.h" 35#include "lighting/lightInfo.h" 36#include "gfx/sim/gfxStateBlockData.h" 37#include "gfx/gfxTransformSaver.h" 38#include "gfx/gfxDrawUtil.h" 39#include "gfx/sim/cubemapData.h" 40#include "materials/shaderData.h" 41#include "materials/materialManager.h" 42#include "materials/baseMatInstance.h" 43#include "materials/sceneData.h" 44#include "environment/timeOfDay.h" 45 46 47ConsoleDocClass( ScatterSky, 48 "@brief Represents both the sun and sky for scenes with a dynamic time of day.\n\n" 49 50 "%ScatterSky renders as a dome shaped mesh which is camera relative and always overhead. " 51 "It is intended to be part of the background of your scene and renders before all " 52 "other objects types.\n\n" 53 54 "%ScatterSky is designed for outdoor scenes which need to transition fluidly " 55 "between radically different times of day. It will respond to time changes " 56 "originating from a TimeOfDay object or the elevation field can be directly " 57 "adjusted.\n\n" 58 59 "During day, %ScatterSky uses atmosphereic sunlight scattering " 60 "aproximations to generate a sky gradient and sun corona. It also calculates " 61 "the fog color, ambient color, and sun color, which are used for scene " 62 "lighting. This is user controlled by fields within the ScatterSky group.\n\n" 63 64 "During night, %ScatterSky supports can transition to a night sky cubemap and " 65 "moon sprite. The user can control this and night time colors used for scene " 66 "lighting with fields within the Night group.\n\n" 67 68 "A scene with a ScatterSky should not have any other sky or sun objects " 69 "as it already fulfills both roles.\n\n" 70 71 "%ScatterSky is intended to be used with CloudLayer and TimeOfDay as part of " 72 "a scene with dynamic lighting. Having a %ScatterSky without a changing " 73 "time of day would unnecessarily give up artistic control compared and fillrate " 74 "compared to a SkyBox + Sun setup.\n\n" 75 76 "@ingroup Atmosphere" 77); 78 79 80IMPLEMENT_CO_NETOBJECT_V1(ScatterSky); 81 82const F32 ScatterSky::smEarthRadius = (6378.0f * 1000.0f); 83const F32 ScatterSky::smAtmosphereRadius = 200000.0f; 84const F32 ScatterSky::smViewerHeight = 1.0f; 85 86ScatterSky::ScatterSky() 87{ 88 mPrimCount = 0; 89 mVertCount = 0; 90 91 92 // Rayleigh scattering constant. 93 mRayleighScattering = 0.0035f; 94 mRayleighScattering4PI = mRayleighScattering * 4.0f * M_PI_F; 95 96 // Mie scattering constant. 97 mMieScattering = 0.0045f; 98 mMieScattering4PI = mMieScattering * 4.0f * M_PI_F; 99 100 // Overall scatter scalar. 101 mSkyBrightness = 25.0f; 102 103 // The Mie phase asymmetry factor. 104 mMiePhaseAssymetry = -0.75f; 105 106 mSphereInnerRadius = 1.0f; 107 mSphereOuterRadius = 1.0f * 1.025f; 108 mScale = 1.0f / (mSphereOuterRadius - mSphereInnerRadius); 109 110 // 650 nm for red 111 // 570 nm for green 112 // 475 nm for blue 113 mWavelength.set( 0.650f, 0.570f, 0.475f, 0 ); 114 115 mWavelength4[0] = mPow(mWavelength[0], 4.0f); 116 mWavelength4[1] = mPow(mWavelength[1], 4.0f); 117 mWavelength4[2] = mPow(mWavelength[2], 4.0f); 118 119 mRayleighScaleDepth = 0.25f; 120 mMieScaleDepth = 0.1f; 121 122 mAmbientColor.set( 0, 0, 0, 1.0f ); 123 mAmbientScale.set( 1.0f, 1.0f, 1.0f, 1.0f ); 124 125 mSunColor.set( 0, 0, 0, 1.0f ); 126 mSunScale = LinearColorF::WHITE; 127 128 mFogColor.set( 0, 0, 0, 1.0f ); 129 mFogScale = LinearColorF::WHITE; 130 131 mExposure = 1.0f; 132 mNightInterpolant = 0; 133 mZOffset = 0.0f; 134 135 mShader = NULL; 136 137 mTimeOfDay = 0; 138 139 mSunAzimuth = 0.0f; 140 mSunElevation = 35.0f; 141 142 mMoonAzimuth = 0.0f; 143 mMoonElevation = 45.0f; 144 145 mBrightness = 1.0f; 146 147 mCastShadows = true; 148 mStaticRefreshFreq = 8; 149 mDynamicRefreshFreq = 8; 150 mDirty = true; 151 152 mLight = LightManager::createLightInfo(); 153 mLight->setType( LightInfo::Vector ); 154 155 mFlareData = NULL; 156 mFlareState.clear(); 157 mFlareScale = 1.0f; 158 159 mMoonEnabled = true; 160 mMoonScale = 0.2f; 161 mMoonTint.set( 0.192157f, 0.192157f, 0.192157f, 1.0f ); 162 MathUtils::getVectorFromAngles( mMoonLightDir, 0.0f, 45.0f ); 163 mMoonLightDir.normalize(); 164 mMoonLightDir = -mMoonLightDir; 165 mNightCubemap = NULL; 166 mNightColor.set( 0.0196078f, 0.0117647f, 0.109804f, 1.0f ); 167 mNightFogColor = mNightColor; 168 mUseNightCubemap = false; 169 mSunSize = 1.0f; 170 171 mMoonMatInst = NULL; 172 173 mNetFlags.set( Ghostable | ScopeAlways ); 174 mTypeMask |= EnvironmentObjectType | LightObjectType | StaticObjectType; 175 176 _generateSkyPoints(); 177 178 mMatrixSet = reinterpret_cast<MatrixSet *>(dMalloc_aligned(sizeof(MatrixSet), 16)); 179 constructInPlace(mMatrixSet); 180 181 mColorizeAmt = 0; 182 mColorize.set(0,0,0); 183} 184 185ScatterSky::~ScatterSky() 186{ 187 SAFE_DELETE( mLight ); 188 SAFE_DELETE( mMoonMatInst ); 189 190 dFree_aligned(mMatrixSet); 191} 192 193bool ScatterSky::onAdd() 194{ 195 PROFILE_SCOPE(ScatterSky_onAdd); 196 197 // onNewDatablock for the server is called here 198 // for the client it is called in unpackUpdate 199 200 if ( !Parent::onAdd() ) 201 return false; 202 203 if ( isClientObject() ) 204 TimeOfDay::getTimeOfDayUpdateSignal().notify( this, &ScatterSky::_updateTimeOfDay ); 205 206 setGlobalBounds(); 207 resetWorldBox(); 208 209 addToScene(); 210 211 if ( isClientObject() ) 212 { 213 _initMoon(); 214 Sim::findObject( mNightCubemapName, mNightCubemap ); 215 } 216 217 return true; 218} 219 220void ScatterSky::onRemove() 221{ 222 removeFromScene(); 223 224 if ( isClientObject() ) 225 TimeOfDay::getTimeOfDayUpdateSignal().remove( this, &ScatterSky::_updateTimeOfDay ); 226 227 Parent::onRemove(); 228} 229 230void ScatterSky::_conformLights() 231{ 232 _initCurves(); 233 234 F32 val = mCurves[0].getVal( mTimeOfDay ); 235 mNightInterpolant = 1.0f - val; 236 237 VectorF lightDirection; 238 F32 brightness; 239 240 // Build the light direction from the azimuth and elevation. 241 F32 yaw = mDegToRad(mClampF(mSunAzimuth,0,359)); 242 F32 pitch = mDegToRad(mClampF(mSunElevation,-360,+360)); 243 MathUtils::getVectorFromAngles(lightDirection, yaw, pitch); 244 lightDirection.normalize(); 245 mSunDir = -lightDirection; 246 247 yaw = mDegToRad(mClampF(mMoonAzimuth,0,359)); 248 pitch = mDegToRad(mClampF(mMoonElevation,-360,+360)); 249 MathUtils::getVectorFromAngles( mMoonLightDir, yaw, pitch ); 250 mMoonLightDir.normalize(); 251 mMoonLightDir = -mMoonLightDir; 252 253 brightness = mCurves[2].getVal( mTimeOfDay ); 254 255 if ( mNightInterpolant >= 1.0f ) 256 lightDirection = -mMoonLightDir; 257 258 mLight->setDirection( -lightDirection ); 259 mLight->setBrightness( brightness * mBrightness ); 260 mLightDir = lightDirection; 261 262 // Have to do interpolation 263 // after the light direction is set 264 // otherwise the sun color will be invalid. 265 _interpolateColors(); 266 267 mLight->setAmbient( mAmbientColor ); 268 mLight->setColor( mSunColor ); 269 mLight->setCastShadows( mCastShadows ); 270 mLight->setStaticRefreshFreq(mStaticRefreshFreq); 271 mLight->setDynamicRefreshFreq(mDynamicRefreshFreq); 272 273 FogData fog = getSceneManager()->getFogData(); 274 fog.color = mFogColor; 275 getSceneManager()->setFogData( fog ); 276} 277 278void ScatterSky::submitLights( LightManager *lm, bool staticLighting ) 279{ 280 if ( mDirty ) 281 { 282 _conformLights(); 283 mDirty = false; 284 } 285 286 // The sun is a special light and needs special registration. 287 lm->setSpecialLight( LightManager::slSunLightType, mLight ); 288} 289 290void ScatterSky::setAzimuth( F32 azimuth ) 291{ 292 mSunAzimuth = azimuth; 293 mDirty = true; 294 setMaskBits( TimeMask ); 295} 296 297void ScatterSky::setElevation( F32 elevation ) 298{ 299 mSunElevation = elevation; 300 301 while( elevation < 0 ) 302 elevation += 360.0f; 303 304 while( elevation >= 360.0f ) 305 elevation -= 360.0f; 306 307 mTimeOfDay = elevation / 180.0f; 308 mDirty = true; 309 setMaskBits( TimeMask ); 310} 311 312void ScatterSky::inspectPostApply() 313{ 314 mDirty = true; 315 setMaskBits( 0xFFFFFFFF ); 316} 317 318void ScatterSky::initPersistFields() 319{ 320 addGroup( "ScatterSky", 321 "Only azimuth and elevation are networked fields. To trigger a full update of all other fields use the applyChanges ConsoleMethod." ); 322 323 addField( "skyBrightness", TypeF32, Offset( mSkyBrightness, ScatterSky ), 324 "Global brightness and intensity applied to the sky and objects in the level." ); 325 326 addField( "sunSize", TypeF32, Offset( mSunSize, ScatterSky ), 327 "Affects the size of the sun's disk." ); 328 329 addField( "colorizeAmount", TypeF32, Offset( mColorizeAmt, ScatterSky ), 330 "Controls how much the alpha component of colorize brigthens the sky. Setting to 0 returns default behavior." ); 331 332 addField( "colorize", TypeColorF, Offset( mColorize, ScatterSky ), 333 "Tints the sky the color specified, the alpha controls the brigthness. The brightness is multipled by the value of colorizeAmt." ); 334 335 addField( "rayleighScattering", TypeF32, Offset( mRayleighScattering, ScatterSky ), 336 "Controls how blue the atmosphere is during the day." ); 337 338 addField( "sunScale", TypeColorF, Offset( mSunScale, ScatterSky ), 339 "Modulates the directional color of sunlight." ); 340 341 addField( "ambientScale", TypeColorF, Offset( mAmbientScale, ScatterSky ), 342 "Modulates the ambient color of sunlight." ); 343 344 addField( "fogScale", TypeColorF, Offset( mFogScale, ScatterSky ), 345 "Modulates the fog color. Note that this overrides the LevelInfo.fogColor " 346 "property, so you should not use LevelInfo.fogColor if the level contains " 347 "a ScatterSky object." ); 348 349 addField( "exposure", TypeF32, Offset( mExposure, ScatterSky ), 350 "Controls the contrast of the sky and sun during daytime." ); 351 352 addField( "zOffset", TypeF32, Offset( mZOffset, ScatterSky ), 353 "Offsets the scatterSky to avoid canvas rendering. Use 5000 or greater for the initial adjustment" ); 354 355 endGroup( "ScatterSky" ); 356 357 addGroup( "Orbit" ); 358 359 addProtectedField( "azimuth", TypeF32, Offset( mSunAzimuth, ScatterSky ), &ScatterSky::ptSetAzimuth, &defaultProtectedGetFn, 360 "The horizontal angle of the sun measured clockwise from the positive Y world axis. This field is networked." ); 361 362 addProtectedField( "elevation", TypeF32, Offset( mSunElevation, ScatterSky ), &ScatterSky::ptSetElevation, &defaultProtectedGetFn, 363 "The elevation angle of the sun above or below the horizon. This field is networked." ); 364 365 addField( "moonAzimuth", TypeF32, Offset( mMoonAzimuth, ScatterSky ), 366 "The horizontal angle of the moon measured clockwise from the positive Y world axis. This is not animated by time or networked." ); 367 368 addField( "moonElevation", TypeF32, Offset( mMoonElevation, ScatterSky ), 369 "The elevation angle of the moon above or below the horizon. This is not animated by time or networked." ); 370 371 endGroup( "Orbit" ); 372 373 // We only add the basic lighting options that all lighting 374 // systems would use... the specific lighting system options 375 // are injected at runtime by the lighting system itself. 376 377 addGroup( "Lighting" ); 378 379 addField( "castShadows", TypeBool, Offset( mCastShadows, ScatterSky ), 380 "Enables/disables shadows cast by objects due to ScatterSky light." ); 381 382 addField("staticRefreshFreq", TypeS32, Offset(mStaticRefreshFreq, ScatterSky), "static shadow refresh rate (milliseconds)"); 383 addField("dynamicRefreshFreq", TypeS32, Offset(mDynamicRefreshFreq, ScatterSky), "dynamic shadow refresh rate (milliseconds)"); 384 385 addField( "brightness", TypeF32, Offset( mBrightness, ScatterSky ), 386 "The brightness of the ScatterSky's light object." ); 387 388 endGroup( "Lighting" ); 389 390 addGroup( "Misc" ); 391 392 addField( "flareType", TYPEID< LightFlareData >(), Offset( mFlareData, ScatterSky ), 393 "Datablock for the flare produced by the ScatterSky." ); 394 395 addField( "flareScale", TypeF32, Offset( mFlareScale, ScatterSky ), 396 "Changes the size and intensity of the flare." ); 397 398 endGroup( "Misc" ); 399 400 addGroup( "Night" ); 401 402 addField( "nightColor", TypeColorF, Offset( mNightColor, ScatterSky ), 403 "The ambient color during night. Also used for the sky color if useNightCubemap is false." ); 404 405 addField( "nightFogColor", TypeColorF, Offset( mNightFogColor, ScatterSky ), 406 "The fog color during night." ); 407 408 addField( "moonEnabled", TypeBool, Offset( mMoonEnabled, ScatterSky ), 409 "Enable or disable rendering of the moon sprite during night." ); 410 411 addField( "moonMat", TypeMaterialName, Offset( mMoonMatName, ScatterSky ), 412 "Material for the moon sprite." ); 413 414 addField( "moonScale", TypeF32, Offset( mMoonScale, ScatterSky ), 415 "Controls size the moon sprite renders, specified as a fractional amount of the screen height." ); 416 417 addField( "moonLightColor", TypeColorF, Offset( mMoonTint, ScatterSky ), 418 "Color of light cast by the directional light during night." ); 419 420 addField( "useNightCubemap", TypeBool, Offset( mUseNightCubemap, ScatterSky ), 421 "Transition to the nightCubemap during night. If false we use nightColor." ); 422 423 addField( "nightCubemap", TypeCubemapName, Offset( mNightCubemapName, ScatterSky ), 424 "Cubemap visible during night." ); 425 426 endGroup( "Night" ); 427 428 // Now inject any light manager specific fields. 429 LightManager::initLightFields(); 430 431 Parent::initPersistFields(); 432} 433 434U32 ScatterSky::packUpdate(NetConnection *con, U32 mask, BitStream *stream) 435{ 436 U32 retMask = Parent::packUpdate(con, mask, stream); 437 438 if ( stream->writeFlag( mask & TimeMask ) ) 439 { 440 stream->write( mSunAzimuth ); 441 stream->write( mSunElevation ); 442 } 443 444 if ( stream->writeFlag( mask & UpdateMask ) ) 445 { 446 stream->write( mRayleighScattering ); 447 mRayleighScattering4PI = mRayleighScattering * 4.0f * M_PI_F; 448 449 stream->write( mRayleighScattering4PI ); 450 451 stream->write( mMieScattering ); 452 mMieScattering4PI = mMieScattering * 4.0f * M_PI_F; 453 454 stream->write( mMieScattering4PI ); 455 456 stream->write( mSunSize ); 457 458 stream->write( mSkyBrightness ); 459 460 stream->write( mMiePhaseAssymetry ); 461 462 stream->write( mSphereInnerRadius ); 463 stream->write( mSphereOuterRadius ); 464 465 stream->write( mScale ); 466 467 stream->write( mWavelength ); 468 469 stream->write( mWavelength4[0] ); 470 stream->write( mWavelength4[1] ); 471 stream->write( mWavelength4[2] ); 472 473 stream->write( mRayleighScaleDepth ); 474 stream->write( mMieScaleDepth ); 475 476 stream->write( mNightColor ); 477 stream->write( mNightFogColor ); 478 stream->write( mAmbientScale ); 479 stream->write( mSunScale ); 480 stream->write( mFogScale ); 481 stream->write( mColorizeAmt ); 482 stream->write( mColorize ); 483 484 stream->write( mExposure ); 485 486 stream->write( mZOffset ); 487 488 stream->write( mBrightness ); 489 490 stream->writeFlag( mCastShadows ); 491 stream->write(mStaticRefreshFreq); 492 stream->write(mDynamicRefreshFreq); 493 494 stream->write( mFlareScale ); 495 496 if ( stream->writeFlag( mFlareData ) ) 497 { 498 stream->writeRangedU32( mFlareData->getId(), 499 DataBlockObjectIdFirst, 500 DataBlockObjectIdLast ); 501 } 502 503 stream->writeFlag( mMoonEnabled ); 504 stream->write( mMoonMatName ); 505 stream->write( mMoonScale ); 506 stream->write( mMoonTint ); 507 stream->writeFlag( mUseNightCubemap ); 508 stream->write( mNightCubemapName ); 509 510 stream->write( mMoonAzimuth ); 511 stream->write( mMoonElevation ); 512 513 mLight->packExtended( stream ); 514 } 515 516 return retMask; 517} 518 519void ScatterSky::unpackUpdate(NetConnection *con, BitStream *stream) 520{ 521 Parent::unpackUpdate(con, stream); 522 523 if ( stream->readFlag() ) // TimeMask 524 { 525 F32 temp = 0; 526 stream->read( &temp ); 527 setAzimuth( temp ); 528 529 stream->read( &temp ); 530 setElevation( temp ); 531 } 532 533 if ( stream->readFlag() ) // UpdateMask 534 { 535 stream->read( &mRayleighScattering ); 536 stream->read( &mRayleighScattering4PI ); 537 538 stream->read( &mMieScattering ); 539 stream->read( &mMieScattering4PI ); 540 541 stream->read( &mSunSize ); 542 543 stream->read( &mSkyBrightness ); 544 545 stream->read( &mMiePhaseAssymetry ); 546 547 stream->read( &mSphereInnerRadius ); 548 stream->read( &mSphereOuterRadius ); 549 550 stream->read( &mScale ); 551 552 LinearColorF tmpColor( 0, 0, 0 ); 553 554 stream->read( &tmpColor ); 555 556 stream->read( &mWavelength4[0] ); 557 stream->read( &mWavelength4[1] ); 558 stream->read( &mWavelength4[2] ); 559 560 stream->read( &mRayleighScaleDepth ); 561 stream->read( &mMieScaleDepth ); 562 563 stream->read( &mNightColor ); 564 stream->read( &mNightFogColor ); 565 stream->read( &mAmbientScale ); 566 stream->read( &mSunScale ); 567 stream->read( &mFogScale ); 568 F32 colorizeAmt; 569 stream->read( &colorizeAmt ); 570 571 if(mColorizeAmt != colorizeAmt) { 572 mColorizeAmt = colorizeAmt; 573 mShader = NULL; //forces shader refresh 574 } 575 576 stream->read( &mColorize ); 577 578 579 if ( tmpColor != mWavelength ) 580 { 581 mWavelength = tmpColor; 582 mWavelength4[0] = mPow(mWavelength[0], 4.0f); 583 mWavelength4[1] = mPow(mWavelength[1], 4.0f); 584 mWavelength4[2] = mPow(mWavelength[2], 4.0f); 585 } 586 587 stream->read( &mExposure ); 588 589 stream->read( &mZOffset ); 590 591 stream->read( &mBrightness ); 592 593 mCastShadows = stream->readFlag(); 594 stream->read(&mStaticRefreshFreq); 595 stream->read(&mDynamicRefreshFreq); 596 597 stream->read( &mFlareScale ); 598 599 if ( stream->readFlag() ) 600 { 601 SimObjectId id = stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast ); 602 LightFlareData *datablock = NULL; 603 604 if ( Sim::findObject( id, datablock ) ) 605 mFlareData = datablock; 606 else 607 { 608 con->setLastError( "ScatterSky::unpackUpdate() - invalid LightFlareData!" ); 609 mFlareData = NULL; 610 } 611 } 612 else 613 mFlareData = NULL; 614 615 mMoonEnabled = stream->readFlag(); 616 stream->read( &mMoonMatName ); 617 stream->read( &mMoonScale ); 618 stream->read( &mMoonTint ); 619 mUseNightCubemap = stream->readFlag(); 620 stream->read( &mNightCubemapName ); 621 622 stream->read( &mMoonAzimuth ); 623 stream->read( &mMoonElevation ); 624 625 mLight->unpackExtended( stream ); 626 627 if ( isProperlyAdded() ) 628 { 629 mDirty = true; 630 _initMoon(); 631 Sim::findObject( mNightCubemapName, mNightCubemap ); 632 } 633 } 634} 635 636void ScatterSky::prepRenderImage( SceneRenderState *state ) 637{ 638 // Only render into diffuse and reflect passes. 639 640 if( !state->isDiffusePass() && 641 !state->isReflectPass() ) 642 return; 643 644 // Regular sky render instance. 645 RenderPassManager* renderPass = state->getRenderPass(); 646 ObjectRenderInst *ri = renderPass->allocInst<ObjectRenderInst>(); 647 ri->renderDelegate.bind( this, &ScatterSky::_render ); 648 ri->type = RenderPassManager::RIT_Sky; 649 ri->defaultKey = 10; 650 ri->defaultKey2 = 0; 651 renderPass->addInst(ri); 652 653 // Debug render instance. 654 /* 655 if ( Con::getBoolVariable( "$ScatterSky::debug", false ) ) 656 { 657 ri = state->getRenderPass()->allocInst<ObjectRenderInst>(); 658 ri->renderDelegate.bind( this, &ScatterSky::_debugRender ); 659 ri->type = RenderPassManager::RIT_Editor; 660 state->getRenderPass()->addInst( ri ); 661 } 662 */ 663 664 // Light flare effect render instance. 665 if ( mFlareData && mNightInterpolant != 1.0f ) 666 { 667 mFlareState.fullBrightness = mBrightness; 668 mFlareState.scale = mFlareScale; 669 mFlareState.lightInfo = mLight; 670 671 Point3F lightPos = state->getDiffuseCameraPosition() - state->getFarPlane() * mLight->getDirection() * 0.9f; 672 mFlareState.lightMat.identity(); 673 mFlareState.lightMat.setPosition( lightPos ); 674 675 F32 dist = ( lightPos - state->getDiffuseCameraPosition( ) ).len( ); 676 F32 coronaScale = 0.5f; 677 F32 screenRadius = GFX->getViewport( ).extent.y * coronaScale * 0.5f; 678 mFlareState.worldRadius = screenRadius * dist / state->getWorldToScreenScale( ).y; 679 680 mFlareData->prepRender( state, &mFlareState ); 681 } 682 683 // Render instances for Night effects. 684 if ( mNightInterpolant <= 0.0f ) 685 return; 686 687 // Render instance for Moon sprite. 688 if ( mMoonEnabled && mMoonMatInst ) 689 { 690 mMatrixSet->setSceneView(GFX->getWorldMatrix()); 691 mMatrixSet->setSceneProjection(GFX->getProjectionMatrix()); 692 mMatrixSet->setWorld(GFX->getWorldMatrix()); 693 694 ObjectRenderInst *moonRI = renderPass->allocInst<ObjectRenderInst>(); 695 moonRI->renderDelegate.bind( this, &ScatterSky::_renderMoon ); 696 moonRI->type = RenderPassManager::RIT_Sky; 697 // Render after sky objects and before CloudLayer! 698 moonRI->defaultKey = 5; 699 moonRI->defaultKey2 = 0; 700 renderPass->addInst(moonRI); 701 } 702} 703 704bool ScatterSky::_initShader() 705{ 706 ShaderData *shaderData; 707 if ( !Sim::findObject( "ScatterSkyShaderData", shaderData ) ) 708 { 709 Con::warnf( "ScatterSky::_initShader - failed to locate shader ScatterSkyShaderData!" ); 710 return false; 711 } 712 Vector<GFXShaderMacro> macros; 713 if ( mColorizeAmt ) 714 macros.push_back( GFXShaderMacro( "USE_COLORIZE" ) ); 715 716 mShader = shaderData->getShader( macros ); 717 718 if ( !mShader ) 719 return false; 720 721 if ( mStateBlock.isNull() ) 722 { 723 GFXStateBlockData *data = NULL; 724 if ( !Sim::findObject( "ScatterSkySBData", data ) ) 725 Con::warnf( "ScatterSky::_initShader - failed to locate ScatterSkySBData!" ); 726 else 727 mStateBlock = GFX->createStateBlock( data->getState() ); 728 } 729 730 if ( !mStateBlock ) 731 return false; 732 733 mShaderConsts = mShader->allocConstBuffer(); 734 mModelViewProjSC = mShader->getShaderConstHandle( "$modelView" ); 735 736 // Camera height, cam height squared, scale and scale over depth. 737 mMiscSC = mShader->getShaderConstHandle( "$misc" ); 738 739 // Inner and out radius, and inner and outer radius squared. 740 mSphereRadiiSC = mShader->getShaderConstHandle( "$sphereRadii" ); 741 742 // Rayleigh sun brightness, mie sun brightness and 4 * PI * coefficients. 743 mScatteringCoefficientsSC = mShader->getShaderConstHandle( "$scatteringCoeffs" ); 744 mCamPosSC = mShader->getShaderConstHandle( "$camPos" ); 745 mLightDirSC = mShader->getShaderConstHandle( "$lightDir" ); 746 mSunDirSC = mShader->getShaderConstHandle( "$sunDir" ); 747 mNightColorSC = mShader->getShaderConstHandle( "$nightColor" ); 748 mInverseWavelengthSC = mShader->getShaderConstHandle( "$invWaveLength" ); 749 mNightInterpolantAndExposureSC = mShader->getShaderConstHandle( "$nightInterpAndExposure" ); 750 mUseCubemapSC = mShader->getShaderConstHandle( "$useCubemap" ); 751 mColorizeSC = mShader->getShaderConstHandle( "$colorize" ); 752 753 return true; 754} 755 756void ScatterSky::_initVBIB() 757{ 758 // Vertex Buffer... 759 U32 vertStride = 50; 760 U32 strideMinusOne = vertStride - 1; 761 mVertCount = vertStride * vertStride; 762 mPrimCount = strideMinusOne * strideMinusOne * 2; 763 764 Point3F vertScale( 16.0f, 16.0f, 4.0f ); 765 766 F32 zOffset = -( mCos( mSqrt( 1.0f ) ) + 0.01f ); 767 768 mVB.set( GFX, mVertCount, GFXBufferTypeStatic ); 769 GFXVertexP *pVert = mVB.lock(); 770 if(!pVert) return; 771 772 for ( U32 y = 0; y < vertStride; y++ ) 773 { 774 F32 v = ( (F32)y / (F32)strideMinusOne - 0.5f ) * 2.0f; 775 776 for ( U32 x = 0; x < vertStride; x++ ) 777 { 778 F32 u = ( (F32)x / (F32)strideMinusOne - 0.5f ) * 2.0f; 779 780 F32 sx = u; 781 F32 sy = v; 782 F32 sz = (mCos( mSqrt( sx*sx + sy*sy ) ) * 1.0f) + zOffset; 783 //F32 sz = 1.0f; 784 pVert->point.set( sx, sy, sz ); 785 pVert->point *= vertScale; 786 787 pVert->point.normalize(); 788 pVert->point *= 200000.0f; 789 790 pVert++; 791 } 792 } 793 794 mVB.unlock(); 795 796 // Primitive Buffer... 797 mPrimBuffer.set( GFX, mPrimCount * 3, mPrimCount, GFXBufferTypeStatic ); 798 799 U16 *pIdx = NULL; 800 mPrimBuffer.lock(&pIdx); 801 U32 curIdx = 0; 802 803 for ( U32 y = 0; y < strideMinusOne; y++ ) 804 { 805 for ( U32 x = 0; x < strideMinusOne; x++ ) 806 { 807 U32 offset = x + y * vertStride; 808 809 pIdx[curIdx] = offset; 810 curIdx++; 811 pIdx[curIdx] = offset + 1; 812 curIdx++; 813 pIdx[curIdx] = offset + vertStride + 1; 814 curIdx++; 815 816 pIdx[curIdx] = offset; 817 curIdx++; 818 pIdx[curIdx] = offset + vertStride + 1; 819 curIdx++; 820 pIdx[curIdx] = offset + vertStride; 821 curIdx++; 822 } 823 } 824 825 mPrimBuffer.unlock(); 826} 827 828void ScatterSky::_initMoon() 829{ 830 if ( isServerObject() ) 831 return; 832 833 if ( mMoonMatInst ) 834 SAFE_DELETE( mMoonMatInst ); 835 836 if ( mMoonMatName.isNotEmpty() ) 837 mMoonMatInst = MATMGR->createMatInstance( mMoonMatName, MATMGR->getDefaultFeatures(), getGFXVertexFormat<GFXVertexPCT>() ); 838} 839 840void ScatterSky::_initCurves() 841{ 842 if ( mCurves->getSampleCount() > 0 ) 843 return; 844 845 // Takes time of day (0-2) and returns 846 // the night interpolant (0-1) day/night factor. 847 // moonlight = 0, sunlight > 0 848 mCurves[0].clear(); 849 mCurves[0].addPoint( 0.0f, 0.5f );// Sunrise 850 mCurves[0].addPoint( 0.025f, 1.0f );// 851 mCurves[0].addPoint( 0.975f, 1.0f );// 852 mCurves[0].addPoint( 1.0f, 0.5f );//Sunset 853 mCurves[0].addPoint( 1.02f, 0.0f );//Sunlight ends 854 mCurves[0].addPoint( 1.98f, 0.0f );//Sunlight begins 855 mCurves[0].addPoint( 2.0f, 0.5f );// Sunrise 856 857 // Takes time of day (0-2) and returns mieScattering factor 858 // Regulates the size of the sun's disk 859 mCurves[1].clear(); 860 mCurves[1].addPoint( 0.0f, 0.0006f ); 861 mCurves[1].addPoint( 0.01f, 0.00035f ); 862 mCurves[1].addPoint( 0.03f, 0.00023f ); 863 mCurves[1].addPoint( 0.1f, 0.00022f ); 864 mCurves[1].addPoint( 0.2f, 0.00043f ); 865 mCurves[1].addPoint( 0.3f, 0.00062f ); 866 mCurves[1].addPoint( 0.4f, 0.0008f ); 867 mCurves[1].addPoint( 0.5f, 0.00086f );// High noon 868 mCurves[1].addPoint( 0.6f, 0.0008f ); 869 mCurves[1].addPoint( 0.7f, 0.00062f ); 870 mCurves[1].addPoint( 0.8f, 0.00043f ); 871 mCurves[1].addPoint( 0.9f, 0.00022f ); 872 mCurves[1].addPoint( 0.97f, 0.00023f ); 873 mCurves[1].addPoint( 0.99f, 0.00035f ); 874 mCurves[1].addPoint( 1.0f, 0.0006f ); 875 mCurves[1].addPoint( 2.0f, 0.0006f ); 876 877 // Takes time of day and returns brightness 878 // Controls sunlight and moonlight brightness 879 mCurves[2].clear(); 880 mCurves[2].addPoint( 0.0f, 0.2f );// Sunrise 881 mCurves[2].addPoint( 0.1f, 1.0f ); 882 mCurves[2].addPoint( 0.9f, 1.0f );// Sunset 883 mCurves[2].addPoint( 1.008f, 0.0f );//Adjust end of sun's reflection 884 mCurves[2].addPoint( 1.02001f, 0.0f ); 885 mCurves[2].addPoint( 1.05f, 0.5f );// Turn brightness up for moonlight 886 mCurves[2].addPoint( 1.93f, 0.5f ); 887 mCurves[2].addPoint( 1.97999f, 0.0f );// No brightness when sunlight starts 888 mCurves[2].addPoint( 1.992f, 0.0f );//Adjust start of sun's reflection 889 mCurves[2].addPoint( 2.0f, 0.2f ); // Sunrise 890 891 // Interpolation of day/night color sets 892 // 0/1 ambient/nightcolor 893 // 0 = day colors only anytime 894 // 1 = night colors only anytime 895 // between 0 and 1 renders both color sets anytime 896 897 mCurves[3].clear(); 898 mCurves[3].addPoint( 0.0f, 0.8f );//Sunrise 899 mCurves[3].addPoint( 0.1f, 0.0f ); 900 mCurves[3].addPoint( 0.99f, 0.0f ); 901 mCurves[3].addPoint( 1.0f, 0.8f );// Sunset 902 mCurves[3].addPoint( 1.01999f, 1.0f );// 903 mCurves[3].addPoint( 1.98001f, 1.0f );// Sunlight begins with full night colors 904 mCurves[3].addPoint( 2.0f, 0.8f ); //Sunrise 905 906 // Takes time of day (0-2) and returns smoothing factor 907 // Interpolates between mMoonTint color and mNightColor 908 909 mCurves[4].clear(); 910 mCurves[4].addPoint( 0.0f, 1.0f ); 911 mCurves[4].addPoint( 0.96f, 1.0f ); 912 mCurves[4].addPoint( 1.01999f, 0.5f ); 913 mCurves[4].addPoint( 1.02001f, 0.5f ); 914 mCurves[4].addPoint( 1.08f, 1.0f ); 915 mCurves[4].addPoint( 1.92f, 1.0f ); 916 mCurves[4].addPoint( 1.97999f, 0.5f ); 917 mCurves[4].addPoint( 1.98001f, 0.5f ); 918 mCurves[4].addPoint( 2.0f, 1.0f ); 919} 920void ScatterSky::_updateTimeOfDay( TimeOfDay *timeOfDay, F32 time ) 921{ 922 setElevation( timeOfDay->getElevationDegrees() ); 923 setAzimuth( timeOfDay->getAzimuthDegrees() ); 924} 925 926void ScatterSky::_render( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat ) 927{ 928 if ( overrideMat || (!mShader && !_initShader()) ) 929 return; 930 931 GFXTransformSaver saver; 932 933 if ( mVB.isNull() || mPrimBuffer.isNull() ) 934 _initVBIB(); 935 936 GFX->setShader( mShader ); 937 GFX->setShaderConstBuffer( mShaderConsts ); 938 939 Point4F sphereRadii( mSphereOuterRadius, mSphereOuterRadius * mSphereOuterRadius, 940 mSphereInnerRadius, mSphereInnerRadius * mSphereInnerRadius ); 941 942 Point4F scatteringCoeffs( mRayleighScattering * mSkyBrightness, mRayleighScattering4PI, 943 mMieScattering * mSkyBrightness, mMieScattering4PI ); 944 945 Point4F invWavelength( 1.0f / mWavelength4[0], 946 1.0f / mWavelength4[1], 947 1.0f / mWavelength4[2], 1.0f ); 948 949 Point3F camPos( 0, 0, smViewerHeight ); 950 Point4F miscParams( camPos.z, camPos.z * camPos.z, mScale, mScale / mRayleighScaleDepth ); 951 952 Frustum frust = state->getCameraFrustum(); 953 frust.setFarDist( smEarthRadius + smAtmosphereRadius ); 954 MatrixF proj( true ); 955 frust.getProjectionMatrix( &proj ); 956 957 Point3F camPos2 = state->getCameraPosition(); 958 MatrixF xfm(true); 959 xfm.setPosition(camPos2 - Point3F(0, 0, mZOffset)); 960 GFX->multWorld(xfm); 961 962 MatrixF xform(proj);//GFX->getProjectionMatrix()); 963 xform *= GFX->getViewMatrix(); 964 xform *= GFX->getWorldMatrix(); 965 966 if(state->isReflectPass()) 967 { 968 static MatrixF rotMat(EulerF(0.0, 0.0, M_PI_F)); 969 xform.mul(rotMat); 970 rotMat.set(EulerF(M_PI_F, 0.0, 0.0)); 971 xform.mul(rotMat); 972 } 973 974 mShaderConsts->setSafe( mModelViewProjSC, xform ); 975 mShaderConsts->setSafe( mMiscSC, miscParams ); 976 mShaderConsts->setSafe( mSphereRadiiSC, sphereRadii ); 977 mShaderConsts->setSafe( mScatteringCoefficientsSC, scatteringCoeffs ); 978 mShaderConsts->setSafe( mCamPosSC, camPos ); 979 mShaderConsts->setSafe( mLightDirSC, mLightDir ); 980 mShaderConsts->setSafe( mSunDirSC, mSunDir ); 981 mShaderConsts->setSafe( mNightColorSC, mNightColor ); 982 mShaderConsts->setSafe( mInverseWavelengthSC, invWavelength ); 983 mShaderConsts->setSafe( mNightInterpolantAndExposureSC, Point2F( mExposure, mNightInterpolant ) ); 984 mShaderConsts->setSafe( mColorizeSC, mColorize*mColorizeAmt ); 985 986 if ( GFXDevice::getWireframe() ) 987 { 988 GFXStateBlockDesc desc( mStateBlock->getDesc() ); 989 desc.setFillModeWireframe(); 990 GFX->setStateBlockByDesc( desc ); 991 } 992 else 993 GFX->setStateBlock( mStateBlock ); 994 995 if ( mUseNightCubemap && mNightCubemap ) 996 { 997 mShaderConsts->setSafe( mUseCubemapSC, 1.0f ); 998 999 if ( !mNightCubemap->mCubemap ) 1000 mNightCubemap->createMap(); 1001 1002 GFX->setCubeTexture( 0, mNightCubemap->mCubemap ); 1003 } 1004 else 1005 { 1006 GFX->setCubeTexture( 0, NULL ); 1007 mShaderConsts->setSafe( mUseCubemapSC, 0.0f ); 1008 } 1009 1010 GFX->setPrimitiveBuffer( mPrimBuffer ); 1011 GFX->setVertexBuffer( mVB ); 1012 1013 GFX->drawIndexedPrimitive( GFXTriangleList, 0, 0, mVertCount, 0, mPrimCount ); 1014} 1015 1016void ScatterSky::_debugRender( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat ) 1017{ 1018 GFXStateBlockDesc desc; 1019 desc.fillMode = GFXFillSolid; 1020 desc.setBlend( false, GFXBlendOne, GFXBlendZero ); 1021 desc.setZReadWrite( false, false ); 1022 GFXStateBlockRef sb = GFX->GFX->createStateBlock( desc ); 1023 1024 GFX->setStateBlock( sb ); 1025 1026 PrimBuild::begin( GFXLineStrip, mSkyPoints.size() ); 1027 PrimBuild::color3i( 255, 0, 255 ); 1028 1029 for ( U32 i = 0; i < mSkyPoints.size(); i++ ) 1030 { 1031 Point3F pnt = mSkyPoints[i]; 1032 pnt.normalize(); 1033 pnt *= 500; 1034 pnt += state->getCameraPosition(); 1035 PrimBuild::vertex3fv( pnt ); 1036 } 1037 1038 PrimBuild::end(); 1039} 1040 1041void ScatterSky::_renderMoon( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat ) 1042{ 1043 if ( !mMoonMatInst ) 1044 return; 1045 1046 Point3F moonlightPosition = state->getCameraPosition() - /*mLight->getDirection()*/ mMoonLightDir * state->getFarPlane() * 0.9f; 1047 F32 dist = (moonlightPosition - state->getCameraPosition()).len(); 1048 1049 // worldRadius = screenRadius * dist / worldToScreen 1050 // screenRadius = worldRadius / dist * worldToScreen 1051 1052 // 1053 F32 screenRadius = GFX->getViewport().extent.y * mMoonScale * 0.5f; 1054 F32 worldRadius = screenRadius * dist / state->getWorldToScreenScale().y; 1055 1056 // Calculate Billboard Radius (in world units) to be constant, independent of distance. 1057 // Takes into account distance, viewport size, and specified size in editor 1058 1059 F32 BBRadius = worldRadius; 1060 1061 1062 mMatrixSet->restoreSceneViewProjection(); 1063 1064 if ( state->isReflectPass() ) 1065 mMatrixSet->setProjection( state->getSceneManager()->getNonClipProjection() ); 1066 1067 mMatrixSet->setWorld( MatrixF::Identity ); 1068 1069 // Initialize points with basic info 1070 Point3F points[4]; 1071 points[0] = Point3F( -BBRadius, 0.0, -BBRadius); 1072 points[1] = Point3F( -BBRadius, 0.0, BBRadius); 1073 points[2] = Point3F( BBRadius, 0.0, -BBRadius); 1074 points[3] = Point3F( BBRadius, 0.0, BBRadius); 1075 1076 static const Point2F sCoords[4] = 1077 { 1078 Point2F( 0.0f, 0.0f ), 1079 Point2F( 0.0f, 1.0f ), 1080 Point2F( 1.0f, 0.0f ), 1081 Point2F( 1.0f, 1.0f ) 1082 }; 1083 1084 // Get info we need to adjust points 1085 const MatrixF &camView = state->getCameraTransform(); 1086 1087 // Finalize points 1088 for(S32 i = 0; i < 4; i++) 1089 { 1090 // align with camera 1091 camView.mulV(points[i]); 1092 // offset 1093 points[i] += moonlightPosition; 1094 } 1095 1096 // Vertex color. 1097 LinearColorF moonVertColor( 1.0f, 1.0f, 1.0f, mNightInterpolant ); 1098 1099 // Copy points to buffer. 1100 1101 GFXVertexBufferHandle< GFXVertexPCT> vb; 1102 vb.set( GFX, 4, GFXBufferTypeVolatile ); 1103 GFXVertexPCT *pVert = vb.lock(); 1104 if(!pVert) return; 1105 1106 for ( S32 i = 0; i < 4; i++ ) 1107 { 1108 pVert->color.set( moonVertColor.toColorI()); 1109 pVert->point.set( points[i] ); 1110 pVert->texCoord.set( sCoords[i].x, sCoords[i].y ); 1111 pVert++; 1112 } 1113 1114 vb.unlock(); 1115 1116 // Setup SceneData struct. 1117 1118 SceneData sgData; 1119 sgData.wireframe = GFXDevice::getWireframe(); 1120 sgData.visibility = 1.0f; 1121 1122 // Draw it 1123 1124 while ( mMoonMatInst->setupPass( state, sgData ) ) 1125 { 1126 mMoonMatInst->setTransforms( *mMatrixSet, state ); 1127 mMoonMatInst->setSceneInfo( state, sgData ); 1128 1129 GFX->setVertexBuffer( vb ); 1130 GFX->drawPrimitive( GFXTriangleStrip, 0, 2 ); 1131 } 1132} 1133 1134void ScatterSky::_generateSkyPoints() 1135{ 1136 U32 rings=60, segments=20;//rings=160, segments=20; 1137 1138 Point3F tmpPoint( 0, 0, 0 ); 1139 1140 // Establish constants used in sphere generation. 1141 F32 deltaRingAngle = ( M_PI_F / (F32)(rings * 2) ); 1142 F32 deltaSegAngle = ( 2.0f * M_PI_F / (F32)segments ); 1143 1144 // Generate the group of rings for the sphere. 1145 for( S32 ring = 0; ring < 2; ring++ ) 1146 { 1147 F32 r0 = mSin( ring * deltaRingAngle ); 1148 F32 y0 = mCos( ring * deltaRingAngle ); 1149 1150 // Generate the group of segments for the current ring. 1151 for( S32 seg = 0; seg < segments + 1 ; seg++ ) 1152 { 1153 F32 x0 = r0 * sinf( seg * deltaSegAngle ); 1154 F32 z0 = r0 * cosf( seg * deltaSegAngle ); 1155 1156 tmpPoint.set( x0, z0, y0 ); 1157 tmpPoint.normalizeSafe(); 1158 1159 tmpPoint.x *= smEarthRadius + smAtmosphereRadius; 1160 tmpPoint.y *= smEarthRadius + smAtmosphereRadius; 1161 tmpPoint.z *= smEarthRadius + smAtmosphereRadius; 1162 tmpPoint.z -= smEarthRadius; 1163 1164 if ( ring == 1 ) 1165 mSkyPoints.push_back( tmpPoint ); 1166 } 1167 } 1168} 1169 1170void ScatterSky::_interpolateColors() 1171{ 1172 mFogColor.set( 0, 0, 0, 0 ); 1173 mAmbientColor.set( 0, 0, 0, 0 ); 1174 mSunColor.set( 0, 0, 0, 0 ); 1175 1176 _getFogColor( &mFogColor ); 1177 _getAmbientColor( &mAmbientColor ); 1178 _getSunColor( &mSunColor ); 1179 1180 mAmbientColor *= mAmbientScale; 1181 mSunColor *= mSunScale; 1182 mFogColor *= mFogScale; 1183 1184 mMieScattering = (mCurves[1].getVal( mTimeOfDay) * mSunSize ); //Scale the size of the sun's disk 1185 1186 LinearColorF moonTemp = mMoonTint; 1187 LinearColorF nightTemp = mNightColor; 1188 1189 moonTemp.interpolate( mNightColor, mMoonTint, mCurves[4].getVal( mTimeOfDay ) ); 1190 nightTemp.interpolate( mMoonTint, mNightColor, mCurves[4].getVal( mTimeOfDay ) ); 1191 1192 mFogColor.interpolate( mFogColor, mNightFogColor, mCurves[3].getVal( mTimeOfDay ) );//mNightInterpolant ); 1193 mFogColor.alpha = 1.0f; 1194 1195 mAmbientColor.interpolate( mAmbientColor, mNightColor, mCurves[3].getVal( mTimeOfDay ) );//mNightInterpolant ); 1196 mSunColor.interpolate( mSunColor, mMoonTint, mCurves[3].getVal( mTimeOfDay ) );//mNightInterpolant ); 1197} 1198 1199void ScatterSky::_getSunColor( LinearColorF *outColor ) 1200{ 1201 PROFILE_SCOPE( ScatterSky_GetSunColor ); 1202 1203 U32 count = 0; 1204 LinearColorF tmpColor( 0, 0, 0 ); 1205 VectorF tmpVec( 0, 0, 0 ); 1206 1207 tmpVec = mLightDir; 1208 tmpVec.x *= smEarthRadius + smAtmosphereRadius; 1209 tmpVec.y *= smEarthRadius + smAtmosphereRadius; 1210 tmpVec.z *= smEarthRadius + smAtmosphereRadius; 1211 tmpVec.z -= smAtmosphereRadius; 1212 1213 for ( U32 i = 0; i < 10; i++ ) 1214 { 1215 _getColor( tmpVec, &tmpColor ); 1216 (*outColor) += tmpColor; 1217 tmpVec.x += (smEarthRadius * 0.5f) + (smAtmosphereRadius * 0.5f); 1218 count++; 1219 } 1220 1221 if ( count > 0 ) 1222 (*outColor) /= count; 1223} 1224 1225void ScatterSky::_getAmbientColor( LinearColorF *outColor ) 1226{ 1227 PROFILE_SCOPE( ScatterSky_GetAmbientColor ); 1228 1229 LinearColorF tmpColor( 0, 0, 0, 0 ); 1230 U32 count = 0; 1231 1232 // Disable mieScattering for purposes of calculating the ambient color. 1233 F32 oldMieScattering = mMieScattering; 1234 mMieScattering = 0.0f; 1235 1236 for ( U32 i = 0; i < mSkyPoints.size(); i++ ) 1237 { 1238 Point3F pnt( mSkyPoints[i] ); 1239 1240 _getColor( pnt, &tmpColor ); 1241 (*outColor) += tmpColor; 1242 count++; 1243 } 1244 1245 if ( count > 0 ) 1246 (*outColor) /= count; 1247 mMieScattering = oldMieScattering; 1248} 1249 1250void ScatterSky::_getFogColor( LinearColorF *outColor ) 1251{ 1252 PROFILE_SCOPE( ScatterSky_GetFogColor ); 1253 1254 VectorF scatterPos( 0, 0, 0 ); 1255 1256 F32 sunBrightness = mSkyBrightness; 1257 mSkyBrightness *= 0.25f; 1258 1259 F32 yaw = 0, pitch = 0, originalYaw = 0; 1260 VectorF fwd( 0, 1.0f, 0 ); 1261 MathUtils::getAnglesFromVector( fwd, yaw, pitch ); 1262 originalYaw = yaw; 1263 pitch = mDegToRad( 10.0f ); 1264 1265 LinearColorF tmpColor( 0, 0, 0 ); 1266 1267 U32 i = 0; 1268 for ( i = 0; i < 10; i++ ) 1269 { 1270 MathUtils::getVectorFromAngles( scatterPos, yaw, pitch ); 1271 1272 scatterPos.x *= smEarthRadius + smAtmosphereRadius; 1273 scatterPos.y *= smEarthRadius + smAtmosphereRadius; 1274 scatterPos.z *= smEarthRadius + smAtmosphereRadius; 1275 scatterPos.y -= smEarthRadius; 1276 1277 _getColor( scatterPos, &tmpColor ); 1278 (*outColor) += tmpColor; 1279 1280 if ( i <= 5 ) 1281 yaw += mDegToRad( 5.0f ); 1282 else 1283 { 1284 originalYaw += mDegToRad( -5.0f ); 1285 yaw = originalYaw; 1286 } 1287 1288 yaw = mFmod( yaw, M_2PI_F ); 1289 } 1290 1291 if ( i > 0 ) 1292 (*outColor) /= i; 1293 1294 mSkyBrightness = sunBrightness; 1295} 1296 1297F32 ScatterSky::_vernierScale( F32 fCos ) 1298{ 1299 F32 x = 1.0 - fCos; 1300 return 0.25f * exp( -0.00287f + x * (0.459f + x * (3.83f + x * ((-6.80f + (x * 5.25f))))) ); 1301} 1302 1303F32 ScatterSky::_getMiePhase( F32 fCos, F32 fCos2, F32 g, F32 g2) 1304{ 1305 return 1.5f * ((1.0f - g2) / (2.0f + g2)) * (1.0f + fCos2) / mPow(mFabs(1.0f + g2 - 2.0f*g*fCos), 1.5f); 1306} 1307 1308F32 ScatterSky::_getRayleighPhase( F32 fCos2 ) 1309{ 1310 return 0.75 + 0.75 * fCos2; 1311} 1312 1313void ScatterSky::_getColor( const Point3F &pos, LinearColorF *outColor ) 1314{ 1315 PROFILE_SCOPE( ScatterSky_GetColor ); 1316 1317 F32 scaleOverScaleDepth = mScale / mRayleighScaleDepth; 1318 F32 rayleighBrightness = mRayleighScattering * mSkyBrightness; 1319 F32 mieBrightness = mMieScattering * mSkyBrightness; 1320 1321 Point3F invWaveLength( 1.0f / mWavelength4[0], 1322 1.0f / mWavelength4[1], 1323 1.0f / mWavelength4[2] ); 1324 1325 Point3F v3Pos = pos / 6378000.0f; 1326 v3Pos.z += mSphereInnerRadius; 1327 1328 Point3F newCamPos( 0, 0, smViewerHeight ); 1329 1330 VectorF v3Ray = v3Pos - newCamPos; 1331 F32 fFar = v3Ray.len(); 1332 v3Ray / fFar; 1333 v3Ray.normalizeSafe(); 1334 1335 Point3F v3Start = newCamPos; 1336 F32 fDepth = mExp( scaleOverScaleDepth * (mSphereInnerRadius - smViewerHeight ) ); 1337 F32 fStartAngle = mDot( v3Ray, v3Start ); 1338 1339 F32 fStartOffset = fDepth * _vernierScale( fStartAngle ); 1340 1341 F32 fSampleLength = fFar / 2.0f; 1342 F32 fScaledLength = fSampleLength * mScale; 1343 VectorF v3SampleRay = v3Ray * fSampleLength; 1344 Point3F v3SamplePoint = v3Start + v3SampleRay * 0.5f; 1345 1346 Point3F v3FrontColor( 0, 0, 0 ); 1347 for ( U32 i = 0; i < 2; i++ ) 1348 { 1349 F32 fHeight = v3SamplePoint.len(); 1350 fDepth = mExp( scaleOverScaleDepth * (mSphereInnerRadius - smViewerHeight) ); 1351 F32 fLightAngle = mDot( mLightDir, v3SamplePoint ) / fHeight; 1352 F32 fCameraAngle = mDot( v3Ray, v3SamplePoint ) / fHeight; 1353 1354 F32 fScatter = (fStartOffset + fDepth * ( _vernierScale( fLightAngle ) - _vernierScale( fCameraAngle ) )); 1355 Point3F v3Attenuate( 0, 0, 0 ); 1356 1357 F32 tmp = mExp( -fScatter * (invWaveLength[0] * mRayleighScattering4PI + mMieScattering4PI) ); 1358 v3Attenuate.x = tmp; 1359 1360 tmp = mExp( -fScatter * (invWaveLength[1] * mRayleighScattering4PI + mMieScattering4PI) ); 1361 v3Attenuate.y = tmp; 1362 1363 tmp = mExp( -fScatter * (invWaveLength[2] * mRayleighScattering4PI + mMieScattering4PI) ); 1364 v3Attenuate.z = tmp; 1365 1366 v3FrontColor += v3Attenuate * (fDepth * fScaledLength); 1367 v3SamplePoint += v3SampleRay; 1368 } 1369 1370 Point3F mieColor = v3FrontColor * mieBrightness; 1371 Point3F rayleighColor = v3FrontColor * (invWaveLength * rayleighBrightness); 1372 Point3F v3Direction = newCamPos - v3Pos; 1373 v3Direction.normalize(); 1374 1375 F32 fCos = mDot( mLightDir, v3Direction ) / v3Direction.len(); 1376 F32 fCos2 = fCos * fCos; 1377 1378 F32 g = -0.991f; 1379 F32 g2 = g * g; 1380 F32 miePhase = _getMiePhase( fCos, fCos2, g, g2 ); 1381 1382 Point3F color = rayleighColor + (miePhase * mieColor); 1383 LinearColorF tmp( color.x, color.y, color.z, color.y ); 1384 1385 Point3F expColor( 0, 0, 0 ); 1386 expColor.x = 1.0f - exp(-mExposure * color.x); 1387 expColor.y = 1.0f - exp(-mExposure * color.y); 1388 expColor.z = 1.0f - exp(-mExposure * color.z); 1389 1390 tmp.set( expColor.x, expColor.y, expColor.z, 1.0f ); 1391 1392 if ( !tmp.isClamped() ) 1393 { 1394 F32 len = expColor.len(); 1395 if ( len > 0 ) 1396 expColor /= len; 1397 } 1398 1399 outColor->set( expColor.x, expColor.y, expColor.z, 1.0f ); 1400} 1401 1402// Static protected field set methods 1403 1404bool ScatterSky::ptSetElevation( void *object, const char *index, const char *data ) 1405{ 1406 ScatterSky *sky = static_cast<ScatterSky*>( object ); 1407 F32 val = dAtof( data ); 1408 1409 sky->setElevation( val ); 1410 1411 // we already set the field 1412 return false; 1413} 1414 1415bool ScatterSky::ptSetAzimuth( void *object, const char *index, const char *data ) 1416{ 1417 ScatterSky *sky = static_cast<ScatterSky*>( object ); 1418 F32 val = dAtof( data ); 1419 1420 sky->setAzimuth( val ); 1421 1422 // we already set the field 1423 return false; 1424} 1425 1426void ScatterSky::_onSelected() 1427{ 1428#ifdef TORQUE_DEBUG 1429 // Enable debug rendering on the light. 1430 if( isClientObject() ) 1431 mLight->enableDebugRendering( true ); 1432#endif 1433 1434 Parent::_onSelected(); 1435} 1436 1437void ScatterSky::_onUnselected() 1438{ 1439#ifdef TORQUE_DEBUG 1440 // Disable debug rendering on the light. 1441 if( isClientObject() ) 1442 mLight->enableDebugRendering( false ); 1443#endif 1444 1445 Parent::_onUnselected(); 1446} 1447 1448// ConsoleMethods 1449 1450DefineEngineMethod( ScatterSky, applyChanges, void, (),, 1451 "Apply a full network update of all fields to all clients." 1452 ) 1453{ 1454 object->inspectPostApply(); 1455} 1456