skyBox.cpp

Engine/source/environment/skyBox.cpp

More...

Public Functions

ConsoleDocClass(SkyBox , "@brief Represents the sky with an artist-created <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">cubemap.\n\n</a>" "<a href="/coding/class/classskybox/">SkyBox</a> is not <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> directional light and should be used in conjunction with <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classsun/">Sun</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "@ingroup Atmosphere" )
DefineEngineMethod(SkyBox , postApply , void , () , "" )

Detailed Description

Public Functions

ConsoleDocClass(SkyBox , "@brief Represents the sky with an artist-created <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">cubemap.\n\n</a>" "<a href="/coding/class/classskybox/">SkyBox</a> is not <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> directional light and should be used in conjunction with <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classsun/">Sun</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "@ingroup Atmosphere" )

DefineEngineMethod(SkyBox , postApply , void , () , "" )

IMPLEMENT_CO_NETOBJECT_V1(SkyBox )

  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 "environment/skyBox.h"
 26
 27#include "console/consoleTypes.h"
 28#include "console/engineAPI.h"
 29#include "scene/sceneRenderState.h"
 30#include "renderInstance/renderPassManager.h"
 31#include "gfx/primBuilder.h"
 32#include "gfx/gfxTransformSaver.h"
 33#include "core/stream/fileStream.h"
 34#include "core/stream/bitStream.h"
 35#include "materials/materialManager.h"
 36#include "materials/materialFeatureTypes.h"
 37#include "materials/sceneData.h"
 38#include "T3D/gameFunctions.h"
 39#include "renderInstance/renderBinManager.h"
 40#include "materials/processedMaterial.h"
 41#include "gfx/gfxDebugEvent.h"
 42#include "math/util/matrixSet.h"
 43
 44
 45IMPLEMENT_CO_NETOBJECT_V1( SkyBox );
 46
 47ConsoleDocClass( SkyBox,
 48   "@brief Represents the sky with an artist-created cubemap.\n\n"
 49
 50   "SkyBox is not a directional light and should be used in conjunction with a Sun object.\n\n"
 51
 52   "@ingroup Atmosphere"
 53);
 54
 55SkyBox::SkyBox()
 56{
 57   mTypeMask |= EnvironmentObjectType | StaticObjectType;
 58   mNetFlags.set(Ghostable | ScopeAlways);
 59
 60   mMatName = "";
 61   mMatInstance = NULL;
 62
 63   mIsVBDirty = false;
 64   mDrawBottom = true;
 65   mPrimCount = 0;
 66   mFogBandHeight = 0;
 67
 68   mMatrixSet = reinterpret_cast<MatrixSet *>(dMalloc_aligned(sizeof(MatrixSet), 16));
 69   constructInPlace(mMatrixSet);
 70
 71   mFogBandMat = NULL;
 72   mFogBandMatInst = NULL;
 73}
 74
 75SkyBox::~SkyBox()
 76{
 77   dFree_aligned(mMatrixSet);
 78
 79   if( mMatInstance )
 80      SAFE_DELETE( mMatInstance );
 81
 82   SAFE_DELETE( mFogBandMatInst );
 83
 84   if ( mFogBandMat )
 85   {
 86      mFogBandMat->deleteObject();
 87      mFogBandMat = NULL;
 88   }   
 89}
 90
 91bool SkyBox::onAdd()
 92{
 93   if ( !Parent::onAdd() )
 94      return false;
 95
 96   setGlobalBounds();
 97   resetWorldBox();
 98
 99   addToScene();
100
101   if ( isClientObject() )
102   {
103      _initRender();
104      _updateMaterial();
105   }
106
107   return true;
108}
109
110void SkyBox::onRemove()
111{
112   removeFromScene();
113   Parent::onRemove();
114}
115
116void SkyBox::initPersistFields()
117{
118   addGroup( "Sky Box" );  
119
120   addField( "material", TypeMaterialName, Offset( mMatName, SkyBox ), 
121      "The name of a cubemap material for the sky box." );
122
123   addField( "drawBottom", TypeBool, Offset( mDrawBottom, SkyBox ),
124      "If false the bottom of the skybox is not rendered." );
125
126   addField( "fogBandHeight", TypeF32, Offset( mFogBandHeight, SkyBox ),
127      "The height (0-1) of the fog band from the horizon to the top of the SkyBox." );
128
129   endGroup( "Sky Box" );
130
131   Parent::initPersistFields();
132}
133
134void SkyBox::inspectPostApply()
135{
136   Parent::inspectPostApply();
137   _updateMaterial();
138}
139
140U32 SkyBox::packUpdate( NetConnection *conn, U32 mask, BitStream *stream )
141{
142   U32 retMask = Parent::packUpdate( conn, mask, stream );
143   
144   stream->write( mMatName );
145   stream->writeFlag( mDrawBottom );
146   stream->write( mFogBandHeight );
147
148   return retMask;
149}
150
151void SkyBox::unpackUpdate( NetConnection *conn, BitStream *stream )
152{
153   Parent::unpackUpdate( conn, stream );
154
155   String tmpString( "" );
156   stream->read( &tmpString );
157   if ( !tmpString.equal( mMatName, String::NoCase ) )
158   {
159      mMatName = tmpString;
160      _updateMaterial();
161   }
162
163   bool drawBottom = stream->readFlag();
164   F32 bandHeight = 0;
165   stream->read( &bandHeight );
166
167   // If this flag has changed
168   // we need to update the vertex buffer.
169   if (  drawBottom != mDrawBottom || 
170         bandHeight != mFogBandHeight )
171   {
172      mDrawBottom = drawBottom;
173      mFogBandHeight = bandHeight;
174      mIsVBDirty = true;
175      _initRender();
176   }
177}
178
179void SkyBox::prepRenderImage( SceneRenderState *state )
180{
181   PROFILE_SCOPE( SkyBox_prepRenderImage );
182
183   if (  state->isShadowPass() || 
184         mVB.isNull() || 
185         mFogBandVB.isNull() || 
186         !mMatInstance )
187      return;
188
189   mMatrixSet->setSceneView(GFX->getWorldMatrix());
190   mMatrixSet->setSceneProjection(GFX->getProjectionMatrix());
191
192   ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
193   ri->renderDelegate.bind( this, &SkyBox::_renderObject );
194   ri->type = RenderPassManager::RIT_Sky;
195   ri->defaultKey = 10;
196   ri->defaultKey2 = 0;
197   state->getRenderPass()->addInst( ri );
198}
199
200void SkyBox::_renderObject( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *mi )
201{
202   GFXDEBUGEVENT_SCOPE( SkyBox_RenderObject, ColorI::WHITE );
203
204   GFXTransformSaver saver;  
205   GFX->setVertexBuffer( mVB );         
206
207   MatrixF worldMat = MatrixF::Identity;
208   worldMat.setPosition( state->getCameraPosition() );
209
210   SceneData sgData;
211   sgData.init( state );
212   sgData.objTrans = &worldMat;
213
214   mMatrixSet->restoreSceneViewProjection();
215   mMatrixSet->setWorld( worldMat );
216   if ( state->isReflectPass() )
217      mMatrixSet->setProjection( state->getSceneManager()->getNonClipProjection() );
218
219   while ( mMatInstance->setupPass( state, sgData ) )
220   {         
221      mMatInstance->setTransforms( *mMatrixSet, state );
222      mMatInstance->setSceneInfo( state, sgData );
223
224      GFX->drawPrimitive( GFXTriangleList, 0, mPrimCount );     
225   }
226
227   // Draw render band.
228   if ( mFogBandHeight > 0 && mFogBandMatInst )
229   {
230      const FogData &fog = state->getSceneManager()->getFogData();
231      if ( mLastFogColor != fog.color )
232      {
233         mLastFogColor = fog.color;
234         _initRender();
235      }
236
237      // Just need it to follow the camera... no rotation.
238      MatrixF camPosMat( MatrixF::Identity );
239      camPosMat.setPosition( worldMat.getPosition() );
240      sgData.objTrans = &camPosMat;
241      mMatrixSet->setWorld( *sgData.objTrans );
242
243      while ( mFogBandMatInst->setupPass( state, sgData ) )
244      {
245         mFogBandMatInst->setTransforms( *mMatrixSet, state );
246         mFogBandMatInst->setSceneInfo( state, sgData );
247
248         GFX->setVertexBuffer( mFogBandVB );      
249         GFX->drawPrimitive( GFXTriangleList, 0, 16 );
250      }
251   }
252}
253
254void SkyBox::_initRender()
255{
256   GFXVertexPNT *tmpVerts = NULL;
257
258   U32 vertCount = 36;
259
260   if ( !mDrawBottom )
261      vertCount = 30;
262
263   mPrimCount = vertCount / 3;
264
265   // Create temp vertex pointer
266   // so we can read from it
267   // for generating the normals below.
268   tmpVerts = new GFXVertexPNT[vertCount];
269
270   // We don't bother sharing
271   // vertices here, in order to
272   // avoid using a primitive buffer.
273   tmpVerts[0].point.set( -1, -1, 1 );
274   tmpVerts[1].point.set( 1, -1, 1 );
275   tmpVerts[2].point.set( 1, -1, -1 );
276
277   tmpVerts[0].texCoord.set( 0, 0 );
278   tmpVerts[1].texCoord.set( 1.0f, 0 );
279   tmpVerts[2].texCoord.set( 1.0f, 1.0f );
280
281   tmpVerts[3].point.set( -1, -1, 1 );
282   tmpVerts[4].point.set( 1, -1, -1 );
283   tmpVerts[5].point.set( -1, -1, -1 );
284
285   tmpVerts[3].texCoord.set( 0, 0 );
286   tmpVerts[4].texCoord.set( 1.0f, 1.0f );
287   tmpVerts[5].texCoord.set( 0, 1.0f );
288
289   tmpVerts[6].point.set( 1, -1, 1 );
290   tmpVerts[7].point.set( 1, 1, 1 );
291   tmpVerts[8].point.set( 1, 1, -1 );
292
293   tmpVerts[6].texCoord.set( 0, 0 );
294   tmpVerts[7].texCoord.set( 1.0f, 0 );
295   tmpVerts[8].texCoord.set( 1.0f, 1.0f );
296
297   tmpVerts[9].point.set( 1, -1, 1 );
298   tmpVerts[10].point.set( 1, 1, -1 );
299   tmpVerts[11].point.set( 1, -1, -1 );
300
301   tmpVerts[9].texCoord.set( 0, 0 );
302   tmpVerts[10].texCoord.set( 1.0f, 1.0f );
303   tmpVerts[11].texCoord.set( 0, 1.0f );
304
305   tmpVerts[12].point.set( -1, 1, 1 );
306   tmpVerts[13].point.set( -1, -1, 1 );
307   tmpVerts[14].point.set( -1, -1, -1 );
308
309   tmpVerts[12].texCoord.set( 0, 0 );
310   tmpVerts[13].texCoord.set( 1.0f, 0 );
311   tmpVerts[14].texCoord.set( 1.0f, 1.0f );
312
313   tmpVerts[15].point.set( -1, 1, 1 );
314   tmpVerts[16].point.set( -1, -1, -1 ); 
315   tmpVerts[17].point.set( -1, 1, -1 );
316
317   tmpVerts[15].texCoord.set( 0, 0 );
318   tmpVerts[16].texCoord.set( 1.0f, 1.0f ); 
319   tmpVerts[17].texCoord.set( 1.0f, 0 );
320
321   tmpVerts[18].point.set( 1, 1, 1 );
322   tmpVerts[19].point.set( -1, 1, 1 );
323   tmpVerts[20].point.set( -1, 1, -1 );
324
325   tmpVerts[18].texCoord.set( 0, 0 );
326   tmpVerts[19].texCoord.set( 1.0f, 0 );
327   tmpVerts[20].texCoord.set( 1.0f, 1.0f );
328
329   tmpVerts[21].point.set( 1, 1, 1 );
330   tmpVerts[22].point.set( -1, 1, -1 );
331   tmpVerts[23].point.set( 1, 1, -1 );
332
333   tmpVerts[21].texCoord.set( 0, 0 );
334   tmpVerts[22].texCoord.set( 1.0f, 1.0f );
335   tmpVerts[23].texCoord.set( 0, 1.0f );
336
337   tmpVerts[24].point.set( -1, -1, 1 );
338   tmpVerts[25].point.set( -1, 1, 1 );
339   tmpVerts[26].point.set( 1, 1, 1 );
340
341   tmpVerts[24].texCoord.set( 0, 0 );
342   tmpVerts[25].texCoord.set( 1.0f, 0 );
343   tmpVerts[26].texCoord.set( 1.0f, 1.0f );
344
345   tmpVerts[27].point.set( -1, -1, 1 );
346   tmpVerts[28].point.set( 1, 1, 1 );
347   tmpVerts[29].point.set( 1, -1, 1 );
348
349   tmpVerts[27].texCoord.set( 0, 0 );
350   tmpVerts[28].texCoord.set( 1.0f, 1.0f );
351   tmpVerts[29].texCoord.set( 0, 1.0f );
352
353   // Only set up these
354   // vertices if the SkyBox
355   // is set to render the bottom face.
356   if ( mDrawBottom )
357   {
358      tmpVerts[30].point.set( 1, 1, -1 ); 
359      tmpVerts[31].point.set( -1, 1, -1 );
360      tmpVerts[32].point.set( -1, -1, -1 );
361
362      tmpVerts[30].texCoord.set( 1.0f, 1.0f ); 
363      tmpVerts[31].texCoord.set( 1.0f, 0 );
364      tmpVerts[32].texCoord.set( 0, 0 );
365
366      tmpVerts[33].point.set( 1, -1, -1 ); 
367      tmpVerts[34].point.set( 1, 1, -1 );
368      tmpVerts[35].point.set( -1, -1, -1 );
369
370      tmpVerts[33].texCoord.set( 0, 1.0f ); 
371      tmpVerts[34].texCoord.set( 1.0f, 1.0f );
372      tmpVerts[35].texCoord.set( 0, 0 );
373   }
374
375   VectorF tmp( 0, 0, 0 );
376
377   for ( U32 i = 0; i < vertCount; i++ )
378   {
379      //tmp = tmpVerts[i].point;
380      //tmp.normalize();
381      //tmpVerts[i].normal.set( tmp );
382
383      // Note: SkyBox renders with a regular material, which uses the "Reflect Cube"
384      // feature. 
385      //
386      // This feature is really designed a cubemap representing a reflection
387      // on an objects surface and therefore looks up into the cubemap with the 
388      // cubemap-space view vector reflected by the vert normal. 
389      //
390      // Since we are actually viewing the skybox from "inside" not from 
391      // "outside" this reflection ends up making the cubemap appear upsidown. 
392      // Therefore we set the vert-normals to "zero" so that the reflection 
393      // operation returns the input, unreflected, vector.
394
395      tmpVerts[i].normal.set( Point3F::Zero );
396   }
397
398   if ( mVB.isNull() || mIsVBDirty )
399   {
400      mVB.set( GFX, vertCount, GFXBufferTypeStatic );
401      mIsVBDirty = false;
402   }
403
404   GFXVertexPNT *vertPtr = mVB.lock();
405   if (!vertPtr)
406   {
407      delete[] tmpVerts;
408      return;
409   }
410
411   dMemcpy(vertPtr, tmpVerts, sizeof( GFXVertexPNT) * vertCount);
412
413   mVB.unlock();
414
415   // Clean up temp verts.
416   delete [] tmpVerts;
417
418   if ( mFogBandVB.isNull() )
419      mFogBandVB.set( GFX, 48, GFXBufferTypeStatic );
420
421   GFXVertexPC *bandVertPtr = mFogBandVB.lock();
422   if(!bandVertPtr) return;
423
424   // Grab the fog color.
425   ColorI fogColor( mLastFogColor.red * 255, mLastFogColor.green * 255, mLastFogColor.blue * 255 );
426   ColorI fogColorAlpha( mLastFogColor.red * 255, mLastFogColor.green * 255, mLastFogColor.blue * 255, 0 );
427
428   // Upper portion of band geometry.
429   {
430      bandVertPtr[0].point.set( -1, -1, mFogBandHeight );
431      bandVertPtr[1].point.set( 1, -1, mFogBandHeight );
432      bandVertPtr[2].point.set( 1, -1, 0 );
433
434      bandVertPtr[0].color.set( fogColorAlpha );
435      bandVertPtr[1].color.set( fogColorAlpha );
436      bandVertPtr[2].color.set( fogColor );
437
438      bandVertPtr[3].point.set( -1, -1, mFogBandHeight );
439      bandVertPtr[4].point.set( 1, -1, 0 );
440      bandVertPtr[5].point.set( -1, -1, 0 );
441
442      bandVertPtr[3].color.set( fogColorAlpha );
443      bandVertPtr[4].color.set( fogColor );
444      bandVertPtr[5].color.set( fogColor );
445
446      bandVertPtr[6].point.set( 1, -1, mFogBandHeight );
447      bandVertPtr[7].point.set( 1, 1, mFogBandHeight );
448      bandVertPtr[8].point.set( 1, 1, 0 );
449
450      bandVertPtr[6].color.set( fogColorAlpha );
451      bandVertPtr[7].color.set( fogColorAlpha );
452      bandVertPtr[8].color.set( fogColor );
453
454      bandVertPtr[9].point.set( 1, -1, mFogBandHeight );
455      bandVertPtr[10].point.set( 1, 1, 0 );
456      bandVertPtr[11].point.set( 1, -1, 0 );
457
458      bandVertPtr[9].color.set( fogColorAlpha );
459      bandVertPtr[10].color.set( fogColor );
460      bandVertPtr[11].color.set( fogColor );
461
462      bandVertPtr[12].point.set( -1, 1, mFogBandHeight );
463      bandVertPtr[13].point.set( -1, -1, mFogBandHeight );
464      bandVertPtr[14].point.set( -1, -1, 0 );
465
466      bandVertPtr[12].color.set( fogColorAlpha );
467      bandVertPtr[13].color.set( fogColorAlpha );
468      bandVertPtr[14].color.set( fogColor );
469
470      bandVertPtr[15].point.set( -1, 1, mFogBandHeight );
471      bandVertPtr[16].point.set( -1, -1, 0 ); 
472      bandVertPtr[17].point.set( -1, 1, 0 );
473
474      bandVertPtr[15].color.set( fogColorAlpha );
475      bandVertPtr[16].color.set( fogColor );
476      bandVertPtr[17].color.set( fogColor );
477
478      bandVertPtr[18].point.set( 1, 1, mFogBandHeight );
479      bandVertPtr[19].point.set( -1, 1, mFogBandHeight );
480      bandVertPtr[20].point.set( -1, 1, 0 );
481
482      bandVertPtr[18].color.set( fogColorAlpha );
483      bandVertPtr[19].color.set( fogColorAlpha );
484      bandVertPtr[20].color.set( fogColor );
485
486      bandVertPtr[21].point.set( 1, 1, mFogBandHeight );
487      bandVertPtr[22].point.set( -1, 1, 0 );
488      bandVertPtr[23].point.set( 1, 1, 0 );
489
490      bandVertPtr[21].color.set( fogColorAlpha );
491      bandVertPtr[22].color.set( fogColor );
492      bandVertPtr[23].color.set( fogColor );
493   }
494
495   // Lower portion of band geometry.
496   {
497      bandVertPtr[24].point.set( -1, -1, 0 );
498      bandVertPtr[25].point.set( 1, -1, 0 );
499      bandVertPtr[26].point.set( 1, -1, -1 );
500
501      bandVertPtr[24].color.set( fogColor );
502      bandVertPtr[25].color.set( fogColor );
503      bandVertPtr[26].color.set( fogColor );
504
505      bandVertPtr[27].point.set( -1, -1, 0 );
506      bandVertPtr[28].point.set( 1, -1, -1 );
507      bandVertPtr[29].point.set( -1, -1, -1 );
508
509      bandVertPtr[27].color.set( fogColor );
510      bandVertPtr[28].color.set( fogColor );
511      bandVertPtr[29].color.set( fogColor );
512
513      bandVertPtr[30].point.set( 1, -1, 0 );
514      bandVertPtr[31].point.set( 1, 1, 0 );
515      bandVertPtr[32].point.set( 1, 1, -1 );
516
517      bandVertPtr[30].color.set( fogColor );
518      bandVertPtr[31].color.set( fogColor );
519      bandVertPtr[32].color.set( fogColor );
520
521      bandVertPtr[33].point.set( 1, -1, 0 );
522      bandVertPtr[34].point.set( 1, 1, -1 );
523      bandVertPtr[35].point.set( 1, -1, -1 );
524
525      bandVertPtr[33].color.set( fogColor );
526      bandVertPtr[34].color.set( fogColor );
527      bandVertPtr[35].color.set( fogColor );
528
529      bandVertPtr[36].point.set( -1, 1, 0 );
530      bandVertPtr[37].point.set( -1, -1, 0 );
531      bandVertPtr[38].point.set( -1, -1, -1 );
532
533      bandVertPtr[36].color.set( fogColor );
534      bandVertPtr[37].color.set( fogColor );
535      bandVertPtr[38].color.set( fogColor );
536
537      bandVertPtr[39].point.set( -1, 1, 0 );
538      bandVertPtr[40].point.set( -1, -1, -1 ); 
539      bandVertPtr[41].point.set( -1, 1, -1 );
540
541      bandVertPtr[39].color.set( fogColor );
542      bandVertPtr[40].color.set( fogColor );
543      bandVertPtr[41].color.set( fogColor );
544
545      bandVertPtr[42].point.set( 1, 1, 0 );
546      bandVertPtr[43].point.set( -1, 1, 0 );
547      bandVertPtr[44].point.set( -1, 1, -1 );
548
549      bandVertPtr[42].color.set( fogColor );
550      bandVertPtr[43].color.set( fogColor );
551      bandVertPtr[44].color.set( fogColor );
552
553      bandVertPtr[45].point.set( 1, 1, 0 );
554      bandVertPtr[46].point.set( -1, 1, -1 );
555      bandVertPtr[47].point.set( 1, 1, -1 );
556
557      bandVertPtr[45].color.set( fogColor );
558      bandVertPtr[46].color.set( fogColor );
559      bandVertPtr[47].color.set( fogColor );
560   }
561
562   mFogBandVB.unlock();
563
564   SAFE_DELETE( mFogBandMatInst );
565   if ( mFogBandMat )
566   {
567      mFogBandMat->deleteObject();
568      mFogBandMat = NULL;
569   }
570
571   // Setup the material for this imposter.
572   mFogBandMat = MATMGR->allocateAndRegister( String::EmptyString );
573   mFogBandMat->mAutoGenerated = true;   
574   mFogBandMat->mTranslucent = true;   
575   mFogBandMat->mVertColor[0] = true;
576   mFogBandMat->mDoubleSided = true;
577   mFogBandMat->mEmissive[0] = true;
578
579   FeatureSet features = MATMGR->getDefaultFeatures();
580   features.addFeature(MFT_isBackground);
581   mFogBandMatInst = mFogBandMat->createMatInstance();
582   mFogBandMatInst->init(features, getGFXVertexFormat<GFXVertexPC>() );
583}
584
585void SkyBox::onStaticModified( const char *slotName, const char *newValue )
586{
587   Parent::onStaticModified( slotName, newValue );
588
589   if ( dStricmp( slotName, "material" ) == 0 )
590      setMaskBits( 0xFFFFFFFF );
591}
592
593void SkyBox::_initMaterial()
594{
595   if ( mMatInstance )
596      SAFE_DELETE( mMatInstance );
597
598   if ( mMaterial )
599      mMatInstance = mMaterial->createMatInstance();
600   else
601      mMatInstance = MATMGR->createMatInstance( "WarningMaterial" );
602
603   // We want to disable culling and z write.
604   GFXStateBlockDesc desc;
605   desc.setCullMode( GFXCullNone );
606   desc.setBlend( true );
607   desc.setZReadWrite( true, false );
608   desc.zFunc = GFXCmpLessEqual;
609   mMatInstance->addStateBlockDesc( desc );
610
611   // Also disable lighting on the skybox material by default.
612   FeatureSet features = MATMGR->getDefaultFeatures();
613   features.removeFeature( MFT_RTLighting );
614   features.removeFeature( MFT_Visibility );
615   features.addFeature(MFT_isBackground);   
616   features.addFeature(MFT_SkyBox);
617
618   // Now initialize the material.
619   mMatInstance->init(features, getGFXVertexFormat<GFXVertexPNT>());
620}
621
622void SkyBox::_updateMaterial()
623{
624   if ( mMatName.isEmpty() )
625      return;
626
627   Material *pMat = NULL;
628   if ( !Sim::findObject( mMatName, pMat ) )
629      Con::printf( "SkyBox::_updateMaterial, failed to find Material of name %s!", mMatName.c_str() );
630   else if ( isProperlyAdded() )
631   {
632      mMaterial = pMat;
633      _initMaterial(); 
634   }
635}
636
637BaseMatInstance* SkyBox::_getMaterialInstance()
638{
639   if ( !mMaterial || !mMatInstance || mMatInstance->getMaterial() != mMaterial )
640      _initMaterial();
641
642   if ( !mMatInstance )
643      return NULL;
644
645   return mMatInstance;
646}
647
648DefineEngineMethod( SkyBox, postApply, void, (), , "")
649{
650   object->inspectPostApply();
651}
652