Need projection matrix for *this* frame in GuiTSCtrl:onPreRender
by Orion Elenzil · in Torque Game Engine · 01/10/2007 (4:14 pm) · 11 replies
Hey all.
another esoteric question here.
i don't really anticipate an easy answer, but you never know.
i'm making a new GuiControl which's purpose is to track points in the 3D world on the 2D gui.
- the idea is that it's a more flexible replacement for the GuiShapeNameHud.
during onPreRender(), i can call the parent GuiTSCtrl's project() to convert from worldspace to screenspace,
and this works well, except that the GuiTSCtrl has the projection matrix from the *previous* frame, not this one.
I tried updating mSaveProjection and mSaveModelView in GuiTSCtrl's onPreRender(), but that doesn't really help because i still only have mLastCameraQuery to work with.
so what i've ended up doing is repositioning my GuiControl in its actual OnRender() function.
that gets rid of the one-frame lag, but i don't like it because i need to call dglSetClipRect() to get the new position to take, and that in turn calls glViewport(), which is fairly expensive, i think. - i may have a hundred or so of these buggers on screen at once. so that'd be a hundred or so glViewport()s per frame.
a workaround would be to make a big control which covers the whole screen,
who's child controls can be repositioned during its onRender(). - that way i wouldn't have to call dglSetClipRect(), i could just pass down fudged updateRects, i think.
that one frame of lag is pretty annoying.
thanks in advance for any thoughts.
orion
another esoteric question here.
i don't really anticipate an easy answer, but you never know.
i'm making a new GuiControl which's purpose is to track points in the 3D world on the 2D gui.
- the idea is that it's a more flexible replacement for the GuiShapeNameHud.
during onPreRender(), i can call the parent GuiTSCtrl's project() to convert from worldspace to screenspace,
and this works well, except that the GuiTSCtrl has the projection matrix from the *previous* frame, not this one.
I tried updating mSaveProjection and mSaveModelView in GuiTSCtrl's onPreRender(), but that doesn't really help because i still only have mLastCameraQuery to work with.
so what i've ended up doing is repositioning my GuiControl in its actual OnRender() function.
that gets rid of the one-frame lag, but i don't like it because i need to call dglSetClipRect() to get the new position to take, and that in turn calls glViewport(), which is fairly expensive, i think. - i may have a hundred or so of these buggers on screen at once. so that'd be a hundred or so glViewport()s per frame.
a workaround would be to make a big control which covers the whole screen,
who's child controls can be repositioned during its onRender(). - that way i wouldn't have to call dglSetClipRect(), i could just pass down fudged updateRects, i think.
that one frame of lag is pretty annoying.
thanks in advance for any thoughts.
orion
About the author
#2
Just for comparison, the TGE 1.5 demo calls glViewport about 50 times per frame on average. In total, those calls represent about 0.06% of Torque's time, and glViewport is the most expensive gl function dglSetClipRect uses.
So, ya, if calling dglSetClipRect 100 times per frame is what it takes to make it work, go for it.
01/10/2007 (5:21 pm)
While calling dglSetClipRect 100 times or more per frame isn't necessarily the ideal solution, you won't notice it. All of the gl functions it calls (including glViewport) are very lightweight.Just for comparison, the TGE 1.5 demo calls glViewport about 50 times per frame on average. In total, those calls represent about 0.06% of Torque's time, and glViewport is the most expensive gl function dglSetClipRect uses.
So, ya, if calling dglSetClipRect 100 times per frame is what it takes to make it work, go for it.
#3
- does it look to you like dglSetClipRect() is being called once per control ?
while 0.06% (you mean TotalTime X 0.00006, yeah?) is pretty darned small,
it's tempting to only call that function for controls which themselves have children.
.. if it's there for the reason i think.
01/10/2007 (5:28 pm)
Hey sweet, thanks for the input alex.- does it look to you like dglSetClipRect() is being called once per control ?
while 0.06% (you mean TotalTime X 0.00006, yeah?) is pretty darned small,
it's tempting to only call that function for controls which themselves have children.
.. if it's there for the reason i think.
#4
And yes, it does look like dglSetClipRect is called for every rendered gui control. No matter. Optimizing away some of those calls would take a while and ultimately result in no gain.
01/10/2007 (5:49 pm)
0.06% is TotalTime * 0.0006 = very small numberAnd yes, it does look like dglSetClipRect is called for every rendered gui control. No matter. Optimizing away some of those calls would take a while and ultimately result in no gain.
#5
well except i think the optimization would be relatively simple:
i'll give it a shot tomorrow and see what it breaks.
01/10/2007 (7:31 pm)
I'm with ya. thanks again for the extra eyes.well except i think the optimization would be relatively simple:
if (ctrl->numberOfChildren() > 0) dglSetClipRect(childClip);
i'll give it a shot tomorrow and see what it breaks.
#6
01/11/2007 (9:11 am)
Heh, well it breaks only about half of everything. do not use my suggested optimization, folks !
#7
I'm a little unclear what you're trying to solve here - having GUI controls that move around to track objects in the 3d view? They should be rendered after their parent control - which is the GuiTSCtrl - so it seems like you should be able to figure out some way to get them to show up correctly in the current render order, without having to rejigger stuff very much, just by having them update in onRender.
01/11/2007 (8:12 pm)
GlViewport is not an overhead. Don't worry about it unless it starts showing up as a meaningful part of the profiler output (I'd say, over 1%). The text/graphics rendering you'll be doing from within you GUI controls is probably much higher cost than the glViewport calls!I'm a little unclear what you're trying to solve here - having GUI controls that move around to track objects in the 3d view? They should be rendered after their parent control - which is the GuiTSCtrl - so it seems like you should be able to figure out some way to get them to show up correctly in the current render order, without having to rejigger stuff very much, just by having them update in onRender.
#8
thanks for the advice.
i think the core of my problem was that you can't simply resize/reposition during onRender() because the viewport has already been set during the parent's onRenderChildControls(), as well as a test for whether or not to render the child:
ie:
.. so i got around that with the introduction of an optional repositioning call just before childClip is created.
alternatively, dglSetClipRect() could be moved into onRender() itself (makes sense to me) - but that would mean a bunch of refactoring existing controls, and there would still be the issue of testing if the child control is within the bounds of the parent.
BTW,
i upped this last night as a resource if anyone's interested in checking it out.
i think it's kinda neat.
01/12/2007 (10:06 am)
Hey ben -thanks for the advice.
i think the core of my problem was that you can't simply resize/reposition during onRender() because the viewport has already been set during the parent's onRenderChildControls(), as well as a test for whether or not to render the child:
ie:
if (childClip.intersect(clipRect))
{
dglSetClipRect(childClip);
glDisable(GL_CULL_FACE);
ctrl->onRender(childPosition, childClip);
}.. so i got around that with the introduction of an optional repositioning call just before childClip is created.
alternatively, dglSetClipRect() could be moved into onRender() itself (makes sense to me) - but that would mean a bunch of refactoring existing controls, and there would still be the issue of testing if the child control is within the bounds of the parent.
BTW,
i upped this last night as a resource if anyone's interested in checking it out.
i think it's kinda neat.
#9
01/12/2007 (10:34 am)
Why not just... set the clip rect again? Several controls already do this - it's not the super-optimal thing but as previously discussed it's pretty survivable.
#10
01/12/2007 (11:05 am)
Right - but there's still the issue of visibility testing being done in the parent control.
#11
01/12/2007 (12:13 pm)
Do you ever get partial update regions such that this is an issue? You could also just override that call for your parent control so it always draws all of them - it's virtual IIRC.
Associate Orion Elenzil
Real Life Plus
at least, it introduces no new calls to glViewport().
instead of auto-repositioning the control in onPreRender(),
i created a new virtual method of GuiControl itself called "resizeDuringRender()",
which is empty by default, but which i've overridden for my special control.
resizeDuringRender() is called (you guessed it) during the parent control's renderChildControls().
so the base GuiControl class now looks like this:
void GuiControl::renderChildControls(Point2I offset, const RectI &updateRect) { // offset is the upper-left corner of this control in screen coordinates // updateRect is the intersection rectangle in screen coords of the control // hierarchy. This can be set as the clip rectangle in most cases. RectI clipRect = updateRect; iterator i; for(i = begin(); i != end(); i++) { GuiControl *ctrl = static_cast<GuiControl *>(*i); if (ctrl->mVisible) { ctrl->resizeDuringRender(); Point2I childPosition = offset + ctrl->getPosition(); RectI childClip(childPosition, ctrl->getExtent()); if (childClip.intersect(clipRect)) { dglSetClipRect(childClip); glDisable(GL_CULL_FACE); ctrl->onRender(childPosition, childClip); } } } } void GuiControl::resizeDuringRender() { // do nothing }while my custom control has this:
void Gui3DProjectionCtrl::resizeDuringRender() { doPositioning(); doProjection (); doAlignment (); }.. do alignment there finally updates mBounds,
which is the source of getPosition() and getExtent() back in renderChildControls().
note, according to my reading of renderChildControls() there,
it looks to me like glViewport is going to be called each time a control is rendered.
seems a bit excessive, neh ?