Scene Fading
by Kevin Epps · in Torque Game Builder · 07/08/2007 (4:16 pm) · 17 replies
Did someone ever figure this out? Did someone ever add at a Alpha Value to scenes or anything like that?
About the author
#2
Thanks for the idea, David. I'll try that out and post what I come up with.
Do you know if they're planning on adding an alpha and blending value to the scenegraph object? Does anyone know this?
07/08/2007 (9:06 pm)
Yeah, my post was referring to the topic title.Thanks for the idea, David. I'll try that out and post what I come up with.
Do you know if they're planning on adding an alpha and blending value to the scenegraph object? Does anyone know this?
#3
07/08/2007 (9:52 pm)
Kevin -- no clue if they plan to add this, but whats wrong with the solution I proposed? Are you looking for something else?
#4
All the t2dSceneObject already have an alpha value though.
If you want to fade entire screen (scene window) consider to use GuiFadeinBitmapCtrl gui object (v1.1.3)
07/08/2007 (10:59 pm)
Scenegraph isn't visible object. so what alpha can imply to scenegraph?All the t2dSceneObject already have an alpha value though.
If you want to fade entire screen (scene window) consider to use GuiFadeinBitmapCtrl gui object (v1.1.3)
#5
@Igor: That doesn't work for what I need, as you can't, for one, change the fade color, like in David's suggestion, and two, you can't give a indefinite wait time value or call the fade in and fade out at will. That wouldn't work for stages, as you don't know how long a person's going to take to finish a stage before moving on to the next one.
07/09/2007 (5:04 am)
@David: There's nothing wrong with your approach. I just wanted to know if they planned on doing adding those values is all. Just saves time and space to fade a scenegraph, and you could also do all kinds of other transition magic, like scene crossfading and such.@Igor: That doesn't work for what I need, as you can't, for one, change the fade color, like in David's suggestion, and two, you can't give a indefinite wait time value or call the fade in and fade out at will. That wouldn't work for stages, as you don't know how long a person's going to take to finish a stage before moving on to the next one.
#6
Doing this in the engine source is pretty easy. Add a new ColorF variable to t2dSceneWindow called something like blendModifier and a method to fetch it. Then in t2dSceneObject, in the setBlendOptions method, do this:
I also added a bool and a method check (isBlendModifierActive) to t2dSceneWindow to enable/disable global blending so I didn't do unnecessary math each render pass if I wasn't trying to fade.
This allows for some really neat multi-window cinematic cross fading. If you create two SceneWindows pointing to the same scenegraph you can fade between a full-scene shot and a zoom-in shot on the character, for example.
Also implementing it in this way takes the SceneObject's BlendingEnabled value into account. If you call %mySprite.setBlending(false) (or set %mySprite.BlendingEnabled = false) then %mySprite won't fade out with the rest of the scene. So you could do stuff like blend the entire scene to dark red except for your player during death.
Whole-scene blending entirely in script can be done by looping through the scenegraph's objects and adjusting their blend colors by some global value, but it probably wouldn't scale well with lots of objects particularly if you're attempting to fade smoothly over a short time. You'd need to save the original blend value for each object to preserve any existing blend settings and apply the modifier to that too.
07/09/2007 (11:11 am)
I'd guess adding a blend modifier onto the scenegraph object isn't going to happen officially anytime soon. You might want the modifier on t2dSceneWindow anyway so you could fade between two SceneWindows pointing to the same scenegraph.Doing this in the engine source is pretty easy. Add a new ColorF variable to t2dSceneWindow called something like blendModifier and a method to fetch it. Then in t2dSceneObject, in the setBlendOptions method, do this:
t2dSceneWindow* pSceneWindow = getSceneGraph()->getCurrentRenderWindow();
if (pSceneWindow && pSceneWindow->isBlendModifierActive())
{
ColorF modBlendColor = mBlendColour * pSceneWindow->getBlendModifierColor();
glColor4fv( (GLfloat*)&modBlendColor );
} else {
glColor4fv( (GLfloat*)&mBlendColour );
}I also added a bool and a method check (isBlendModifierActive) to t2dSceneWindow to enable/disable global blending so I didn't do unnecessary math each render pass if I wasn't trying to fade.
This allows for some really neat multi-window cinematic cross fading. If you create two SceneWindows pointing to the same scenegraph you can fade between a full-scene shot and a zoom-in shot on the character, for example.
Also implementing it in this way takes the SceneObject's BlendingEnabled value into account. If you call %mySprite.setBlending(false) (or set %mySprite.BlendingEnabled = false) then %mySprite won't fade out with the rest of the scene. So you could do stuff like blend the entire scene to dark red except for your player during death.
Whole-scene blending entirely in script can be done by looping through the scenegraph's objects and adjusting their blend colors by some global value, but it probably wouldn't scale well with lots of objects particularly if you're attempting to fade smoothly over a short time. You'd need to save the original blend value for each object to preserve any existing blend settings and apply the modifier to that too.
#7
07/09/2007 (3:40 pm)
Couldn't I just add all the blending variables and functions from SceneObject and add them to SceneWindow? I see what you're saying but I'm confused on how just creating the variable and adding that line of code could do all of that. How would you be able to crossfade if there's no alpha value in scenewindow?
#8
I think the way you're picturing it is the SceneGraph or SceneWindow is like it's own separate canvas, and if you fade the canvas you also fade everything drawn on that canvas. That's not really how it's structured. There's only one real 'canvas' in this implementation (the screen buffer) and the contents of all SceneWindows get rendered in layer order on top of each other.
When the view of a SceneWindow is being drawn to the screen, the engine loops through the associated SceneGraph's list of t2dSceneObjects (parent class to all the renderable stuff) and tells each one to render itself. As part of this, each object's color/alpha value gets set (which is done in t2dSceneObject's setBlendOptions method) based on that object's local blendColor variable.
What the implementation above does is add a new value to the SceneWindow, a global 'color modifier' that gets multiplied against the color value of every object within that SceneWindow as they get told to render themselves. All it does is hijack setBlendOptions to check and see if the current view (a.k.a. SceneWindow) has a global color modifier, and if so we apply it to each and every object as they get drawn to the screen.
Sorry if that was long-winded, but I figure being more descriptive about the rendering flow and SceneWindow/SceneGraph relationship might help some. :)
07/09/2007 (4:04 pm)
SceneWindow (and SceneGraph) aren't things that get rendered to the screen. SceneGraph is more or less a container for render-able objects (staticsprites, particle effects, etc.) and SceneWindow just defines a specific view (like a camera) into a SceneGraph. So neither SceneWindow or SceneGraph have a concept of 'color' (including alpha) and don't get rendered themselves. I think the way you're picturing it is the SceneGraph or SceneWindow is like it's own separate canvas, and if you fade the canvas you also fade everything drawn on that canvas. That's not really how it's structured. There's only one real 'canvas' in this implementation (the screen buffer) and the contents of all SceneWindows get rendered in layer order on top of each other.
When the view of a SceneWindow is being drawn to the screen, the engine loops through the associated SceneGraph's list of t2dSceneObjects (parent class to all the renderable stuff) and tells each one to render itself. As part of this, each object's color/alpha value gets set (which is done in t2dSceneObject's setBlendOptions method) based on that object's local blendColor variable.
What the implementation above does is add a new value to the SceneWindow, a global 'color modifier' that gets multiplied against the color value of every object within that SceneWindow as they get told to render themselves. All it does is hijack setBlendOptions to check and see if the current view (a.k.a. SceneWindow) has a global color modifier, and if so we apply it to each and every object as they get drawn to the screen.
Sorry if that was long-winded, but I figure being more descriptive about the rendering flow and SceneWindow/SceneGraph relationship might help some. :)
#9
Based off of this snippet:
Will I need to create a setBlendModifierColor() for SceneWindow as well, and toggle the blend modifier bool variable inside that function?
That's the part that's confusing me, how does that happen for that snippet to be able to use those variables?
07/09/2007 (4:29 pm)
No need to apologize, I'm grateful for your help. There's one part that's still confusing me, though: You said this:Quote:What the implementation above does is add a new value to the SceneWindow, a global 'color modifier' that gets multiplied against the color value of every object within that SceneWindow as they get told to render themselves. All it does is hijack setBlendOptions to check and see if the current view (a.k.a. SceneWindow) has a global color modifier, and if so we apply it to each and every object as they get drawn to the screen.
Based off of this snippet:
t2dSceneWindow* pSceneWindow = getSceneGraph()->getCurrentRenderWindow();
if (pSceneWindow && pSceneWindow->isBlendModifierActive())
{
ColorF modBlendColor = mBlendColour * pSceneWindow->getBlendModifierColor();
glColor4fv( (GLfloat*)&modBlendColor );
} else {
glColor4fv( (GLfloat*)&mBlendColour );
}Will I need to create a setBlendModifierColor() for SceneWindow as well, and toggle the blend modifier bool variable inside that function?
That's the part that's confusing me, how does that happen for that snippet to be able to use those variables?
#10
Here's the entire implementation, just to make it clear. I added a standard set of variable getter/setter ConsoleMethods, that's the bulk of the change really. The color string processing function is redundant and should be factored out since it's used elsewhere too but I didn't bother this time.
Here's the additions (v1.1.3, by the way):
t2dSceneWindow.h around line 80:
t2dSceneWindow.h around line 230:
t2dSceneWindow.cc around line 109 (amongst the other default values in the constructor) :
t2dSceneWindow.cc around line 1580 (near other consoleMethods such as setViewLimitOff):
t2dSceneObject.cc around line 7896 (after glBlendFunc is called):
(that last change shows the existing glColor4fv comment out, replaced by the rest).
I think this covers all the required changes. Then you should be able to call:
MySceneWindow.setBlendModifierActive();
MySceneWindow.setBlendModifierColor(1, 1, 1, 0);
which will make the entire scene transparent. Add in a schedule to interpolate the alpha over time and you've got your full scene cross-fade. :)
07/09/2007 (5:15 pm)
Yes, I should have posted all the bits and pieces, I glossed over that in the sentence above the code snippet:Quote:
Add a new ColorF variable to t2dSceneWindow called something like blendModifier and a method to fetch it.
Here's the entire implementation, just to make it clear. I added a standard set of variable getter/setter ConsoleMethods, that's the bulk of the change really. The color string processing function is redundant and should be factored out since it's used elsewhere too but I didn't bother this time.
Here's the additions (v1.1.3, by the way):
t2dSceneWindow.h around line 80:
bool mBlendModifierActive; ColorF mBlendModifierColor;
t2dSceneWindow.h around line 230:
void setBlendModifierActive( bool active) { mBlendModifierActive = active; };
bool isBlendModifierActive( void ) const { return mBlendModifierActive; };
ColorF getBlendModifierColor( void ) { return mBlendModifierColor; };
void setBlendModifierColor( const ColorF& blendModifierColor );
void setBlendModifierColorString( S32 argc, const char** argv );t2dSceneWindow.cc around line 109 (amongst the other default values in the constructor) :
mBlendModifierActive(false), mBlendModifierColor(ColorF(1.0f,1.0f,1.0f,1.0f)),
t2dSceneWindow.cc around line 1580 (near other consoleMethods such as setViewLimitOff):
ConsoleMethod(t2dSceneWindow, setBlendModifierActive, void, 2, 2, "Set Window blend modifier active.")
{
object->setBlendModifierActive(true);
}
ConsoleMethod(t2dSceneWindow, setBlendModifierInactive, void, 2, 2, "Set Window blend modifier inactive.")
{
object->setBlendModifierActive(false);
}
ConsoleMethod(t2dSceneWindow, getBlendModifierColor, const char*, 2, 2, "Get Window blend modifier Color.")
{
ColorF blendModifierColor = object->getBlendModifierColor();
// Create Returnable Buffer.
char* pBuffer = Con::getReturnBuffer(64);
// Format Buffer.
dSprintf(pBuffer, 64, "%f %f %f %f", blendModifierColor.red, blendModifierColor.green, blendModifierColor.blue, blendModifierColor.alpha );
// Return buffer.
return pBuffer;
}
ConsoleMethod(t2dSceneWindow, setBlendModifierColor, void, 3, 6, "(blend R / G / B / [A]) - Sets the Rendering Blend Color.")
{
object->setBlendModifierColorString(argc, argv);
}
ConsoleMethod(t2dSceneWindow, isBlendModifierActive, bool, 2, 2, "Is Window color blend modifier active.")
{
return object->isBlendModifierActive();
}
void t2dSceneWindow::setBlendModifierColorString( S32 argc, const char** argv )
{
// The colors.
F32 red;
F32 green;
F32 blue;
F32 alpha = 1.0f;
// Grab the element count.
U32 elementCount = t2dSceneObject::getStringElementCount(argv[2]);
// Space separated.
if (argc < 4)
{
// ("R G B [A]")
if ((elementCount == 3) || (elementCount == 4))
{
// Extract the color.
red = dAtof(t2dSceneObject::getStringElement(argv[2], 0));
green = dAtof(t2dSceneObject::getStringElement(argv[2], 1));
blue = dAtof(t2dSceneObject::getStringElement(argv[2], 2));
// Grab the alpha if it's there.
if (elementCount > 3)
alpha = dAtof(t2dSceneObject::getStringElement(argv[2], 3));
}
// Invalid.
else
{
Con::warnf("t2dSceneWindow::setBlendModifierColor() - Invalid Number of parameters!");
return;
}
}
// (R, G, B)
else if (argc >= 5)
{
red = dAtof(argv[2]);
green = dAtof(argv[3]);
blue = dAtof(argv[4]);
// Grab the alpha if it's there.
if (argc > 5)
alpha = dAtof(argv[5]);
}
// Invalid.
else
{
Con::warnf("t2dSceneWindow::setBlendModifierColor() - Invalid Number of parameters!");
return;
}
// Set Blend Color.
setBlendModifierColor(ColorF(red, green, blue, alpha));
}
void t2dSceneWindow::setBlendModifierColor( const ColorF& blendModifierColor )
{
mBlendModifierColor = blendModifierColor;
}t2dSceneObject.cc around line 7896 (after glBlendFunc is called):
t2dSceneWindow* pSceneWindow = getSceneGraph()->getCurrentRenderWindow();
if (pSceneWindow && pSceneWindow->isBlendModifierActive())
{
ColorF modBlendColor = mBlendColour * pSceneWindow->getBlendModifierColor();
glColor4fv( (GLfloat*)&modBlendColor );
} else
{
glColor4fv( (GLfloat*)&mBlendColour );
}
//glColor4fv( (GLfloat*)&mBlendColour );(that last change shows the existing glColor4fv comment out, replaced by the rest).
I think this covers all the required changes. Then you should be able to call:
MySceneWindow.setBlendModifierActive();
MySceneWindow.setBlendModifierColor(1, 1, 1, 0);
which will make the entire scene transparent. Add in a schedule to interpolate the alpha over time and you've got your full scene cross-fade. :)
#11
Worked like a charm. Tested just fine!
I'm also going to see if I can add this to the ParticleEffect class, since particles aren't affected by the blend. If I figure it out. I'll post it.
07/09/2007 (5:47 pm)
Thanks so much for that! I figured I had to do just a little more to it. Thanks for writing it out for me as well! :)Worked like a charm. Tested just fine!
I'm also going to see if I can add this to the ParticleEffect class, since particles aren't affected by the blend. If I figure it out. I'll post it.
#12
07/09/2007 (6:32 pm)
Yeah, particles are a different beast. ParticleEffects are really a collection of ParticleEmitters, and neither of them blend using setBlendOptions (lots of optimizations specific to the particle system I imagine) and the applications I've used this for so far had no lasting particle effects to get in the way so I never tackled it. I'd be very interested in your results. :)
#13
Great work --
07/09/2007 (8:52 pm)
Luke -- awesome little tweak there, think you'd be so inclined to post it as a resource on TDN?Great work --
#14
a) set fade-in time
b) set fade-out time
c) set the color of fade with small modification of code (or make this field scriptable)
pros:
a) you don't have to modify t2dSceneWindow and t2dSceneObject
b) performance is tend to be higher (if there is a lot of t2dSceneObject)
c) You don't need to set up schedule to interpolate alpha value
d) you can fade anything in scenewindow(include particles), even GUI objects.
cons:
a) only entire window fading
07/10/2007 (7:18 am)
Quote:That doesn't work for what I needActually, with GuiFadeinBitmapCtrl you can:
a) set fade-in time
b) set fade-out time
c) set the color of fade with small modification of code (or make this field scriptable)
pros:
a) you don't have to modify t2dSceneWindow and t2dSceneObject
b) performance is tend to be higher (if there is a lot of t2dSceneObject)
c) You don't need to set up schedule to interpolate alpha value
d) you can fade anything in scenewindow(include particles), even GUI objects.
cons:
a) only entire window fading
#15
You don't have to. Only what you need is push this gui control to the parent(scenewindow for example) at right moment.
07/10/2007 (7:21 am)
Quote:you can't give a indefinite wait time value
You don't have to. Only what you need is push this gui control to the parent(scenewindow for example) at right moment.
#16
07/10/2007 (9:41 am)
Ahh, I get you. Then once it finishs, pop the dialog. Thanks, Igor.
#17
If you're looking for fade-to-black (or whatever color) then there's no need to modify the engine source and guiFadeInBitmapCtrl or the full-scene StaticSprite fader are way easier and likely more performant.
@David Sure but I'm going to wait until 1.5 gets released; there's already a lot of outdated TDN reference info & code and I don't want to add to that. Since I'll be porting all my own custom engine mods from 1.1.3 to 1.5 anyway, I can write up step-by-step instructions and test them before unleashing them on the masses. It'll also give me an opportunity to write up some of the more interesting engine mods like stencil buffer support. (Talk about scene transition possibilities!)
07/10/2007 (10:07 am)
(For clarification for anyone stumbling on this thread in the distant future) The only reason to make engine modifications is if you're either trying to play with the tint of the entire scene all at once or need the objects in it to all fade to transparent (e.g. crossfading between scenes). If you're looking for fade-to-black (or whatever color) then there's no need to modify the engine source and guiFadeInBitmapCtrl or the full-scene StaticSprite fader are way easier and likely more performant.
@David Sure but I'm going to wait until 1.5 gets released; there's already a lot of outdated TDN reference info & code and I don't want to add to that. Since I'll be porting all my own custom engine mods from 1.1.3 to 1.5 anyway, I can write up step-by-step instructions and test them before unleashing them on the masses. It'll also give me an opportunity to write up some of the more interesting engine mods like stencil buffer support. (Talk about scene transition possibilities!)
Associate David Higgins
DPHCoders.com
Not really sure what your referring too ... your question makes it sound like this was a previous discussion in another thread.
The topic "Scene Fading" though, brings a question and an answer to mind...
Do you want to fade the entire scene?
Yes? K, here's how I would tackle it (first thought approach, untested), create a simple 128,128,128 filled 1x1 pixel image and import it into your project and call it "PixelImageMap" or whatever ... now, in your code for 'fading the levels' use one of the various different techniques found on the forums (there's a handful of really good ones, just search for "fade") ... but, instead of just fading the opacity, change the blend color ...
To accomplish this, create a simple t2dStaticSprite and size it to fit the screen, and use the PixelImageMap ... set the opacity to 100 so it's invisible and the blend color so that it's the color you want it to be when it starts to fade-in (Grey's work really well with Blending cause you can make them any color you want really, with the right adjustments). Now, as the object is fading in and the opacity is decreasing ... the object is starting to slowing darken the screen (or brighten if your color is bright, haha) ... as this occurs, you can optionally start changing the color to another one ...
Picture a 'fade from red to black' but with opacity change outs -- this could be used to simulate a 'death' overlay of red while the screen gradually goes to black --
Fairly nifty effect.