Game Development Community

Enabling shader when sun is visible (ala light flare)

by Felix Willebrand Westin · in Torque 3D Professional · 07/11/2014 (1:57 pm) · 13 replies

I've written a post process shader that adds screen dirt/bokeh on top of the scene based on the position of the sun. It adds it both around the sun and at the edges opposite of the sun's position.
I ran into some problems however when I tried to disable it when the sun is not visible, so I was wondering if anyone know if there'd be a way of writing a script that does exactly that?

Here's some screenshots to show how it looks/the problem:

puu.sh/a781O.jpg

About the author

Hobbyist turned game dev. Worked at DICE for a short while, now working on personal stuff and Dota 2 things.


#1
07/11/2014 (2:35 pm)
Maybe raycast toward the sun and if you find anything disable the effect? Or use triggers? Or a combination of the two - trigger where you usually go from outdoor to indoor and onLeaveTrigger() do the raycast - that way when you're indoors it will hit the building and outdoors it will not, but you're not scheduling raycasts all the time....
#2
07/11/2014 (11:56 pm)
Just a heads up, I got this working.

Name your scattersky "sunlight", add a boolean called inSunlight and drop this function into Player.cpp.

void Player::updateSunlight()
{
	if(mScatterSky == NULL)
	{
		ScatterSky* pSky = dynamic_cast<ScatterSky*>(Sim::findObject("Sunlight"));
		if(pSky)
			mScatterSky = pSky;
		else
			return;
	}
	else
	{
		VectorF sunDir;
		MatrixF eyeMat;
		getEyeTransform(&eyeMat);

		// Build the light direction from the azimuth and elevation.
		F32 yaw = mDegToRad(mClampF(mScatterSky->getAzimuth(),0,359));
		F32 pitch = mDegToRad(mClampF(mScatterSky->getElevation(),-360,+360));
		MathUtils::getVectorFromAngles(sunDir, yaw, pitch);
		sunDir.normalize();

		RayInfo ri;
		Point3F endPos = eyeMat.getPosition() + (sunDir * 1000);
		if(gClientContainer.castRay(eyeMat.getPosition(), endPos, STATIC_COLLISION_TYPEMASK, &ri))
      {
         //Obscured by shadow
			if(inSunlight)
			{
				inSunlight = false;
				Con::executef(this,"onLeaveSunlight");
			}
      }
		else
		{
			if(!inSunlight)
			{
				inSunlight = true;
				Con::executef(this,"onEnterSunlight");
			}
		}
	}


	
}

Activate it within processTick in a isClientObject conditional block.

Also in your player.cs file add...

function Player::onEnterSunlight(%this, %obj)
{
	sunBokehPostFX.enable();
}

function Player::onLeaveSunlight(%this, %obj)
{
	sunBokehPostFX.disable();
}
#3
07/12/2014 (1:37 am)
For bonus points, fade it in/out ;). I haven't anything more constructive to add, just wanted to say that looks damn pretty.
#4
07/12/2014 (2:27 am)
The problem with that code is that a raycast simply isn't accurate enough. Even if it is set to hitting all visible geometry it won't take alpha testing into account (didn't test this but I'm guessing).

What Daniel said about fading set me in the right direction however!
In lightFlareData there is a variable that keeps track of how bright the flare currently is based on how occluded it is. What I did was create a new variable based on that but tweaked to my liking and then simply write this value to a post process shader constant called sunVisibility which smoothly fades based on the flare size set in the scatterSky object (bigger flare = larger fade radius, just like the flare opacity itself).

Currently this works just like I want it to. The only problem is I use
ScatterSky* pSky = dynamic_cast<ScatterSky*>(Sim::findObject("Sunlight"));
(from Jlea's post above) to get the ScatterSky object in postEffect.cpp, which isn't pretty and requires the ScatterSky object to be named "Sunlight".

If anyone can shed some light (heheheheheh) on a less hacky way to do this I can collect all the stuff and upload the shader/code for anyone that wants it :)
#5
07/12/2014 (2:38 am)
You could always read the object name from a console variable (Con::getStringVariable, maybe?), and if it's empty then don't bother. Then just stick the object name in a global variable somewhere in your scripts.

EDIT: And upload the code? You're too generous!
#6
07/12/2014 (4:57 am)
Also here is a video of it in motion and a picture showing what just the final effect looks like:

puu.sh/a7XY0.jpg

#7
07/12/2014 (5:16 am)
That looks pretty neat,
havent been much around lately but comin back and seein what you ppl did
really nice.

#8
07/12/2014 (5:29 am)
Just out of curiosity, what are you using for your trees? Are they handmade?
#9
07/12/2014 (7:33 am)
Oh, very nice. And no, the raycast doesn't care about alpha at all. Great way to take it to source, too - I was trying to give a simple, script-based hack....

You guys are doing some really cool stuff here. Keep it up!
#10
07/12/2014 (8:03 am)
@Daniel The trees I just got off the web. Plan to replace them with handmade ones soon though!
#11
07/13/2014 (6:16 am)
GRRR! That is what I was doing wrong.... I did not take into account the sun flare 'intensity' and really naming the scattersky 'sunlight' is not that big of a deal.

Besides, you can use that object name for other 'flare based' effects since it is already set.

Nice job Felix. You guys are REALLY doing some great stuff with this project.

Ron
#12
07/13/2014 (7:43 am)
I agree keep up the work!!
#13
07/13/2014 (8:19 am)
Thanks guys, I'm glad you like it!
I added a resource for implementing this if anyone is interested in doing so:
http://www.garagegames.com/community/resources/view/22785