Dynamic snow accumulation using Sahara for Torque 3D 1.1
by Konrad Kiss · 09/11/2011 (3:55 pm) · 36 comments
This is a resource that allows you to dynamically change the accumulation of snow on mission objects depending on the weather. It requires Sahara for Torque 3D 1.1.
This resource is not functional by itself! You need Sahara for Torque 3D 1.1 to be able to follow this tutorial.
Of course, this resource is a shameless plug! :) But it's also a nice resource requested by Sahara licensees. It also has many pretty pictures and a video.
There's now a Torque 3D 1.1 Final compatible version along with a price drop to $34.95 for the Indie license. Check out the manual, the discussion thread and the website for more information about Sahara.
Let's get down to business then...
What I'm trying to achieve here is having warmer objects melt snow on them while it is calm in my scene, but gather some snow while it is snowing.
I chose the built-in Deathball Desert mission to get started.

First of all, I changed the environment and the terrain to a winter theme, so my demo object - the Cheetah - would fit the surroundings better.

I already had Sahara installed, so I started out with creating a new material that I would be able to use as a basis for other snowy materials:
Replace that snowy texture with yours, of course.
Then I made every material that I wanted to have snow on them be descended from this material. This was useful, because this way I only had to set up Sahara's accu* parameters on a single Material. Ie.:

Now I had all my objects covered in snow. I created a new client side script file, scripts/client/saharaSnow.cs and added the following (see the code for comments):
The above pretty much handles everything we need. It schedules a change on all materials that are descended from our SnowyMaterial and it also updates the dynamically created Snowfall precipitation object to reflect the strength of the snowstorm. It also takes care of randomizing the weather by changing it at least once every minute. The "weather" being the $isSnowing boolean global - either true or false.
I made sure this file is used by exec'ing it in scripts/client/init.cs in initClient() just after the loadMaterials call:
To make it start snowing, call manageSnow(); once your mission has loaded.

Finally, here is a quick time-lapse video of the resource in action on the Cheetah:
Thanks for reading through. As always, comments are much appreciated.
--Konrad
@konradkiss
KonradKiss @ GitHub
konradkiss.com
This resource is not functional by itself! You need Sahara for Torque 3D 1.1 to be able to follow this tutorial.
Of course, this resource is a shameless plug! :) But it's also a nice resource requested by Sahara licensees. It also has many pretty pictures and a video.
There's now a Torque 3D 1.1 Final compatible version along with a price drop to $34.95 for the Indie license. Check out the manual, the discussion thread and the website for more information about Sahara.
Let's get down to business then...
What I'm trying to achieve here is having warmer objects melt snow on them while it is calm in my scene, but gather some snow while it is snowing.
I chose the built-in Deathball Desert mission to get started.

First of all, I changed the environment and the terrain to a winter theme, so my demo object - the Cheetah - would fit the surroundings better.

I already had Sahara installed, so I started out with creating a new material that I would be able to use as a basis for other snowy materials:
singleton Material(SnowyMaterial)
{
superClass = "SnowyMaterial";
accuMap[0] = "art/terrains/winter/Snow_05.jpg";
accuStrength[0] = "0.862745";
accuCoverage[0] = "1.56863";
accuSpecular[0] = "2";
materialTag0 = "Vegetation";
};Replace that snowy texture with yours, of course.
Then I made every material that I wanted to have snow on them be descended from this material. This was useful, because this way I only had to set up Sahara's accu* parameters on a single Material. Ie.:
singleton Material(Cheetah_Body_Cheetah : SnowyMaterial) ...

Now I had all my objects covered in snow. I created a new client side script file, scripts/client/saharaSnow.cs and added the following (see the code for comments):
/// A global that controls snowing and snow accumulation
$isSnowing = false;
/// Material method that adds a bit more snow
function SnowyMaterial::moreSnow(%this)
{
// a bit more snow
%this.accuStrength = %this.accuStrength + 0.01;
%this.reload();
}
/// Material method that melts some snow
function SnowyMaterial::lessSnow(%this)
{
// a bit less snow
%this.accuStrength = %this.accuStrength - 0.01;
%this.reload();
}
/// SimGroup method that is called every %delay msecs to
/// modify snow accumulation strength on all affected surfaces.
function SnowGroup::manageSnow(%this, %delay)
{
// delay defaults to 1 second (1000 msecs)
if (%delay $= "") %delay = 1000;
// handle our "Snowfall" snow precipitation
// use Snowfall.snowPerc to keep track of the actual percentage
// of snow that we see.
if ($isSnowing) {
Snowfall.snowPerc = Snowfall.snowPerc + 10;
if (Snowfall.snowPerc>100) Snowfall.snowPerc = 100;
} else {
Snowfall.snowPerc = Snowfall.snowPerc - 10;
if (Snowfall.snowPerc<1) Snowfall.snowPerc = 1;
}
Snowfall.setPercentage(Snowfall.snowPerc/100);
// iterate through all members of the SnowGroup and make them gather
// more or less snow depending on the value of the $isSnowing global var
for ( %i = 0; %i < %this.getCount(); %i++ )
{
%obj = %this.getObject( %i );
if ($isSnowing) {
if (%obj.accuStrength<0.86) %obj.moreSnow();
} else {
if (%obj.accuStrength>0.56) %obj.lessSnow();
}
}
// schedule this method to run again
%this.snowSchedule = %this.schedule(%delay, "manageSnow");
}
/// A convenience function that initializes and starts the snowing
function manageSnow(%delay)
{
// create a snow precipitation in the mission but never save with the mission
if (!isObject(Snowfall)) {
new Precipitation(Snowfall) {
numDrops = "8092";
boxWidth = "100";
boxHeight = "100";
dropSize = "0.1";
animateSplashes = "0";
doCollision = "0";
minSpeed = "0.2";
maxSpeed = "0.6";
minMass = "6";
maxMass = "10";
useTurbulence = "0";
maxTurbulence = "0.01";
turbulenceSpeed = "0.02";
dataBlock = "HeavySnow";
position = "0 0 0";
rotation = "1 0 0 0";
scale = "1 1 1";
canSave = "0";
snowPerc = 100;
canSaveDynamicFields = "0";
};
MissionGroup.add(Snowfall);
}
// create a SnowGroup simgroup or cancel any previous schedules
if (!isObject(SnowGroup)) {
new SimGroup(SnowGroup);
} else if (SnowGroup.snowSchedule !$= "")
cancel(SnowGroup.snowSchedule);
// add the right materials to the SnowGroup group
for(%i = 0; %i < RootGroup.getCount(); %i++)
if( RootGroup.getObject(%i).getSuperClassNamespace() $= "SnowyMaterial" )
SnowGroup.add(RootGroup.getObject(%i));
// start "managing" snow - fire SnowGroup.manageSnow every <%delay> milliseconds
SnowGroup.manageSnow(%delay);
randomizeWeather();
}
/// Changes weather at least once every minute
function randomizeWeather()
{
$isSnowing = !$isSnowing;
schedule(getRandom(60000), 0, "randomizeWeather");
}The above pretty much handles everything we need. It schedules a change on all materials that are descended from our SnowyMaterial and it also updates the dynamically created Snowfall precipitation object to reflect the strength of the snowstorm. It also takes care of randomizing the weather by changing it at least once every minute. The "weather" being the $isSnowing boolean global - either true or false.
I made sure this file is used by exec'ing it in scripts/client/init.cs in initClient() just after the loadMaterials call:
// >>>
exec("scripts/client/saharaSnow.cs");
// <<<To make it start snowing, call manageSnow(); once your mission has loaded.

Finally, here is a quick time-lapse video of the resource in action on the Cheetah:
Thanks for reading through. As always, comments are much appreciated.
--Konrad
@konradkiss
KonradKiss @ GitHub
konradkiss.com
About the author
http://about.me/konrad.kiss
#2
09/11/2011 (4:24 pm)
Nice work Konrad. Must pickup the latest Sahara release from your site.
#3
09/11/2011 (4:27 pm)
Thanks! Hope you'll be able to make use of it! :)
#4
09/11/2011 (4:35 pm)
winter coming soon :) nice resource.
#5
09/11/2011 (4:36 pm)
Lol, yes, winter is coming! :) Thanks Daniel.
#6
09/11/2011 (4:37 pm)
Now that is some cool stuff right there.
#7
09/11/2011 (4:41 pm)
Konrad - yes most definately! Well in time for a Christmas snow theme :) Could also be used for ash/sand/dust. Many uses.
#9
09/11/2011 (4:51 pm)
Nice work Konrad. Sahara is the 'must have' module for my projects. The adaptability of your accumulation system is amazing!
#10
09/11/2011 (5:06 pm)
That's very cool. Definitely a tempting purchase!
#11
09/11/2011 (5:19 pm)
Looks good, I will make sure I test it out.
#12
Incidentally, is the Sahara 1.1F different from the 1.1B3 version? Do I need to download the update?
edit: just checked my email found the answer :P
09/11/2011 (5:28 pm)
Smart stuff, Konrad. :)Incidentally, is the Sahara 1.1F different from the 1.1B3 version? Do I need to download the update?
edit: just checked my email found the answer :P
#13
*I look forward to coming home and tamper with this update ;)
09/11/2011 (11:27 pm)
Cheers Konrad, awesome as always!*I look forward to coming home and tamper with this update ;)
#14
09/12/2011 (1:31 am)
Awesome, it's buy today, thank you for this great work!
#15
@Steve: no changes at all, just created new patches that work with 1.1F and made sure that everything was in order.
@Jean-louis: thanks for picking it up! Hope you will like it! :)
09/12/2011 (1:48 am)
Wow, guys, thank you for the awesome comments! :)@Steve: no changes at all, just created new patches that work with 1.1F and made sure that everything was in order.
@Jean-louis: thanks for picking it up! Hope you will like it! :)
#16
09/12/2011 (1:52 am)
I have been waiting eagerly for this thanks Konrad :-D
#17
09/12/2011 (3:35 am)
Hope the wait was worth it, thanks David! :)
#18
09/12/2011 (7:39 am)
Nice work Konrad :)
#19
Thanks :)
09/12/2011 (10:55 am)
Nice work Konrad. The vid gives me some new ideas I could try in my levels.Thanks :)
#20
09/12/2011 (6:06 pm)
Sahara, get it now, thank me later. 
Associate Konrad Kiss
Bitgap Games