blobShadow.cpp

Engine/source/lighting/common/blobShadow.cpp

More...

Detailed Description

Public Variables

Box3F gBlobShadowBox 
Point3F gBlobShadowPoly [4]
SphereF gBlobShadowSphere 
  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 "lighting/common/blobShadow.h"
 26
 27#include "gfx/primBuilder.h"
 28#include "gfx/gfxTextureManager.h"
 29#include "gfx/bitmap/gBitmap.h"
 30#include "math/mathUtils.h"
 31#include "lighting/lightInfo.h"
 32#include "lighting/lightingInterfaces.h"
 33#include "T3D/shapeBase.h"
 34#include "scene/sceneManager.h"
 35#include "lighting/lightManager.h"
 36#include "ts/tsMesh.h"
 37
 38DepthSortList BlobShadow::smDepthSortList;
 39GFXTexHandle BlobShadow::smGenericShadowTexture = NULL;
 40S32 BlobShadow::smGenericShadowDim = 32;
 41U32 BlobShadow::smShadowMask = TerrainObjectType;
 42F32 BlobShadow::smGenericRadiusSkew = 0.4f; // shrink radius of shape when it always uses generic shadow...
 43
 44Box3F gBlobShadowBox;
 45SphereF gBlobShadowSphere;
 46Point3F gBlobShadowPoly[4];
 47
 48//--------------------------------------------------------------
 49
 50BlobShadow::BlobShadow(SceneObject* parentObject, LightInfo* light, TSShapeInstance* shapeInstance)
 51{
 52   mParentObject = parentObject;
 53   mShapeBase = dynamic_cast<ShapeBase*>(parentObject);
 54   mParentLight = light;
 55   mShapeInstance = shapeInstance;
 56   mRadius = 0.0f;
 57   mLastRenderTime = 0;
 58   mDepthBias = -0.0002f;  
 59   mInvShadowDistance = 1.0f;
 60   generateGenericShadowBitmap(smGenericShadowDim);
 61   setupStateBlocks();
 62}
 63
 64void BlobShadow::setupStateBlocks()
 65{
 66   GFXStateBlockDesc sh;
 67   sh.cullDefined = true;
 68   sh.cullMode = GFXCullNone;
 69   sh.zDefined = true;
 70   sh.zEnable = true;
 71   sh.zWriteEnable = false;
 72   
 73   sh.zBias = mDepthBias; 
 74   sh.blendDefined = true;
 75   sh.blendEnable = true;
 76   sh.blendSrc = GFXBlendSrcAlpha;
 77   sh.blendDest = GFXBlendInvSrcAlpha;
 78   sh.alphaDefined = true;
 79   sh.alphaTestEnable = true;
 80   sh.alphaTestFunc = GFXCmpGreater;
 81   sh.alphaTestRef = 0;
 82   sh.samplersDefined = true;
 83   sh.samplers[0] = GFXSamplerStateDesc::getClampLinear();
 84   mShadowSB = GFX->createStateBlock(sh);
 85}
 86
 87BlobShadow::~BlobShadow()
 88{
 89   mShadowBuffer = NULL;
 90}
 91
 92bool BlobShadow::shouldRender(F32 camDist)
 93{
 94   Point3F lightDir;
 95
 96   if (mShapeBase && mShapeBase->getFadeVal() < TSMesh::VISIBILITY_EPSILON)
 97      return false;
 98
 99   F32 shadowLen = 10.0f * mShapeInstance->getShape()->mRadius;
100   Point3F pos = mShapeInstance->getShape()->center;
101
102   // this is a bit of a hack...move generic shadows towards feet/base of shape
103   pos *= 0.5f;
104   pos.convolve(mParentObject->getScale());
105   mParentObject->getRenderTransform().mulP(pos);
106   if(mParentLight->getType() == LightInfo::Vector)
107   {
108      lightDir = mParentLight->getDirection();
109   }
110   else
111   {
112      lightDir = pos - mParentLight->getPosition();
113      lightDir.normalize();
114   }
115
116   // pos is where shadow will be centered (in world space)
117   setRadius(mShapeInstance, mParentObject->getScale());
118   bool render = prepare(pos, lightDir, shadowLen);
119   return render;
120}
121
122void BlobShadow::generateGenericShadowBitmap(S32 dim)
123{
124   if(smGenericShadowTexture)
125      return;
126   GBitmap * bitmap = new GBitmap(dim,dim,false,GFXFormatR8G8B8A8);
127   U8 * bits = bitmap->getWritableBits();
128   dMemset(bits, 0, dim*dim*4);
129   S32 center = dim >> 1;
130   F32 invRadiusSq = 1.0f / (F32)(center*center);
131   F32 tmpF;
132   for (S32 i=0; i<dim; i++)
133   {
134      for (S32 j=0; j<dim; j++)
135      {
136         tmpF = (F32)((i-center)*(i-center)+(j-center)*(j-center)) * invRadiusSq;
137         U8 val = tmpF>0.99f ? 0 : (U8)(180.0f*(1.0f-tmpF)); // 180 out of 255 max
138         bits[(i*dim*4)+(j*4)+3] = val;
139      }
140   }
141
142   smGenericShadowTexture.set( bitmap, &GFXStaticTextureSRGBProfile, true, "BlobShadow" );
143}
144
145//--------------------------------------------------------------
146
147void BlobShadow::setLightMatrices(const Point3F & lightDir, const Point3F & pos)
148{
149   AssertFatal(mDot(lightDir,lightDir)>0.0001f,"BlobShadow::setLightDir: light direction must be a non-zero vector.");
150
151   // construct light matrix
152   Point3F x,z;
153   if (mFabs(lightDir.z)>0.001f)
154   {
155      // mCross(Point3F(1,0,0),lightDir,&z);
156      z.x = 0.0f;
157      z.y =  lightDir.z;
158      z.z = -lightDir.y;
159      z.normalize();
160      mCross(lightDir,z,&x);
161   }
162   else
163   {
164      mCross(lightDir,Point3F(0,0,1),&x);
165      x.normalize();
166      mCross(x,lightDir,&z);
167   }
168
169   mLightToWorld.identity();
170   mLightToWorld.setColumn(0,x);
171   mLightToWorld.setColumn(1,lightDir);
172   mLightToWorld.setColumn(2,z);
173   mLightToWorld.setColumn(3,pos);
174
175   mWorldToLight = mLightToWorld;
176   mWorldToLight.inverse();
177}
178
179void BlobShadow::setRadius(F32 radius)
180{
181   mRadius = radius;
182}
183
184void BlobShadow::setRadius(TSShapeInstance * shapeInstance, const Point3F & scale)
185{
186   const Box3F & bounds = shapeInstance->getShape()->mBounds;
187   F32 dx = 0.5f * (bounds.maxExtents.x-bounds.minExtents.x) * scale.x;
188   F32 dy = 0.5f * (bounds.maxExtents.y-bounds.minExtents.y) * scale.y;
189   F32 dz = 0.5f * (bounds.maxExtents.z-bounds.minExtents.z) * scale.z;
190   mRadius = mSqrt(dx*dx+dy*dy+dz*dz);
191}
192
193
194//--------------------------------------------------------------
195
196bool BlobShadow::prepare(const Point3F & pos, Point3F lightDir, F32 shadowLen)
197{
198   if (mPartition.empty())
199   {
200      // --------------------------------------
201      // 1.
202      F32 dirMult = (1.0f) * (1.0f);
203      if (dirMult < 0.99f)
204      {
205         lightDir.z *= dirMult;
206         lightDir.z -= 1.0f - dirMult;
207      }
208      lightDir.normalize();
209      shadowLen *= (1.0f) * (1.0f);
210
211      // --------------------------------------
212      // 2. get polys
213      F32 radius = mRadius;
214      radius *= smGenericRadiusSkew;
215      buildPartition(pos,lightDir,radius,shadowLen);
216   }
217   if (mPartition.empty())
218      // no need to draw shadow if nothing to cast it onto
219      return false;
220
221   return true;
222}
223
224//--------------------------------------------------------------
225
226void BlobShadow::buildPartition(const Point3F & p, const Point3F & lightDir, F32 radius, F32 shadowLen)
227{
228   setLightMatrices(lightDir,p);
229
230   Point3F extent(2.0f*radius,shadowLen,2.0f*radius);
231   smDepthSortList.clear();
232   smDepthSortList.set(mWorldToLight,extent);
233   smDepthSortList.setInterestNormal(lightDir);
234
235   if (shadowLen<1.0f)
236      // no point in even this short of a shadow...
237      shadowLen = 1.0f;
238   mInvShadowDistance = 1.0f / shadowLen;
239
240   // build world space box and sphere around shadow
241
242   Point3F x,y,z;
243   mLightToWorld.getColumn(0,&x);
244   mLightToWorld.getColumn(1,&y);
245   mLightToWorld.getColumn(2,&z);
246   x *= radius;
247   y *= shadowLen;
248   z *= radius;
249   gBlobShadowBox.maxExtents.set(mFabs(x.x)+mFabs(y.x)+mFabs(z.x),
250      mFabs(x.y)+mFabs(y.y)+mFabs(z.y),
251      mFabs(x.z)+mFabs(y.z)+mFabs(z.z));
252   y *= 0.5f;
253   gBlobShadowSphere.radius = gBlobShadowBox.maxExtents.len();
254   gBlobShadowSphere.center = p + y;
255   gBlobShadowBox.minExtents  = y + p - gBlobShadowBox.maxExtents;
256   gBlobShadowBox.maxExtents += y + p;
257
258   // get polys
259
260   gClientContainer.findObjects(STATIC_COLLISION_TYPEMASK, BlobShadow::collisionCallback, this);
261
262   // setup partition list
263   gBlobShadowPoly[0].set(-radius,0,-radius);
264   gBlobShadowPoly[1].set(-radius,0, radius);
265   gBlobShadowPoly[2].set( radius,0, radius);
266   gBlobShadowPoly[3].set( radius,0,-radius);
267
268   mPartition.clear();
269   mPartitionVerts.clear();
270   smDepthSortList.depthPartition(gBlobShadowPoly,4,mPartition,mPartitionVerts);
271
272   if(mPartitionVerts.empty())
273      return;
274
275   // Find the rough distance of the shadow verts
276   // from the object position and use that to scale
277   // the visibleAlpha so that the shadow fades out
278   // the further away from you it gets
279   F32 dist = 0.0f;
280
281   // Calculate the center of the partition verts
282   Point3F shadowCenter(0.0f, 0.0f, 0.0f);
283   for (U32 i = 0; i < mPartitionVerts.size(); i++)
284      shadowCenter += mPartitionVerts[i];
285
286   shadowCenter /= mPartitionVerts.size();
287
288   mLightToWorld.mulP(shadowCenter);
289
290   dist = (p - shadowCenter).len();
291
292   // now set up tverts & colors
293   mShadowBuffer.set(GFX, mPartitionVerts.size(), GFXBufferTypeVolatile);
294   mShadowBuffer.lock();
295
296   F32 visibleAlpha = 255.0f;
297   if (mShapeBase && mShapeBase->getFadeVal())
298      visibleAlpha = mClampF(255.0f * mShapeBase->getFadeVal(), 0, 255);
299   visibleAlpha *= 1.0f - (dist / gBlobShadowSphere.radius);
300   F32 invRadius = 1.0f / radius;
301   for (S32 i=0; i<mPartitionVerts.size(); i++)
302   {
303      Point3F vert = mPartitionVerts[i];
304      mShadowBuffer[i].point.set(vert);
305      mShadowBuffer[i].color.set(255, 255, 255, visibleAlpha);
306      mShadowBuffer[i].texCoord.set(0.5f + 0.5f * mPartitionVerts[i].x * invRadius, 0.5f + 0.5f * mPartitionVerts[i].z * invRadius);
307   };
308
309   mShadowBuffer.unlock();
310}
311
312//--------------------------------------------------------------
313
314void BlobShadow::collisionCallback(SceneObject * obj, void* thisPtr)
315{
316   if (obj->getWorldBox().isOverlapped(gBlobShadowBox))
317   {
318      // only interiors clip...
319      ClippedPolyList::allowClipping = (obj->getTypeMask() & LIGHTMGR->getSceneLightingInterface()->mClippingMask) != 0;
320      obj->buildPolyList(PLC_Collision,&smDepthSortList,gBlobShadowBox,gBlobShadowSphere);
321      ClippedPolyList::allowClipping = true;
322   }
323}
324
325//--------------------------------------------------------------
326
327void BlobShadow::render( F32 camDist, const TSRenderState &rdata )
328{
329   mLastRenderTime = Platform::getRealMilliseconds();
330   GFX->pushWorldMatrix();
331   MatrixF world = GFX->getWorldMatrix();
332   world.mul(mLightToWorld);
333   GFX->setWorldMatrix(world);
334
335   GFX->setupGenericShaders(GFXDevice::GSModColorTexture);
336
337   GFX->setStateBlock(mShadowSB);
338   GFX->setTexture(0, smGenericShadowTexture);
339   GFX->setVertexBuffer(mShadowBuffer);
340
341   for(U32 p=0; p<mPartition.size(); p++)
342      GFX->drawPrimitive(GFXTriangleStrip, mPartition[p].vertexStart, (mPartition[p].vertexCount - 2));
343
344   // This is a bad nasty hack which forces the shadow to reconstruct itself every frame.
345   mPartition.clear();
346
347   GFX->popWorldMatrix();
348}
349
350void BlobShadow::deleteGenericShadowBitmap()
351{
352   smGenericShadowTexture = NULL;
353}
354