예제 #1
0
static inline F32 mCbrt(F32 val)
{
   if(val < 0.f)
      return(-mPow(-val, F32(1.f/3.f)));
   else
      return(mPow(val, F32(1.f/3.f)));
}
예제 #2
0
void PSSMLightShadowMap::_calcSplitPos(const Frustum& currFrustum)
{
   const F32 nearDist = 0.01f; // TODO: Should this be adjustable or different?
   const F32 farDist = currFrustum.getFarDist();

   for ( U32 i = 1; i < mNumSplits; i++ )
   {
      F32 step = (F32) i / (F32) mNumSplits;
      F32 logSplit = nearDist * mPow(farDist / nearDist, step);
      F32 linearSplit = nearDist + (farDist - nearDist) * step;
      mSplitDist[i] = mLerp( linearSplit, logSplit, mClampF( mLogWeight, 0.0f, 1.0f ) );
   }

   mSplitDist[0] = nearDist;
   mSplitDist[mNumSplits] = farDist;
}
예제 #3
0
ScatterSky::ScatterSky()
{
   mPrimCount = 0;
   mVertCount = 0;


   // Rayleigh scattering constant.
   mRayleighScattering = 0.0035f;
   mRayleighScattering4PI = mRayleighScattering * 4.0f * M_PI_F;

   // Mie scattering constant.
   mMieScattering = 0.0045f;
   mMieScattering4PI = mMieScattering * 4.0f * M_PI_F;

   // Overall scatter scalar.
   mSkyBrightness = 25.0f;

   // The Mie phase asymmetry factor.
   mMiePhaseAssymetry = -0.75f;

   mSphereInnerRadius = 1.0f;
   mSphereOuterRadius = 1.0f * 1.025f;
   mScale = 1.0f / (mSphereOuterRadius - mSphereInnerRadius);

   // 650 nm for red
   // 570 nm for green
   // 475 nm for blue
   mWavelength.set( 0.650f, 0.570f, 0.475f, 0 );

   mWavelength4[0] = mPow(mWavelength[0], 4.0f);
   mWavelength4[1] = mPow(mWavelength[1], 4.0f);
   mWavelength4[2] = mPow(mWavelength[2], 4.0f);

   mRayleighScaleDepth = 0.25f;
   mMieScaleDepth = 0.1f;

   mAmbientColor.set( 0, 0, 0, 1.0f );
   mAmbientScale.set( 1.0f, 1.0f, 1.0f, 1.0f );

   mSunColor.set( 0, 0, 0, 1.0f );
   mSunScale = ColorF::WHITE;

   mFogColor.set( 0, 0, 0, 1.0f );
   mFogScale = ColorF::WHITE;

   mExposure = 1.0f;
   mNightInterpolant = 0;

   mShader = NULL;

   mTimeOfDay = 0;

   mSunAzimuth = 0.0f;
   mSunElevation = 35.0f;

   mMoonAzimuth = 0.0f;
   mMoonElevation = 45.0f;

   mBrightness = 1.0f;

   mCastShadows = true;
   mDirty = true;

   mLight = LightManager::createLightInfo();
   mLight->setType( LightInfo::Vector );

   mFlareData = NULL;
   mFlareState.clear();
   mFlareScale = 1.0f;

   mMoonEnabled = true;
   mMoonScale = 0.2f;
   mMoonTint.set( 0.192157f, 0.192157f, 0.192157f, 1.0f );
   MathUtils::getVectorFromAngles( mMoonLightDir, 0.0f, 45.0f );
   mMoonLightDir.normalize();
   mMoonLightDir = -mMoonLightDir;
   mNightCubemap = NULL;
   mNightColor.set( 0.0196078f, 0.0117647f, 0.109804f, 1.0f );
   mNightFogColor = mNightColor;
   mUseNightCubemap = false;
   mSunSize = 1.0f;

   mMoonMatInst = NULL;

   mNetFlags.set( Ghostable | ScopeAlways );
   mTypeMask |= EnvironmentObjectType | LightObjectType | StaticObjectType;

   _generateSkyPoints();

   mMatrixSet = reinterpret_cast<MatrixSet *>(dMalloc_aligned(sizeof(MatrixSet), 16));
   constructInPlace(mMatrixSet);

   mColorizeAmt = 0;
   mColorize.set(0,0,0);
}
예제 #4
0
void ScatterSky::unpackUpdate(NetConnection *con, BitStream *stream)
{
   Parent::unpackUpdate(con, stream);

   if ( stream->readFlag() ) // TimeMask
   {
      F32 temp = 0;
      stream->read( &temp );
      setAzimuth( temp );

      stream->read( &temp );
      setElevation( temp );
   }

   if ( stream->readFlag() ) // UpdateMask
   {
      stream->read( &mRayleighScattering );
      stream->read( &mRayleighScattering4PI );

      stream->read( &mMieScattering );
      stream->read( &mMieScattering4PI );

      stream->read( &mSunSize );

      stream->read( &mSkyBrightness );

      stream->read( &mMiePhaseAssymetry );

      stream->read( &mSphereInnerRadius );
      stream->read( &mSphereOuterRadius );

      stream->read( &mScale );

      ColorF tmpColor( 0, 0, 0 );

      stream->read( &tmpColor );

      stream->read( &mWavelength4[0] );
      stream->read( &mWavelength4[1] );
      stream->read( &mWavelength4[2] );

      stream->read( &mRayleighScaleDepth );
      stream->read( &mMieScaleDepth );

      stream->read( &mNightColor );
      stream->read( &mNightFogColor );
      stream->read( &mAmbientScale );
      stream->read( &mSunScale );
      stream->read( &mFogScale );
	  F32 colorizeAmt;
      stream->read( &colorizeAmt );

      if(mColorizeAmt != colorizeAmt) {
         mColorizeAmt = colorizeAmt;
         mShader = NULL; //forces shader refresh
      }

      stream->read( &mColorize );


      if ( tmpColor != mWavelength )
      {
         mWavelength = tmpColor;
         mWavelength4[0] = mPow(mWavelength[0], 4.0f);
         mWavelength4[1] = mPow(mWavelength[1], 4.0f);
         mWavelength4[2] = mPow(mWavelength[2], 4.0f);
      }

      stream->read( &mExposure );

      stream->read( &mBrightness );

      mCastShadows = stream->readFlag();

      stream->read( &mFlareScale );

      if ( stream->readFlag() )
      {
         SimObjectId id = stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast );
         LightFlareData *datablock = NULL;

         if ( Sim::findObject( id, datablock ) )
            mFlareData = datablock;
         else
         {
            con->setLastError( "ScatterSky::unpackUpdate() - invalid LightFlareData!" );
            mFlareData = NULL;
         }
      }
      else
         mFlareData = NULL;

      mMoonEnabled = stream->readFlag();
      stream->read( &mMoonMatName );
      stream->read( &mMoonScale );
      stream->read( &mMoonTint );
      mUseNightCubemap = stream->readFlag();
      stream->read( &mNightCubemapName );

      stream->read( &mMoonAzimuth );
      stream->read( &mMoonElevation );

      mLight->unpackExtended( stream );

      if ( isProperlyAdded() )
      {
         mDirty = true;
         _initMoon();
         Sim::findObject( mNightCubemapName, mNightCubemap );
      }
   }
}
예제 #5
0
F32 ScatterSky::_getMiePhase( F32 fCos, F32 fCos2, F32 g, F32 g2)
{
   return 1.5f * ((1.0f - g2) / (2.0f + g2)) * (1.0f + fCos2) / mPow(mFabs(1.0f + g2 - 2.0f*g*fCos), 1.5f);
}
예제 #6
0
void LightFlareData::prepRender( SceneRenderState *state, LightFlareState *flareState )
{
   PROFILE_SCOPE( LightFlareData_prepRender );

   const LightInfo *lightInfo = flareState->lightInfo;

   if (  mIsZero( flareState->fullBrightness ) ||
         mIsZero( lightInfo->getBrightness() ) )
      return;

   // Figure out the element count to render.
   U32 elementCount = mElementCount;
   const bool isReflectPass = state->isReflectPass();
   if ( isReflectPass )
   {
      // Then we don't render anything this pass.
      if ( !mRenderReflectPass )
         return;

      // Find the zero distance elements which make 
      // up the corona of the light flare.
      elementCount = 0.0f;
      for ( U32 i=0; i < mElementCount; i++ )
         if ( mIsZero( mElementDist[i] ) )
            elementCount++;
   }

   // Better have something to render.
   if ( elementCount == 0 )
      return;
  
   U32 visDelta = U32_MAX;
   F32 occlusionFade = 1.0f;
   Point3F lightPosSS;
   bool lightVisible = _testVisibility( state, flareState, &visDelta, &occlusionFade, &lightPosSS );
   
   // We can only skip rendering if the light is not 
   // visible, and it has elapsed the fade out time.
   if (  mIsZero( occlusionFade ) ||
         !lightVisible && visDelta > FadeOutTime )
      return;

   const RectI &viewport = GFX->getViewport();
   Point3F oneOverViewportExtent( 1.0f / (F32)viewport.extent.x, 1.0f / (F32)viewport.extent.y, 0.0f );

   // Really convert it to screen space.
   lightPosSS.x -= viewport.point.x;
   lightPosSS.y -= viewport.point.y;
   lightPosSS *= oneOverViewportExtent;
   lightPosSS = ( lightPosSS * 2.0f ) - Point3F::One;
   lightPosSS.y = -lightPosSS.y;
   lightPosSS.z = 0.0f;

   // Take any projection offset into account so that the point where the flare's
   // elements converge is at the 'eye' point rather than the center of the viewport.
   const Point2F& projOffset = state->getCameraFrustum().getProjectionOffset();
   Point3F flareVec( -lightPosSS + Point3F(projOffset.x, projOffset.y, 0.0f) );
   const F32 flareLength = flareVec.len();
   if ( flareLength > 0.0f )
      flareVec *= 1.0f / flareLength;

   // Setup the flare quad points.
   Point3F rotatedBasePoints[4];
   dMemcpy(rotatedBasePoints, sBasePoints, sizeof( sBasePoints ));

   // Rotate the flare quad.
   F32 rot = mAcos( -1.0f * flareVec.x );
   rot *= flareVec.y > 0.0f ? -1.0f : 1.0f;
   MathUtils::vectorRotateZAxis( rot, rotatedBasePoints, 4 );

   // Here we calculate a the light source's influence on 
   // the effect's size and brightness.

   // Scale based on the current light brightness compared to its normal output.
   F32 lightSourceBrightnessScale = lightInfo->getBrightness() / flareState->fullBrightness;

   const Point3F &camPos = state->getCameraPosition();
   const Point3F &lightPos = flareState->lightMat.getPosition();   
   const bool isVectorLight = lightInfo->getType() == LightInfo::Vector;

   // Scale based on world space distance from camera to light source.
   F32 distToCamera = ( camPos - lightPos ).len();
   F32 lightSourceWSDistanceScale = isVectorLight && distToCamera > 0.0f ? 1.0f : getMin( 10.0f / distToCamera, 10.0f );

   // Scale based on screen space distance from screen position of light source to the screen center.
   F32 lightSourceSSDistanceScale = getMax( ( 1.5f - flareLength ) / 1.5f, 0.0f );

   // Scale based on recent visibility changes, fading in or out.
   F32 fadeInOutScale = 1.0f;   
   if (  lightVisible &&
         visDelta < FadeInTime && 
         flareState->occlusion > 0.0f )
      fadeInOutScale = (F32)visDelta / (F32)FadeInTime;
   else if (   !lightVisible && 
               visDelta < FadeOutTime )
      fadeInOutScale = 1.0f - (F32)visDelta / (F32)FadeOutTime;

   // This combined scale influences the size of all elements this effect renders.
   // Note we also add in a scale that is user specified in the Light.
   F32 lightSourceIntensityScale = lightSourceBrightnessScale * 
                                   lightSourceWSDistanceScale * 
                                   lightSourceSSDistanceScale * 
                                   fadeInOutScale * 
                                   flareState->scale *
                                   occlusionFade;

   if ( mIsZero( lightSourceIntensityScale ) )
      return;

   // The baseColor which modulates the color of all elements.
   //
   // These are the factors which affect the "alpha" of the flare effect.
   // Modulate more in as appropriate.
   ColorF baseColor = ColorF::WHITE * lightSourceBrightnessScale * occlusionFade;

   // Setup the vertex buffer for the maximum flare elements.
   const U32 vertCount = 4 * mElementCount;
   if (  flareState->vertBuffer.isNull() || 
         flareState->vertBuffer->mNumVerts != vertCount )
         flareState->vertBuffer.set( GFX, vertCount, GFXBufferTypeDynamic );

   GFXVertexPCT *vert = flareState->vertBuffer.lock();

   const Point2F oneOverTexSize( 1.0f / (F32)mFlareTexture.getWidth(), 1.0f / (F32)mFlareTexture.getHeight() );

   for ( U32 i = 0; i < mElementCount; i++ )
   {      
      // Skip non-zero elements for reflections.
      if ( isReflectPass && mElementDist[i] > 0.0f )
         continue;

      Point3F *basePos = mElementRotate[i] ? rotatedBasePoints : sBasePoints;

      ColorF color( baseColor * mElementTint[i] );
      if ( mElementUseLightColor[i] )
         color *= lightInfo->getColor();
      color.clamp();

      Point3F pos( lightPosSS + flareVec * mElementDist[i] * flareLength );

      const RectF &rect = mElementRect[i];
      Point3F size( rect.extent.x, rect.extent.y, 1.0f );
      size *= mElementScale[i] * mScale * lightSourceIntensityScale;

      AssertFatal( size.x >= 0.0f, "LightFlareData::prepRender - Got a negative element size?" );

      if ( size.x < 100.0f )
      {
         F32 alphaScale = mPow( size.x / 100.0f, 2 );
         color *= alphaScale;
      }

      Point2F texCoordMin, texCoordMax;
      texCoordMin = rect.point * oneOverTexSize;
      texCoordMax = ( rect.point + rect.extent ) * oneOverTexSize;          

      size.x = getMax( size.x, 1.0f );
      size.y = getMax( size.y, 1.0f );
      size *= oneOverViewportExtent;

      vert->color = color;
      vert->point = ( basePos[0] * size ) + pos;      
      vert->texCoord.set( texCoordMin.x, texCoordMax.y );
      vert++;

      vert->color = color;
      vert->point = ( basePos[1] * size ) + pos;
      vert->texCoord.set( texCoordMax.x, texCoordMax.y );
      vert++;

      vert->color = color;
      vert->point = ( basePos[2] * size ) + pos;
      vert->texCoord.set( texCoordMax.x, texCoordMin.y );
      vert++;

      vert->color = color;
      vert->point = ( basePos[3] * size ) + pos;
      vert->texCoord.set( texCoordMin.x, texCoordMin.y );
      vert++;
   }   

   flareState->vertBuffer.unlock();   

   RenderPassManager *rpm = state->getRenderPass();

   // Create and submit the render instance.   
   ParticleRenderInst *ri = rpm->allocInst<ParticleRenderInst>();
   ri->type = RenderPassManager::RIT_Particle;
   ri->vertBuff = &flareState->vertBuffer;
   ri->primBuff = &mFlarePrimBuffer;
   ri->translucentSort = true;
   ri->sortDistSq = ( lightPos - camPos ).lenSquared();
   ri->modelViewProj = &MatrixF::Identity;
   ri->bbModelViewProj = &MatrixF::Identity;
   ri->count = elementCount;
   ri->blendStyle = ParticleRenderInst::BlendGreyscale;
   ri->diffuseTex = mFlareTexture;
   ri->softnessDistance = 1.0f; 
   ri->defaultKey = ri->diffuseTex ? (U32)ri->diffuseTex : (U32)ri->vertBuff; // Sort by texture too.

   // NOTE: Offscreen partical code is currently disabled.
   ri->systemState = PSS_AwaitingHighResDraw;

   rpm->addInst( ri );
}
예제 #7
0
void PxSingleActor::_updateContainerForces()
{   
   if ( !mWorld->getEnabled() )
      return;

   PROFILE_SCOPE( PxSingleActor_updateContainerForces );

   // Update container drag and buoyancy properties      

   ContainerQueryInfo info;
   info.box = getWorldBox();
   info.mass = getMass();

   // Find and retreive physics info from intersecting WaterObject(s)
   mContainer->findObjects( getWorldBox(), WaterObjectType|PhysicalZoneObjectType, findRouter, &info );
   
   // Calculate buoyancy and drag
   F32 angDrag = mBuildAngDrag;
   F32 linDrag = mBuildLinDrag;
   F32 buoyancy = 0.0f;

   if ( true ) //info.waterCoverage >= 0.1f) 
   {
      F32 waterDragScale = info.waterViscosity * mDataBlock->waterDragScale;
      F32 powCoverage = mPow( info.waterCoverage, 0.25f );

      if ( info.waterCoverage > 0.0f )
      {
         //angDrag = mBuildAngDrag * waterDragScale;
         //linDrag = mBuildLinDrag * waterDragScale;
         angDrag = mLerp( mBuildAngDrag, mBuildAngDrag * waterDragScale, powCoverage );
         linDrag = mLerp( mBuildLinDrag, mBuildLinDrag * waterDragScale, powCoverage );
      }

      buoyancy = ( info.waterDensity / mDataBlock->buoyancyDensity ) * mPow( info.waterCoverage, 2.0f );
   }

   // Apply drag (dampening)
   mActor->setLinearDamping( linDrag );
   mActor->setAngularDamping( angDrag );   

   // Apply buoyancy force
   if ( buoyancy != 0 )
   {     
      // A little hackery to prevent oscillation
      // Based on this blog post (http://reinot.blogspot.com/2005/11/oh-yes-they-float-georgie-they-all.html)
      // JCF: DISABLED
      NxVec3 gravity;
      mWorld->getScene()->getGravity(gravity);
      //NxVec3 velocity = mActor->getLinearVelocity();

      NxVec3 buoyancyForce = buoyancy * -gravity * TickSec;
      //F32 currHeight = getPosition().z;
      //const F32 C = 2.0f;
      //const F32 M = 0.1f;

      //if ( currHeight + velocity.z * TickSec * C > info.waterHeight )
      //   buoyancyForce *= M;

      mActor->addForceAtPos( buoyancyForce, mActor->getCMassGlobalPosition(), NX_IMPULSE );
   }

   // Apply physical zone forces
   if ( info.appliedForce.len() > 0.001f )
      mActor->addForceAtPos( pxCast<NxVec3>(info.appliedForce), mActor->getCMassGlobalPosition(), NX_IMPULSE );
}
 void pow(wint p){
     mPow(res,mat,p);
     memcpy(mat,res,n*size*sizeof(tmp[0][0]));
 }
예제 #9
0
void LightFlareData::prepRender( SceneState *state, LightFlareState *flareState )
{    
   PROFILE_SCOPE( LightFlareData_prepRender );

   // No elements then nothing to render.
   if ( mElementCount == 0 )
      return;

   // We need these all over the place later.
   const Point3F &camPos = state->getCameraPosition();
   const RectI &viewport = GFX->getViewport();
   const Point3F &lightPos = flareState->lightMat.getPosition();
   LightInfo *lightInfo = flareState->lightInfo;

   bool isVectorLight = lightInfo->getType() == LightInfo::Vector;

   // Perform visibility testing on the light...
   // Project the light position from world to screen space, we need this
   // position later, and it tells us if it is actually onscreen.   
   
   Point3F lightPosSS;
   bool onscreen = MathUtils::mProjectWorldToScreen( lightPos, &lightPosSS, viewport, GFX->getWorldMatrix(), gClientSceneGraph->getNonClipProjection() );  

   U32 visDelta = U32_MAX;
   U32 fadeOutTime = 20;
   U32 fadeInTime = 125;    

   // Fade factor based on amount of occlusion.
   F32 occlusionFade = 1.0f;

   bool lightVisible = true;
   
   if ( !state->isReflectPass() )
   {
      // It is onscreen, so raycast as a simple occlusion test.

      U32 losMask =	STATIC_COLLISION_MASK |
                     ShapeBaseObjectType |
                     StaticTSObjectType |
                     ItemObjectType |
                     PlayerObjectType;

      GameConnection *conn = GameConnection::getConnectionToServer();
      if ( !conn )
         return;

      bool needsRaycast = true;

      // NOTE: if hardware does not support HOQ it will return NULL
      // and we will retry every time but there is not currently a good place
      // for one-shot initialization of LightFlareState
      if ( flareState->occlusionQuery == NULL )
         flareState->occlusionQuery = GFX->createOcclusionQuery();
      if ( flareState->fullPixelQuery == NULL )
         flareState->fullPixelQuery = GFX->createOcclusionQuery();

      if ( flareState->occlusionQuery && 
           ( ( isVectorLight && flareState->worldRadius > 0.0f ) || 
             ( !isVectorLight && mOcclusionRadius > 0.0f ) ) )
      {
         // Always treat light as onscreen if using HOQ
         // it will be faded out if offscreen anyway.
         onscreen = true;

         U32 pixels = -1;
         GFXOcclusionQuery::OcclusionQueryStatus status = flareState->occlusionQuery->getStatus( true, &pixels );

         String str = flareState->occlusionQuery->statusToString( status );
         Con::setVariable( "$Flare::OcclusionStatus", str.c_str() );
         Con::setIntVariable( "$Flare::OcclusionVal", pixels );
         
         if ( status == GFXOcclusionQuery::Occluded )
            occlusionFade = 0.0f;

         if ( status != GFXOcclusionQuery::Unset )         
            needsRaycast = false;

         RenderPassManager *pass = state->getRenderPass();

         OccluderRenderInst *ri = pass->allocInst<OccluderRenderInst>();   

         Point3F scale( Point3F::One );

         if ( isVectorLight && flareState->worldRadius > 0.0f )         
            scale *= flareState->worldRadius;
         else
            scale *= mOcclusionRadius;
         
         ri->type = RenderPassManager::RIT_Occluder;
         ri->query = flareState->occlusionQuery;   
         ri->query2 = flareState->fullPixelQuery;
         ri->position = lightPos;
         ri->scale = scale;
         ri->orientation = pass->allocUniqueXform( lightInfo->getTransform() );         
         ri->isSphere = true;
         state->getRenderPass()->addInst( ri );

         if ( status == GFXOcclusionQuery::NotOccluded )
         {
            U32 fullPixels;
            flareState->fullPixelQuery->getStatus( true, &fullPixels );

            occlusionFade = (F32)pixels / (F32)fullPixels;

            // Approximation of the full pixel count rather than doing
            // two queries, but it is not very accurate.
            /*
            F32 dist = ( camPos - lightPos ).len();
            F32 radius = scale.x;
            radius = ( radius / dist ) * state->getWorldToScreenScale().y;

            occlusionFade = (F32)pixels / (4.0f * radius * radius);
            occlusionFade = mClampF( occlusionFade, 0.0f, 1.0f );            
            */
         }
      }

      Con::setFloatVariable( "$Flare::OcclusionFade", occlusionFade );

      if ( needsRaycast )
      {
         // Use a raycast to determine occlusion.

         bool fps = conn->isFirstPerson();

         GameBase *control = conn->getControlObject();
         if ( control && fps )
            control->disableCollision();

         RayInfo rayInfo;

         if ( gClientContainer.castRayRendered( camPos, lightPos, losMask, &rayInfo ) )
            occlusionFade = 0.0f;

         if ( control && fps )
            control->enableCollision();
      }

      lightVisible = onscreen && occlusionFade > 0.0f;

      // To perform a fade in/out when we gain or lose visibility
      // we must update/store the visibility state and time.

      U32 currentTime = Sim::getCurrentTime();

      if ( lightVisible != flareState->visible )
      {
         flareState->visible = lightVisible;
         flareState->visChangedTime = currentTime;
      }      

      // Save this in the state so that we have it during the reflect pass.
      flareState->occlusion = occlusionFade;

      visDelta = currentTime - flareState->visChangedTime;      
   }
   else // state->isReflectPass()
   {
      occlusionFade = flareState->occlusion;
      lightVisible = flareState->visible;
      visDelta = Sim::getCurrentTime() - flareState->visChangedTime;
   }

   // We can only skip rendering if the light is not visible, and it
   // has elapsed the fadeOutTime.
   if ( !lightVisible && visDelta > fadeOutTime )
      return;

   // In a reflection we only render the elements with zero distance.   
   U32 elementCount = mElementCount;
   if ( state->isReflectPass()  )
   {
      elementCount = 0;
      for ( ; elementCount < mElementCount; elementCount++ )
      {
         if ( mElementDist[elementCount] > 0.0f )
            break;
      }
   }

   if ( elementCount == 0 )
      return;

   // A bunch of preparatory math before generating verts...

   const Point2I &vpExtent = viewport.extent;
   Point3F viewportExtent( vpExtent.x, vpExtent.y, 1.0f );
   Point2I halfViewportExtentI( viewport.extent / 2 );
   Point3F halfViewportExtentF( (F32)halfViewportExtentI.x * 0.5f, (F32)halfViewportExtentI.y, 0.0f );
   Point3F screenCenter( 0,0,0 );
   Point3F oneOverViewportExtent( 1.0f / viewportExtent.x, 1.0f / viewportExtent.y, 1.0f );

   lightPosSS.y -= viewport.point.y;
   lightPosSS *= oneOverViewportExtent;
   lightPosSS = ( lightPosSS * 2.0f ) - Point3F::One;
   lightPosSS.y = -lightPosSS.y;
   lightPosSS.z = 0.0f;

   Point3F flareVec( screenCenter - lightPosSS );
   F32 flareLength = flareVec.len();   
   flareVec.normalizeSafe();

   Point3F basePoints[4];
   basePoints[0] = Point3F( -0.5, 0.5, 0.0 );  
   basePoints[1] = Point3F( -0.5, -0.5, 0.0 );   
   basePoints[2] = Point3F( 0.5, -0.5, 0.0 );   
   basePoints[3] = Point3F( 0.5, 0.5, 0.0 );

   Point3F rotatedBasePoints[4];
   rotatedBasePoints[0] = basePoints[0];
   rotatedBasePoints[1] = basePoints[1];
   rotatedBasePoints[2] = basePoints[2];
   rotatedBasePoints[3] = basePoints[3];

   Point3F fvec( -1, 0, 0 );   
   F32 rot = mAcos( mDot( fvec, flareVec ) );
   Point3F rvec( 0, -1, 0 );
   rot *= mDot( rvec, flareVec ) > 0.0f ? 1.0f : -1.0f;

   vectorRotateZAxis( rotatedBasePoints[0], rot );
   vectorRotateZAxis( rotatedBasePoints[1], rot );
   vectorRotateZAxis( rotatedBasePoints[2], rot );
   vectorRotateZAxis( rotatedBasePoints[3], rot );

   // Here we calculate a the light source's influence on the effect's size
   // and brightness...

   // Scale based on the current light brightness compared to its normal output.
   F32 lightSourceBrightnessScale = lightInfo->getBrightness() / flareState->fullBrightness;
   // Scale based on world space distance from camera to light source.
   F32 lightSourceWSDistanceScale = ( isVectorLight ) ? 1.0f : getMin( 10.0f / ( lightPos - camPos ).len(), 1.5f );   
   // Scale based on screen space distance from screen position of light source to the screen center.
   F32 lightSourceSSDistanceScale = ( 1.5f - ( lightPosSS - screenCenter ).len() ) / 1.5f;

   // Scale based on recent visibility changes, fading in or out.
   F32 fadeInOutScale = 1.0f;
   if ( lightVisible && visDelta < fadeInTime && flareState->occlusion )
      fadeInOutScale = (F32)visDelta / (F32)fadeInTime;
   else if ( !lightVisible && visDelta < fadeOutTime )
      fadeInOutScale = 1.0f - (F32)visDelta / (F32)fadeOutTime;

   // This combined scale influences the size of all elements this effect renders.
   // Note we also add in a scale that is user specified in the Light.
   F32 lightSourceIntensityScale = lightSourceBrightnessScale * 
                                   lightSourceWSDistanceScale * 
                                   lightSourceSSDistanceScale * 
                                   fadeInOutScale * 
                                   flareState->scale *
                                   occlusionFade;

   // The baseColor which modulates the color of all elements.
   ColorF baseColor;
   if ( flareState->fullBrightness == 0.0f )
      baseColor = ColorF::BLACK;
   else
      // These are the factors which affect the "alpha" of the flare effect.
      // Modulate more in as appropriate.
      baseColor = ColorF::WHITE * lightSourceBrightnessScale * occlusionFade;

   // Fill in the vertex buffer...
   const U32 vertCount = 4 * elementCount;
   if (  flareState->vertBuffer.isNull() || 
         flareState->vertBuffer->mNumVerts != vertCount )
         flareState->vertBuffer.set( GFX, vertCount, GFXBufferTypeDynamic );

   GFXVertexPCT *pVert = flareState->vertBuffer.lock();

   const Point2I &widthHeightI = mFlareTexture.getWidthHeight();
   Point2F oneOverTexSize( 1.0f / (F32)widthHeightI.x, 1.0f / (F32)widthHeightI.y );

   for ( U32 i = 0; i < elementCount; i++ )
   {      
      Point3F *basePos = mElementRotate[i] ? rotatedBasePoints : basePoints;

      ColorF elementColor( baseColor * mElementTint[i] );
      if ( mElementUseLightColor[i] )
         elementColor *= lightInfo->getColor();

      Point3F elementPos;
      elementPos = lightPosSS + flareVec * mElementDist[i] * flareLength;      
      elementPos.z = 0.0f;

      F32 maxDist = 1.5f;
      F32 elementDist = mSqrt( ( elementPos.x * elementPos.x ) + ( elementPos.y * elementPos.y ) );
      F32 distanceScale = ( maxDist - elementDist ) / maxDist;
      distanceScale = 1.0f;

      const RectF &elementRect = mElementRect[i];
      Point3F elementSize( elementRect.extent.x, elementRect.extent.y, 1.0f );
      elementSize *= mElementScale[i] * distanceScale * mScale * lightSourceIntensityScale;

      if ( elementSize.x < 100.0f )
      {
         F32 alphaScale = mPow( elementSize.x / 100.0f, 2 );
         elementColor *= alphaScale;
      }

      elementColor.clamp();

      Point2F texCoordMin, texCoordMax;
      texCoordMin = elementRect.point * oneOverTexSize;
      texCoordMax = ( elementRect.point + elementRect.extent ) * oneOverTexSize;          

      pVert->color = elementColor;
      pVert->point = ( basePos[0] * elementSize * oneOverViewportExtent ) + elementPos;      
      pVert->texCoord.set( texCoordMin.x, texCoordMax.y );
      pVert++;

      pVert->color = elementColor;
      pVert->point = ( basePos[1] * elementSize * oneOverViewportExtent ) + elementPos;
      pVert->texCoord.set( texCoordMax.x, texCoordMax.y );
      pVert++;

      pVert->color = elementColor;
      pVert->point = ( basePos[2] * elementSize * oneOverViewportExtent ) + elementPos;
      pVert->texCoord.set( texCoordMax.x, texCoordMin.y );
      pVert++;

      pVert->color = elementColor;
      pVert->point = ( basePos[3] * elementSize * oneOverViewportExtent ) + elementPos;
      pVert->texCoord.set( texCoordMin.x, texCoordMin.y );
      pVert++;
   }   

   flareState->vertBuffer.unlock();   

   // Create and submit the render instance...
   
   RenderPassManager *renderManager = state->getRenderPass();
   ParticleRenderInst *ri = renderManager->allocInst<ParticleRenderInst>();

   ri->vertBuff = &flareState->vertBuffer;
   ri->primBuff = &mFlarePrimBuffer;
   ri->translucentSort = true;
   ri->type = RenderPassManager::RIT_Particle;
   ri->sortDistSq = ( lightPos - camPos ).lenSquared();

   ri->modelViewProj = &MatrixF::Identity;
   ri->bbModelViewProj = ri->modelViewProj;

   ri->count = elementCount;

   // Only draw the light flare in high-res mode, never off-screen mode
   ri->systemState = ParticleRenderInst::AwaitingHighResDraw;

   ri->blendStyle = ParticleRenderInst::BlendGreyscale;

   ri->diffuseTex = &*(mFlareTexture);

   ri->softnessDistance = 1.0f; 

   // Sort by texture too.
   ri->defaultKey = ri->diffuseTex ? (U32)ri->diffuseTex : (U32)ri->vertBuff;

   renderManager->addInst( ri );
}