Game Development Community

TGEA 1.7.0 Bug: Position coordinates passed badly to shaders.

by John Hopkins · in Torque Game Engine Advanced · 04/22/2008 (11:08 pm) · 1 replies

Greetings, I believe the following is a bug. I found this when trying to calculate the world coordinates of the eye(camera) in a vertex shader. Using a debugger, I have found that TGEA was passing (x, y, z, 0.0) in the VC_EYE_POS register, whereas points in homogeneous space need the w coordinate as 1.0. This was due to the old code (processedShaderMaterial.cpp):

void ProcessedShaderMaterial::setEyePosition(MatrixF objTrans, Point3F position, U32 pass)
{
   // Set cubemap stuff here (it's convenient!)
   if(hasCubemap(pass) || mMaterial->dynamicCubemap)
   {
      Point3F cubeEyePos = position - objTrans.getPosition();
      GFX->setVertexShaderConstF( VC_CUBE_EYE_POS, (float*)&cubeEyePos, 1 );
   }
   objTrans.inverse();
   objTrans.mulP( position );
   position.convolveInverse(objTrans.getScale());
   GFX->setVertexShaderConstF( VC_EYE_POS, (float*)&position, 1 );
}

Which was simply passing Point3Fs to the setVertexShaderConstF() function as seen in the above code. Because the setVertexShaderConstF() function inadvertently passes the same data to DirectX's SetVertexShaderConstantF(), this actually constitutes a memory overrun. The DirectX function takes vectors of four(4) floats, and the Point3F has only three(3). Luckily for me, whatever memory was read after the Point3D was a zero, probably compiler allocated vtable or something else funky. Anyway, I propose the following function in lieu of the previous:

void ProcessedShaderMaterial::setEyePosition(MatrixF objTrans, Point3F position, U32 pass)
{
   // Set cubemap stuff here (it's convenient!)
   if(hasCubemap(pass) || mMaterial->dynamicCubemap)
   {
      // Initialise new cube eye position with default ctor because there
      // is no ctor that takes 3 values from a Point3F.
      Point4F cubeEyePos;
	  cubeEyePos.w = 1.0; // Points have homogenous coord w == 1.0.
	  // Copy remaining values.
	  cubeEyePos = (position - objTrans.getPosition());
	  // Before the conversion of the cubeEyePos to a Point4F, this was actually
	  // a memory overrun, because the DX Library (which essentially receives the
	  // point in the end) takes four floats for a float4, not 3 as in Point3F.
      GFX->setVertexShaderConstF( VC_CUBE_EYE_POS, (float*)&cubeEyePos, 1 );
   }
   objTrans.inverse();
   objTrans.mulP( position );
   position.convolveInverse(objTrans.getScale());
   // Convert to Point4F before passing as a shader constant; see above.
   Point4F newPosition(position.x, position.y, position.z, 1.0);
   GFX->setVertexShaderConstF( VC_EYE_POS, (float*)&newPosition, 1 );
}

Let me know whether I'm totally off the mark on this one. I could be. It happens.
Thanks.

Ryan "The Master of the Toaster" Green

#1
05/21/2008 (11:14 am)
Good catch! I am going to be looking into this but it probably won't be changed in the next version (there are some longer range plans that should help fix this sort of thing).