cloudLayer.cpp
Engine/source/environment/cloudLayer.cpp
Public Functions
ConsoleDocClass(CloudLayer , "@brief A layer of clouds which change shape over time and are affected by scene <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">lighting.\n\n</a>" "%<a href="/coding/class/classcloudlayer/">CloudLayer</a> always renders overhead, following the camera. It is intended " "as part of the background of your level, rendering in front of Sky/<a href="/coding/class/classsun/">Sun</a> " "type objects and behind everything <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">else.\n\n</a>" "The illusion of clouds forming and changing over time is controlled by the " "normal/opacity texture and the three sets of texture animation parameters. " "The texture is sampled three times. The first sample defines overall cloud " " density, where clouds are likely <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> form and their general <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1ab7d671599a7b25ca99a487fa341bc33a">size</a> and shape. " "The second two samples <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> how it changes over time;they are " "combined and used as modifiers <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the first <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">sample.\n\n</a>" "%<a href="/coding/class/classcloudlayer/">CloudLayer</a> is affected by scene lighting and is designed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be used in " "scenes with dynamic lighting or time of day <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">changes.\n\n</a>" " @ingroup Atmosphere" )
GFXImplementVertexFormat(GFXCloudVertex )
Detailed Description
Public Functions
ConsoleDocClass(CloudLayer , "@brief A layer of clouds which change shape over time and are affected by scene <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">lighting.\n\n</a>" "%<a href="/coding/class/classcloudlayer/">CloudLayer</a> always renders overhead, following the camera. It is intended " "as part of the background of your level, rendering in front of Sky/<a href="/coding/class/classsun/">Sun</a> " "type objects and behind everything <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">else.\n\n</a>" "The illusion of clouds forming and changing over time is controlled by the " "normal/opacity texture and the three sets of texture animation parameters. " "The texture is sampled three times. The first sample defines overall cloud " " density, where clouds are likely <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> form and their general <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1ab7d671599a7b25ca99a487fa341bc33a">size</a> and shape. " "The second two samples <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> how it changes over time;they are " "combined and used as modifiers <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the first <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">sample.\n\n</a>" "%<a href="/coding/class/classcloudlayer/">CloudLayer</a> is affected by scene lighting and is designed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be used in " "scenes with dynamic lighting or time of day <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">changes.\n\n</a>" " @ingroup Atmosphere" )
GFXImplementVertexFormat(GFXCloudVertex )
IMPLEMENT_CO_NETOBJECT_V1(CloudLayer )
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 "platform/profiler.h" 26#include "console/consoleTypes.h" 27#include "cloudLayer.h" 28 29#include "gfx/gfxTransformSaver.h" 30#include "gfx/gfxTextureManager.h" 31#include "core/stream/fileStream.h" 32#include "core/stream/bitStream.h" 33#include "scene/sceneRenderState.h" 34#include "renderInstance/renderPassManager.h" 35#include "gfx/primBuilder.h" 36#include "materials/materialManager.h" 37#include "materials/customMaterialDefinition.h" 38#include "materials/shaderData.h" 39#include "lighting/lightInfo.h" 40#include "math/mathIO.h" 41 42ConsoleDocClass( CloudLayer, 43 "@brief A layer of clouds which change shape over time and are affected by scene lighting.\n\n" 44 45 "%CloudLayer always renders overhead, following the camera. It is intended " 46 "as part of the background of your level, rendering in front of Sky/Sun " 47 "type objects and behind everything else.\n\n" 48 49 "The illusion of clouds forming and changing over time is controlled by the " 50 "normal/opacity texture and the three sets of texture animation parameters. " 51 "The texture is sampled three times. The first sample defines overall cloud " 52 "density, where clouds are likely to form and their general size and shape. " 53 "The second two samples control how it changes over time; they are " 54 "combined and used as modifiers to the first sample.\n\n" 55 56 "%CloudLayer is affected by scene lighting and is designed to be used in " 57 "scenes with dynamic lighting or time of day changes.\n\n" 58 59 "@ingroup Atmosphere" 60); 61 62GFXImplementVertexFormat( GFXCloudVertex ) 63{ 64 addElement( "POSITION", GFXDeclType_Float3 ); 65 addElement( "NORMAL", GFXDeclType_Float3 ); 66 addElement( "BINORMAL", GFXDeclType_Float3 ); 67 addElement( "TANGENT", GFXDeclType_Float3 ); 68 addElement( "TEXCOORD", GFXDeclType_Float2, 0 ); 69} 70 71U32 CloudLayer::smVertStride = 50; 72U32 CloudLayer::smStrideMinusOne = smVertStride - 1; 73U32 CloudLayer::smVertCount = smVertStride * smVertStride; 74U32 CloudLayer::smTriangleCount = smStrideMinusOne * smStrideMinusOne * 2; 75 76CloudLayer::CloudLayer() 77: mLastTime( 0 ), 78 mBaseColor( 0.9f, 0.9f, 0.9f, 1.0f ), 79 mExposure( 1.0f ), 80 mCoverage( 0.5f ), 81 mWindSpeed( 1.0f ) 82{ 83 mTypeMask |= EnvironmentObjectType | StaticObjectType; 84 mNetFlags.set(Ghostable | ScopeAlways); 85 86 mModelViewProjSC = NULL; 87 mAmbientColorSC = NULL; 88 mSunColorSC = NULL; 89 mSunVecSC = NULL; 90 mTexScaleSC = NULL; 91 mBaseColorSC = NULL; 92 mCoverageSC = NULL; 93 mExposureSC = NULL; 94 mEyePosWorldSC = NULL; 95 mNormalHeightMapSC = NULL; 96 97 mTexOffsetSC[0] = mTexOffsetSC[1] = mTexOffsetSC[2] = 0; 98 99 mTexScale[0] = 1.0; 100 mTexScale[1] = 1.0; 101 mTexScale[2] = 1.0; 102 103 mTexDirection[0].set( 1.0f, 0.0f ); 104 mTexDirection[1].set( 0.0f, 1.0f ); 105 mTexDirection[2].set( 0.5f, 0.0f ); 106 107 mTexSpeed[0] = 0.005f; 108 mTexSpeed[1] = 0.005f; 109 mTexSpeed[2] = 0.005f; 110 111 mTexOffset[0] = mTexOffset[1] = mTexOffset[2] = Point2F::Zero; 112 113 mHeight = 4.0f; 114} 115 116IMPLEMENT_CO_NETOBJECT_V1( CloudLayer ); 117 118// ConsoleObject... 119 120 121bool CloudLayer::onAdd() 122{ 123 if ( !Parent::onAdd() ) 124 return false; 125 126 setGlobalBounds(); 127 resetWorldBox(); 128 129 addToScene(); 130 131 if ( isClientObject() ) 132 { 133 _initTexture(); 134 _initBuffers(); 135 136 // Find ShaderData 137 ShaderData *shaderData; 138 mShader = Sim::findObject( "CloudLayerShader", shaderData ) ? 139 shaderData->getShader() : NULL; 140 if ( !mShader ) 141 { 142 Con::errorf( "CloudLayer::onAdd - could not find CloudLayerShader" ); 143 return false; 144 } 145 146 // Create ShaderConstBuffer and Handles 147 mShaderConsts = mShader->allocConstBuffer(); 148 mModelViewProjSC = mShader->getShaderConstHandle( "$modelView" ); 149 mEyePosWorldSC = mShader->getShaderConstHandle( "$eyePosWorld" ); 150 mSunVecSC = mShader->getShaderConstHandle( "$sunVec" ); 151 mTexOffsetSC[0] = mShader->getShaderConstHandle( "$texOffset0" ); 152 mTexOffsetSC[1] = mShader->getShaderConstHandle( "$texOffset1" ); 153 mTexOffsetSC[2] = mShader->getShaderConstHandle( "$texOffset2" ); 154 mTexScaleSC = mShader->getShaderConstHandle( "$texScale" ); 155 mAmbientColorSC = mShader->getShaderConstHandle( "$ambientColor" ); 156 mSunColorSC = mShader->getShaderConstHandle( "$sunColor" ); 157 mCoverageSC = mShader->getShaderConstHandle( "$cloudCoverage" ); 158 mExposureSC = mShader->getShaderConstHandle( "$cloudExposure" ); 159 mBaseColorSC = mShader->getShaderConstHandle( "$cloudBaseColor" ); 160 mNormalHeightMapSC = mShader->getShaderConstHandle( "$normalHeightMap" ); 161 162 // Create StateBlocks 163 GFXStateBlockDesc desc; 164 desc.setCullMode( GFXCullNone ); 165 desc.setBlend( true ); 166 desc.setZReadWrite( true, false ); 167 desc.samplersDefined = true; 168 desc.samplers[0].addressModeU = GFXAddressWrap; 169 desc.samplers[0].addressModeV = GFXAddressWrap; 170 desc.samplers[0].addressModeW = GFXAddressWrap; 171 desc.samplers[0].magFilter = GFXTextureFilterLinear; 172 desc.samplers[0].minFilter = GFXTextureFilterLinear; 173 desc.samplers[0].mipFilter = GFXTextureFilterLinear; 174 175 mStateblock = GFX->createStateBlock( desc ); 176 } 177 178 return true; 179} 180 181void CloudLayer::onRemove() 182{ 183 removeFromScene(); 184 185 Parent::onRemove(); 186} 187 188void CloudLayer::initPersistFields() 189{ 190 addGroup( "CloudLayer" ); 191 192 addField( "texture", TypeImageFilename, Offset( mTextureName, CloudLayer ), 193 "An RGBA texture which should contain normals and opacity (density)." ); 194 195 addArray( "Textures", TEX_COUNT ); 196 197 addField( "texScale", TypeF32, Offset( mTexScale, CloudLayer ), TEX_COUNT, 198 "Controls the texture repeat of this slot." ); 199 200 addField( "texDirection", TypePoint2F, Offset( mTexDirection, CloudLayer ), TEX_COUNT, 201 "Controls the direction this slot scrolls." ); 202 203 addField( "texSpeed", TypeF32, Offset( mTexSpeed, CloudLayer ), TEX_COUNT, 204 "Controls the speed this slot scrolls." ); 205 206 endArray( "Textures" ); 207 208 addField( "baseColor", TypeColorF, Offset( mBaseColor, CloudLayer ), 209 "Base cloud color before lighting." ); 210 211 addField( "exposure", TypeF32, Offset( mExposure, CloudLayer ), 212 "Brightness scale so CloudLayer can be overblown if desired." ); 213 214 addField( "coverage", TypeF32, Offset( mCoverage, CloudLayer ), 215 "Fraction of sky covered by clouds 0-1." ); 216 217 addField( "windSpeed", TypeF32, Offset( mWindSpeed, CloudLayer ), 218 "Overall scalar to texture scroll speed." ); 219 220 addField( "height", TypeF32, Offset( mHeight, CloudLayer ), 221 "Abstract number which controls the curvature and height of the dome mesh." ); 222 223 endGroup( "CloudLayer" ); 224 225 Parent::initPersistFields(); 226} 227 228void CloudLayer::inspectPostApply() 229{ 230 Parent::inspectPostApply(); 231 setMaskBits( CloudLayerMask ); 232} 233 234 235// NetObject... 236 237 238U32 CloudLayer::packUpdate( NetConnection *conn, U32 mask, BitStream *stream ) 239{ 240 U32 retMask = Parent::packUpdate( conn, mask, stream ); 241 242 stream->write( mTextureName ); 243 244 for ( U32 i = 0; i < TEX_COUNT; i++ ) 245 { 246 stream->write( mTexScale[i] ); 247 stream->write( mTexSpeed[i] ); 248 mathWrite( *stream, mTexDirection[i] ); 249 } 250 251 stream->write( mBaseColor ); 252 stream->write( mCoverage ); 253 stream->write( mExposure ); 254 stream->write( mWindSpeed ); 255 stream->write( mHeight ); 256 257 return retMask; 258} 259 260void CloudLayer::unpackUpdate( NetConnection *conn, BitStream *stream ) 261{ 262 Parent::unpackUpdate( conn, stream ); 263 264 String oldTextureName = mTextureName; 265 stream->read( &mTextureName ); 266 267 for ( U32 i = 0; i < TEX_COUNT; i++ ) 268 { 269 stream->read( &mTexScale[i] ); 270 stream->read( &mTexSpeed[i] ); 271 mathRead( *stream, &mTexDirection[i] ); 272 } 273 274 stream->read( &mBaseColor ); 275 276 F32 oldCoverage = mCoverage; 277 stream->read( &mCoverage ); 278 stream->read( &mExposure ); 279 280 stream->read( &mWindSpeed ); 281 282 F32 oldHeight = mHeight; 283 stream->read( &mHeight ); 284 285 if ( isProperlyAdded() ) 286 { 287 if ( ( oldTextureName != mTextureName ) || ( ( oldCoverage == 0.0f ) != ( mCoverage == 0.0f ) ) ) 288 _initTexture(); 289 if ( oldHeight != mHeight ) 290 _initBuffers(); 291 } 292} 293 294 295// SceneObject... 296 297 298void CloudLayer::prepRenderImage( SceneRenderState *state ) 299{ 300 PROFILE_SCOPE( CloudLayer_prepRenderImage ); 301 302 if ( mCoverage <= 0.0f ) 303 return; 304 305 if ( state->isDiffusePass() ) 306 { 307 // Scroll textures... 308 309 U32 time = Sim::getCurrentTime(); 310 F32 delta = (F32)( time - mLastTime ) / 1000.0f; 311 mLastTime = time; 312 313 for ( U32 i = 0; i < 3; i++ ) 314 { 315 mTexOffset[i] += mTexDirection[i] * mTexSpeed[i] * delta * mWindSpeed; 316 } 317 } 318 319 // This should be sufficient for most objects that don't manage zones, and 320 // don't need to return a specialized RenderImage... 321 322 ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>(); 323 ri->renderDelegate.bind( this, &CloudLayer::renderObject ); 324 ri->type = RenderPassManager::RIT_Sky; 325 ri->defaultKey = 0; 326 ri->defaultKey2 = 0; 327 state->getRenderPass()->addInst( ri ); 328} 329 330void CloudLayer::renderObject( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *mi ) 331{ 332 GFXTransformSaver saver; 333 334 const Point3F &camPos = state->getCameraPosition(); 335 MatrixF xfm(true); 336 xfm.setPosition(camPos); 337 GFX->multWorld(xfm); 338 339 if ( state->isReflectPass() ) 340 GFX->setProjectionMatrix( state->getSceneManager()->getNonClipProjection() ); 341 342 GFX->setShader( mShader ); 343 GFX->setShaderConstBuffer( mShaderConsts ); 344 GFX->setStateBlock( mStateblock ); 345 346 // Set all the shader consts... 347 348 MatrixF xform(GFX->getProjectionMatrix()); 349 xform *= GFX->getViewMatrix(); 350 xform *= GFX->getWorldMatrix(); 351 352 mShaderConsts->setSafe( mModelViewProjSC, xform ); 353 354 mShaderConsts->setSafe( mEyePosWorldSC, camPos ); 355 356 LightInfo *lightinfo = LIGHTMGR->getSpecialLight(LightManager::slSunLightType); 357 const LinearColorF &sunlight = state->getAmbientLightColor(); 358 359 Point3F ambientColor( sunlight.red, sunlight.green, sunlight.blue ); 360 mShaderConsts->setSafe( mAmbientColorSC, ambientColor ); 361 362 const LinearColorF &sunColor = lightinfo->getColor(); 363 Point3F data( sunColor.red, sunColor.green, sunColor.blue ); 364 mShaderConsts->setSafe( mSunColorSC, data ); 365 366 mShaderConsts->setSafe( mSunVecSC, lightinfo->getDirection() ); 367 368 for ( U32 i = 0; i < TEX_COUNT; i++ ) 369 mShaderConsts->setSafe( mTexOffsetSC[i], mTexOffset[i] ); 370 371 Point3F scale( mTexScale[0], mTexScale[1], mTexScale[2] ); 372 mShaderConsts->setSafe( mTexScaleSC, scale ); 373 374 Point3F color; 375 color.set( mBaseColor.red, mBaseColor.green, mBaseColor.blue ); 376 mShaderConsts->setSafe( mBaseColorSC, color ); 377 378 mShaderConsts->setSafe( mCoverageSC, mCoverage ); 379 380 mShaderConsts->setSafe( mExposureSC, mExposure ); 381 382 GFX->setTexture( mNormalHeightMapSC->getSamplerRegister(), mTexture ); 383 GFX->setVertexBuffer( mVB ); 384 GFX->setPrimitiveBuffer( mPB ); 385 386 GFX->drawIndexedPrimitive( GFXTriangleList, 0, 0, smVertCount, 0, smTriangleCount ); 387} 388 389 390// CloudLayer Internal Methods.... 391 392 393void CloudLayer::_initTexture() 394{ 395 if ( mCoverage <= 0.0f ) 396 { 397 mTexture = NULL; 398 return; 399 } 400 401 if ( mTextureName.isNotEmpty() ) 402 mTexture.set( mTextureName, &GFXNormalMapProfile, "CloudLayer" ); 403 404 if ( mTexture.isNull() ) 405 mTexture.set( GFXTextureManager::getWarningTexturePath(), &GFXNormalMapProfile, "CloudLayer" ); 406} 407 408void CloudLayer::_initBuffers() 409{ 410 // Vertex Buffer... 411 412 Point3F vertScale( 16.0f, 16.0f, mHeight ); 413 F32 zOffset = -( mCos( mSqrt( 1.0f ) ) + 0.01f ); 414 415 mVB.set( GFX, smVertCount, GFXBufferTypeStatic ); 416 GFXCloudVertex *pVert = mVB.lock(); 417 if(!pVert) return; 418 419 for ( U32 y = 0; y < smVertStride; y++ ) 420 { 421 F32 v = ( (F32)y / (F32)smStrideMinusOne - 0.5f ) * 2.0f; 422 423 for ( U32 x = 0; x < smVertStride; x++ ) 424 { 425 F32 u = ( (F32)x / (F32)smStrideMinusOne - 0.5f ) * 2.0f; 426 427 F32 sx = u; 428 F32 sy = v; 429 F32 sz = mCos( mSqrt( sx*sx + sy*sy ) ) + zOffset; 430 //F32 sz = 1.0f; 431 pVert->point.set( sx, sy, sz ); 432 pVert->point *= vertScale; 433 434 // The vert to our right. 435 Point3F rpnt; 436 437 F32 ru = ( (F32)( x + 1 ) / (F32)smStrideMinusOne - 0.5f ) * 2.0f; 438 F32 rv = v; 439 440 rpnt.x = ru; 441 rpnt.y = rv; 442 rpnt.z = mCos( mSqrt( rpnt.x*rpnt.x + rpnt.y*rpnt.y ) ) + zOffset; 443 rpnt *= vertScale; 444 445 // The vert to our front. 446 Point3F fpnt; 447 448 F32 fu = u; 449 F32 fv = ( (F32)( y + 1 ) / (F32)smStrideMinusOne - 0.5f ) * 2.0f; 450 451 fpnt.x = fu; 452 fpnt.y = fv; 453 fpnt.z = mCos( mSqrt( fpnt.x*fpnt.x + fpnt.y*fpnt.y ) ) + zOffset; 454 fpnt *= vertScale; 455 456 Point3F fvec = fpnt - pVert->point; 457 fvec.normalize(); 458 459 Point3F rvec = rpnt - pVert->point; 460 rvec.normalize(); 461 462 pVert->normal = mCross( fvec, rvec ); 463 pVert->normal.normalize(); 464 pVert->binormal = fvec; 465 pVert->tangent = rvec; 466 pVert->texCoord.set( u, v ); 467 pVert++; 468 } 469 } 470 471 mVB.unlock(); 472 473 474 // Primitive Buffer... 475 476 mPB.set( GFX, smTriangleCount * 3, smTriangleCount, GFXBufferTypeStatic ); 477 478 U16 *pIdx = NULL; 479 mPB.lock(&pIdx); 480 U32 curIdx = 0; 481 482 for ( U32 y = 0; y < smStrideMinusOne; y++ ) 483 { 484 for ( U32 x = 0; x < smStrideMinusOne; x++ ) 485 { 486 U32 offset = x + y * smVertStride; 487 488 pIdx[curIdx] = offset; 489 curIdx++; 490 pIdx[curIdx] = offset + 1; 491 curIdx++; 492 pIdx[curIdx] = offset + smVertStride + 1; 493 curIdx++; 494 495 pIdx[curIdx] = offset; 496 curIdx++; 497 pIdx[curIdx] = offset + smVertStride + 1; 498 curIdx++; 499 pIdx[curIdx] = offset + smVertStride; 500 curIdx++; 501 } 502 } 503 504 mPB.unlock(); 505} 506