Bladeren bron

Merge pull request #736 from marauder2k9-torque/SkyImprovements

Sky improvements
Brian Roberts 3 jaren geleden
bovenliggende
commit
32f3194e3e

+ 119 - 42
Engine/source/environment/scatterSky.cpp

@@ -651,7 +651,7 @@ void ScatterSky::prepRenderImage( SceneRenderState *state )
    ObjectRenderInst *ri = renderPass->allocInst<ObjectRenderInst>();
    ri->renderDelegate.bind( this, &ScatterSky::_render );
    ri->type = RenderPassManager::RIT_Sky;
-   ri->defaultKey = 10;
+   ri->defaultKey = 15;
    ri->defaultKey2 = 0;
    renderPass->addInst(ri);
 
@@ -700,7 +700,7 @@ void ScatterSky::prepRenderImage( SceneRenderState *state )
 	  moonRI->renderDelegate.bind( this, &ScatterSky::_renderMoon );
 	  moonRI->type = RenderPassManager::RIT_Sky;
       // Render after sky objects and before CloudLayer!
-	  moonRI->defaultKey = 5;
+	  moonRI->defaultKey = 10;
 	  moonRI->defaultKey2 = 0;
       renderPass->addInst(moonRI);
    }
@@ -758,73 +758,146 @@ bool ScatterSky::_initShader()
    return true;
 }
 
+void ScatterSky::clearVectors()
+{
+   tmpVertices.clear();
+   vertsVec.clear();
+}
+
+void ScatterSky::addVertex(Point3F vert)
+{
+   vertsVec.push_back(vert.x);
+   vertsVec.push_back(vert.y);
+   vertsVec.push_back(vert.z);
+}
+
+void ScatterSky::BuildFinalVert()
+{
+   U32 count = vertsVec.size();
+   U32 i, j;
+   for (i = 0, j = 0; i < count; i += 3, j += 2)
+   {
+      FinalVertexData temp;
+      temp.pos.set(Point3F(vertsVec[i], vertsVec[i + 1], vertsVec[i + 2]));
+
+      finalVertData.push_back(temp);
+   }
+}
+
 void ScatterSky::_initVBIB()
 {
-   // Vertex Buffer...
-   U32 vertStride = 50;
-   U32 strideMinusOne = vertStride - 1;
-   mVertCount = vertStride * vertStride;
-   mPrimCount = strideMinusOne * strideMinusOne * 2;
+   U32 rings = 18;
+   U32 height = 9;
+   U32 radius = 10;
 
-   Point3F vertScale( 16.0f, 16.0f, 4.0f );
+   F32 x, y, z, xy;                     // vertex position
 
-   F32 zOffset = -( mCos( mSqrt( 1.0f ) ) + 0.01f );
+   F32 ringStep = M_2PI / rings;
+   F32 heightStep = M_HALFPI / height; // M_PI for full sphere.
+   F32 ringAng, heightAng;
 
-   mVB.set( GFX, mVertCount, GFXBufferTypeStatic );
-   GFXVertexP *pVert = mVB.lock();
-   if(!pVert) return;
+   //clear vecs
+   clearVectors();
 
-   for ( U32 y = 0; y < vertStride; y++ )
+   for (U32 i = 0; i <= height; ++i)
    {
-      F32 v = ( (F32)y / (F32)strideMinusOne - 0.5f ) * 2.0f;
+      heightAng = M_PI / 2 - (F32)i * heightStep;
+      xy = radius * mCos(heightAng);
+      z = radius * mSin(heightAng);
 
-      for ( U32 x = 0; x < vertStride; x++ )
+      for (U32 j = 0; j <= rings; ++j)
       {
-         F32 u = ( (F32)x / (F32)strideMinusOne - 0.5f ) * 2.0f;
+         SphereVertex vert;
+         ringAng = j * ringStep;
+         x = xy * mCos(ringAng);
+         y = xy * mSin(ringAng);
+         vert.pos.set(Point3F(x, y, z));
 
-         F32 sx = u;
-         F32 sy = v;
-         F32 sz = (mCos( mSqrt( sx*sx + sy*sy ) ) * 1.0f) + zOffset;
-         //F32 sz = 1.0f;
-         pVert->point.set( sx, sy, sz );
-         pVert->point *= vertScale;
+         tmpVertices.push_back(vert);
+      }
+   }
+
+   SphereVertex v1, v2, v3, v4;
+   U32 vi1, vi2 = 0;
+
+   for (U32 i = 0; i < height; ++i)
+   {
+      vi1 = i * (rings + 1);
+      vi2 = (i + 1) * (rings + 1);
+
+      for (U32 j = 0; j < rings; ++j, ++vi1, ++vi2)
+      {
+         v1 = tmpVertices[vi1];
+         v2 = tmpVertices[vi2];
+         v3 = tmpVertices[vi1 + 1];
+         v4 = tmpVertices[vi2 + 1];
+
+         // 1st = triangle.
+         if (i == 0)
+         {
+            // verts for tri.
+            addVertex(v1.pos);
+            addVertex(v2.pos);
+            addVertex(v4.pos);
+         }
+         /* UNCOMMENT WHEN FULL SPHERE
+         else if (i == (height - 1))
+         {
+            // verts for tri.
+            addVertex(v1.pos);
+            addVertex(v2.pos);
+            addVertex(v3.pos);
+         }*/
+         else
+         {
+            // verts for quad.
+            addVertex(v1.pos);
+            addVertex(v2.pos);
+            addVertex(v3.pos);
+
+            addVertex(v3.pos);
+            addVertex(v4.pos);
+            addVertex(v2.pos);
+         }
+      }
+   }
+
+   BuildFinalVert();
+
+   // Vertex Buffer...
+   mVertCount = finalVertData.size();
+   mPrimCount = mVertCount / 3;
+
+   mVB.set( GFX, mVertCount, GFXBufferTypeStatic );
+   GFXVertexP *pVert = mVB.lock();
+   if(!pVert) return;
+
+   for ( U32 i = 0; i < mVertCount; i++ )
+   {
+         pVert->point.set(finalVertData[i].pos);
 
          pVert->point.normalize();
          pVert->point *= 200000.0f;
-
          pVert++;
-      }
    }
 
    mVB.unlock();
 
    // Primitive Buffer...
-   mPrimBuffer.set( GFX, mPrimCount * 3, mPrimCount, GFXBufferTypeStatic );
+   mPrimBuffer.set( GFX, mVertCount, mPrimCount, GFXBufferTypeStatic );
 
    U16 *pIdx = NULL;
    mPrimBuffer.lock(&pIdx);
    U32 curIdx = 0;
 
-   for ( U32 y = 0; y < strideMinusOne; y++ )
+   for ( U32 i = 0, k = 0; i < mPrimCount; i++, k+=3 )
    {
-      for ( U32 x = 0; x < strideMinusOne; x++ )
-      {
-         U32 offset = x + y * vertStride;
-
-         pIdx[curIdx] = offset;
+         pIdx[curIdx] = k;
          curIdx++;
-         pIdx[curIdx] = offset + 1;
+         pIdx[curIdx] = k + 1;
          curIdx++;
-         pIdx[curIdx] = offset + vertStride + 1;
+         pIdx[curIdx] = k + 2;
          curIdx++;
-
-         pIdx[curIdx] = offset;
-         curIdx++;
-         pIdx[curIdx] = offset + vertStride + 1;
-         curIdx++;
-         pIdx[curIdx] = offset + vertStride;
-         curIdx++;
-      }
    }
 
    mPrimBuffer.unlock();
@@ -963,7 +1036,11 @@ void ScatterSky::_render( ObjectRenderInst *ri, SceneRenderState *state, BaseMat
 
    Point3F camPos2 = state->getCameraPosition();
    MatrixF xfm(true);
-   xfm.setPosition(camPos2 - Point3F(0, 0, mZOffset));
+   xfm.setPosition(Point3F(
+      camPos2.x,
+      camPos2.y,
+      mZOffset) );
+
    GFX->multWorld(xfm);
 
    MatrixF xform(proj);//GFX->getProjectionMatrix());

+ 21 - 0
Engine/source/environment/scatterSky.h

@@ -104,6 +104,27 @@ public:
    ///
    F32 getElevation() const { return mSunElevation; }
 
+   struct SphereVertex
+   {
+      Point3F pos;
+   };
+
+   Vector<SphereVertex> tmpVertices;
+   Vector<F32> vertsVec;
+
+   struct FinalVertexData
+   {
+      Point3F pos;
+   };
+
+   Vector<FinalVertexData> finalVertData;
+
+   void addVertex(Point3F vert);
+
+   void BuildFinalVert();
+
+   void clearVectors();
+
 protected:
 
    void _render( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat );

+ 1 - 1
Engine/source/environment/skyBox.cpp

@@ -645,4 +645,4 @@ BaseMatInstance* SkyBox::_getMaterialInstance()
 DefineEngineMethod( SkyBox, postApply, void, (), , "")
 {
 	object->inspectPostApply();
-}
+}

+ 645 - 0
Engine/source/environment/skySphere.cpp

@@ -0,0 +1,645 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#include "platform/platform.h"
+#include "environment/skySphere.h"
+
+#include "console/consoleTypes.h"
+#include "console/engineAPI.h"
+#include "scene/sceneRenderState.h"
+#include "renderInstance/renderPassManager.h"
+#include "gfx/primBuilder.h"
+#include "gfx/gfxTransformSaver.h"
+#include "core/stream/fileStream.h"
+#include "core/stream/bitStream.h"
+#include "materials/materialManager.h"
+#include "materials/materialFeatureTypes.h"
+#include "materials/sceneData.h"
+#include "T3D/gameFunctions.h"
+#include "renderInstance/renderBinManager.h"
+#include "materials/processedMaterial.h"
+#include "gfx/gfxDebugEvent.h"
+#include "math/util/matrixSet.h"
+
+IMPLEMENT_CO_NETOBJECT_V1(SkySphere);
+
+ConsoleDocClass(SkySphere,
+   "@brief Represents the sky with an artist-created spherical map.\n\n"
+
+   "SkySphere is not a directional light and should be used in conjunction with a Sun object.\n\n"
+
+   "@ingroup Atmosphere"
+);
+
+SkySphere::SkySphere()
+{
+   mTypeMask |= EnvironmentObjectType | StaticObjectType;
+   mNetFlags.set(Ghostable | ScopeAlways);
+
+   INIT_ASSET(Material);
+   mMatInstance = NULL;
+
+   mIsVBDirty = false;
+   mPrimCount = 0;
+   mFogBandHeight = 0;
+   mFogPrimCount = 0;
+
+   mMatrixSet = reinterpret_cast<MatrixSet*>(dMalloc_aligned(sizeof(MatrixSet), 16));
+   constructInPlace(mMatrixSet);
+
+   mFogBandMat = NULL;
+   mFogBandMatInst = NULL;
+}
+
+SkySphere::~SkySphere()
+{
+   dFree_aligned(mMatrixSet);
+
+   if (mMatInstance)
+      SAFE_DELETE(mMatInstance);
+
+   SAFE_DELETE(mFogBandMatInst);
+
+   if (mFogBandMat)
+   {
+      mFogBandMat->deleteObject();
+      mFogBandMat = NULL;
+   }
+}
+
+bool SkySphere::onAdd()
+{
+   if (!Parent::onAdd())
+      return false;
+
+   setGlobalBounds();
+   resetWorldBox();
+
+   addToScene();
+
+   if (isClientObject())
+   {
+      _initRender();
+      _updateMaterial();
+   }
+
+   return true;
+}
+
+void SkySphere::onRemove()
+{
+   removeFromScene();
+   Parent::onRemove();
+}
+
+void SkySphere::initPersistFields()
+{
+   addGroup("Sky Sphere");
+
+   INITPERSISTFIELD_MATERIALASSET(Material, SkySphere, "The name of a cubemap material for the sky box.");
+
+   addField("fogBandHeight", TypeF32, Offset(mFogBandHeight, SkySphere),
+      "The height (0-1) of the fog band from the horizon to the top of the SkySphere.");
+
+   endGroup("Sky Sphere");
+
+   Parent::initPersistFields();
+}
+
+void SkySphere::inspectPostApply()
+{
+   Parent::inspectPostApply();
+   _updateMaterial();
+}
+
+U32 SkySphere::packUpdate(NetConnection* conn, U32 mask, BitStream* stream)
+{
+   U32 retMask = Parent::packUpdate(conn, mask, stream);
+
+   PACK_ASSET(conn, Material);
+
+   stream->write(mFogBandHeight);
+
+   return retMask;
+}
+
+void SkySphere::unpackUpdate(NetConnection* conn, BitStream* stream)
+{
+   Parent::unpackUpdate(conn, stream);
+
+   StringTableEntry oldMatName = getMaterial();
+   UNPACK_ASSET(conn, Material);
+   if (oldMatName != getMaterial())
+   {
+      _updateMaterial();
+   }
+
+   F32 bandHeight = 0;
+   stream->read(&bandHeight);
+
+   // If this flag has changed
+   // we need to update the vertex buffer.
+   if ( bandHeight != mFogBandHeight)
+   {
+      mFogBandHeight = bandHeight;
+      mIsVBDirty = true;
+      _initRender();
+   }
+}
+
+void SkySphere::prepRenderImage(SceneRenderState* state)
+{
+   PROFILE_SCOPE(SkySphere_prepRenderImage);
+
+   if (state->isShadowPass() ||
+      mVB.isNull() ||
+      mFogBandVB.isNull() ||
+      !mMatInstance)
+      return;
+
+   mMatrixSet->setSceneView(GFX->getWorldMatrix());
+   mMatrixSet->setSceneProjection(GFX->getProjectionMatrix());
+
+   ObjectRenderInst* ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
+   ri->renderDelegate.bind(this, &SkySphere::_renderObject);
+   ri->type = RenderPassManager::RIT_Sky;
+   ri->defaultKey = 9;
+   ri->defaultKey2 = 0;
+   state->getRenderPass()->addInst(ri);
+}
+
+void SkySphere::_renderObject(ObjectRenderInst* ri, SceneRenderState* state, BaseMatInstance* mi)
+{
+   GFXDEBUGEVENT_SCOPE(SkySphere_RenderObject, ColorI::WHITE);
+
+   GFXTransformSaver saver;
+   GFX->setVertexBuffer(mVB);
+
+   MatrixF worldMat = MatrixF::Identity;
+   worldMat.setPosition(Point3F(
+      state->getCameraPosition().x,
+      state->getCameraPosition().y,
+      state->getCameraPosition().z));
+
+   SceneData sgData;
+   sgData.init(state);
+   sgData.objTrans = &worldMat;
+
+   mMatrixSet->restoreSceneViewProjection();
+   mMatrixSet->setWorld(worldMat);
+   if (state->isReflectPass())
+      mMatrixSet->setProjection(state->getSceneManager()->getNonClipProjection());
+
+   while (mMatInstance->setupPass(state, sgData))
+   {
+      mMatInstance->setTransforms(*mMatrixSet, state);
+      mMatInstance->setSceneInfo(state, sgData);
+
+      GFX->drawPrimitive(GFXTriangleList, 0, mPrimCount);
+   }
+
+   // Draw render band.
+   if (mFogBandHeight > 0 && mFogBandMatInst)
+   {
+      const FogData& fog = state->getSceneManager()->getFogData();
+      if (mLastFogColor != fog.color)
+      {
+         mLastFogColor = fog.color;
+         _initRender();
+      }
+
+      // Just need it to follow the camera... no rotation.
+      MatrixF camPosMat(MatrixF::Identity);
+      camPosMat.setPosition(worldMat.getPosition());
+      sgData.objTrans = &camPosMat;
+      mMatrixSet->setWorld(*sgData.objTrans);
+
+      while (mFogBandMatInst->setupPass(state, sgData))
+      {
+         mFogBandMatInst->setTransforms(*mMatrixSet, state);
+         mFogBandMatInst->setSceneInfo(state, sgData);
+
+         GFX->setVertexBuffer(mFogBandVB);
+         GFX->drawPrimitive(GFXTriangleList, 0, mFogPrimCount);
+      }
+   }
+}
+
+void SkySphere::clearVectors()
+{
+   tmpVertices.clear();
+   finalFogVertex.clear();
+   tempFogVertex.clear();
+   colVec.clear();
+   fogVerts.clear();
+   vertsVec.clear();
+   normsVec.clear();
+   texCoordVec.clear();
+   finalVertData.clear();
+}
+
+void SkySphere::addVertex(Point3F vert)
+{
+   vertsVec.push_back(vert.x);
+   vertsVec.push_back(vert.y);
+   vertsVec.push_back(vert.z);
+}
+
+void SkySphere::addNormal(Point3F nor)
+{
+   normsVec.push_back(nor.x);
+   normsVec.push_back(nor.y);
+   normsVec.push_back(nor.z);
+}
+
+void SkySphere::addTexcoord(F32 s, F32 t)
+{
+   texCoordVec.push_back(s);
+   texCoordVec.push_back(t);
+}
+
+void SkySphere::addColor(ColorI col)
+{
+   colVec.push_back(col);
+}
+
+void SkySphere::BuildFinalVert()
+{
+   U32 count = vertsVec.size();
+   U32 i, j;
+   for (i = 0, j = 0; i < count; i += 3, j += 2)
+   {
+      FinalVertexData temp;
+      temp.pos.set(Point3F(vertsVec[i], vertsVec[i + 1], vertsVec[i + 2]));
+      temp.nor.set(Point3F(normsVec[i], normsVec[i + 1], normsVec[i + 2]));
+      temp.s = texCoordVec[j];
+      temp.t = texCoordVec[j+1];
+
+      finalVertData.push_back(temp);
+   }
+}
+
+void SkySphere::BuildFinalFogVert()
+{
+   U32 count = vertsVec.size();
+   U32 i, j;
+   for (i = 0, j = 0; i < count; i+=3, j++ )
+   {
+      FogVertex temp;
+      temp.pos.set(Point3F(vertsVec[i], vertsVec[i + 1], vertsVec[i + 2]));
+      temp.col = colVec[j];
+
+      finalFogVertex.push_back(temp);
+   }
+}
+
+void SkySphere::_initRender()
+{
+   U32 rings = 32;
+   U32 height = 16;
+   U32 radius = 1;
+
+   F32 x, y, z, xy;                              // vertex position
+   F32 nx, ny, nz, lengthInv = 1.0f / radius;       // normal
+   F32 s, t;                                     // texCoord
+
+   F32 ringStep = M_2PI / rings;
+   F32 heightStep = M_PI / height; // M_HALFPI for dome.
+   F32 ringAng, heightAng;
+
+   //clear vecs
+   clearVectors();
+
+   for (U32 i = 0; i <= height; ++i)
+   {
+      heightAng = M_PI / 2 - (F32)i * heightStep;
+      F32 xy = radius * mCos(heightAng);
+      F32 z = radius * mSin(heightAng);
+
+      for (U32 j = 0; j <= rings; ++j)
+      {
+         SphereVertex vert;
+         ringAng = j * ringStep;
+         x = xy * mCos(ringAng);
+         y = xy * mSin(ringAng);
+         vert.pos.set(Point3F(x,y,z));
+
+         nx = x * lengthInv;
+         ny = y * lengthInv;
+         nz = z * lengthInv;
+         vert.nor.set(Point3F(nx, ny, nz));
+
+         s = (F32)j / rings;
+         t = (F32)i / height;
+         vert.s = s;
+         vert.t = t;
+
+         tmpVertices.push_back(vert);
+      }
+   }
+
+   SphereVertex v1, v2, v3, v4;
+   U32 vi1, vi2 = 0;
+
+   for (U32 i = 0; i < height; ++i)
+   {
+      vi1 = i * (rings + 1);
+      vi2 = (i + 1) * (rings + 1);
+
+      for (U32 j = 0; j < rings; ++j, ++vi1, ++vi2)
+      {
+         v1 = tmpVertices[vi1];
+         v2 = tmpVertices[vi2];
+         v3 = tmpVertices[vi1 + 1];
+         v4 = tmpVertices[vi2 + 1];
+
+         // 1st = triangle.
+         if (i == 0)
+         {
+            // verts for tri.
+            addVertex(v1.pos);
+            addVertex(v2.pos);
+            addVertex(v4.pos);
+
+            // texcoords for tri.
+            addTexcoord(v1.s, v1.t);
+            addTexcoord(v2.s, v2.t);
+            addTexcoord(v4.s, v4.t);
+
+            // normals for tri.
+            addNormal(v1.nor);
+            addNormal(v2.nor);
+            addNormal(v4.nor);
+         }
+         else if (i == (height - 1))
+         {
+            // verts for tri.
+            addVertex(v1.pos);
+            addVertex(v2.pos);
+            addVertex(v3.pos);
+
+            // texcoords for tri.
+            addTexcoord(v1.s, v1.t);
+            addTexcoord(v2.s, v2.t);
+            addTexcoord(v3.s, v3.t);
+
+            // normals for quad.
+            addNormal(v1.nor);
+            addNormal(v2.nor);
+            addNormal(v3.nor);
+         }
+         else
+         {
+            // verts for quad.
+            addVertex(v1.pos);
+            addVertex(v2.pos);
+            addVertex(v3.pos);
+
+            addVertex(v3.pos);
+            addVertex(v4.pos);
+            addVertex(v2.pos);
+
+            // texcoords for quad.
+            addTexcoord(v1.s, v1.t);
+            addTexcoord(v2.s, v2.t);
+            addTexcoord(v3.s, v3.t);
+
+            addTexcoord(v3.s, v3.t);
+            addTexcoord(v4.s, v4.t);
+            addTexcoord(v2.s, v2.t);
+
+            // normals for quad.
+            addNormal(v1.nor);
+            addNormal(v2.nor);
+            addNormal(v3.nor);
+
+            addNormal(v3.nor);
+            addNormal(v4.nor);
+            addNormal(v2.nor);
+         }
+      }
+   }
+
+   BuildFinalVert();
+
+   GFXVertexPNT* tmpVerts = NULL;
+   U32 vertCount = finalVertData.size();
+   tmpVerts = new GFXVertexPNT[(vertCount)];
+   mPrimCount = vertCount / 3;
+
+   for (U32 i = 0; i < vertCount; i++)
+   {
+      tmpVerts[i].point.set(finalVertData[i].pos);
+      tmpVerts[i].normal.set(finalVertData[i].nor);
+      tmpVerts[i].texCoord.set(finalVertData[i].s, finalVertData[i].t);
+   }
+
+   if (mVB.isNull() || mIsVBDirty)
+   {
+      mVB.set(GFX, vertCount, GFXBufferTypeStatic);
+      mIsVBDirty = false;
+   }
+
+   GFXVertexPNT* vertPtr = mVB.lock();
+   if (!vertPtr)
+   {
+      delete[] tmpVerts;
+      return;
+   }
+
+   dMemcpy(vertPtr, tmpVerts, sizeof(GFXVertexPNT) * vertCount);
+
+   mVB.unlock();
+
+   // Clean up temp verts.
+   delete[] tmpVerts;
+
+   // Grab the fog color.
+   ColorI fogColor(mLastFogColor.red * 255, mLastFogColor.green * 255, mLastFogColor.blue * 255);
+   ColorI fogColorAlpha(mLastFogColor.red * 255, mLastFogColor.green * 255, mLastFogColor.blue * 255, 0);
+
+   clearVectors();
+
+   U32 stepCount = 16;
+   F32 cylStep = M_2PI / stepCount;
+   F32 cylAngle;
+   F32 cylRadius = 10;
+
+   for (U32 i = 0; i <= stepCount; ++i)
+   {
+      cylAngle = (F32)i * cylStep;
+      fogVerts.push_back(mCos(cylAngle));
+      fogVerts.push_back(mSin(cylAngle));
+   }
+
+   for (U32 i = 0; i < 2; ++i)
+   {
+      for (U32 j = 0, k = 0; j <= stepCount; ++j, k += 2)
+      {
+         FogVertex temp;
+         F32 ux = fogVerts[k];
+         F32 uy = fogVerts[k+1];
+
+         if (i > 0)
+         {
+            temp.pos.set(Point3F((ux * cylRadius), (uy * cylRadius), mFogBandHeight));
+            temp.col = fogColorAlpha;
+         }
+         else
+         {
+            temp.pos.set(Point3F((ux * cylRadius), (uy * cylRadius), -mFogBandHeight));
+            temp.col = fogColor;
+         }
+
+         tempFogVertex.push_back(temp);
+      }
+   }
+
+   FogVertex f1, f2, f3, f4;
+   U32 k1 = 0;
+   U32 k2 = stepCount + 1;
+
+   for (U32 i = 0; i < stepCount; ++i, ++k1, ++k2)
+   {
+      f1 = tempFogVertex[k1];
+      f2 = tempFogVertex[k1 + 1];
+      f3 = tempFogVertex[k2];
+      f4 = tempFogVertex[k2 + 1];
+      addVertex(f3.pos);
+      addVertex(f2.pos);
+      addVertex(f4.pos);
+      addColor(f3.col);
+      addColor(f2.col);
+      addColor(f4.col);
+      addVertex(f1.pos);
+      addVertex(f2.pos);
+      addVertex(f3.pos);
+      addColor(f1.col);
+      addColor(f2.col);
+      addColor(f3.col);
+   }
+
+   BuildFinalFogVert();
+
+   U32 fogVertCount = finalFogVertex.size();
+   mFogPrimCount = fogVertCount / 3;
+
+   if (mFogBandVB.isNull())
+      mFogBandVB.set(GFX, fogVertCount, GFXBufferTypeStatic);
+
+   GFXVertexPC* bandVertPtr = mFogBandVB.lock();
+   if (!bandVertPtr) return;
+      
+   for (U32 i = 0; i < fogVertCount; i++)
+   {
+      bandVertPtr[i].point.set(finalFogVertex[i].pos);
+      bandVertPtr[i].color.set(finalFogVertex[i].col);
+   }
+
+   mFogBandVB.unlock();
+
+   SAFE_DELETE(mFogBandMatInst);
+   if (mFogBandMat)
+   {
+      mFogBandMat->deleteObject();
+      mFogBandMat = NULL;
+   }
+
+   // Setup the material for this imposter.
+   mFogBandMat = MATMGR->allocateAndRegister(String::EmptyString);
+   mFogBandMat->mAutoGenerated = true;
+   mFogBandMat->mTranslucent = true;
+   mFogBandMat->mVertColor[0] = true;
+   mFogBandMat->mDoubleSided = true;
+   mFogBandMat->mEmissive[0] = true;
+
+   FeatureSet features = MATMGR->getDefaultFeatures();
+   features.addFeature(MFT_isBackground);
+   mFogBandMatInst = mFogBandMat->createMatInstance();
+   mFogBandMatInst->init(features, getGFXVertexFormat<GFXVertexPC>());
+}
+
+void SkySphere::onStaticModified(const char* slotName, const char* newValue)
+{
+   Parent::onStaticModified(slotName, newValue);
+
+   if (dStricmp(slotName, "material") == 0)
+      setMaskBits(0xFFFFFFFF);
+}
+
+void SkySphere::_initMaterial()
+{
+   if (mMatInstance)
+      SAFE_DELETE(mMatInstance);
+
+   if (mMaterial)
+      mMatInstance = mMaterial->createMatInstance();
+   else
+      mMatInstance = MATMGR->createMatInstance("WarningMaterial");
+
+   // We want to disable culling and z write.
+   GFXStateBlockDesc desc;
+   desc.setCullMode(GFXCullNone);
+   desc.setBlend(true);
+   desc.setZReadWrite(true, false);
+   desc.zFunc = GFXCmpLessEqual;
+   mMatInstance->addStateBlockDesc(desc);
+
+   // Also disable lighting on the skysphere material by default.
+   FeatureSet features = MATMGR->getDefaultFeatures();
+   features.removeFeature(MFT_RTLighting);
+   features.removeFeature(MFT_Visibility);
+   features.addFeature(MFT_isBackground);
+
+   // Now initialize the material.
+   mMatInstance->init(features, getGFXVertexFormat<GFXVertexPNT>());
+}
+
+void SkySphere::_updateMaterial()
+{
+   if (!getMaterialResource().isValid())
+   {
+      //If our materialDef isn't valid, try setting it
+      _setMaterial(getMaterial());
+   }
+
+   if (getMaterialResource().isValid())
+   {
+      _initMaterial();
+   }
+}
+
+BaseMatInstance* SkySphere::_getMaterialInstance()
+{
+   if (!mMaterial || !mMatInstance || mMatInstance->getMaterial() != mMaterial)
+      _initMaterial();
+
+   if (!mMatInstance)
+      return NULL;
+
+   return mMatInstance;
+}
+
+DefineEngineMethod(SkySphere, postApply, void, (), , "")
+{
+   object->inspectPostApply();
+}

+ 172 - 0
Engine/source/environment/skySphere.h

@@ -0,0 +1,172 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _SKYSPHERE_H_
+#define _SKYSPHERE_H_
+
+#ifndef _SCENEOBJECT_H_
+#include "scene/sceneObject.h"
+#endif
+
+#ifndef _GFXDEVICE_H_
+#include "gfx/gfxDevice.h"
+#endif
+
+#ifndef _CUBEMAPDATA_H_
+#include "gfx/sim/cubemapData.h"
+#endif
+
+#ifndef _MATERIALLIST_H_
+#include "materials/materialList.h"
+#endif
+
+#ifndef _GFXVERTEXBUFFER_H_
+#include "gfx/gfxVertexBuffer.h"
+#endif
+
+#ifndef _GFXPRIMITIVEBUFFER_H_
+#include "gfx/gfxPrimitiveBuffer.h"
+#endif
+
+#include "T3D/assets/MaterialAsset.h"
+
+struct SkyMatParams
+{
+   void init(BaseMatInstance* matInst) {};
+};
+
+class MatrixSet;
+
+class SkySphere : public SceneObject
+{
+   typedef SceneObject Parent;
+
+public:
+
+   SkySphere();
+   virtual ~SkySphere();
+
+   DECLARE_CONOBJECT(SkySphere);
+
+   // SimObject
+   void onStaticModified(const char* slotName, const char* newValue);
+
+   // ConsoleObject
+   virtual bool onAdd();
+   virtual void onRemove();
+   static void initPersistFields();
+   virtual void inspectPostApply();
+
+   // NetObject
+   virtual U32 packUpdate(NetConnection* conn, U32 mask, BitStream* stream);
+   virtual void unpackUpdate(NetConnection* conn, BitStream* stream);
+
+   // SceneObject
+   void prepRenderImage(SceneRenderState* state);
+
+   /// Our render delegate.
+   void _renderObject(ObjectRenderInst* ri, SceneRenderState* state, BaseMatInstance* mi);
+
+   void clearVectors();
+
+   void addVertex(Point3F vert);
+
+   void addNormal(Point3F nor);
+
+   void addTexcoord(F32 s, F32 t);
+
+   void addColor(ColorI col);
+
+   void BuildFinalVert();
+
+   void BuildFinalFogVert();
+
+   /// Prepares rendering structures and geometry.
+   void _initRender();
+
+   struct SphereVertex
+   {
+      Point3F pos;
+      Point3F nor;
+      F32 s, t;
+   };
+
+   Vector<SphereVertex> tmpVertices;
+   Vector<F32> vertsVec;
+   Vector<F32> texCoordVec;
+   Vector<F32> normsVec;
+
+   struct FinalVertexData
+   {
+      Point3F pos;
+      Point3F nor;
+      F32 s;
+      F32 t;
+   };
+
+   Vector<FinalVertexData> finalVertData;
+
+   struct FogVertex
+   {
+      // might need normals for smoothing.
+      Point3F pos;
+      ColorI col;
+   };
+
+   Vector<FogVertex> finalFogVertex;
+   Vector<FogVertex> tempFogVertex;
+   Vector<ColorI> colVec;
+   Vector<F32> fogVerts;
+
+protected:
+
+   // Material
+   DECLARE_MATERIALASSET(SkySphere, Material);
+   DECLARE_ASSET_NET_SETGET(SkySphere, Material, -1);
+
+   BaseMatInstance* mMatInstance;
+   SkyMatParams mMatParamHandle;
+
+   GFXVertexBufferHandle<GFXVertexPNT> mVB;
+
+   GFXVertexBufferHandle<GFXVertexPC> mFogBandVB;
+   Material* mFogBandMat;
+   BaseMatInstance* mFogBandMatInst;
+
+   LinearColorF mLastFogColor;
+
+   bool mIsVBDirty;
+   U32 mPrimCount;
+
+   MatrixSet* mMatrixSet;
+
+   F32 mFogBandHeight;
+   U32 mFogPrimCount;
+
+   void _updateMaterial();
+   void _initMaterial();
+
+   BaseMatInstance* _getMaterialInstance();
+
+};
+
+#endif

+ 1 - 0
Templates/BaseGame/game/tools/assetBrowser/scripts/creator.tscript

@@ -26,6 +26,7 @@ function AssetBrowser::loadCreatorClasses(%this)
       %this.addCreatorClass( "RibbonNode",         "Ribbon Emitter" );
       %this.addCreatorClass( "ScatterSky",         "Scatter Sky" );
       %this.addCreatorClass( "SkyBox",             "Sky Box" );
+      %this.addCreatorClass( "SkySphere",          "Sky Sphere" );
       %this.addCreatorClass( "SFXEmitter",         "Sound Emitter" );
       %this.addCreatorClass( "TerrainBlock",       "Terrain Block" );
       %this.addCreatorClass( "VolumetricFog",      "Volumetric Fog" );

+ 1 - 0
Templates/BaseGame/game/tools/worldEditor/scripts/editors/creator.ed.tscript

@@ -37,6 +37,7 @@ function ObjectCreator::init( %this )
       // Removed Prefab as there doesn't really seem to be a point in creating a blank one
       //%this.registerMissionObject( "Prefab",              "Prefab" );
       %this.registerMissionObject( "SkyBox",              "Sky Box" );
+      %this.registerMissionObject( "SkySphere",           "Sky Sphere" );
       %this.registerMissionObject( "CloudLayer",          "Cloud Layer" );
       %this.registerMissionObject( "BasicClouds",         "Basic Clouds" );
       %this.registerMissionObject( "ScatterSky",          "Scatter Sky" );