Game Development Community

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):
#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.
www.armageddonroad.net/images/GuiSnooperBugScreenshot.jpgHere it is rendering as it should in the gui editor:
www.armageddonroad.net/images/GuiSnooperinGuiEditorScreenshot.jpg
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

Page «Previous 1 2
#1
08/04/2011 (11:42 am)
For the Bug One:
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
#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
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
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.
img846.imageshack.us/img846/6389/immagineod.th.png
#5
08/05/2011 (3:23 pm)
Cool stuff! That'd be a great addition to the resources section.
#6
08/05/2011 (3:59 pm)
Looking forward to your tweaks Alfio, I never got past the PostFx issue.
#7
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
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
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...

www.eikon-games.com/andy/gg/fxGuiSnooper-reflectionWeirdness.jpg
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
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
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
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
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
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
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
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.
Page «Previous 1 2