Game Development Community

Fixes to get shadowing working ... enjoy!

by Melv May · in Torque Game Engine · 06/13/2003 (2:02 pm) · 58 replies

Guys,

I've noticed a few people struggling to get shadowing working correctly but being as I've already fixed it but just not had the time to get it into the CVS, I thought I'd at least give you the fixes here. Sorry I didn't do this earlier, it's just that our game is taking almost every hour of my freetime.

Anyway, here's how to do it and I will endeavour to get it into the [HEAD] soon. Note that you can scroll down to the bottom if you're not interested in the reasoning and copy the whole functions into the SDK.

First, in "shapebase.h" around line 916, change the levels to something like...
#define StaticShape_GenericShadowLevel 0.4f
#define StaticShape_NoShadowLevel 0.01f

The next problem you will encounter is that shapes with translucency get skipped. You can force it to render these shapes such as the stock trees but you may get artifacts. If you want to stop this then you can amend the line in "void TSStatic::renderShadow(F32 dist, F32 fogAmount)" around line 311 to...

if (mShapeInstance->getShape()->subShapeFirstTranslucentObject.empty()/* || mShapeInstance->getShape()->subShapeFirstTranslucentObject[0]==0*/)
return;

The next two amendments allow you to change the behaviour of the shadows. Since statics don't move or animate, the shadows are set to non-moving/animating. This produces a higher-performance shadow but doesn't animate when you move it in the editor. You may also want to amend this behaviour dynamically as mentioned by Robert Blanchet here. It's a total choice for you but you can amend this functionality by editing two lines in "void TSStatic::renderShadow(F32 dist, F32 fogAmount)", namely...
mShadow->setMoving(true);
mShadow->setAnimating(true);

The next problem is the incorrect reference to the Obj->World transform. Brett Fattori mentions one of these here but there is another on line 331 where the position is transformed into world-space.

Because there are numerous problems in "void TSStatic::renderShadow(F32 dist, F32 fogAmount)", here is the whole function with dynamic shadows turned-on. Be careful with dynamic shadows if you've got lots of statics that don't need it. It could be made to be a $Prefs option that you can turn-on/off at will I guess.

void TSStatic::renderShadow(F32 dist, F32 fogAmount)
{
   if (Shadow::getGlobalShadowDetailLevel()<StaticShape_NoShadowLevel)
      return;
   if (mShapeInstance->getShape()->subShapeFirstTranslucentObject.empty()/* || mShapeInstance->getShape()->subShapeFirstTranslucentObject[0]==0*/)
      return;

   // for safety, since I can't yet guarantee when this gets called.
   dglNPatchEnd();

   if (!mShadow)
      mShadow = new Shadow();
   mShadow->setGeneric(Shadow::getGlobalShadowDetailLevel() < StaticShape_GenericShadowLevel);
   // The following set to TRUE slows things down but you can also see the changes to shadows
   // immediately within the editor.
   mShadow->setMoving(true); // MM: Set this to false to improve performance.
   mShadow->setAnimating(true); // MM: Set this to false to improve performance.
   
   Point3F lightDir(0.57f,0.57f,-0.57f);
   F32 shadowLen = 3.0f * mShapeInstance->getShape()->radius;
   Point3F pos = mShapeInstance->getShape()->center;
   // this is a bit of a hack...move generic shadows towards feet/base of shape
   if (Shadow::getGlobalShadowDetailLevel() < StaticShape_GenericShadowLevel)
      pos *= 0.5f;

   pos.convolve(mObjScale);
   getRenderTransform().mulP(pos);

   // pos is where shadow will be centered (in world space)
   mShadow->setRadius(mShapeInstance,mObjScale);
   if (!mShadow->prepare(pos,lightDir,shadowLen,mObjScale,dist,fogAmount,mShapeInstance))
      return;

   F32 maxScale = getMax(mObjScale.x,getMax(mObjScale.y,mObjScale.z));

   if (mShadow->needBitmap())
   {
      mShadow->beginRenderToBitmap();
      mShadow->selectShapeDetail(mShapeInstance,dist,maxScale);
      mShadow->renderToBitmap(mShapeInstance,getRenderTransform(),pos,mObjScale);
      mShadow->endRenderToBitmap();
   }
   
   mShadow->render();
}

Next up is the function "void TSStatic::renderObject(SceneState* state, SceneRenderImage* image)". This is so wrong! I'll let you work out what I changed so here's the whole thing...

void TSStatic::renderObject(SceneState* state, SceneRenderImage* image)
{
   AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on entry");

   if (!DetailManager::selectCurrentDetail(mShapeInstance))
      // we were detailed out
      return;

   RectI viewport;
   glMatrixMode(GL_PROJECTION);
   glPushMatrix();
   dglGetViewport(&viewport);

   installLights();

   // Uncomment this if this is a "simple" (non-zone managing) object
   state->setupObjectProjection(this);

   // This is something of a hack, but since the 3space objects don't have a
   //  clear conception of texels/meter like the interiors do, we're sorta
   //  stuck.  I can't even claim this is anything more scientific than eyeball
   //  work.  DMM
   F32 axis = (getObjBox().len_x() + getObjBox().len_y() + getObjBox().len_z()) / 3.0;
   F32 dist = (getRenderWorldBox().getClosestPoint(state->getCameraPosition()) - state->getCameraPosition()).len();
   if (dist != 0)
   {
      F32 projected = dglProjectRadius(dist, axis) / 350;
      if (projected < (1.0 / 16.0))
      {
         TextureManager::setSmallTexturesActive(true);
      }
   }
   
   glMatrixMode(GL_MODELVIEW);
   glPushMatrix();
   dglMultMatrix(&mObjToWorld);
   glScalef(mObjScale.x, mObjScale.y, mObjScale.z);

   dglNPatchBegin();

   // RENDER CODE HERE
   mShapeInstance->setEnvironmentMap(state->getEnvironmentMap());
   mShapeInstance->setEnvironmentMapOn(true,1);
   mShapeInstance->setAlphaAlways(1.0);

   Point3F cameraOffset;
   mObjToWorld.getColumn(3,&cameraOffset);
   cameraOffset -= state->getCameraPosition();
   dist = cameraOffset.len();
   F32 fogAmount = state->getHazeAndFog(dist,cameraOffset.z);

   if (image->isTranslucent == true)
   {
      TSShapeInstance::smNoRenderNonTranslucent = true;
      TSShapeInstance::smNoRenderTranslucent    = false;
   }
   else
   {
      TSShapeInstance::smNoRenderNonTranslucent = false;
      TSShapeInstance::smNoRenderTranslucent    = true;
   }

   mShapeInstance->setupFog(fogAmount,state->getFogColor());
   mShapeInstance->animate();
   mShapeInstance->render();

   dglNPatchEnd();


   glMatrixMode(GL_MODELVIEW);
   glPopMatrix();

   renderShadow(dist,fogAmount);

   TSShapeInstance::smNoRenderNonTranslucent = false;
   TSShapeInstance::smNoRenderTranslucent    = false;
   TextureManager::setSmallTexturesActive(false);

   uninstallLights();
   dglSetCanonicalState();

   if (GameBase::gShowBoundingBox) {
      glDisable(GL_DEPTH_TEST);
      Point3F box;
      glPushMatrix();
      dglMultMatrix(&getTransform());
      box = (mObjBox.min + mObjBox.max) * 0.5;
      glTranslatef(box.x,box.y,box.z);
      box = (mObjBox.max - mObjBox.min) * 0.5;
      glScalef(box.x,box.y,box.z);
      glColor3f(1, 0, 1);
      ShapeBase::wireCube(Point3F(1,1,1),Point3F(0,0,0));
      glPopMatrix();

      glPushMatrix();
      box = (mWorldBox.min + mWorldBox.max) * 0.5;
      glTranslatef(box.x,box.y,box.z);
      box = (mWorldBox.max - mWorldBox.min) * 0.5;
      glScalef(box.x,box.y,box.z);
      glColor3f(0, 1, 1);
      ShapeBase::wireCube(Point3F(1,1,1),Point3F(0,0,0));
      glPopMatrix();
      glEnable(GL_DEPTH_TEST);
   }

   glMatrixMode(GL_PROJECTION);
   glPopMatrix();
   glMatrixMode(GL_MODELVIEW);
   dglSetViewport(viewport);

   AssertFatal(dglIsInCanonicalState(), "Error, GL not in canonical state on exit");
}


Enjoy.

- Melv.
Page«First 1 2 3 Next»
#41
04/21/2004 (9:28 am)
Quote:John, this is the regular shadows that players leave on the ground and interiors right?

Yes, the softer "normal" shadows. The shadow in the screenshots I did of the new show tool was using this.
#42
05/10/2004 (9:54 am)
I added this code/resource to my project, and it is working great. It really seems like it should be in HEAD. I do, however, have one question if anyone has any input. Shadowing on static spapes is working very well, unless you move the object, (Either via the editor or through a setPosition call from C++,) in which case, the shadow doesn't move. (I kind of feel like I'm in the world of peter pan.)
I guess I could just relight the scene, but it would be nice if someone who understands this code had a suggestion as to what code I/we would need to add to make the shadow move with the object.
#43
05/11/2004 (4:33 am)
Static shapes as in DIF interior objects? Or statics objects as in DTS? If you're talking DIF, and the shadow against the terrain, then you need to relight the scene. The lightmap is large so, recalculating it for each frame would dramatically drop your framerate (say, to about .25 fps)

However, if it's DTS object's shadows, please describe in more detail so it can be addressed.

- Brett
#44
05/11/2004 (7:59 am)
The code posted above by Melv and myself does control shadows for static shapes.
#45
05/11/2004 (8:03 am)
Quote:
The next two amendments allow you to change the behaviour of the shadows. Since statics don't move or animate, the shadows are set to non-moving/animating. This produces a higher-performance shadow but doesn't animate when you move it in the editor. You may also want to amend this behaviour dynamically as mentioned by Robert Blanchet here. It's a total choice for you but you can amend this functionality by editing two lines in "void TSStatic::renderShadow(F32 dist, F32 fogAmount)", namely...
mShadow->setMoving(true);
mShadow->setAnimating(true);

Make sure you've done that.
#46
05/11/2004 (8:04 am)
I'm just placing a DTS object in the engine using the World Editor. Here's a simple step by step to reproduce the problem, that I just tried, that should reproduce it for anyone.

1) Open the world editor creator.

2) Place a DTS object into the window. (I used Tree2 from the demo stuff.), and move it to a place where it's level with the ground, and you can see the shadow.

3) Exit the editor, and check out the location of the shadow.

4) Hit f11 to go back into the editor, and click on the tree and move it.

5) Unless there is something different in your project vs mine, the shadow of the tree will not move, and will still be in the wrong place when you switch back out of the editor.
#47
05/11/2004 (8:05 am)
In fact, I just tried issuing the relight scene command, and the shadow still did not move from it's original position.
#48
05/11/2004 (8:21 am)
@John

I do have those two lines in renderShadow. I also noticed that in StaticShape::interpolateTick, the line mShadow->setMoving(false) shows up. I will try changing this to true, and see what happens.

Optimally, it would be nice to set setmoving to true when the object gets moved in the editor, and the back after the move is done.
#49
05/11/2004 (8:22 am)
Well ideally you shoudl expose those to scrpit so you can change them any time you want. It isn't too diifcult to do.
#50
05/11/2004 (8:28 am)
When I changed the mShadow->setMoving(false) to true in InterpolateTick, my shadows move just fine in the editor.

Thanks for the help.
#51
05/14/2004 (5:29 am)
I still don't understand what this fix is about :) Shadows are working in 1.2.2 for me, or I am missing something. The shadows cast on the ground from a DTS object and interiors do this too but with lightmaps.

Am I just missing something? (again, you might say) :P
#52
05/14/2004 (5:35 am)
Dunno Stefan. Maybe they're different :) All I know is I never had any working shadows until I did this.

Why don't you detail how to actually have shadows show up in 1.2.2 and i'll try it and compare. Because they never worked for me without modification.
#53
05/14/2004 (5:47 am)
Lol John :) I've not touched the code for Shadows, that's why I don't know what to say other than it have always worked for me and so does for the others that are testing - as shown here.

Edit: Oh wait, I did fiddle around with changing the $pref::shadows - and right now it's set to 2.
#54
05/14/2004 (5:55 am)
Stefan,

Do your shadows only work with statics, or for moving DTS objects as well like players and vehicles?
#55
05/14/2004 (10:17 am)
I'm sure it works with moving DTS objects, the picture above shows the playershadow. It also works with interiors, but I'm not sure about the trees, haven't checked that yet and I ain't at home right now.

Are there problems with non-moving DTS's like trees, you mean?
#56
05/14/2004 (10:29 am)
Didn't notice that was the player shadow the first time I looked at the pic. *Shrug* sounds like it works the same as what this does then.

In Mayhem using this code, all the vehicles have shadows that move with them, and all static DTS shapes like our buildings have shadows. DIFs of course do as well because they already did but we don't use DIFs.
#57
05/14/2004 (10:30 am)
@Stefan, The post I made above was to correct the direction of the shadows AND make them available for staticShapes, TSStatics, and players. The problem I had (particularly for players) was that the shadow was ALWAYS from the southwest direction--most annoying. And it never looked right when the trees has no shadow at all. Plus these changes merged very nicely with Robert Brower's resource for flashlights.

John's post also shows how to make the shadows update realtime in the editor (much better for previewing).
#58
05/16/2004 (10:59 am)
Oh, now I understand. :)

Something I've heard though is that when a static object is animated it doesn't cast a shadow, is that true? I've seen the "bug" in action too.

Maybe that's something that the above code fixes?
I'm lost :P

My trees always have had shadows btw.
Page«First 1 2 3 Next»