fxGuiSnooper T3D
by Ian Backlund · in Torque 3D Professional · 08/04/2011 (11:06 am) · 23 replies
So the fxGuiSnooper has a long and storied history with T3D. For those not in the know, the fxGuiSnooper is a gui object that allows you to render the scene from the perspective of an object. This can be useful for tons of things like splitscreen gameplay or security cameras. Melv May wrote the original code in 2002 and a number of updates have been kicking around. I have been doing some work with it in T3D recently and I thought I would start a discussion about some of the bugs I am seeing.
Original resource:
www.garagegames.com/community/resource/view/2304
2007 era TGEA re-write:
www.garagegames.com/community/blogs/view/13690
The code I am using (mostly from JesseL-2009 era-1.8 port):
Add the file "fxGuiSnooper.cpp" to your engine code (I put it in my projects source folder), compile and you should have a new control named "fxGuiSnooper" in the controls list within the GUI editor.
In the Object Editor, drop a cube object to use as the camera. Name it something like ViewCube.
Switch to the Gui editor and add a fxGuiSnooper control. Change the AttachedObject parameter to ViewCube.
Bugs, problems and workarounds:
Bug One:
The biggest problem is that there is some kind of weird ghosting effect in the fxGuiSnooper rendering. the rendering has a ghost image of the main play gui composited into it somehow. When you open the gui editor, this ghosting bug disappears.
Here it is rendering as it should in the gui editor:

Bug Two:
If you add any lights with shadows to the scene, and you are running a debug build, you will get a crash with the following statement:
Because we are now rendering the sceen twice, the GuiTSCtrl::smFrameCount variable is being incremented twice during a single render loop which causes an assert in GFXD3D9OcclusionQuery::OcclusionQueryStatus GFXD3D9OcclusionQuery::getStatus. I THINK this is all just performance measuring code, so you can get around it by making sure that TORQUE_GATHER_METRICS is not defined.
Goto your projects source file and find torqueConfig.h.
Comment out line 168 which reads:
Original resource:
www.garagegames.com/community/resource/view/2304
2007 era TGEA re-write:
www.garagegames.com/community/blogs/view/13690
The code I am using (mostly from JesseL-2009 era-1.8 port):
#include "T3DgameBasegameConnection.h"
#include "console/consoleTypes.h"
#include "gui/3d/guiTSControl.h"
#include "gfxgfxDrawUtil.h"
#include "gui/core/guiControl.h"
#include "renderInstance/renderPassManager.h"
#include "gfx/gfxDevice.h"
class fxGuiSnooper : public GuiTSCtrl
{
private:
typedef GuiTSCtrl Parent;
Point3F mRotateView; // View Rotation.
Point3F mOffsetView; // Offset Distance.
F32 mFov; // Field of View.
Point3F mSweepAmplitude; // Sweep Amplitude.
Point3F mSweepTime; // Sweep Time.
bool mUseOverlayBitmap; // Use Overlay Bitmap Flag.
bool mUseOverlayColour; // Use Overlay Colour Flag.
bool mOverlayTile; // Overlay Tile Flag.
ColorF mOverlayColor; // Filter Colour Vector.
bool mOverlayRedMask; // Overlay Red Mask Flag.
bool mOverlayGreenMask; // Overlay Green Mask Flag.
bool mOverlayBlueMask; // Overlay Blue Mask Flag.
StringTableEntry mObjectName; // Attached Object Name.
SceneObject* mAttachedObject; // Attached Object.
U32 mLastTimeStamp; // Last Time Stamp.
Point3F mCurrentSweepMagnitude; // Current Sweep Phase.
StringTableEntry mOverlayBitmapName; // Overlay Bitmap Name.
GFXTexHandle mOverlayTextureHandle; // Overlay Texture Handle.
GFXStateBlockRef mSnooperClearSB;
GFXStateBlockRef mDzEnableSB;
GFXStateBlockRef mEcwSB;
GFXStateBlockRef mEcwResetSB;
void renderWorld(const RectI & updateRect);
void onRender(Point2I offset, const RectI &updateRect);
public:
fxGuiSnooper();
static void initPersistFields();
static void consoleInit();
bool processCameraQuery(CameraQuery * query);
void setViewObject(const char* ObjectName);
void setViewRotation(Point3F Rotation);
void setOverlayBitmap(const char *name);
void setOverlayColor(ColorF OverlayColor);
void setOverlayMask(bool RedMask, bool GreenMask, bool BlueMask);
bool onWake();
void onSleep();
DECLARE_CONOBJECT(fxGuiSnooper);
};
//------------------------------------------------------------------------------
IMPLEMENT_CONOBJECT(fxGuiSnooper);
//------------------------------------------------------------------------------
fxGuiSnooper::fxGuiSnooper() :
mRotateView(0,0,0),
mOffsetView(0,0,0),
mFov(60.0),
mSweepAmplitude(0,0,60),
mSweepTime(5000,5000,5000),
mCurrentSweepMagnitude(0,0,0),
mAttachedObject(NULL),
mOverlayRedMask(true),
mOverlayGreenMask(true),
mOverlayBlueMask(true),
mOverlayTile(false),
mUseOverlayBitmap(false),
mUseOverlayColour(false),
mLastTimeStamp(Platform::getRealMilliseconds())
{
// Create Empty Attached Object Name.
mObjectName = StringTable->insert("");
// Create Empty Overlay Bitmap Name.
mOverlayBitmapName = StringTable->insert("");
// Set Default Overlay Colour.
mOverlayColor.set(1, 1, 1, 0.5f);
};
//------------------------------------------------------------------------------
void fxGuiSnooper::initPersistFields()
{
// Initialise parents' persistent fields.
Parent::initPersistFields();
// Add out own persistent fields.
addField( "ViewRotation", TypePoint3F, Offset( mRotateView, fxGuiSnooper ) );
addField( "ViewOffset", TypePoint3F, Offset( mOffsetView, fxGuiSnooper ) );
addField( "FOV", TypeF32, Offset( mFov, fxGuiSnooper ) );
addField( "SweepAmplitude", TypePoint3F, Offset( mSweepAmplitude, fxGuiSnooper ) );
addField( "SweepTime", TypePoint3F, Offset( mSweepTime, fxGuiSnooper ) );
addField( "AttachedObject", TypeString, Offset( mObjectName, fxGuiSnooper ) );
addField( "OverlayBitmap", TypeBool, Offset( mUseOverlayBitmap, fxGuiSnooper ) );
addField( "OverlayTile", TypeBool, Offset( mOverlayTile, fxGuiSnooper ) );
addField( "OverlayColour", TypeBool, Offset( mUseOverlayColour, fxGuiSnooper ) );
addField( "BitmapOverlay", TypeFilename, Offset(mOverlayBitmapName, fxGuiSnooper));
addField( "ColorOverlay", TypeColorF, Offset( mOverlayColor, fxGuiSnooper ) );
addField( "RedMask", TypeBool, Offset( mOverlayRedMask, fxGuiSnooper ) );
addField( "GreenMask", TypeBool, Offset( mOverlayGreenMask, fxGuiSnooper ) );
addField( "BlueMask", TypeBool, Offset( mOverlayBlueMask, fxGuiSnooper ) );
}
//------------------------------------------------------------------------------
bool fxGuiSnooper::onWake()
{
// Wake-up Parent.
if (!Parent::onWake()) return false;
// Set Active.
setActive(true);
// Have we an Attached Object Name?
if (mObjectName)
{
// Yes, so attach to it.
setViewObject(mObjectName);
}
// Set Overlay Bitmap.
setOverlayBitmap(mOverlayBitmapName);
// Return OK.
return true;
}
//------------------------------------------------------------------------------
void fxGuiSnooper::onSleep()
{
// Reset Overlay Texture Handle.
mOverlayTextureHandle = NULL;
// Call Parent.
Parent::onSleep();
}
//------------------------------------------------------------------------------
void fxGuiSnooper::setViewRotation(Point3F Rotation)
{
// Set the Rotation internally.
mRotateView = Rotation;
}
//------------------------------------------------------------------------------
void fxGuiSnooper::setViewObject(const char* ObjectName)
{
// Get Root Group.
SimGroup* SG = Sim::getRootGroup();
// Interate Sim Group.
for (SimSetIterator itr(SG); *itr; ++itr)
{
// Yes, so cast our Object.
SceneObject* SceneObj = static_cast<SceneObject*>(*itr);
// Check that it's a Server Object.
if (SceneObj->isServerObject())
{
const char* getName;
getName = SceneObj->getName();
// Yes, so is this our Object?
if (getName && dStrcmp(getName, ObjectName) == 0)
{
// Store Scene Object.
mAttachedObject = SceneObj;
// Return OK.
return;
}
}
}
// Reset Object.
mAttachedObject = NULL;
}
//------------------------------------------------------------------------------
void fxGuiSnooper::setOverlayBitmap(const char *name)
{
// Set Overlay Bitmap Name.
mOverlayBitmapName = StringTable->insert(name);
if (*mOverlayBitmapName)
// Yes, so get Texture Handle.
mOverlayTextureHandle.set( mOverlayBitmapName, &GFXDefaultGUIProfile, "" );
else
// No, so reset Texture Handle.
mOverlayTextureHandle = NULL;
// Update.
setUpdate();
}
//------------------------------------------------------------------------------
void fxGuiSnooper::setOverlayColor(ColorF OverlayColor)
{
// Set the Overlay Colour internally.
mOverlayColor = OverlayColor;
}
//------------------------------------------------------------------------------
void fxGuiSnooper::setOverlayMask(bool RedMask, bool GreenMask, bool BlueMask)
{
// Set the Overlay Masks internally.
mOverlayRedMask = RedMask;
mOverlayGreenMask = GreenMask;
mOverlayBlueMask = BlueMask;
}
//------------------------------------------------------------------------------
ConsoleMethod(fxGuiSnooper,setViewRotation,void,5,5,"Sets View Rotation.")
{
Point3F Rotation;
// Fetch the fxGuiSnooper object.
fxGuiSnooper *Viewport = static_cast<fxGuiSnooper*>(object);
// Fetch Rotation.
Rotation.set( mDegToRad(dAtof(argv[2])),
mDegToRad(dAtof(argv[3])),
mDegToRad(dAtof(argv[4])));
// Set Rotation.
Viewport->setViewRotation(Rotation);
}
//------------------------------------------------------------------------------
ConsoleMethod(fxGuiSnooper,setViewObject,void,3,3,"Sets View to Object.")
{
F32 Rotation;
// Fetch the fxGuiSnooper object.
fxGuiSnooper *Viewport = static_cast<fxGuiSnooper*>(object);
// Set the GuiFilter Filter Colour.
Viewport->setViewObject(argv[2]);
}
//------------------------------------------------------------------------------
ConsoleMethod(fxGuiSnooper,setOverlayBitmap,void,3,3,"Sets Overlay Bitmap.")
{
// Fetch the fxGuiSnooper object.
fxGuiSnooper *Viewport = static_cast<fxGuiSnooper*>(object);
// Set Overlay Bitmap.
Viewport->setOverlayBitmap(argv[2]);
}
//------------------------------------------------------------------------------
ConsoleMethod(fxGuiSnooper,setOverlayColor,void,5,6,"Sets Overlay Color.")
{
F32 r,g,b,a;
ColorF TempColor;
// Fetch the fxGuiSnooper object.
fxGuiSnooper *Viewport = static_cast<fxGuiSnooper*>(object);
// Convert RGB Ascii parms to float.
r = dAtof(argv[2]);
g = dAtof(argv[3]);
b = dAtof(argv[4]);
// Did we get an alpha param?
if (argc == 6)
// Yep, so convert it.
a = dAtof(argv[5]);
else
// Nope, so default to 1.
a = 1;
// Setup our temporary colour vector.
TempColor.set(r,g,b,a);
// Set the fxGuiSnooper Overlay Colour.
Viewport->setOverlayColor(TempColor);
}
//------------------------------------------------------------------------------
ConsoleMethod(fxGuiSnooper,setOverlayMask,void,5,5,"Sets Overlay Masks.")
{
F32 r,g,b;
// Fetch the fxGuiSnooper object.
fxGuiSnooper *Viewport = static_cast<fxGuiSnooper*>(object);
// Convert RGB Ascii parms to float.
r = dAtof(argv[2]);
g = dAtof(argv[3]);
b = dAtof(argv[4]);
// Set the fxGuiSnooper Masks.
Viewport->setOverlayMask(r,g,b);
}
//------------------------------------------------------------------------------
static void cfxGuiBitmapSetOverlayBitmap(SimObject *obj, S32, const char **argv)
{
// Fetch HUD Control.
fxGuiSnooper *ctrl = static_cast<fxGuiSnooper*>(obj);
// Set Overlay Bitmap.
ctrl->setOverlayBitmap(argv[2]);
}
//------------------------------------------------------------------------------
void fxGuiSnooper::consoleInit()
{
Con::addCommand("fxGuiSnooper", "setOverlayBitmap", cfxGuiBitmapSetOverlayBitmap, "fxGuiSnooper.setOverlayBitmap(Bitmap)", 3, 3);
}
//------------------------------------------------------------------------------
void fxGuiSnooper::renderWorld(const RectI & updateRect)
{
GFX->clear(GFXClearZBuffer, ColorI(0,0,0), 1.0f, 0);
GFXStateBlockDesc snooperClear;
snooperClear.zEnable = true;
snooperClear.zWriteEnable = true;
snooperClear.zFunc = GFXCmpLessEqual;
snooperClear.cullMode = GFXCullNone;
mSnooperClearSB = GFX->createStateBlock(snooperClear);
GFXStateBlockDesc dzEnable;
dzEnable.zEnable = false;
mDzEnableSB = GFX->createStateBlock(dzEnable);
GFX->setStateBlock(mSnooperClearSB);
// Render Client Scene Graph.
gClientSceneGraph->renderScene(SPT_Diffuse);
GFX->setStateBlock(mDzEnableSB);
}
//------------------------------------------------------------------------------
void fxGuiSnooper::onRender(Point2I offset, const RectI &updateRect)
{
// Call Parent Render.
Parent::onRender(offset, updateRect);
// Set Clipping Rectangle to GUI Bounds.
GFX->setClipRect(getBounds());
// Do we have an attached Object?
if (!mAttachedObject)
{
// No, so signal to user this problem ...
ColorF ErrorColor(1,0,0);
GFX->getDrawUtil()->drawRectFill(updateRect, ErrorColor);
ErrorColor.set(1,1,1);
char buf[256];
dSprintf(buf, sizeof(buf), "*** Object not selected ***");
GFX->getDrawUtil()->setBitmapModulation(ErrorColor);
GFX->getDrawUtil()->drawText(mProfile->mFont, offset, buf);
GFX->getDrawUtil()->clearBitmapModulation();
// Return Error.
return;
}
// Are we using the Overlay Bitmap?
if (mUseOverlayBitmap)
{
// Yes, so do we have a texture Handle?
if (mOverlayTextureHandle)
{
// Yes, so clear Bitmap Modulation.
GFX->getDrawUtil()->clearBitmapModulation();
// Are we tiling the Overlay Bitmap?
if(mOverlayTile)
{
RectI SrcRegion;
RectI DstRegion;
// Yes, so fetch texture object.
GFXTextureObject* TextureObj = mOverlayTextureHandle;
// Calculate Tesselation Count.
float XTess = ((float)getWidth()/(float)TextureObj->mBitmapSize.x)+1;
float YTess = ((float)getHeight()/(float)TextureObj->mBitmapSize.y)+1;
for(int y = 0; y < YTess; ++y)
{
for(int x = 0; x < XTess; ++x)
{
// Calculate Source Region.
SrcRegion.set(0,0,TextureObj->mBitmapSize.x, TextureObj->mBitmapSize.y);
// Calculate Destination Region.
DstRegion.set(((TextureObj->mBitmapSize.x*x)+offset.x),
((TextureObj->mBitmapSize.y*y)+offset.y),
TextureObj->mBitmapSize.x,
TextureObj->mBitmapSize.y);
// Draw Tiled Bitmap.
GFX->getDrawUtil()->drawBitmapStretchSR(TextureObj, DstRegion, SrcRegion);
}
}
}
else
{
// No, so draw stretched Bitmap.
GFX->getDrawUtil()->drawBitmapStretch(mOverlayTextureHandle, getBounds());
}
}
}
// Are we using the Overlay Colour?
if (mUseOverlayColour)
{
// Set Colour Mask.
// Declare StateBlocks
GFXStateBlockDesc ecw;
ecw.colorWriteRed |= ( mOverlayRedMask ? GFXCOLORWRITEENABLE_RED : 0 );
ecw.colorWriteGreen |= ( mOverlayGreenMask ? GFXCOLORWRITEENABLE_GREEN : 0 );
ecw.colorWriteBlue |= ( mOverlayBlueMask ? GFXCOLORWRITEENABLE_BLUE : 0 );
ecw.colorWriteAlpha = GFXCOLORWRITEENABLE_ALPHA;
mEcwSB = GFX->createStateBlock(ecw);
GFXStateBlockDesc ecwReset;
ecwReset.colorWriteRed = GFXCOLORWRITEENABLE_RED;
ecwReset.colorWriteGreen = GFXCOLORWRITEENABLE_GREEN;
ecwReset.colorWriteBlue = GFXCOLORWRITEENABLE_BLUE;
ecwReset.colorWriteAlpha = GFXCOLORWRITEENABLE_ALPHA;
mEcwResetSB = GFX->createStateBlock(ecwReset);
GFX->setStateBlock(mEcwSB);
// Draw our filled rectangle with the Filter Colour.
GFX->getDrawUtil()->drawRectFill(updateRect, mOverlayColor);
// Reset the Colour Mask.
GFX->setStateBlock(mEcwResetSB);
}
}
//------------------------------------------------------------------------------
bool fxGuiSnooper::processCameraQuery(CameraQuery * query)
{
Point3F CameraRotation; // Rotated View.
float VisibleDistance = 1100.0f; // Visible Distance.
// Get Game Connection.
GameConnection* pConnection = dynamic_cast<GameConnection *>(NetConnection::getConnectionToServer());
// Did we get the connection?
if (pConnection)
{
// Have we got an Attached Object?
if (mAttachedObject)
{
// Current Sweep.
EulerF mCurrentSweep;
// Create Camera Matrix.
MatrixF Camera(true);
// Craete Rotation Quaternion.
QuatF QRotation;
// Get Time Elapsed.
U32 CurrentTime = Platform::getRealMilliseconds();
U32 TimeElapsed = CurrentTime - mLastTimeStamp;
mLastTimeStamp = CurrentTime;
// Calculate new Sweep.
Point3F NewSweep( (U32)(360.0f / mSweepTime[0] * TimeElapsed) % 360,
(U32)(360.0f / mSweepTime[1] * TimeElapsed) % 360,
(U32)(360.0f / mSweepTime[2] * TimeElapsed) % 360);
// Add to Current Sweep.
mCurrentSweepMagnitude += NewSweep;
// Calculate Current Sweep Angle.
mCurrentSweep.set( mDegToRad((mSweepAmplitude[0] * mCos(mDegToRad(mCurrentSweepMagnitude[0])))/2 + mRotateView[0]),
mDegToRad((mSweepAmplitude[1] * mCos(mDegToRad(mCurrentSweepMagnitude[1])))/2 + mRotateView[1]),
mDegToRad((mSweepAmplitude[2] * mCos(mDegToRad(mCurrentSweepMagnitude[2])))/2 + mRotateView[2]));
// Set-up Quaternion Rotation.
QRotation.set(mCurrentSweep);
// Set Camera Matrix to new Rotation.
QRotation.setMatrix(&Camera);
// Set Position @ Attached Object.
Camera.setColumn(3, mAttachedObject->getBoxCenter() + mOffsetView);
// Set Camera Matrix.
query->cameraMatrix = Camera;
// Set Near/Far Planes.
query->nearPlane = 0.1;
query->farPlane = getMax(VisibleDistance, 50.f);
// Set FOV.
query->fov = mDegToRad(mFov);
// Return OK.
return(true);
}
}
// Return Error.
return(false);
}Usage Instructions:Add the file "fxGuiSnooper.cpp" to your engine code (I put it in my projects source folder), compile and you should have a new control named "fxGuiSnooper" in the controls list within the GUI editor.
In the Object Editor, drop a cube object to use as the camera. Name it something like ViewCube.
Switch to the Gui editor and add a fxGuiSnooper control. Change the AttachedObject parameter to ViewCube.
Bugs, problems and workarounds:
Bug One:
The biggest problem is that there is some kind of weird ghosting effect in the fxGuiSnooper rendering. the rendering has a ghost image of the main play gui composited into it somehow. When you open the gui editor, this ghosting bug disappears.
Here it is rendering as it should in the gui editor:
Bug Two:
If you add any lights with shadows to the scene, and you are running a debug build, you will get a crash with the following statement:
"GFXD3D9OcclusionQuery::getStatus - called on the same frame as begin!"
Because we are now rendering the sceen twice, the GuiTSCtrl::smFrameCount variable is being incremented twice during a single render loop which causes an assert in GFXD3D9OcclusionQuery::OcclusionQueryStatus GFXD3D9OcclusionQuery::getStatus. I THINK this is all just performance measuring code, so you can get around it by making sure that TORQUE_GATHER_METRICS is not defined.
Goto your projects source file and find torqueConfig.h.
Comment out line 168 which reads:
#define TORQUE_GATHER_METRICS 0
#2
08/04/2011 (1:19 pm)
Alas this post isn't helpful ... but I've seen that rendering issue if you have another playGui on screen and it's smaller than the screen/window size.
#3
Take a look at:
void GuiTSCtrl::onRender(Point2I offset, const RectI &updateRect)
Both the playGui (gameTSCtrl) and the fxGuiSnooper inherit from guiTSCtrl and run this method during scene rendering.
OnRender calculates the worldToCamera and cameraToScreen matrices and passes them to the post effect manager just before it calls renderWorld(updateRect); RenderWorld() then does the actual scene rendering.
So during the runtime here is what happens:
1. the playGui runs onRender, passes it's projection matrices to the postFx manger and renders.
2. PlayGui loops through it's children calling their onRender methods.
3. fxGuiSnooper (which is one of those children) runs onRender, which passes a different set of projection matrices to the postFX manager. It then renders it's scene.
4. Sometime later in the frame, the postFX manager runs it's post fx code but because it was passed those matrices twice, it's got bad data and its screwing up all it's calculations.
I can't prove that is what is happening, or fix it yet. But it would seem to fit the symptoms. I will keep poking around and post updates.
08/04/2011 (3:20 pm)
Ok, more info! This is a problem with postFX. I just disabled postFX and the problem goes away. I think I know why too...Take a look at:
void GuiTSCtrl::onRender(Point2I offset, const RectI &updateRect)
Both the playGui (gameTSCtrl) and the fxGuiSnooper inherit from guiTSCtrl and run this method during scene rendering.
OnRender calculates the worldToCamera and cameraToScreen matrices and passes them to the post effect manager just before it calls renderWorld(updateRect); RenderWorld() then does the actual scene rendering.
So during the runtime here is what happens:
1. the playGui runs onRender, passes it's projection matrices to the postFx manger and renders.
2. PlayGui loops through it's children calling their onRender methods.
3. fxGuiSnooper (which is one of those children) runs onRender, which passes a different set of projection matrices to the postFX manager. It then renders it's scene.
4. Sometime later in the frame, the postFX manager runs it's post fx code but because it was passed those matrices twice, it's got bad data and its screwing up all it's calculations.
I can't prove that is what is happening, or fix it yet. But it would seem to fit the symptoms. I will keep poking around and post updates.
#4
Later, i give a cleanup to the code, and i share here the code.
In this screenshot are active SSAO2, HDR, and Image Optimization PostFXs.

08/05/2011 (3:17 pm)
Here, as i thought, with a few tweaks get it to work even on the final version of T3D 1.1.Later, i give a cleanup to the code, and i share here the code.
In this screenshot are active SSAO2, HDR, and Image Optimization PostFXs.

#6
08/05/2011 (3:59 pm)
Looking forward to your tweaks Alfio, I never got past the PostFx issue.
#7
The stupid way is use a custom RenderPassManager and change the renderState to disable the postfx for this viewport:
This solution works 100%, but you lose the PostFX for that viewport.
08/05/2011 (5:13 pm)
[AS EXPERIMENT]The stupid way is use a custom RenderPassManager and change the renderState to disable the postfx for this viewport:
void fxGuiSnooper::onRender(Point2I offset, const RectI &updateRect)
{
// Call Parent Render.
Parent::onRender(offset, updateRect);
// Set Clipping Rectangle to GUI Bounds.
GFX->setClipRect(getBounds());
// Do we have an attached Object?
if (!mAttachedObject)
{
....
}
// Are we using the Overlay Bitmap?
if (mUseOverlayBitmap)
{
....
}
// Are we using the Overlay Colour?
if (mUseOverlayColour)
{
....
}
}
void fxGuiSnooper::renderWorld(const RectI & updateRect)
{
GFXTransformSaver saver;
gClientSceneGraph->setDisplayTargetResolution(getExtent());
// Use a render instance to do the scene
// rendering after HDR is processed and while the depth
// buffer is still intact.
RenderPassManager *rpm = gClientSceneGraph->getDefaultRenderPass();
ObjectRenderInst *inst = rpm->allocInst<ObjectRenderInst>();
inst->type = RenderPassManager::RIT_Editor;
inst->renderDelegate.bind(this, &fxGuiSnooper::_renderScene);
rpm->addInst(inst);
// Render Client Scene Graph.
gClientSceneGraph->renderScene(SPT_Diffuse);
}
void fxGuiSnooper::_renderScene( ObjectRenderInst*, SceneRenderState *state, BaseMatInstance* )
{
GFXTransformSaver saver;
state->usePostEffects(false);
renderScene(mSaveViewport);
GFX->setClipRect(mSaveViewport);
GFX->setStateBlock(mDefaultGuiSB);
}This solution works 100%, but you lose the PostFX for that viewport.
#8
Add the reflectionManager inlude file:
Declare a new CameraQuery on the protected section:
Initialize the mLastCameraQuery on the constructor:
Update the mLastCameraQuery on processCameraQuery:
And finally, on the onRender, send the update to the reflectionManager:
08/21/2011 (5:42 am)
How deepscratch pointed out to me, the reflectionManager going on tilt in some circumstances, render wrong some objects like the waterplane. So you need to update the information for the reflectionManager. To do this just add a few lines of code.Add the reflectionManager inlude file:
#include "scene/reflectionManager.h"
Declare a new CameraQuery on the protected section:
class fxGuiSnooper : public GuiTSCtrl
{
private:
typedef GuiTSCtrl Parent;
....
protected:
CameraQuery mLastCameraQuery;
};Initialize the mLastCameraQuery on the constructor:
fxGuiSnooper::fxGuiSnooper() :
....
mLastCameraQuery.cameraMatrix.identity();
mLastCameraQuery.fov = 45.0f;
mLastCameraQuery.object = NULL;
mLastCameraQuery.farPlane = 10.0f;
mLastCameraQuery.nearPlane = 0.01f
mLastCameraQuery.ortho = false;
};Update the mLastCameraQuery on processCameraQuery:
..... // Set FOV. query->fov = mDegToRad(mFov); mLastCameraQuery.cameraMatrix = query->cameraMatrix; // <- Update mLastCameraQuery // Return OK. return(true); } } // Return Error. return(false); }
And finally, on the onRender, send the update to the reflectionManager:
void fxGuiSnooper::onRender(Point2I offset, const RectI &updateRect)
{
// Call Parent Render.
Parent::onRender(offset, updateRect);
....
REFLECTMGR->update( 1, getExtent(), mLastCameraQuery );
}
#9
I'm still getting my fxGuiSnooper output rendered in the water reflection after adding your code in post #8 above...

Any ideas??
09/07/2011 (3:59 pm)
Alfio - I was wondering if you got any further with this? A resource would be great ;)I'm still getting my fxGuiSnooper output rendered in the water reflection after adding your code in post #8 above...

Any ideas??
#10
09/07/2011 (6:12 pm)
I don't think Alfio is active in the community anymore, Andy.
#11
09/08/2011 (2:50 am)
Really? That's a shame.. The sea really doesn't look as inviting as it should when it has a camera output floating in it..
#12
Thanks...
12/13/2011 (11:49 am)
I have found another possible issue with the guisnooper, if you have it attached to an object 1000m away from the main scene rendering, (arbitrary distance, but far enough that the engine thinks it doesn't need to render it, then what ever it is looking at won't be rendered. If I turn on global bounds for an object that should be rendering, it does render. The problem is that everything that the guisnooper could possibly see will have to have global bounds switched on. Maybe there's an easy fix for this, but I haven't seen it, so any idea's on how to fix this would be appreciated.Thanks...
#13
Looks like Alfio had the code working at some point... would be nice to see if he could be contacted.
12/13/2011 (12:16 pm)
Sounds like a scoping problem - objects far away don't get sent across the network. In rendering the scene, you'll catch all objects that you need to render from a certain position, but if the objects aren't being sent to the client, then it can't render them.Looks like Alfio had the code working at some point... would be nice to see if he could be contacted.
#14
So you probably want to make sure onCameraScopeQuery is being properly called for all your snoopers as well:
Useful info:
12/13/2011 (12:39 pm)
in onCameraScopeQuery:// Get the visible distance.
query->visibleDistance = gServerSceneGraph->getVisibleDistance();
// First, we are certainly in scope, and whatever we're riding is too...
cr->objectInScope(this);
if (isMounted())
cr->objectInScope(mMount.object);
if (mSceneManager == NULL)
{
// Scope everything...
gServerContainer.findObjects(0xFFFFFFFF,scopeCallback,cr);
return;
}
// update the scenemanager
mSceneManager->scopeScene(query->pos, query->visibleDistance, cr);
// let the (game)connection do some scoping of its own (commandermap...)
cr->doneScopingScene();So you probably want to make sure onCameraScopeQuery is being properly called for all your snoopers as well:
void NetConnection::ghostWritePacket(BitStream *bstream, PacketNotify *notify)
{
#ifdef TORQUE_DEBUG_NET
bstream->writeInt(DebugChecksum, 32);
#endif
notify->ghostList = NULL;
if(!isGhostingFrom())
return;
if(!bstream->writeFlag(mGhosting))
return;
// fill a packet (or two) with ghosting data
// first step is to check all our polled ghosts:
// 1. Scope query - find if any new objects have come into
// scope and if any have gone out.
// 2. call scoped objects' priority functions if the flag set is nonzero
// A removed ghost is assumed to have a high priority
// 3. call updates based on sorted priority until the packet is
// full. set flags to zero for all updated objects
CameraScopeQuery camInfo;
camInfo.camera = NULL;
camInfo.pos.set(0,0,0);
camInfo.orientation.set(0,1,0);
camInfo.visibleDistance = 1;
camInfo.fov = (F32)(3.1415f / 4.0f);
camInfo.sinFov = 0.7071f;
camInfo.cosFov = 0.7071f;
GhostInfo *walk;
// only need to worry about the ghosts that have update masks set...
S32 maxIndex = 0;
S32 i;
for(i = 0; i < mGhostZeroUpdateIndex; i++)
{
// increment the updateSkip for everyone... it's all good
walk = mGhostArray[i];
walk->updateSkipCount++;
if(!(walk->flags & (GhostInfo::ScopeAlways | GhostInfo::ScopeLocalAlways)))
walk->flags &= ~GhostInfo::InScope;
}
if(mScopeObject)
mScopeObject->onCameraScopeQuery(this, &camInfo);
//////////////////////////////////////////////
//////////////////////////////////////////////
//////////////////////////////////////////////
// Probably add your snooper scoping code here
//////////////////////////////////////////////
//////////////////////////////////////////////
//////////////////////////////////////////////
for(i = mGhostZeroUpdateIndex - 1; i >= 0; i--)
{
if(!(mGhostArray[i]->flags & GhostInfo::InScope))
detachObject(mGhostArray[i]);
}Useful info:
/// Ghosting is the most complex, and most powerful, part of Torque's networking capabilities. It /// allows the information sent to clients to be very precisely matched to what they need, so that /// no excess bandwidth is wasted. The control object's onCameraScopeQuery() is called, to determine /// scoping information for the client; then objects which are in scope are then transmitted to the /// client, prioritized by the results of their getPriority() method.
#15
12/13/2011 (1:20 pm)
Alfio has posted recently in the Green-Ear forums.
#16
You can contact me privately by email to the address:
info [DOT] collateral [AT] gmail.com
PS: I still need to proceed to purchase the new T3D -.-
12/13/2011 (1:43 pm)
Yes, i'm still alive. For the moment i put aside the T3D for various reasons. However, this does not mean that i abandoned the T3D.You can contact me privately by email to the address:
info [DOT] collateral [AT] gmail.com
PS: I still need to proceed to purchase the new T3D -.-
#17
12/13/2011 (3:17 pm)
Thanks Thomas!
#18
Find-in-Files is super useful.
12/13/2011 (5:16 pm)
No problem. Note that I haven't played with this at all, I just was posting the relevant sections of code based on Daniel's hypothesis (which I thought was quite sound). Find-in-Files is super useful.
#19
http://www.garagegames.com/community/resources/view/21471
As in set the visible players larger than the visibledistance....
01/19/2012 (7:52 pm)
You know you could just apply this resource and reverse it...http://www.garagegames.com/community/resources/view/21471
As in set the visible players larger than the visibledistance....
#20
http://www.garagegames.com/community/resource/view/10899
In order to view the output of the FXsnoopergui on a texture, as a remote camera, essentially.
On the server, this works flawlessly, but on the client, I always get a red texture with "Object not selected" written on it. It's being triggered in the code from fxGuiSnooper::onRender, because mAttachedObect is not set.
I assume this is a networking/scope issue, but I have tried setting the server object to ghost always, and resolving the ghost id on the client, and then changing it's name to match the server object, but that hasn't worked.
Is it possible to make this resource work the way I want it? Or am I way off track?
Thanks for any advice.
05/21/2012 (7:28 pm)
I have combined this resource, with this one:http://www.garagegames.com/community/resource/view/10899
In order to view the output of the FXsnoopergui on a texture, as a remote camera, essentially.
On the server, this works flawlessly, but on the client, I always get a red texture with "Object not selected" written on it. It's being triggered in the code from fxGuiSnooper::onRender, because mAttachedObect is not set.
I assume this is a networking/scope issue, but I have tried setting the server object to ghost always, and resolving the ghost id on the client, and then changing it's name to match the server object, but that hasn't worked.
Is it possible to make this resource work the way I want it? Or am I way off track?
Thanks for any advice.
Torque Owner Alfio Saitta
Collateral Studios
I have somewhere a fully functional copy for T3D 1.1 Beta3. Later i seek, and maybe can understand why you have that bug.
For the Bug Two:
A same bug solved with the increase of the variable at the begin of the call. Check here