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):
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:
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
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
About the author
Associate Matt Fairfax
PopCap